http_parser.rb 0.5.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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