Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/Streams.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ mutable struct Stream{M <: Message, S <: IO} <: IO
readchunked::Bool
warn_not_to_read_one_byte_at_a_time::Bool
ntoread::Int
nwritten::Int
nread::Int # number of read body bytes
nwritten::Int # number of written body bytes
end

"""
Expand All @@ -36,7 +37,7 @@ Creates a `HTTP.Stream` that wraps an existing `IO` stream.
for reuse. If a complete response has not been received, `closeread` throws
`EOFError`.
"""
Stream(r::M, io::S) where {M, S} = Stream{M, S}(r, io, false, false, true, 0, 0)
Stream(r::M, io::S) where {M, S} = Stream{M, S}(r, io, false, false, true, 0, 0, 0)

Messages.header(http::Stream, a...) = header(http.message, a...)
setstatus(http::Stream, status) = (http.message.response.status = status)
Expand Down Expand Up @@ -208,6 +209,9 @@ end

@inline function update_ntoread(http::Stream, n)

# Record number of read bytes for logging
http.nread += n

if http.ntoread != unknown_length
http.ntoread -= n
end
Expand Down
4 changes: 3 additions & 1 deletion src/access_log.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The following variables are currently supported:
- `$time_local`: local time in Common Log Format
- `$status`: response status code
- `$body_bytes_sent`: number of bytes in response body
- `$body_bytes_received`: number of bytes read from client

## Examples
```julia
Expand All @@ -34,7 +35,6 @@ end

function logfmt_parser(s)
s = String(s)
vars = Symbol[]
ex = Expr(:call, :print, :io)
i = 1
while i <= lastindex(s)
Expand Down Expand Up @@ -101,6 +101,8 @@ function symbol_mapping(s::Symbol)
:(http.message.response.status)
elseif s === :body_bytes_sent
return :(http.nwritten)
elseif s === :body_bytes_received
return :(http.nread)
else
error("unknown variable in logfmt: $s")
end
Expand Down
20 changes: 14 additions & 6 deletions test/server.jl
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ end # @testset
close(http.stream)
return
end
if http.message.method == "POST" && http.message.target == "/post"
read(http, String)
HTTP.setstatus(http, 200)
HTTP.startwrite(http)
return
end
HTTP.setstatus(http, 200)
HTTP.setheader(http, "Content-Type" => "text/plain")
msg = "hello, world"
Expand Down Expand Up @@ -270,19 +276,21 @@ end # @testset
@test occursin(r"^127.0.0.1 - - \[(\d{2})/.*/(\d{4}):\d{2}:\d{2}:\d{2}.*\] \"HEAD / HTTP/1.1\" 200 0 \"-\" \"HTTP\.jl/.*\"$", logs[4].message)

# Custom log format
fmt = logfmt"$http_accept $sent_http_content_type $request $request_method $request_uri $remote_addr $remote_port $remote_user $server_protocol $time_iso8601 $time_local $status $body_bytes_sent"
fmt = logfmt"$http_accept $sent_http_content_type $request $request_method $request_uri $remote_addr $remote_port $remote_user $server_protocol $time_iso8601 $time_local $status $body_bytes_sent $body_bytes_received"
logs = with_testserver(fmt) do
HTTP.get("http://localhost:32612", ["Accept" => "application/json"])
HTTP.get("http://localhost:32612/index.html")
HTTP.get("http://localhost:32612/index.html?a=b")
HTTP.head("http://localhost:32612")
HTTP.post("http://localhost:32612/post", [], "hello, world")
end
@test length(logs) == 4
@test length(logs) == 5
@test all(x -> x.group === :access, logs)
@test occursin(r"^application/json text/plain GET / HTTP/1\.1 GET / 127\.0\.0\.1 \d+ - HTTP/1\.1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \d+/.*/\d{4}:\d{2}:\d{2}:\d{2}.* 200 12$", logs[1].message)
@test occursin(r"^\*/\* text/plain GET /index\.html HTTP/1\.1 GET /index\.html 127\.0\.0\.1 \d+ - HTTP/1\.1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \d+/.*/\d{4}:\d{2}:\d{2}:\d{2}.* 200 12$", logs[2].message)
@test occursin(r"^\*/\* text/plain GET /index\.html\?a=b HTTP/1\.1 GET /index\.html\?a=b 127\.0\.0\.1 \d+ - HTTP/1\.1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \d+/.*/\d{4}:\d{2}:\d{2}:\d{2}.* 200 12$", logs[3].message)
@test occursin(r"^\*/\* text/plain HEAD / HTTP/1\.1 HEAD / 127\.0\.0\.1 \d+ - HTTP/1\.1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \d+/.*/\d{4}:\d{2}:\d{2}:\d{2}.* 200 0$", logs[4].message)
@test occursin(r"^application/json text/plain GET / HTTP/1\.1 GET / 127\.0\.0\.1 \d+ - HTTP/1\.1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \d+/.*/\d{4}:\d{2}:\d{2}:\d{2}.* 200 12 0$", logs[1].message)
@test occursin(r"^\*/\* text/plain GET /index\.html HTTP/1\.1 GET /index\.html 127\.0\.0\.1 \d+ - HTTP/1\.1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \d+/.*/\d{4}:\d{2}:\d{2}:\d{2}.* 200 12 0$", logs[2].message)
@test occursin(r"^\*/\* text/plain GET /index\.html\?a=b HTTP/1\.1 GET /index\.html\?a=b 127\.0\.0\.1 \d+ - HTTP/1\.1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \d+/.*/\d{4}:\d{2}:\d{2}:\d{2}.* 200 12 0$", logs[3].message)
@test occursin(r"^\*/\* text/plain HEAD / HTTP/1\.1 HEAD / 127\.0\.0\.1 \d+ - HTTP/1\.1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \d+/.*/\d{4}:\d{2}:\d{2}:\d{2}.* 200 0 0$", logs[4].message)
@test occursin(r"^\*/\* - POST /post HTTP/1\.1 POST /post 127\.0\.0\.1 \d+ - HTTP/1\.1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.* \d+/.*/\d{4}:\d{2}:\d{2}:\d{2}.* 200 0 12$", logs[5].message)
end

end # module