2 require 'test/test_helper'
7 class HttpParserNgTest < Test::Unit::TestCase
10 @parser = HttpParser.new
13 def test_identity_step_headers
15 str = "PUT / HTTP/1.1\r\n"
16 assert ! @parser.headers(req, str)
17 str << "Content-Length: 123\r\n"
18 assert ! @parser.headers(req, str)
20 assert_equal req.object_id, @parser.headers(req, str).object_id
21 assert_equal '123', req['CONTENT_LENGTH']
22 assert_equal 0, str.size
23 assert ! @parser.keepalive?
26 def test_identity_oneshot_header
28 str = "PUT / HTTP/1.1\r\nContent-Length: 123\r\n\r\n"
29 assert_equal req.object_id, @parser.headers(req, str).object_id
30 assert_equal '123', req['CONTENT_LENGTH']
31 assert_equal 0, str.size
32 assert ! @parser.keepalive?
35 def test_identity_oneshot_header_with_body
36 body = ('a' * 123).freeze
38 str = "PUT / HTTP/1.1\r\n" \
39 "Content-Length: #{body.length}\r\n" \
41 assert_equal req.object_id, @parser.headers(req, str).object_id
42 assert_equal '123', req['CONTENT_LENGTH']
43 assert_equal 123, str.size
44 assert_equal body, str
46 assert_nil @parser.filter_body(tmp, str)
47 assert_equal 0, str.size
48 assert_equal tmp, body
49 assert_equal "", @parser.filter_body(tmp, str)
50 assert ! @parser.keepalive?
53 def test_identity_oneshot_header_with_body_partial
54 str = "PUT / HTTP/1.1\r\nContent-Length: 123\r\n\r\na"
55 assert_equal Hash, @parser.headers({}, str).class
56 assert_equal 1, str.size
59 assert_nil @parser.filter_body(tmp, str)
63 rv = @parser.filter_body(tmp, str)
64 assert_equal 122, tmp.size
67 assert_equal str.object_id, @parser.filter_body(tmp, str).object_id
68 assert ! @parser.keepalive?
71 def test_identity_oneshot_header_with_body_slop
72 str = "PUT / HTTP/1.1\r\nContent-Length: 1\r\n\r\naG"
73 assert_equal Hash, @parser.headers({}, str).class
74 assert_equal 2, str.size
75 assert_equal 'aG', str
77 assert_nil @parser.filter_body(tmp, str)
79 assert_equal "G", @parser.filter_body(tmp, str)
80 assert_equal 1, tmp.size
82 assert ! @parser.keepalive?
86 str = "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
88 assert_equal req, @parser.headers(req, str)
89 assert_equal 0, str.size
91 assert_nil @parser.filter_body(tmp, "6")
92 assert_equal 0, tmp.size
93 assert_nil @parser.filter_body(tmp, rv = "\r\n")
94 assert_equal 0, rv.size
95 assert_equal 0, tmp.size
97 assert_nil @parser.filter_body(tmp, "..")
98 assert_equal "..", tmp
99 assert_nil @parser.filter_body(tmp, "abcd\r\n0\r\n")
100 assert_equal "abcd", tmp
102 assert_equal rv.object_id, @parser.filter_body(tmp, rv).object_id
103 assert_equal "PUT", rv
104 assert ! @parser.keepalive?
108 str = "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
110 assert_equal req, @parser.headers(req, str)
111 assert_equal 0, str.size
113 assert_nil @parser.filter_body(tmp, "6")
114 assert_equal 0, tmp.size
115 assert_nil @parser.filter_body(tmp, rv = "\r\n")
117 assert_equal 0, tmp.size
119 assert_nil @parser.filter_body(tmp, "..")
120 assert_equal 2, tmp.size
121 assert_equal "..", tmp
122 assert_nil @parser.filter_body(tmp, "abcd\r\n1")
123 assert_equal "abcd", tmp
124 assert_nil @parser.filter_body(tmp, "\r")
126 assert_nil @parser.filter_body(tmp, "\n")
128 assert_nil @parser.filter_body(tmp, "z")
129 assert_equal "z", tmp
130 assert_nil @parser.filter_body(tmp, "\r\n")
131 assert_nil @parser.filter_body(tmp, "0")
132 assert_nil @parser.filter_body(tmp, "\r")
133 rv = @parser.filter_body(tmp, buf = "\nGET")
134 assert_equal "GET", rv
135 assert_equal buf.object_id, rv.object_id
136 assert ! @parser.keepalive?
140 str = "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n" \
143 assert_equal req, @parser.headers(req, str)
145 assert_nil @parser.filter_body(tmp, str)
148 assert_nil @parser.filter_body(tmp, str)
151 assert_nil @parser.filter_body(tmp, str)
153 assert ! @parser.body_eof?
154 assert_equal "", @parser.filter_body(tmp, "\r\n0\r\n")
155 assert @parser.body_eof?
156 assert ! @parser.keepalive?
159 def test_two_chunks_oneshot
160 str = "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n" \
161 "1\r\na\r\n2\r\n..\r\n0\r\n"
163 assert_equal req, @parser.headers(req, str)
165 assert_nil @parser.filter_body(tmp, str)
166 assert_equal 'a..', tmp
167 rv = @parser.filter_body(tmp, str)
168 assert_equal rv.object_id, str.object_id
169 assert ! @parser.keepalive?
173 str = "PUT / HTTP/1.1\r\n" \
174 "Trailer: Content-MD5\r\n" \
175 "transfer-Encoding: chunked\r\n\r\n" \
176 "1\r\na\r\n2\r\n..\r\n0\r\n"
178 assert_equal req, @parser.headers(req, str)
179 assert_equal 'Content-MD5', req['HTTP_TRAILER']
180 assert_nil req['HTTP_CONTENT_MD5']
182 assert_nil @parser.filter_body(tmp, str)
183 assert_equal 'a..', tmp
184 md5_b64 = [ Digest::MD5.digest(tmp) ].pack('m').strip.freeze
185 rv = @parser.filter_body(tmp, str)
186 assert_equal rv.object_id, str.object_id
188 md5_hdr = "Content-MD5: #{md5_b64}\r\n".freeze
190 assert_nil @parser.trailers(req, str)
191 assert_equal md5_b64, req['HTTP_CONTENT_MD5']
192 assert_equal "CONTENT_MD5: #{md5_b64}\r\n", str
193 assert_nil @parser.trailers(req, str << "\r")
194 assert_equal req, @parser.trailers(req, str << "\nGET / ")
195 assert_equal "GET / ", str
196 assert ! @parser.keepalive?
200 str = "PUT / HTTP/1.1\r\n" \
201 "transfer-Encoding: chunked\r\n\r\n" \
202 "#{HttpParser::CHUNK_MAX.to_s(16)}\r\na\r\n2\r\n..\r\n0\r\n"
204 assert_equal req, @parser.headers(req, str)
205 assert_nil @parser.content_length
206 assert_nothing_raised { @parser.filter_body('', str) }
207 assert ! @parser.keepalive?
211 n = HttpParser::LENGTH_MAX
212 str = "PUT / HTTP/1.1\r\nContent-Length: #{n}\r\n\r\n"
214 assert_nothing_raised { @parser.headers(req, str) }
215 assert_equal n, req['CONTENT_LENGTH'].to_i
216 assert ! @parser.keepalive?
219 def test_overflow_chunk
220 n = HttpParser::CHUNK_MAX + 1
221 str = "PUT / HTTP/1.1\r\n" \
222 "transfer-Encoding: chunked\r\n\r\n" \
223 "#{n.to_s(16)}\r\na\r\n2\r\n..\r\n0\r\n"
225 assert_equal req, @parser.headers(req, str)
226 assert_nil @parser.content_length
227 assert_raise(HttpParserError) { @parser.filter_body('', str) }
228 assert ! @parser.keepalive?
231 def test_overflow_content_length
232 n = HttpParser::LENGTH_MAX + 1
233 str = "PUT / HTTP/1.1\r\nContent-Length: #{n}\r\n\r\n"
234 assert_raise(HttpParserError) { @parser.headers({}, str) }
235 assert ! @parser.keepalive?
239 str = "PUT / HTTP/1.1\r\n" \
240 "transfer-Encoding: chunked\r\n\r\n" \
241 "#zzz\r\na\r\n2\r\n..\r\n0\r\n"
243 assert_equal req, @parser.headers(req, str)
244 assert_nil @parser.content_length
245 assert_raise(HttpParserError) { @parser.filter_body('', str) }
246 assert ! @parser.keepalive?
249 def test_bad_content_length
250 str = "PUT / HTTP/1.1\r\nContent-Length: 7ff\r\n\r\n"
251 assert_raise(HttpParserError) { @parser.headers({}, str) }
252 assert ! @parser.keepalive?
255 def test_bad_trailers
256 str = "PUT / HTTP/1.1\r\n" \
257 "Trailer: Transfer-Encoding\r\n" \
258 "transfer-Encoding: chunked\r\n\r\n" \
259 "1\r\na\r\n2\r\n..\r\n0\r\n"
261 assert_equal req, @parser.headers(req, str)
262 assert_equal 'Transfer-Encoding', req['HTTP_TRAILER']
264 assert_nil @parser.filter_body(tmp, str)
265 assert_equal 'a..', tmp
267 str << "Transfer-Encoding: identity\r\n\r\n"
268 assert_raise(HttpParserError) { @parser.trailers(req, str) }
269 assert ! @parser.keepalive?
272 def test_repeat_headers
273 str = "PUT / HTTP/1.1\r\n" \
274 "Trailer: Content-MD5\r\n" \
275 "Trailer: Content-SHA1\r\n" \
276 "transfer-Encoding: chunked\r\n\r\n" \
277 "1\r\na\r\n2\r\n..\r\n0\r\n"
279 assert_equal req, @parser.headers(req, str)
280 assert_equal 'Content-MD5,Content-SHA1', req['HTTP_TRAILER']
281 assert ! @parser.keepalive?
284 def test_parse_simple_request
285 parser = HttpParser.new
287 http = "GET /read-rfc1945-if-you-dont-believe-me\r\n"
288 assert_equal req, parser.headers(req, http)
289 assert_equal '', http
291 "SERVER_NAME"=>"localhost",
292 "rack.url_scheme"=>"http",
293 "REQUEST_PATH"=>"/read-rfc1945-if-you-dont-believe-me",
294 "PATH_INFO"=>"/read-rfc1945-if-you-dont-believe-me",
295 "REQUEST_URI"=>"/read-rfc1945-if-you-dont-believe-me",
297 "SERVER_PROTOCOL"=>"HTTP/1.1", # FIXME
298 "REQUEST_METHOD"=>"GET",
301 assert_equal expect, req