http_parser.rb 0.5.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/linux.yml +23 -0
  3. data/.github/workflows/windows.yml +23 -0
  4. data/.gitignore +5 -4
  5. data/.gitmodules +4 -4
  6. data/Gemfile +1 -1
  7. data/README.md +52 -47
  8. data/Rakefile +1 -0
  9. data/bench/standalone.rb +23 -0
  10. data/bench/thin.rb +1 -0
  11. data/ext/ruby_http_parser/extconf.rb +1 -1
  12. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +139 -83
  13. data/ext/ruby_http_parser/ruby_http_parser.c +40 -41
  14. data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
  15. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +5 -1
  16. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +133 -1
  17. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +6 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1202 -671
  19. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +79 -0
  20. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +172 -51
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +22 -0
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +41 -0
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +8 -3
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +35 -102
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +6 -6
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +775 -682
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +8 -4
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +70 -20
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +1 -1
  32. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +1 -0
  33. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +2 -1
  34. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +1 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +6 -17
  36. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +1 -0
  37. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +1 -0
  38. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +1 -0
  39. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
  40. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +80 -9
  41. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +2 -1
  42. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1637 -280
  43. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
  44. data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +68 -0
  45. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -1
  46. data/ext/ruby_http_parser/vendor/http-parser/README.md +113 -38
  47. data/ext/ruby_http_parser/vendor/http-parser/bench.c +128 -0
  48. data/ext/ruby_http_parser/vendor/http-parser/contrib/parsertrace.c +157 -0
  49. data/ext/ruby_http_parser/vendor/http-parser/contrib/url_parser.c +47 -0
  50. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1576 -780
  51. data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +111 -0
  52. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +308 -58
  53. data/ext/ruby_http_parser/vendor/http-parser/test.c +2964 -460
  54. data/http_parser.rb.gemspec +14 -7
  55. data/spec/parser_spec.rb +196 -102
  56. data/spec/support/requests.json +236 -24
  57. data/spec/support/responses.json +202 -36
  58. data/tasks/compile.rake +2 -2
  59. data/tasks/fixtures.rake +8 -2
  60. data/tasks/spec.rake +1 -1
  61. metadata +141 -134
  62. data/Gemfile.lock +0 -32
  63. data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
  64. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
  65. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
  66. data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +0 -1
  67. data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +0 -4
@@ -1,25 +1,32 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "http_parser.rb"
3
- s.version = "0.5.2"
3
+ s.version = "0.7.0"
4
4
  s.summary = "Simple callback-based HTTP request/response parser"
5
- s.description = "Ruby bindings to http://github.com/ry/http-parser and http://github.com/a2800276/http-parser.java"
5
+ s.description = "Ruby bindings to https://github.com/joyent/http-parser and https://github.com/http-parser/http-parser.java"
6
6
 
7
7
  s.authors = ["Marc-Andre Cournoyer", "Aman Gupta"]
8
8
  s.email = ["macournoyer@gmail.com", "aman@tmm1.net"]
9
+ s.license = 'MIT'
9
10
 
10
- s.homepage = "http://github.com/tmm1/http_parser.rb"
11
+ s.homepage = "https://github.com/tmm1/http_parser.rb"
11
12
  s.files = `git ls-files`.split("\n") + Dir['ext/ruby_http_parser/vendor/**/*']
12
13
 
13
14
  s.require_paths = ["lib"]
14
15
  s.extensions = ["ext/ruby_http_parser/extconf.rb"]
15
16
 
16
- s.add_development_dependency 'rake-compiler', '>= 0.7.9'
17
- s.add_development_dependency 'rspec', '>= 2.0.1'
18
- s.add_development_dependency 'json', '>= 1.4.6'
17
+ s.add_development_dependency 'rake-compiler', '~> 1.0'
18
+ s.add_development_dependency 'rspec', '~> 3'
19
+ s.add_development_dependency 'json', '~> 2.1'
20
+ s.add_development_dependency 'benchmark_suite', '~> 1.0'
21
+ s.add_development_dependency 'ffi', '~> 1.9'
19
22
 
20
23
  if RUBY_PLATFORM =~ /java/
21
24
  s.add_development_dependency 'jruby-openssl'
22
25
  else
23
- s.add_development_dependency 'yajl-ruby', '>= 0.8.1'
26
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.4.0')
27
+ s.add_development_dependency 'yajl-ruby', '~> 1.3'
28
+ else
29
+ s.add_development_dependency 'yajl-ruby', '= 1.2.1'
30
+ end
24
31
  end
25
32
  end
data/spec/parser_spec.rb CHANGED
@@ -1,3 +1,6 @@
1
+ if defined?(Encoding)
2
+ Encoding.default_external = "UTF-8"
3
+ end
1
4
  require "spec_helper"
2
5
  require "json"
3
6
 
@@ -17,27 +20,24 @@ describe HTTP::Parser do
17
20
  end
18
21
 
19
22
  it "should have initial state" do
20
- @parser.headers.should be_nil
23
+ expect(@parser.headers).to be_nil
21
24
 
22
- @parser.http_version.should be_nil
23
- @parser.http_method.should be_nil
24
- @parser.status_code.should be_nil
25
+ expect(@parser.http_version).to be_nil
26
+ expect(@parser.http_method).to be_nil
27
+ expect(@parser.status_code).to be_nil
25
28
 
26
- @parser.request_url.should be_nil
27
- @parser.request_path.should be_nil
28
- @parser.query_string.should be_nil
29
- @parser.fragment.should be_nil
29
+ expect(@parser.request_url).to be_nil
30
30
 
31
- @parser.header_value_type.should == :mixed
31
+ expect(@parser.header_value_type).to eq(:mixed)
32
32
  end
33
33
 
34
34
  it "should allow us to set the header value type" do
35
35
  [:mixed, :arrays, :strings].each do |type|
36
36
  @parser.header_value_type = type
37
- @parser.header_value_type.should == type
37
+ expect(@parser.header_value_type).to eq(type)
38
38
 
39
39
  parser_tmp = HTTP::Parser.new(nil, type)
40
- parser_tmp.header_value_type.should == type
40
+ expect(parser_tmp.header_value_type).to eq(type)
41
41
  end
42
42
  end
43
43
 
@@ -46,18 +46,18 @@ describe HTTP::Parser do
46
46
  HTTP::Parser.default_header_value_type = type
47
47
 
48
48
  parser = HTTP::Parser.new
49
- parser.header_value_type.should == type
49
+ expect(parser.header_value_type).to eq(type)
50
50
  end
51
51
  end
52
52
 
53
53
  it "should throw an Argument Error if header value type is invalid" do
54
- proc{ @parser.header_value_type = 'bob' }.should raise_error(ArgumentError)
54
+ expect{ @parser.header_value_type = 'bob' }.to raise_error(ArgumentError)
55
55
  end
56
-
56
+
57
57
  it "should throw an Argument Error if default header value type is invalid" do
58
- proc{ HTTP::Parser.default_header_value_type = 'bob' }.should raise_error(ArgumentError)
58
+ expect{ HTTP::Parser.default_header_value_type = 'bob' }.to raise_error(ArgumentError)
59
59
  end
60
-
60
+
61
61
  it "should implement basic api" do
62
62
  @parser <<
63
63
  "GET /test?ok=1 HTTP/1.1\r\n" +
@@ -68,32 +68,29 @@ describe HTTP::Parser do
68
68
  "\r\n" +
69
69
  "World"
70
70
 
71
- @started.should be_true
72
- @done.should be_true
71
+ expect(@started).to be true
72
+ expect(@done).to be true
73
73
 
74
- @parser.http_major.should == 1
75
- @parser.http_minor.should == 1
76
- @parser.http_version.should == [1,1]
77
- @parser.http_method.should == 'GET'
78
- @parser.status_code.should be_nil
74
+ expect(@parser.http_major).to eq(1)
75
+ expect(@parser.http_minor).to eq(1)
76
+ expect(@parser.http_version).to eq([1,1])
77
+ expect(@parser.http_method).to eq('GET')
78
+ expect(@parser.status_code).to be_nil
79
79
 
80
- @parser.request_url.should == '/test?ok=1'
81
- @parser.request_path.should == '/test'
82
- @parser.query_string.should == 'ok=1'
83
- @parser.fragment.should be_empty
80
+ expect(@parser.request_url).to eq('/test?ok=1')
84
81
 
85
- @parser.headers.should == @headers
86
- @parser.headers['User-Agent'].should == 'curl/7.18.0'
87
- @parser.headers['Host'].should == '0.0.0.0:5000'
82
+ expect(@parser.headers).to eq(@headers)
83
+ expect(@parser.headers['User-Agent']).to eq('curl/7.18.0')
84
+ expect(@parser.headers['Host']).to eq('0.0.0.0:5000')
88
85
 
89
- @body.should == "World"
86
+ expect(@body).to eq("World")
90
87
  end
91
88
 
92
89
  it "should raise errors on invalid data" do
93
- proc{ @parser << "BLAH" }.should raise_error(HTTP::Parser::Error)
90
+ expect{ @parser << "BLAH" }.to raise_error(HTTP::Parser::Error)
94
91
  end
95
92
 
96
- it "should abort parser via callback" do
93
+ it "should abort parser via header complete callback with a body" do
97
94
  @parser.on_headers_complete = proc { |e| @headers = e; :stop }
98
95
 
99
96
  data =
@@ -104,44 +101,114 @@ describe HTTP::Parser do
104
101
 
105
102
  bytes = @parser << data
106
103
 
107
- bytes.should == 37
108
- data[bytes..-1].should == 'World'
104
+ expect(bytes).to eq(37)
105
+ expect(data[bytes..-1]).to eq('World')
106
+
107
+ expect(@headers).to eq({'Content-Length' => '5'})
108
+ expect(@body).to be_empty
109
+ expect(@done).to be false
110
+ end
111
+
112
+ it "should abort parser via header complete callback without a body" do
113
+ @parser.on_headers_complete = proc { |e| @headers = e; :stop }
114
+
115
+ data =
116
+ "GET / HTTP/1.0\r\n" +
117
+ "Content-Length: 0\r\n" +
118
+ "\r\n"
119
+
120
+ bytes = @parser << data
121
+
122
+ expect(bytes).to eq(37)
123
+ expect(data[bytes..-1]).to eq('')
109
124
 
110
- @headers.should == {'Content-Length' => '5'}
111
- @body.should be_empty
112
- @done.should be_false
125
+ expect(@headers).to eq({'Content-Length' => '0'})
126
+ expect(@body).to be_empty
127
+ expect(@done).to be false
128
+ end
129
+
130
+ it "should abort parser via message complete callback with a body" do
131
+ @parser.on_message_complete = proc { :stop }
132
+
133
+ data =
134
+ "CONNECT www.example.com:443 HTTP/1.0\r\n" +
135
+ "Connection: keep-alive\r\n" +
136
+ "\r\n" +
137
+ "World"
138
+
139
+ bytes = @parser << data
140
+
141
+ expect(bytes).to eq(64)
142
+ expect(data[bytes..-1]).to eq('World')
143
+
144
+ expect(@headers).to eq({'Connection' => 'keep-alive'})
145
+ expect(@parser.upgrade_data).to eq('World')
146
+ expect(@body).to be_empty
147
+ expect(@done).to be false
148
+ end
149
+
150
+ it "should abort parser via message complete callback without a body" do
151
+ @parser.on_message_complete = proc { :stop }
152
+
153
+ data =
154
+ "CONNECT www.example.com:443 HTTP/1.0\r\n" +
155
+ "Connection: keep-alive\r\n" +
156
+ "\r\n"
157
+
158
+ bytes = @parser << data
159
+
160
+ expect(bytes).to eq(64)
161
+ expect(data[bytes..-1]).to eq('')
162
+
163
+ expect(@headers).to eq({'Connection' => 'keep-alive'})
164
+ expect(@parser.upgrade_data).to eq('')
165
+ expect(@body).to be_empty
166
+ expect(@done).to be false
113
167
  end
114
168
 
115
169
  it "should reset to initial state" do
116
170
  @parser << "GET / HTTP/1.0\r\n\r\n"
117
171
 
118
- @parser.http_method.should == 'GET'
119
- @parser.http_version.should == [1,0]
172
+ expect(@parser.http_method).to eq('GET')
173
+ expect(@parser.http_version).to eq([1,0])
120
174
 
121
- @parser.request_url.should == '/'
122
- @parser.request_path.should == '/'
123
- @parser.query_string.should == ''
124
- @parser.fragment.should == ''
175
+ expect(@parser.request_url).to eq('/')
125
176
 
126
- @parser.reset!.should be_true
177
+ expect(@parser.reset!).to be true
127
178
 
128
- @parser.http_version.should be_nil
129
- @parser.http_method.should be_nil
130
- @parser.status_code.should be_nil
179
+ expect(@parser.http_version).to be_nil
180
+ expect(@parser.http_method).to be_nil
181
+ expect(@parser.status_code).to be_nil
131
182
 
132
- @parser.request_url.should be_nil
133
- @parser.request_path.should be_nil
134
- @parser.query_string.should be_nil
135
- @parser.fragment.should be_nil
183
+ expect(@parser.request_url).to be_nil
184
+ end
185
+
186
+ it "should optionally reset parser state on no-body responses" do
187
+ expect(@parser.reset!).to be true
188
+
189
+ @head, @complete = 0, 0
190
+ @parser.on_headers_complete = proc {|h| @head += 1; :reset }
191
+ @parser.on_message_complete = proc { @complete += 1 }
192
+ @parser.on_body = proc {|b| fail }
193
+
194
+ head_response = "HTTP/1.1 200 OK\r\nContent-Length:10\r\n\r\n"
195
+
196
+ @parser << head_response
197
+ expect(@head).to eq(1)
198
+ expect(@complete).to eq(1)
199
+
200
+ @parser << head_response
201
+ expect(@head).to eq(2)
202
+ expect(@complete).to eq(2)
136
203
  end
137
204
 
138
205
  it "should retain callbacks after reset" do
139
- @parser.reset!.should be_true
206
+ expect(@parser.reset!).to be true
140
207
 
141
208
  @parser << "GET / HTTP/1.0\r\n\r\n"
142
- @started.should be_true
143
- @headers.should == {}
144
- @done.should be_true
209
+ expect(@started).to be true
210
+ expect(@headers).to eq({})
211
+ expect(@done).to be true
145
212
  end
146
213
 
147
214
  it "should parse headers incrementally" do
@@ -155,10 +222,10 @@ describe HTTP::Parser do
155
222
  @parser << chunk
156
223
  end
157
224
 
158
- @parser.headers.should == {
225
+ expect(@parser.headers).to eq({
159
226
  'Header1' => 'value 1',
160
227
  'Header2' => 'value 2'
161
- }
228
+ })
162
229
  end
163
230
 
164
231
  it "should handle multiple headers using strings" do
@@ -170,7 +237,7 @@ describe HTTP::Parser do
170
237
  "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
171
238
  "\r\n"
172
239
 
173
- @parser.headers["Set-Cookie"].should == "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com, NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
240
+ expect(@parser.headers["Set-Cookie"]).to eq("PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com, NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly")
174
241
  end
175
242
 
176
243
  it "should handle multiple headers using strings" do
@@ -182,10 +249,10 @@ describe HTTP::Parser do
182
249
  "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
183
250
  "\r\n"
184
251
 
185
- @parser.headers["Set-Cookie"].should == [
252
+ expect(@parser.headers["Set-Cookie"]).to eq([
186
253
  "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com",
187
254
  "NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
188
- ]
255
+ ])
189
256
  end
190
257
 
191
258
  it "should handle multiple headers using mixed" do
@@ -197,10 +264,10 @@ describe HTTP::Parser do
197
264
  "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
198
265
  "\r\n"
199
266
 
200
- @parser.headers["Set-Cookie"].should == [
267
+ expect(@parser.headers["Set-Cookie"]).to eq([
201
268
  "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com",
202
269
  "NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
203
- ]
270
+ ])
204
271
  end
205
272
 
206
273
  it "should handle a single cookie using mixed" do
@@ -211,23 +278,23 @@ describe HTTP::Parser do
211
278
  "Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
212
279
  "\r\n"
213
280
 
214
- @parser.headers["Set-Cookie"].should == "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com"
281
+ expect(@parser.headers["Set-Cookie"]).to eq("PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com")
215
282
  end
216
283
 
217
284
  it "should support alternative api" do
218
285
  callbacks = double('callbacks')
219
- callbacks.stub(:on_message_begin){ @started = true }
220
- callbacks.stub(:on_headers_complete){ |e| @headers = e }
221
- callbacks.stub(:on_body){ |chunk| @body << chunk }
222
- callbacks.stub(:on_message_complete){ @done = true }
286
+ allow(callbacks).to receive(:on_message_begin){ @started = true }
287
+ allow(callbacks).to receive(:on_headers_complete){ |e| @headers = e }
288
+ allow(callbacks).to receive(:on_body){ |chunk| @body << chunk }
289
+ allow(callbacks).to receive(:on_message_complete){ @done = true }
223
290
 
224
291
  @parser = HTTP::Parser.new(callbacks)
225
292
  @parser << "GET / HTTP/1.0\r\n\r\n"
226
293
 
227
- @started.should be_true
228
- @headers.should == {}
229
- @body.should == ''
230
- @done.should be_true
294
+ expect(@started).to be true
295
+ expect(@headers).to eq({})
296
+ expect(@body).to eq('')
297
+ expect(@done).to be true
231
298
  end
232
299
 
233
300
  it "should ignore extra content beyond specified length" do
@@ -238,8 +305,8 @@ describe HTTP::Parser do
238
305
  "hello" +
239
306
  " \n"
240
307
 
241
- @body.should == 'hello'
242
- @done.should be_true
308
+ expect(@body).to eq('hello')
309
+ expect(@done).to be true
243
310
  end
244
311
 
245
312
  it 'sets upgrade_data if available' do
@@ -249,8 +316,8 @@ describe HTTP::Parser do
249
316
  "Upgrade: WebSocket\r\n\r\n" +
250
317
  "third key data"
251
318
 
252
- @parser.upgrade?.should be_true
253
- @parser.upgrade_data.should == 'third key data'
319
+ expect(@parser.upgrade?).to be true
320
+ expect(@parser.upgrade_data).to eq('third key data')
254
321
  end
255
322
 
256
323
  it 'sets upgrade_data to blank if un-available' do
@@ -259,48 +326,75 @@ describe HTTP::Parser do
259
326
  "Connection: Upgrade\r\n" +
260
327
  "Upgrade: WebSocket\r\n\r\n"
261
328
 
262
- @parser.upgrade?.should be_true
263
- @parser.upgrade_data.should == ''
329
+ expect(@parser.upgrade?).to be true
330
+ expect(@parser.upgrade_data).to eq('')
331
+ end
332
+
333
+ it 'should stop parsing headers when instructed' do
334
+ request = "GET /websocket HTTP/1.1\r\n" +
335
+ "host: localhost\r\n" +
336
+ "connection: Upgrade\r\n" +
337
+ "upgrade: websocket\r\n" +
338
+ "sec-websocket-key: SD6/hpYbKjQ6Sown7pBbWQ==\r\n" +
339
+ "sec-websocket-version: 13\r\n" +
340
+ "\r\n"
341
+
342
+ @parser.on_headers_complete = proc { |e| :stop }
343
+ offset = (@parser << request)
344
+ expect(@parser.upgrade?).to be true
345
+ expect(@parser.upgrade_data).to eq('')
346
+ expect(offset).to eq(request.length)
264
347
  end
265
348
 
349
+ it "should execute on_body on requests with no content-length" do
350
+ expect(@parser.reset!).to be true
351
+
352
+ @head, @complete, @body = 0, 0, 0
353
+ @parser.on_headers_complete = proc {|h| @head += 1 }
354
+ @parser.on_message_complete = proc { @complete += 1 }
355
+ @parser.on_body = proc {|b| @body += 1 }
356
+
357
+ head_response = "HTTP/1.1 200 OK\r\n\r\nstuff"
358
+
359
+ @parser << head_response
360
+ @parser << ''
361
+ expect(@head).to eq(1)
362
+ expect(@complete).to eq(1)
363
+ expect(@body).to eq(1)
364
+ end
365
+
366
+
266
367
  %w[ request response ].each do |type|
267
368
  JSON.parse(File.read(File.expand_path("../support/#{type}s.json", __FILE__))).each do |test|
268
369
  test['headers'] ||= {}
370
+ next if !defined?(JRUBY_VERSION) and HTTP::Parser.strict? != test['strict']
269
371
 
270
372
  it "should parse #{type}: #{test['name']}" do
271
373
  @parser << test['raw']
272
374
 
273
- @parser.keep_alive?.should == test['should_keep_alive']
274
- @parser.upgrade?.should == (test['upgrade']==1)
275
- @parser.http_method.should == test['method']
375
+ expect(@parser.http_method).to eq(test['method'])
376
+ expect(@parser.keep_alive?).to eq(test['should_keep_alive'])
377
+
378
+ if test.has_key?('upgrade') and test['upgrade'] != 0
379
+ expect(@parser.upgrade?).to be true
380
+ expect(@parser.upgrade_data).to eq(test['upgrade'])
381
+ end
276
382
 
277
- fields = %w[
278
- http_major
279
- http_minor
280
- ]
383
+ expect(@parser.send("http_major")).to eq(test["http_major"])
384
+ expect(@parser.send("http_minor")).to eq(test["http_minor"])
281
385
 
282
386
  if test['type'] == 'HTTP_REQUEST'
283
- fields += %w[
284
- request_url
285
- request_path
286
- query_string
287
- fragment
288
- ]
387
+ expect(@parser.send("request_url")).to eq(test["request_url"].force_encoding(Encoding::BINARY))
289
388
  else
290
- fields += %w[
291
- status_code
292
- ]
293
- end
294
-
295
- fields.each do |field|
296
- @parser.send(field).should == test[field]
389
+ expect(@parser.send("status_code")).to eq(test["status_code"])
390
+ expect(@parser.send("status")).to eq(test["status"].force_encoding(Encoding::BINARY))
297
391
  end
298
392
 
299
- @headers.size.should == test['num_headers']
300
- @headers.should == test['headers']
393
+ expect(@headers.size).to eq(test['num_headers'])
394
+ expect(@headers).to eq(test['headers'])
301
395
 
302
- @body.should == test['body']
303
- @body.size.should == test['body_size'] if test['body_size']
396
+ expect(@body).to eq(test['body'])
397
+ expect(@body.size).to eq(test['body_size']) if test['body_size']
304
398
  end
305
399
  end
306
400
  end