8000 Merge pull request #113 from wookay/fix_header_corruption · JuliaWeb/HttpServer.jl@d7ad86e · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Sep 4, 2019. It is now read-only.

Commit d7ad86e

Browse files
authored
Merge pull request #113 from wookay/fix_header_corruption
Fix corruption in header parsing with Julia 0.6
2 parents 70e309b + 5030041 commit d7ad86e

File tree

4 files changed

+41
-14
lines changed

4 files changed

+41
-14
lines changed

REQUIRE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ julia 0.4
22
HttpCommon
33
HttpParser
44
MbedTLS
5-
Compat 0.7.16
5+
Compat 0.17.0

src/HttpServer.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ The methods `is_websocket_handshake` and `handle` will be called if `Server.
121121
sockets` is populated. Concrete types of `WebSocketInterface` are required
122122
to define these methods.
123123
"""
124-
abstract WebSocketInterface
124+
@compat abstract type WebSocketInterface end
125125

126126
""" `is_websocket_handshake` should determine if `req` is a valid websocket
127127
upgrade request.

src/RequestParser.jl

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,24 +48,37 @@ end
4848
# this: https://github.com/joyent/node/blob/master/src/node_http_parser.cc#L207
4949

5050
function on_header_field(parser, at, len)
51-
r = pd(parser).request
51+
par = pd(parser)
52+
if par.num_fields == par.num_values
53+
par.num_fields += 1
54+
push!(par.vec_fields, "")
55+
end
5256
header = unsafe_string(convert(Ptr{UInt8}, at))
5357
header_field = header[1:len]
54-
r.headers["current_header"] = header_field
58+
par.vec_fields[par.num_fields] = string(par.vec_fields[par.num_fields], header_field)
5559
return 0
5660
end
5761

5862
function on_header_value(parser, at, len)
59-
r = pd(parser).request
63+
par = pd(parser)
64+
if par.num_values != par.num_fields
65+
par.num_values += 1
66+
push!(par.vec_values, "")
67+
end
6068
s = unsafe_string(convert(Ptr{UInt8}, at), Int(len))
61-
r.headers[r.headers["current_header"]] = s
62-
r.headers["current_header"] = ""
63-
# delete!(r.headers, "current_header")
69+
header_value = s[1:len]
70+
par.vec_values[par.num_values] = string(par.vec_values[par.num_values], header_value)
6471
return 0
6572
end
6673

6774
function on_headers_complete(parser)
68-
r = pd(parser).request
75+
par = pd(parser)
76+
r = par.request
77+
merge!(r.headers, Dict(zip(par.vec_fields, par.vec_values)))
78+
par.num_fields = 0
79+
par.num_values = 0
80+
empty!(par.vec_fields)
81+
empty!(par.vec_values)
6982
p = unsafe_load(parser)
7083
# get first two bits of p.type_and_flags
7184
ptype = p.type_and_flags & 0x03
@@ -93,10 +106,6 @@ function on_message_complete(parser)
93106
r = state.request
94107
# r.data = takebuf_array(state.data)
95108

96-
# delete the temporary header key
97-
# delete!(r.headers, "current_header")
98-
pop!(r.headers, "current_header", nothing)
99-
100109
# Get the `parser.id` from the C pointer `parser`.
101110
# Retrieve our callback function from the global Dict.
102111
# Call it with the completed `Request`
@@ -112,8 +121,12 @@ default_complete_cb(r::Request) = nothing
112121
type RequestParserState
113122
request::Request
114123
complete_cb::Function
124+
num_fields::Int
125+
num_values::Int
126+
vec_fields::Vector{String}
127+
vec_values::Vector{String}
115128
end
116-
RequestParserState() = RequestParserState(Request(),default_complete_cb)
129+
RequestParserState() = RequestParserState(Request(),default_complete_cb,0,0,Vector{String}(),Vector{String}())
117130

118131
pd(p::Ptr{Parser}) = (unsafe_load(p).data)::RequestParserState
119132

test/runtests.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,18 @@ facts("HttpServer runs") do
136136
@fact text(ret) --> "hello"
137137
close(server)
138138
end
139+
140+
# Issue #111
141+
context("Parse HTTP headers") do
142+
http = HttpHandler() do req::Request, res::Response
143+
Response(req.headers["Content-Type"])
144+
end
145+
server = Server(http)
146+
@async run(server, 8000)
147+
sleep(1.0)
148+
149+
ret = Requests.post("http://localhost:8000/", data = "", headers = Dict("Content-Type" => "text/plain"))
150+
@fact text(ret) --> "text/plain"
151+
close(server)
152+
end
139153
end

0 commit comments

Comments
 (0)
0