http_parser.rb 0.6.0 → 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.
@@ -1,28 +1,32 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "http_parser.rb"
3
- s.version = "0.6.0"
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
9
  s.license = 'MIT'
10
10
 
11
- s.homepage = "http://github.com/tmm1/http_parser.rb"
11
+ s.homepage = "https://github.com/tmm1/http_parser.rb"
12
12
  s.files = `git ls-files`.split("\n") + Dir['ext/ruby_http_parser/vendor/**/*']
13
13
 
14
14
  s.require_paths = ["lib"]
15
15
  s.extensions = ["ext/ruby_http_parser/extconf.rb"]
16
16
 
17
- s.add_development_dependency 'rake-compiler', '>= 0.7.9'
18
- s.add_development_dependency 'rspec', '>= 2.0.1'
19
- s.add_development_dependency 'json', '>= 1.4.6'
20
- s.add_development_dependency 'benchmark_suite'
21
- s.add_development_dependency 'ffi'
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'
22
22
 
23
23
  if RUBY_PLATFORM =~ /java/
24
24
  s.add_development_dependency 'jruby-openssl'
25
25
  else
26
- 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
27
31
  end
28
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,24 +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
29
+ expect(@parser.request_url).to be_nil
27
30
 
28
- @parser.header_value_type.should == :mixed
31
+ expect(@parser.header_value_type).to eq(:mixed)
29
32
  end
30
33
 
31
34
  it "should allow us to set the header value type" do
32
35
  [:mixed, :arrays, :strings].each do |type|
33
36
  @parser.header_value_type = type
34
- @parser.header_value_type.should == type
37
+ expect(@parser.header_value_type).to eq(type)
35
38
 
36
39
  parser_tmp = HTTP::Parser.new(nil, type)
37
- parser_tmp.header_value_type.should == type
40
+ expect(parser_tmp.header_value_type).to eq(type)
38
41
  end
39
42
  end
40
43
 
@@ -43,16 +46,16 @@ describe HTTP::Parser do
43
46
  HTTP::Parser.default_header_value_type = type
44
47
 
45
48
  parser = HTTP::Parser.new
46
- parser.header_value_type.should == type
49
+ expect(parser.header_value_type).to eq(type)
47
50
  end
48
51
  end
49
52
 
50
53
  it "should throw an Argument Error if header value type is invalid" do
51
- proc{ @parser.header_value_type = 'bob' }.should raise_error(ArgumentError)
54
+ expect{ @parser.header_value_type = 'bob' }.to raise_error(ArgumentError)
52
55
  end
53
56
 
54
57
  it "should throw an Argument Error if default header value type is invalid" do
55
- 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)
56
59
  end
57
60
 
58
61
  it "should implement basic api" do
@@ -65,29 +68,29 @@ describe HTTP::Parser do
65
68
  "\r\n" +
66
69
  "World"
67
70
 
68
- @started.should be_true
69
- @done.should be_true
71
+ expect(@started).to be true
72
+ expect(@done).to be true
70
73
 
71
- @parser.http_major.should == 1
72
- @parser.http_minor.should == 1
73
- @parser.http_version.should == [1,1]
74
- @parser.http_method.should == 'GET'
75
- @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
76
79
 
77
- @parser.request_url.should == '/test?ok=1'
80
+ expect(@parser.request_url).to eq('/test?ok=1')
78
81
 
79
- @parser.headers.should == @headers
80
- @parser.headers['User-Agent'].should == 'curl/7.18.0'
81
- @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')
82
85
 
83
- @body.should == "World"
86
+ expect(@body).to eq("World")
84
87
  end
85
88
 
86
89
  it "should raise errors on invalid data" do
87
- proc{ @parser << "BLAH" }.should raise_error(HTTP::Parser::Error)
90
+ expect{ @parser << "BLAH" }.to raise_error(HTTP::Parser::Error)
88
91
  end
89
92
 
90
- it "should abort parser via callback" do
93
+ it "should abort parser via header complete callback with a body" do
91
94
  @parser.on_headers_complete = proc { |e| @headers = e; :stop }
92
95
 
93
96
  data =
@@ -98,33 +101,90 @@ describe HTTP::Parser do
98
101
 
99
102
  bytes = @parser << data
100
103
 
101
- bytes.should == 37
102
- data[bytes..-1].should == 'World'
104
+ expect(bytes).to eq(37)
105
+ expect(data[bytes..-1]).to eq('World')
103
106
 
104
- @headers.should == {'Content-Length' => '5'}
105
- @body.should be_empty
106
- @done.should be_false
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('')
124
+
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
107
167
  end
108
168
 
109
169
  it "should reset to initial state" do
110
170
  @parser << "GET / HTTP/1.0\r\n\r\n"
111
171
 
112
- @parser.http_method.should == 'GET'
113
- @parser.http_version.should == [1,0]
172
+ expect(@parser.http_method).to eq('GET')
173
+ expect(@parser.http_version).to eq([1,0])
114
174
 
115
- @parser.request_url.should == '/'
175
+ expect(@parser.request_url).to eq('/')
116
176
 
117
- @parser.reset!.should be_true
177
+ expect(@parser.reset!).to be true
118
178
 
119
- @parser.http_version.should be_nil
120
- @parser.http_method.should be_nil
121
- @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
122
182
 
123
- @parser.request_url.should be_nil
183
+ expect(@parser.request_url).to be_nil
124
184
  end
125
185
 
126
186
  it "should optionally reset parser state on no-body responses" do
127
- @parser.reset!.should be_true
187
+ expect(@parser.reset!).to be true
128
188
 
129
189
  @head, @complete = 0, 0
130
190
  @parser.on_headers_complete = proc {|h| @head += 1; :reset }
@@ -134,21 +194,21 @@ describe HTTP::Parser do
134
194
  head_response = "HTTP/1.1 200 OK\r\nContent-Length:10\r\n\r\n"
135
195
 
136
196
  @parser << head_response
137
- @head.should == 1
138
- @complete.should == 1
197
+ expect(@head).to eq(1)
198
+ expect(@complete).to eq(1)
139
199
 
140
200
  @parser << head_response
141
- @head.should == 2
142
- @complete.should == 2
201
+ expect(@head).to eq(2)
202
+ expect(@complete).to eq(2)
143
203
  end
144
204
 
145
205
  it "should retain callbacks after reset" do
146
- @parser.reset!.should be_true
206
+ expect(@parser.reset!).to be true
147
207
 
148
208
  @parser << "GET / HTTP/1.0\r\n\r\n"
149
- @started.should be_true
150
- @headers.should == {}
151
- @done.should be_true
209
+ expect(@started).to be true
210
+ expect(@headers).to eq({})
211
+ expect(@done).to be true
152
212
  end
153
213
 
154
214
  it "should parse headers incrementally" do
@@ -162,10 +222,10 @@ describe HTTP::Parser do
162
222
  @parser << chunk
163
223
  end
164
224
 
165
- @parser.headers.should == {
225
+ expect(@parser.headers).to eq({
166
226
  'Header1' => 'value 1',
167
227
  'Header2' => 'value 2'
168
- }
228
+ })
169
229
  end
170
230
 
171
231
  it "should handle multiple headers using strings" do
@@ -177,7 +237,7 @@ describe HTTP::Parser do
177
237
  "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
178
238
  "\r\n"
179
239
 
180
- @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")
181
241
  end
182
242
 
183
243
  it "should handle multiple headers using strings" do
@@ -189,10 +249,10 @@ describe HTTP::Parser do
189
249
  "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
190
250
  "\r\n"
191
251
 
192
- @parser.headers["Set-Cookie"].should == [
252
+ expect(@parser.headers["Set-Cookie"]).to eq([
193
253
  "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com",
194
254
  "NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
195
- ]
255
+ ])
196
256
  end
197
257
 
198
258
  it "should handle multiple headers using mixed" do
@@ -204,10 +264,10 @@ describe HTTP::Parser do
204
264
  "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
205
265
  "\r\n"
206
266
 
207
- @parser.headers["Set-Cookie"].should == [
267
+ expect(@parser.headers["Set-Cookie"]).to eq([
208
268
  "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com",
209
269
  "NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
210
- ]
270
+ ])
211
271
  end
212
272
 
213
273
  it "should handle a single cookie using mixed" do
@@ -218,23 +278,23 @@ describe HTTP::Parser do
218
278
  "Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
219
279
  "\r\n"
220
280
 
221
- @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")
222
282
  end
223
283
 
224
284
  it "should support alternative api" do
225
285
  callbacks = double('callbacks')
226
- callbacks.stub(:on_message_begin){ @started = true }
227
- callbacks.stub(:on_headers_complete){ |e| @headers = e }
228
- callbacks.stub(:on_body){ |chunk| @body << chunk }
229
- 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 }
230
290
 
231
291
  @parser = HTTP::Parser.new(callbacks)
232
292
  @parser << "GET / HTTP/1.0\r\n\r\n"
233
293
 
234
- @started.should be_true
235
- @headers.should == {}
236
- @body.should == ''
237
- @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
238
298
  end
239
299
 
240
300
  it "should ignore extra content beyond specified length" do
@@ -245,8 +305,8 @@ describe HTTP::Parser do
245
305
  "hello" +
246
306
  " \n"
247
307
 
248
- @body.should == 'hello'
249
- @done.should be_true
308
+ expect(@body).to eq('hello')
309
+ expect(@done).to be true
250
310
  end
251
311
 
252
312
  it 'sets upgrade_data if available' do
@@ -256,8 +316,8 @@ describe HTTP::Parser do
256
316
  "Upgrade: WebSocket\r\n\r\n" +
257
317
  "third key data"
258
318
 
259
- @parser.upgrade?.should be_true
260
- @parser.upgrade_data.should == 'third key data'
319
+ expect(@parser.upgrade?).to be true
320
+ expect(@parser.upgrade_data).to eq('third key data')
261
321
  end
262
322
 
263
323
  it 'sets upgrade_data to blank if un-available' do
@@ -266,8 +326,8 @@ describe HTTP::Parser do
266
326
  "Connection: Upgrade\r\n" +
267
327
  "Upgrade: WebSocket\r\n\r\n"
268
328
 
269
- @parser.upgrade?.should be_true
270
- @parser.upgrade_data.should == ''
329
+ expect(@parser.upgrade?).to be true
330
+ expect(@parser.upgrade_data).to eq('')
271
331
  end
272
332
 
273
333
  it 'should stop parsing headers when instructed' do
@@ -281,13 +341,13 @@ describe HTTP::Parser do
281
341
 
282
342
  @parser.on_headers_complete = proc { |e| :stop }
283
343
  offset = (@parser << request)
284
- @parser.upgrade?.should be_true
285
- @parser.upgrade_data.should == ''
286
- offset.should == request.length
344
+ expect(@parser.upgrade?).to be true
345
+ expect(@parser.upgrade_data).to eq('')
346
+ expect(offset).to eq(request.length)
287
347
  end
288
348
 
289
349
  it "should execute on_body on requests with no content-length" do
290
- @parser.reset!.should be_true
350
+ expect(@parser.reset!).to be true
291
351
 
292
352
  @head, @complete, @body = 0, 0, 0
293
353
  @parser.on_headers_complete = proc {|h| @head += 1 }
@@ -298,9 +358,9 @@ describe HTTP::Parser do
298
358
 
299
359
  @parser << head_response
300
360
  @parser << ''
301
- @head.should == 1
302
- @complete.should == 1
303
- @body.should == 1
361
+ expect(@head).to eq(1)
362
+ expect(@complete).to eq(1)
363
+ expect(@body).to eq(1)
304
364
  end
305
365
 
306
366
 
@@ -312,38 +372,29 @@ describe HTTP::Parser do
312
372
  it "should parse #{type}: #{test['name']}" do
313
373
  @parser << test['raw']
314
374
 
315
- @parser.http_method.should == test['method']
316
- @parser.keep_alive?.should == test['should_keep_alive']
375
+ expect(@parser.http_method).to eq(test['method'])
376
+ expect(@parser.keep_alive?).to eq(test['should_keep_alive'])
317
377
 
318
378
  if test.has_key?('upgrade') and test['upgrade'] != 0
319
- @parser.upgrade?.should be_true
320
- @parser.upgrade_data.should == test['upgrade']
379
+ expect(@parser.upgrade?).to be true
380
+ expect(@parser.upgrade_data).to eq(test['upgrade'])
321
381
  end
322
382
 
323
- fields = %w[
324
- http_major
325
- http_minor
326
- ]
383
+ expect(@parser.send("http_major")).to eq(test["http_major"])
384
+ expect(@parser.send("http_minor")).to eq(test["http_minor"])
327
385
 
328
386
  if test['type'] == 'HTTP_REQUEST'
329
- fields += %w[
330
- request_url
331
- ]
387
+ expect(@parser.send("request_url")).to eq(test["request_url"].force_encoding(Encoding::BINARY))
332
388
  else
333
- fields += %w[
334
- status_code
335
- ]
336
- end
337
-
338
- fields.each do |field|
339
- @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))
340
391
  end
341
392
 
342
- @headers.size.should == test['num_headers']
343
- @headers.should == test['headers']
393
+ expect(@headers.size).to eq(test['num_headers'])
394
+ expect(@headers).to eq(test['headers'])
344
395
 
345
- @body.should == test['body']
346
- @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']
347
398
  end
348
399
  end
349
400
  end