kcar 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,257 @@
1
+ # -*- encoding: binary -*-
2
+ require 'test/unit'
3
+ require 'pp'
4
+ require 'kcar'
5
+ require 'rack'
6
+
7
+ class TestParser < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @hp = Kcar::Parser.new
11
+ end
12
+
13
+ def test_reset
14
+ assert_nothing_raised { @hp.reset }
15
+ end
16
+
17
+ def test_parser_status_eof
18
+ buf = "HTTP/1.0 200 OK\r\n\r\n"
19
+ hdr = []
20
+ hdr_object_id = hdr.object_id
21
+ response = @hp.headers(hdr, buf)
22
+ assert_equal(["200 OK", hdr], response)
23
+ assert hdr.empty?
24
+ assert ! @hp.keepalive?
25
+ assert_equal hdr_object_id, hdr.object_id
26
+ assert_equal "", buf
27
+ end
28
+
29
+ def test_parser_status_eof_one_one
30
+ buf = "HTTP/1.1 200 OK\r\n\r\n"
31
+ hdr = []
32
+ response = @hp.headers(hdr, buf)
33
+ assert_equal(["200 OK", hdr], response)
34
+ assert hdr.empty?
35
+ assert ! @hp.keepalive? # no content-length
36
+ end
37
+
38
+ def test_parser_status_with_content_length
39
+ buf = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
40
+ hdr = []
41
+ response = @hp.headers(hdr, buf)
42
+ assert_equal(["200 OK", hdr], response)
43
+ assert_equal([%w(Content-Length 0)], hdr)
44
+ assert @hp.keepalive?
45
+ end
46
+
47
+ def test_parser_content_length
48
+ buf = "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"
49
+ rv = @hp.headers([], buf)
50
+ assert_equal "200 OK", rv[0]
51
+ assert_equal([ %w(Content-Length 5) ], rv[1])
52
+ assert_equal 2, rv.size
53
+ assert_equal "", buf
54
+ assert_equal 5, @hp.body_bytes_left
55
+ end
56
+
57
+ def test_parser_content_length_with_body
58
+ buf = "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nabcde"
59
+ rv = @hp.headers([], buf)
60
+ assert_equal "200 OK", rv[0]
61
+ assert_equal([ %w(Content-Length 5) ], rv[1])
62
+ assert_equal "abcde", buf
63
+ assert_equal 5, @hp.body_bytes_left
64
+ end
65
+
66
+ def test_bad_crlf
67
+ buf = "HTTP/1.1 200 OK\nContent-Length: 5\n\r\nabcde"
68
+ rv = @hp.headers([], buf)
69
+ assert_equal "200 OK", rv[0]
70
+ assert_equal([ %w(Content-Length 5) ], rv[1])
71
+ assert_equal "abcde", buf
72
+ assert_equal 5, @hp.body_bytes_left
73
+ assert ! @hp.chunked?
74
+ end
75
+
76
+ def test_chunky_bad_crlf
77
+ buf = "HTTP/1.1 200 OK\n" \
78
+ "Transfer-Encoding: chunked\n\n" \
79
+ "6\nabcdef\n0\n\n"
80
+ rv = @hp.headers([], buf)
81
+ assert_equal "200 OK", rv[0]
82
+ assert_equal([ %w(Transfer-Encoding chunked) ], rv[1])
83
+ assert_equal "6\nabcdef\n0\n\n", buf
84
+ assert_nil @hp.body_bytes_left
85
+ assert @hp.chunked?
86
+ assert_nil @hp.filter_body(tmp = "", buf)
87
+ assert_equal "abcdef", tmp
88
+ assert @hp.keepalive?
89
+ end
90
+
91
+ def test_chunky
92
+ buf = "HTTP/1.1 200 OK\r\n" \
93
+ "Transfer-Encoding: chunked\r\n\r\n" \
94
+ "6\r\nabcdef\r\n0\r\n\r\n"
95
+ rv = @hp.headers([], buf)
96
+ assert_equal "200 OK", rv[0]
97
+ assert_equal([ %w(Transfer-Encoding chunked) ], rv[1])
98
+ assert_equal "6\r\nabcdef\r\n0\r\n\r\n", buf
99
+ assert_nil @hp.body_bytes_left
100
+ assert @hp.chunked?
101
+ assert_nil @hp.filter_body(tmp = "", buf)
102
+ assert_equal "abcdef", tmp
103
+ assert @hp.body_eof?
104
+ assert @hp.keepalive?
105
+ end
106
+
107
+ def test_chunky_two_step
108
+ buf = "HTTP/1.1 200 OK\r\n" \
109
+ "Transfer-Encoding: chunked\r\n\r\n" \
110
+ "6\r\nabcd"
111
+ buf2 = "ef\r\n0\r\n\r\n"
112
+ rv = @hp.headers([], buf)
113
+ assert_equal "200 OK", rv[0]
114
+ assert_equal([ %w(Transfer-Encoding chunked) ], rv[1])
115
+ assert_equal "6\r\nabcd", buf
116
+ assert_nil @hp.body_bytes_left
117
+ assert @hp.chunked?
118
+ assert_nil @hp.filter_body(tmp = "", buf)
119
+ assert_equal "abcd", tmp
120
+ assert_equal "", buf
121
+ assert ! @hp.body_eof?
122
+ assert_nil @hp.filter_body(tmp = "", buf2)
123
+ assert_equal "ef", tmp
124
+ assert @hp.body_eof?
125
+ assert_equal({}, @hp.trailers(tmp = {}, buf2))
126
+ assert @hp.keepalive?
127
+ assert_nothing_raised { @hp.reset }
128
+ end
129
+
130
+ def test_trailers_ary
131
+ buf = "HTTP/1.1 200 OK\r\n" \
132
+ "Trailer: Foo\r\n" \
133
+ "Transfer-Encoding: chunked\r\n\r\n" \
134
+ "6\r\nabcdef\r\n0\r\nFoo: bar\r\n\r\n"
135
+ rv = @hp.headers([], buf)
136
+ assert_equal "200 OK", rv[0]
137
+ assert_equal([ %w(Trailer Foo), %w(Transfer-Encoding chunked) ], rv[1])
138
+ assert_equal "6\r\nabcdef\r\n0\r\nFoo: bar\r\n\r\n", buf
139
+ assert_nil @hp.body_bytes_left
140
+ assert @hp.chunked?
141
+ assert_nil @hp.filter_body(tmp = "", buf)
142
+ assert_equal "abcdef", tmp
143
+ assert @hp.body_eof?
144
+ expect = [ %w(Trailer Foo),
145
+ %w(Transfer-Encoding chunked),
146
+ %w(Foo bar) ]
147
+ assert_equal(expect, @hp.trailers(rv[1], buf))
148
+ assert @hp.keepalive?
149
+ assert_nothing_raised { @hp.reset }
150
+ end
151
+
152
+ def test_extract_trailers_ary
153
+ tmp = [ %w(Trailer Foo), %w(Transfer-Encoding chunked), %w(Foo bar) ]
154
+ assert_equal [ %w(Foo bar) ], @hp.extract_trailers(tmp)
155
+ end
156
+
157
+ def test_extract_trailers_hash
158
+ tmp = {
159
+ 'Trailer' => 'Foo',
160
+ 'Transfer-Encoding' => 'chunked',
161
+ 'Foo' => 'bar'
162
+ }
163
+ assert_equal [ %w(Foo bar) ], @hp.extract_trailers(tmp)
164
+ end
165
+
166
+ def test_extract_trailers_header_hash
167
+ tmp = Rack::Utils::HeaderHash.new(
168
+ 'Trailer' => 'foo',
169
+ 'Transfer-Encoding' => 'chunked',
170
+ 'Foo' => 'bar'
171
+ )
172
+ assert_equal [ %w(foo bar) ], @hp.extract_trailers(tmp)
173
+ end
174
+
175
+ def test_repeated_headers_rack_hash
176
+ hdr = Rack::Utils::HeaderHash.new
177
+ buf = "HTTP/1.1 200 OK\r\nSet-Cookie: a=b\r\n"
178
+ assert_nil @hp.headers(hdr, buf)
179
+ assert_equal({ 'Set-Cookie' => 'a=b' }, hdr.to_hash)
180
+ assert_nil @hp.headers(hdr, buf << "set-cookie: c=d\r\n")
181
+ assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n"))
182
+ assert_equal "", buf
183
+ assert_equal({ 'Set-Cookie' => "a=b\nc=d" }, hdr.to_hash)
184
+ end
185
+
186
+ def test_repeated_headers_plain_hash
187
+ hdr = {}
188
+ buf = "HTTP/1.1 200 OK\r\nSet-Cookie: a=b\r\n"
189
+ assert_nil @hp.headers(hdr, buf)
190
+ assert_equal({ 'Set-Cookie' => 'a=b' }, hdr)
191
+ assert_nil @hp.headers(hdr, buf << "set-cookie: c=d\r\n")
192
+ assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n"))
193
+ assert_equal "", buf
194
+ assert_equal({ 'Set-Cookie' => 'a=b', 'set-cookie' => 'c=d' }, hdr)
195
+ end
196
+
197
+ def test_repeated_headers_array
198
+ hdr = []
199
+ buf = "HTTP/1.1 200 OK\r\nSet-Cookie: a=b\r\n"
200
+ assert_nil @hp.headers(hdr, buf)
201
+ assert_equal([ %w(Set-Cookie a=b) ] , hdr)
202
+ assert_nil @hp.headers(hdr, buf << "set-cookie: c=d\r\n")
203
+ assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n"))
204
+ assert_equal "", buf
205
+ assert_equal([ %w(Set-Cookie a=b), %w(set-cookie c=d) ], hdr)
206
+ end
207
+
208
+ def test_long_line_headers_array
209
+ hdr = []
210
+ buf = "HTTP/1.1 200 OK\r\na: b\r\n"
211
+ assert_nil @hp.headers(hdr, buf)
212
+ assert_equal([ %w(a b) ] , hdr)
213
+ assert_nil @hp.headers(hdr, buf << " c\r\n")
214
+ assert_equal([ [ 'a', 'b c'] ], hdr)
215
+ assert_nil @hp.headers(hdr, buf << " d\n")
216
+ assert_equal([ [ 'a', 'b c d'] ], hdr)
217
+ assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n"))
218
+ assert_equal([ [ 'a', 'b c d'] ], hdr)
219
+ end
220
+
221
+ def test_long_line_headers_plain_hash
222
+ hdr = {}
223
+ buf = "HTTP/1.1 200 OK\r\na: b\r\n"
224
+ assert_nil @hp.headers(hdr, buf)
225
+ assert_equal({ 'a' => 'b' }, hdr)
226
+ assert_nil @hp.headers(hdr, buf << " c\r\n")
227
+ assert_equal({ 'a' => 'b c' }, hdr)
228
+ assert_nil @hp.headers(hdr, buf << " d\r\n")
229
+ assert_equal({ 'a' => 'b c d' }, hdr)
230
+ assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n"))
231
+ assert_equal({ 'a' => 'b c d' }, hdr)
232
+ end
233
+
234
+ def test_long_line_headers_rack_hash
235
+ hdr = Rack::Utils::HeaderHash.new
236
+ buf = "HTTP/1.1 200 OK\r\na: b\r\n"
237
+ assert_nil @hp.headers(hdr, buf)
238
+ assert_equal({ 'a' => 'b' }, hdr.to_hash)
239
+ assert_nil @hp.headers(hdr, buf << " c\r\n")
240
+ assert_equal({ 'a' => 'b c' }, hdr)
241
+ assert_nil @hp.headers(hdr, buf << " d\r\n")
242
+ assert_equal({ 'a' => 'b c d' }, hdr)
243
+ assert_nil @hp.headers(hdr, buf << "A: e\r\n")
244
+ assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n"))
245
+ assert_equal({ 'a' => "b c d\ne"}, hdr.to_hash)
246
+ end
247
+
248
+ def test_content_length_invalid
249
+ assert_raises(Kcar::ParserError) do
250
+ @hp.headers([], "HTTP/1.1 200 OK\r\nContent-Length: 5a\r\n\r\n")
251
+ end
252
+ assert_raises(Kcar::ParserError) do
253
+ @hp.headers([], "HTTP/1.1 200 OK\r\nContent-Length: -1\r\n\r\n")
254
+ end
255
+ end
256
+
257
+ end
@@ -0,0 +1,415 @@
1
+ # -*- encoding: binary -*-
2
+ require 'test/unit'
3
+ require 'pp'
4
+ require 'socket'
5
+ require 'kcar'
6
+
7
+ class TestSession < Test::Unit::TestCase
8
+ def setup
9
+ @s, @c = UNIXSocket.pair
10
+ end
11
+
12
+ def test_http_one_zero
13
+ pid = fork do
14
+ @s << "HTTP/1.0 200 OK\r\n\r\nHI"
15
+ @s.close
16
+ end
17
+ @s.close
18
+ @response = Kcar::Response.new(@c)
19
+ status, headers, body = @response.read
20
+ assert_equal status, "200 OK"
21
+ assert headers.empty?
22
+ tmp = []
23
+ assert ! body.parser.keepalive?
24
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
25
+ assert_equal [ "HI" ], tmp
26
+ _, status = Process.waitpid2(pid)
27
+ assert status.success?
28
+ body.close
29
+ assert @c.closed?
30
+ end
31
+
32
+ def test_http_keepalive
33
+ pid = fork do
34
+ @s << "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nHI"
35
+ end
36
+ @response = Kcar::Response.new(@c)
37
+ status, headers, body = @response.read
38
+ assert_equal status, "200 OK"
39
+ assert_equal({"Content-Length" => "2" }, headers)
40
+ tmp = []
41
+ assert body.parser.keepalive?
42
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
43
+ assert_equal [ "HI" ], tmp
44
+ _, status = Process.waitpid2(pid)
45
+ assert status.success?
46
+ body.close
47
+ assert ! @c.closed?
48
+
49
+ pid = fork do
50
+ @s << "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n"
51
+ @s << "Connection: close\r\n\r\nBYE"
52
+ end
53
+ status, headers, body = @response.read
54
+ assert_equal status, "200 OK"
55
+ assert_equal({ "Content-Length" => "3", "Connection" => "close" }, headers)
56
+ tmp = []
57
+ assert ! body.parser.keepalive?
58
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
59
+ assert_equal [ "BYE" ], tmp
60
+ _, status = Process.waitpid2(pid)
61
+ assert status.success?
62
+ body.close
63
+ assert @c.closed?
64
+ end
65
+
66
+ def test_http_keepalive_chunky
67
+ @response = Kcar::Response.new(@c)
68
+ pid = fork do
69
+ @s << "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"
70
+ @s << "5\r\nabcde\r\n"
71
+ @s << "0\r\n\r\nHTTP/1.1 " # partial response
72
+ end
73
+ status, headers, body = @response.read
74
+ assert_equal status, "200 OK"
75
+ assert_equal({"Transfer-Encoding" => "chunked" }, headers)
76
+ tmp = []
77
+ assert body.parser.keepalive?
78
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
79
+ assert_equal [ "abcde" ], tmp
80
+ _, status = Process.waitpid2(pid)
81
+ assert status.success?
82
+ body.close
83
+ assert ! @c.closed?
84
+ assert_equal "HTTP/1.1 ", @response.buf
85
+
86
+ pid = fork do
87
+ @s << "200 OK\r\nContent-Length: 3\r\n"
88
+ @s << "Connection: close\r\n\r\nBYE"
89
+ end
90
+ status, headers, body = @response.read
91
+ assert_equal status, "200 OK"
92
+ assert_equal({ "Content-Length" => "3", "Connection" => "close" }, headers)
93
+ tmp = []
94
+ assert ! body.parser.keepalive?
95
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
96
+ assert_equal [ "BYE" ], tmp
97
+ _, status = Process.waitpid2(pid)
98
+ assert status.success?
99
+ body.close
100
+ assert @c.closed?
101
+ end
102
+
103
+ def test_http_no_body_keepalive
104
+ pid = fork { @s << "HTTP/1.1 100 Continue\r\n\r\n" }
105
+ @response = Kcar::Response.new(@c)
106
+ status, headers, body = @response.read
107
+ assert_equal status, "100 Continue"
108
+ assert_equal({}, headers)
109
+ tmp = []
110
+ assert body.parser.keepalive?
111
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
112
+ assert tmp.empty?
113
+ _, status = Process.waitpid2(pid)
114
+ assert status.success?
115
+ body.close
116
+ assert ! @c.closed?
117
+
118
+ pid = fork { @s << "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nhello" }
119
+ @s.close
120
+ status, headers, body = @response.read
121
+ assert_equal status, "200 OK"
122
+ assert_equal({'Connection' => 'close'}, headers)
123
+ tmp = []
124
+ assert ! body.parser.keepalive?
125
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
126
+ assert_equal(%w(hello), tmp)
127
+ _, status = Process.waitpid2(pid)
128
+ assert status.success?
129
+ body.close
130
+ assert @c.closed?
131
+ end
132
+
133
+ def test_trailers
134
+ pid = fork do
135
+ @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
136
+ @s << "Transfer-Encoding: chunked\r\n\r\n"
137
+ end
138
+ @response = Kcar::Response.new(@c)
139
+ status, headers, body = @response.read
140
+ assert_equal status, "200 OK"
141
+ expect = {
142
+ "Trailer" => "Foo",
143
+ "Transfer-Encoding" => "chunked",
144
+ }
145
+ assert_equal(expect, headers)
146
+ assert body.parser.keepalive?
147
+ _, status = Process.waitpid2(pid)
148
+ assert status.success?
149
+ tmp = []
150
+ pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n" }
151
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
152
+ assert_equal %w(hello), tmp
153
+ expect['Foo'] = 'bar'
154
+ assert_equal(expect, headers)
155
+ _, status = Process.waitpid2(pid)
156
+ assert status.success?
157
+ body.close
158
+ assert ! @c.closed?
159
+ end
160
+
161
+ def test_trailers_pass_through
162
+ pid = fork do
163
+ @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
164
+ @s << "Transfer-Encoding: chunked\r\n\r\n"
165
+ end
166
+ @response = Kcar::Response.new(@c, {}, false)
167
+ status, headers, body = @response.read
168
+ assert_equal status, "200 OK"
169
+ expect = {
170
+ "Trailer" => "Foo",
171
+ "Transfer-Encoding" => "chunked",
172
+ }
173
+ assert_equal(expect, headers)
174
+ assert body.parser.keepalive?
175
+ _, status = Process.waitpid2(pid)
176
+ assert status.success?
177
+ tmp = []
178
+ pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n" }
179
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
180
+ assert_equal ["5\r\n", "hello\r\n", "0\r\n", "Foo: bar\r\n\r\n"], tmp
181
+ expect['Foo'] = 'bar'
182
+ assert_equal(expect, headers)
183
+ _, status = Process.waitpid2(pid)
184
+ assert status.success?
185
+ body.close
186
+ assert ! @c.closed?
187
+ end
188
+
189
+ def test_pass_through_one_oh
190
+ pid = fork do
191
+ @s << "HTTP/1.0 200 OK\r\n"
192
+ @s << "Content-Type: text/plain\r\n\r\n"
193
+ end
194
+ @response = Kcar::Response.new(@c, {}, false)
195
+ status, headers, body = @response.read
196
+ assert_equal status, "200 OK"
197
+ expect = { "Content-Type" => "text/plain", }
198
+ assert_equal(expect, headers)
199
+ assert ! body.parser.keepalive?
200
+ _, status = Process.waitpid2(pid)
201
+ assert status.success?
202
+ tmp = []
203
+ pid = fork { @s << "hello" }
204
+ @s.close
205
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
206
+ assert_equal %w(hello), tmp
207
+ assert_equal(expect, headers)
208
+ _, status = Process.waitpid2(pid)
209
+ assert status.success?
210
+ body.close
211
+ assert @c.closed?
212
+ end
213
+
214
+ def test_trailers_burpy
215
+ pid = fork do
216
+ @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
217
+ @s << "Transfer-Encoding: chunked\r\n\r\n"
218
+ end
219
+ @response = Kcar::Response.new(@c)
220
+ status, headers, body = @response.read
221
+ assert_equal status, "200 OK"
222
+ expect = {
223
+ "Trailer" => "Foo",
224
+ "Transfer-Encoding" => "chunked",
225
+ }
226
+ assert_equal(expect, headers)
227
+ assert body.parser.keepalive?
228
+ _, status = Process.waitpid2(pid)
229
+ assert status.success?
230
+ tmp = []
231
+ pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar" }
232
+ rd, wr = IO.pipe
233
+ crlf_pid = fork do
234
+ wr.close
235
+ @s << rd.sysread(4)
236
+ end
237
+ rd.close
238
+ assert_nothing_raised do
239
+ first = true
240
+ body.each do |chunk|
241
+ tmp << chunk.dup
242
+ if first
243
+ first = false
244
+ wr.syswrite "\r\n\r\n"
245
+ end
246
+ end
247
+ end
248
+ assert_equal %w(hello), tmp
249
+ _, status = Process.waitpid2(pid)
250
+ assert status.success?
251
+ _, status = Process.waitpid2(crlf_pid)
252
+ assert status.success?
253
+ expect['Foo'] = 'bar'
254
+ assert_equal(expect, headers)
255
+ body.close
256
+ assert ! @c.closed?
257
+ end
258
+
259
+ def test_pass_through_trailers_burpy
260
+ pid = fork do
261
+ @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
262
+ @s << "Transfer-Encoding: chunked\r\n\r\n"
263
+ end
264
+ @response = Kcar::Response.new(@c, {}, false)
265
+ status, headers, body = @response.read
266
+ assert_equal status, "200 OK"
267
+ expect = {
268
+ "Trailer" => "Foo",
269
+ "Transfer-Encoding" => "chunked",
270
+ }
271
+ assert_equal(expect, headers)
272
+ assert body.parser.keepalive?
273
+ _, status = Process.waitpid2(pid)
274
+ assert status.success?
275
+ tmp = []
276
+ pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar" }
277
+ rd, wr = IO.pipe
278
+ crlf_pid = fork do
279
+ wr.close
280
+ @s << rd.sysread(4)
281
+ end
282
+ rd.close
283
+ assert_nothing_raised do
284
+ first = true
285
+ body.each do |chunk|
286
+ tmp << chunk.dup
287
+ if first
288
+ first = false
289
+ wr.syswrite "\r\n\r\n"
290
+ end
291
+ end
292
+ end
293
+ assert_equal ["5\r\n", "hello\r\n", "0\r\n", "Foo: bar\r\n\r\n"], tmp
294
+ _, status = Process.waitpid2(pid)
295
+ assert status.success?
296
+ _, status = Process.waitpid2(crlf_pid)
297
+ assert status.success?
298
+ expect['Foo'] = 'bar'
299
+ assert_equal(expect, headers)
300
+ body.close
301
+ assert ! @c.closed?
302
+ end
303
+
304
+ def test_identity_burpy
305
+ pid = fork { @s << "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n" }
306
+ @response = Kcar::Response.new(@c)
307
+ status, headers, body = @response.read
308
+ assert_equal status, "200 OK"
309
+ expect = { "Content-Length" => '5' }
310
+ assert_equal(expect, headers)
311
+ assert body.parser.keepalive?
312
+ _, status = Process.waitpid2(pid)
313
+ assert status.success?
314
+ tmp = []
315
+ pid = fork { @s << "h" }
316
+ rd, wr = IO.pipe
317
+ crlf_pid = fork do
318
+ wr.close
319
+ @s << rd.sysread(4)
320
+ end
321
+ rd.close
322
+ assert_nothing_raised do
323
+ first = true
324
+ body.each do |chunk|
325
+ tmp << chunk.dup
326
+ if first
327
+ first = false
328
+ wr.syswrite "ello"
329
+ end
330
+ end
331
+ end
332
+ assert_equal %w(h ello), tmp
333
+ _, status = Process.waitpid2(pid)
334
+ assert status.success?
335
+ _, status = Process.waitpid2(crlf_pid)
336
+ assert status.success?
337
+ assert_equal(expect, headers)
338
+ body.close
339
+ assert ! @c.closed?
340
+ end
341
+
342
+ def test_rack_preserve_chunk_hash
343
+ pid = fork do
344
+ @s << "HTTP/1.1 200 OK\r\n"
345
+ @s << "Trailer: Foo\r\n"
346
+ @s << "Transfer-Encoding: chunked\r\n\r\n"
347
+ @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n"
348
+ end
349
+ @response = Kcar::Response.new(@c)
350
+ status, headers, body = @response.rack
351
+ assert_equal status, "200 OK"
352
+ expect = {
353
+ "Trailer" => "Foo",
354
+ "Transfer-Encoding" => "chunked",
355
+ }
356
+ assert_equal expect, headers
357
+ tmp = []
358
+ assert body.parser.keepalive?
359
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
360
+ assert_equal ["5\r\n", "hello\r\n", "0\r\n", "Foo: bar\r\n\r\n"], tmp
361
+ expect["Foo"] = "bar"
362
+ assert_equal expect, headers
363
+ _, status = Process.waitpid2(pid)
364
+ assert status.success?
365
+ body.close
366
+ assert ! @c.closed?
367
+ end
368
+
369
+ def test_rack_preserve_chunk_ary
370
+ pid = fork do
371
+ @s << "HTTP/1.1 200 OK\r\n"
372
+ @s << "Trailer: Foo\r\n"
373
+ @s << "Transfer-Encoding: chunked\r\n\r\n"
374
+ @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n"
375
+ end
376
+ @response = Kcar::Response.new(@c, [])
377
+ status, headers, body = @response.rack
378
+ assert_equal status, "200 OK"
379
+ expect = [ %w(Trailer Foo), %w(Transfer-Encoding chunked) ]
380
+ assert_equal expect, headers
381
+ tmp = []
382
+ assert body.parser.keepalive?
383
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
384
+ assert_equal ["5\r\n", "hello\r\n", "0\r\n", "Foo: bar\r\n\r\n"], tmp
385
+ expect << %w(Foo bar)
386
+ assert_equal expect, headers
387
+ _, status = Process.waitpid2(pid)
388
+ assert status.success?
389
+ body.close
390
+ assert ! @c.closed?
391
+ end
392
+
393
+ def test_rack_preserve_chunk_ary_no_keepalive
394
+ pid = fork do
395
+ @s << "HTTP/1.1 200 OK\r\n"
396
+ @s << "Connection: close\r\n"
397
+ @s << "Trailer: Foo\r\n"
398
+ @s << "Transfer-Encoding: chunked\r\n\r\n"
399
+ @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n"
400
+ end
401
+ @s.close
402
+ @response = Kcar::Response.new(@c, [])
403
+ status, headers, body = @response.rack
404
+ assert_equal status, "200 OK"
405
+ tmp = []
406
+ assert ! body.parser.keepalive?
407
+ assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
408
+ assert_equal ["5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n"], tmp
409
+ _, status = Process.waitpid2(pid)
410
+ assert status.success?
411
+ body.close
412
+ assert @c.closed?
413
+ end
414
+
415
+ end