http_parser.rb 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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