1 # -*- encoding: binary -*-
9 class TestSession < Test::Unit::TestCase
11 @s, @c = UNIXSocket.pair
14 def test_http_status_only_pipelined
15 resp = "HTTP/1.1 404 Not Found\r\n\r\n" \
16 "HTTP/1.1 404 Not Found\r\n\r\n"
23 @response = Kcar::Response.new(@c)
24 status, headers, body = @response.rack
25 assert_equal status, "404 Not Found"
26 assert_equal({}, headers)
28 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
30 assert @response.parser.keepalive?
31 assert @response.parser.body_eof?
34 status, headers, body = @response.rack
35 assert_equal status, "404 Not Found"
36 assert_equal({},headers)
38 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
41 _, status = Process.waitpid2(pid)
42 assert status.success?
46 def test_http_small_pipelined_identity
47 resp = "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nhello world\n" \
48 "HTTP/1.1 200 OK\r\nContent-Length: 14\r\n\r\ngoodbye world\n"
54 @response = Kcar::Response.new(@c)
55 status, headers, body = @response.rack
56 assert_equal status, "200 OK"
57 assert_equal({'Content-Length'=>'12'},headers)
59 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
60 assert_equal [ "hello world\n" ], tmp
64 status, headers, body = @response.rack
65 assert_equal status, "200 OK"
66 assert_equal({'Content-Length'=>'14'},headers)
68 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
69 assert_equal [ "goodbye world\n" ], tmp
71 _, status = Process.waitpid2(pid)
72 assert status.success?
76 def test_http_big_pipelined_identity
80 template = "%0#{width - 1}x\n"
81 expect = Digest::SHA1.new
82 nr.times { |i| expect << sprintf(template, i) }
85 @s << "HTTP/1.1 200 OK\r\nContent-Length: #{length}\r\n\r\n"
86 nr.times { |i| @s.printf(template, i) }
87 @s << "HTTP/1.1 200 OK\r\nContent-Length: #{length}\r\n\r\n"
88 nr.times { |i| @s.printf(template, i) }
92 @response = Kcar::Response.new(@c)
95 status, headers, body = @response.rack
96 assert_equal status, "200 OK"
97 assert_equal({'Content-Length'=>length.to_s}, headers)
98 sha1 = Digest::SHA1.new
99 assert_nothing_raised { body.each { |chunk| sha1 << chunk } }
100 assert_equal expect, sha1, "#{expect.hexdigest} != #{sha1.hexdigest}"
104 _, status = Process.waitpid2(pid)
105 assert status.success?
108 def test_http_one_zero
110 @s << "HTTP/1.0 200 OK\r\n\r\nHI"
114 @response = Kcar::Response.new(@c)
115 status, headers, body = @response.read
116 assert_equal status, "200 OK"
117 assert headers.empty?
119 assert ! body.parser.keepalive?
120 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
121 assert_equal [ "HI" ], tmp
122 _, status = Process.waitpid2(pid)
123 assert status.success?
128 def test_http_keepalive
130 @s << "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nHI"
132 @response = Kcar::Response.new(@c)
133 status, headers, body = @response.read
134 assert_equal status, "200 OK"
135 assert_equal({"Content-Length" => "2" }, headers)
137 assert body.parser.keepalive?
138 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
139 assert body.parser.body_eof?
140 assert body.parser.keepalive?
141 assert_equal [ "HI" ], tmp
142 _, status = Process.waitpid2(pid)
143 assert status.success?
148 @s << "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n"
149 @s << "Connection: close\r\n\r\nBYE"
151 status, headers, body = @response.read
152 assert_equal status, "200 OK"
153 assert_equal({ "Content-Length" => "3", "Connection" => "close" }, headers)
155 assert ! body.parser.keepalive?
156 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
157 assert_equal [ "BYE" ], tmp
158 _, status = Process.waitpid2(pid)
159 assert status.success?
164 def test_http_keepalive_chunky
165 @response = Kcar::Response.new(@c)
167 @s << "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"
168 @s << "5\r\nabcde\r\n"
169 @s << "0\r\n\r\nHTTP/1.1 " # partial response
171 status, headers, body = @response.read
172 assert_equal status, "200 OK"
173 assert_equal({"Transfer-Encoding" => "chunked" }, headers)
175 assert body.parser.keepalive?
176 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
177 assert body.parser.keepalive?
178 assert body.parser.body_eof?
179 assert_equal [ "abcde" ], tmp
180 _, status = Process.waitpid2(pid)
181 assert status.success?
184 assert_equal "HTTP/1.1 ", @response.buf
187 @s << "200 OK\r\nContent-Length: 3\r\n"
188 @s << "Connection: close\r\n\r\nBYE"
190 status, headers, body = @response.read
191 assert_equal status, "200 OK"
192 assert_equal({ "Content-Length" => "3", "Connection" => "close" }, headers)
194 assert ! body.parser.keepalive?
195 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
196 assert_equal [ "BYE" ], tmp
197 _, status = Process.waitpid2(pid)
198 assert status.success?
203 def test_http_no_body_keepalive
204 pid = fork { @s << "HTTP/1.1 100 Continue\r\n\r\n" }
205 @response = Kcar::Response.new(@c)
206 status, headers, body = @response.read
207 assert_equal status, "100 Continue"
208 assert_equal({}, headers)
210 assert body.parser.keepalive?
211 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
213 _, status = Process.waitpid2(pid)
214 assert status.success?
218 pid = fork { @s << "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nhello" }
220 status, headers, body = @response.read
221 assert_equal status, "200 OK"
222 assert_equal({'Connection' => 'close'}, headers)
224 assert ! body.parser.keepalive?
225 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
226 assert_equal(%w(hello), tmp)
227 _, status = Process.waitpid2(pid)
228 assert status.success?
235 @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
236 @s << "Transfer-Encoding: chunked\r\n\r\n"
238 @response = Kcar::Response.new(@c)
239 status, headers, body = @response.read
240 assert_equal status, "200 OK"
243 "Transfer-Encoding" => "chunked",
245 assert_equal(expect, headers)
246 assert body.parser.keepalive?
247 _, status = Process.waitpid2(pid)
248 assert status.success?
250 pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n" }
251 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
252 assert_equal %w(hello), tmp
253 expect['Foo'] = 'bar'
254 assert_equal(expect, headers)
255 _, status = Process.waitpid2(pid)
256 assert status.success?
261 def test_trailers_pass_through
263 @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
264 @s << "Transfer-Encoding: chunked\r\n\r\n"
266 @response = Kcar::Response.new(@c, {}, false)
267 status, headers, body = @response.read
268 assert_equal status, "200 OK"
271 "Transfer-Encoding" => "chunked",
273 assert_equal(expect, headers)
274 assert body.parser.keepalive?
275 _, status = Process.waitpid2(pid)
276 assert status.success?
278 pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n" }
279 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
280 assert_equal ["5\r\n", "hello\r\n", "0\r\n", "Foo: bar\r\n\r\n"], tmp
281 expect['Foo'] = 'bar'
282 assert_equal(expect, headers)
283 _, status = Process.waitpid2(pid)
284 assert status.success?
289 def test_pass_through_one_oh
291 @s << "HTTP/1.0 200 OK\r\n"
292 @s << "Content-Type: text/plain\r\n\r\n"
294 @response = Kcar::Response.new(@c, {}, false)
295 status, headers, body = @response.read
296 assert_equal status, "200 OK"
297 expect = { "Content-Type" => "text/plain", }
298 assert_equal(expect, headers)
299 assert ! body.parser.keepalive?
300 _, status = Process.waitpid2(pid)
301 assert status.success?
303 pid = fork { @s << "hello" }
305 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
306 assert_equal %w(hello), tmp
307 assert_equal(expect, headers)
308 _, status = Process.waitpid2(pid)
309 assert status.success?
314 def test_trailers_burpy
316 @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
317 @s << "Transfer-Encoding: chunked\r\n\r\n"
319 @response = Kcar::Response.new(@c)
320 status, headers, body = @response.read
321 assert_equal status, "200 OK"
324 "Transfer-Encoding" => "chunked",
326 assert_equal(expect, headers)
327 assert body.parser.keepalive?
328 _, status = Process.waitpid2(pid)
329 assert status.success?
331 pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar" }
338 assert_nothing_raised do
344 wr.syswrite "\r\n\r\n"
348 assert_equal %w(hello), tmp
349 _, status = Process.waitpid2(pid)
350 assert status.success?
351 _, status = Process.waitpid2(crlf_pid)
352 assert status.success?
353 expect['Foo'] = 'bar'
354 assert_equal(expect, headers)
359 def test_pass_through_trailers_burpy
361 @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
362 @s << "Transfer-Encoding: chunked\r\n\r\n"
364 @response = Kcar::Response.new(@c, {}, false)
365 status, headers, body = @response.read
366 assert_equal status, "200 OK"
369 "Transfer-Encoding" => "chunked",
371 assert_equal(expect, headers)
372 assert body.parser.keepalive?
373 _, status = Process.waitpid2(pid)
374 assert status.success?
376 pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar" }
383 assert_nothing_raised do
389 wr.syswrite "\r\n\r\n"
393 assert_equal ["5\r\n", "hello\r\n", "0\r\n", "Foo: bar\r\n\r\n"], tmp
394 _, status = Process.waitpid2(pid)
395 assert status.success?
396 _, status = Process.waitpid2(crlf_pid)
397 assert status.success?
398 expect['Foo'] = 'bar'
399 assert_equal(expect, headers)
404 def test_identity_burpy
405 pid = fork { @s << "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n" }
406 @response = Kcar::Response.new(@c)
407 status, headers, body = @response.read
408 assert_equal status, "200 OK"
409 expect = { "Content-Length" => '5' }
410 assert_equal(expect, headers)
411 assert body.parser.keepalive?
412 _, status = Process.waitpid2(pid)
413 assert status.success?
415 pid = fork { @s << "h" }
422 assert_nothing_raised do
432 assert_equal %w(h ello), tmp
433 _, status = Process.waitpid2(pid)
434 assert status.success?
435 _, status = Process.waitpid2(crlf_pid)
436 assert status.success?
437 assert_equal(expect, headers)
442 def test_rack_preserve_chunk_hash
444 @s << "HTTP/1.1 200 OK\r\n"
445 @s << "Trailer: Foo\r\n"
446 @s << "Transfer-Encoding: chunked\r\n\r\n"
447 @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n"
449 @response = Kcar::Response.new(@c)
450 status, headers, body = @response.rack
451 assert_equal status, "200 OK"
454 "Transfer-Encoding" => "chunked",
456 assert_equal expect, headers
458 assert body.parser.keepalive?
459 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
460 assert_equal ["5\r\n", "hello\r\n", "0\r\n", "Foo: bar\r\n\r\n"], tmp
461 expect["Foo"] = "bar"
462 assert_equal expect, headers
463 _, status = Process.waitpid2(pid)
464 assert status.success?
469 def test_rack_preserve_chunk_ary
471 @s << "HTTP/1.1 200 OK\r\n"
472 @s << "Trailer: Foo\r\n"
473 @s << "Transfer-Encoding: chunked\r\n\r\n"
474 @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n"
476 @response = Kcar::Response.new(@c, [])
477 status, headers, body = @response.rack
478 assert_equal status, "200 OK"
479 expect = [ %w(Trailer Foo), %w(Transfer-Encoding chunked) ]
480 assert_equal expect, headers
482 assert body.parser.keepalive?
483 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
484 assert_equal ["5\r\n", "hello\r\n", "0\r\n", "Foo: bar\r\n\r\n"], tmp
485 expect << %w(Foo bar)
486 assert_equal expect, headers
487 _, status = Process.waitpid2(pid)
488 assert status.success?
493 def test_rack_preserve_chunk_no_keepalive
495 @s << "HTTP/1.1 200 OK\r\n"
496 @s << "Connection: close\r\n"
497 @s << "Trailer: Foo\r\n"
498 @s << "Transfer-Encoding: chunked\r\n\r\n"
499 @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n"
502 @response = Kcar::Response.new(@c, [])
503 status, headers, body = @response.rack
504 assert_kind_of Array, headers
505 assert_equal status, "200 OK"
507 assert ! body.parser.keepalive?
508 assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
509 assert_equal "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n", tmp.join
510 _, status = Process.waitpid2(pid)
511 assert status.success?
516 def test_rack_preserve_chunk_no_keepalive_2
517 s = "HTTP/1.1 200 OK\r\n"
518 s << "Connection: close\r\n"
519 s << "Content-Length: 666\r\n"
523 @response = Kcar::Response.new(@c, [])
524 status, headers, body = @response.rack
525 assert_kind_of Array, headers
526 assert_equal status, "200 OK"
528 assert ! body.parser.keepalive?
530 closer = Thread.new do
531 Thread.pass until tmp[0]
534 assert_raises(EOFError) {
535 body.each { |chunk| tmp << chunk.dup }
538 assert_equal "hello", tmp[0]
539 assert_nil closer.value