http_parser.rb 0.7.0 → 0.8.1

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.
data/spec/parser_spec.rb DELETED
@@ -1,401 +0,0 @@
1
- if defined?(Encoding)
2
- Encoding.default_external = "UTF-8"
3
- end
4
- require "spec_helper"
5
- require "json"
6
-
7
- describe HTTP::Parser do
8
- before do
9
- @parser = HTTP::Parser.new
10
-
11
- @headers = nil
12
- @body = ""
13
- @started = false
14
- @done = false
15
-
16
- @parser.on_message_begin = proc{ @started = true }
17
- @parser.on_headers_complete = proc { |e| @headers = e }
18
- @parser.on_body = proc { |chunk| @body << chunk }
19
- @parser.on_message_complete = proc{ @done = true }
20
- end
21
-
22
- it "should have initial state" do
23
- expect(@parser.headers).to be_nil
24
-
25
- expect(@parser.http_version).to be_nil
26
- expect(@parser.http_method).to be_nil
27
- expect(@parser.status_code).to be_nil
28
-
29
- expect(@parser.request_url).to be_nil
30
-
31
- expect(@parser.header_value_type).to eq(:mixed)
32
- end
33
-
34
- it "should allow us to set the header value type" do
35
- [:mixed, :arrays, :strings].each do |type|
36
- @parser.header_value_type = type
37
- expect(@parser.header_value_type).to eq(type)
38
-
39
- parser_tmp = HTTP::Parser.new(nil, type)
40
- expect(parser_tmp.header_value_type).to eq(type)
41
- end
42
- end
43
-
44
- it "should allow us to set the default header value type" do
45
- [:mixed, :arrays, :strings].each do |type|
46
- HTTP::Parser.default_header_value_type = type
47
-
48
- parser = HTTP::Parser.new
49
- expect(parser.header_value_type).to eq(type)
50
- end
51
- end
52
-
53
- it "should throw an Argument Error if header value type is invalid" do
54
- expect{ @parser.header_value_type = 'bob' }.to raise_error(ArgumentError)
55
- end
56
-
57
- it "should throw an Argument Error if default header value type is invalid" do
58
- expect{ HTTP::Parser.default_header_value_type = 'bob' }.to raise_error(ArgumentError)
59
- end
60
-
61
- it "should implement basic api" do
62
- @parser <<
63
- "GET /test?ok=1 HTTP/1.1\r\n" +
64
- "User-Agent: curl/7.18.0\r\n" +
65
- "Host: 0.0.0.0:5000\r\n" +
66
- "Accept: */*\r\n" +
67
- "Content-Length: 5\r\n" +
68
- "\r\n" +
69
- "World"
70
-
71
- expect(@started).to be true
72
- expect(@done).to be true
73
-
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
-
80
- expect(@parser.request_url).to eq('/test?ok=1')
81
-
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')
85
-
86
- expect(@body).to eq("World")
87
- end
88
-
89
- it "should raise errors on invalid data" do
90
- expect{ @parser << "BLAH" }.to raise_error(HTTP::Parser::Error)
91
- end
92
-
93
- it "should abort parser via header complete callback with a body" do
94
- @parser.on_headers_complete = proc { |e| @headers = e; :stop }
95
-
96
- data =
97
- "GET / HTTP/1.0\r\n" +
98
- "Content-Length: 5\r\n" +
99
- "\r\n" +
100
- "World"
101
-
102
- bytes = @parser << data
103
-
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('')
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
167
- end
168
-
169
- it "should reset to initial state" do
170
- @parser << "GET / HTTP/1.0\r\n\r\n"
171
-
172
- expect(@parser.http_method).to eq('GET')
173
- expect(@parser.http_version).to eq([1,0])
174
-
175
- expect(@parser.request_url).to eq('/')
176
-
177
- expect(@parser.reset!).to be true
178
-
179
- expect(@parser.http_version).to be_nil
180
- expect(@parser.http_method).to be_nil
181
- expect(@parser.status_code).to be_nil
182
-
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)
203
- end
204
-
205
- it "should retain callbacks after reset" do
206
- expect(@parser.reset!).to be true
207
-
208
- @parser << "GET / HTTP/1.0\r\n\r\n"
209
- expect(@started).to be true
210
- expect(@headers).to eq({})
211
- expect(@done).to be true
212
- end
213
-
214
- it "should parse headers incrementally" do
215
- request =
216
- "GET / HTTP/1.0\r\n" +
217
- "Header1: value 1\r\n" +
218
- "Header2: value 2\r\n" +
219
- "\r\n"
220
-
221
- while chunk = request.slice!(0,2) and !chunk.empty?
222
- @parser << chunk
223
- end
224
-
225
- expect(@parser.headers).to eq({
226
- 'Header1' => 'value 1',
227
- 'Header2' => 'value 2'
228
- })
229
- end
230
-
231
- it "should handle multiple headers using strings" do
232
- @parser.header_value_type = :strings
233
-
234
- @parser <<
235
- "GET / HTTP/1.0\r\n" +
236
- "Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
237
- "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
238
- "\r\n"
239
-
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")
241
- end
242
-
243
- it "should handle multiple headers using strings" do
244
- @parser.header_value_type = :arrays
245
-
246
- @parser <<
247
- "GET / HTTP/1.0\r\n" +
248
- "Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
249
- "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
250
- "\r\n"
251
-
252
- expect(@parser.headers["Set-Cookie"]).to eq([
253
- "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com",
254
- "NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
255
- ])
256
- end
257
-
258
- it "should handle multiple headers using mixed" do
259
- @parser.header_value_type = :mixed
260
-
261
- @parser <<
262
- "GET / HTTP/1.0\r\n" +
263
- "Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
264
- "Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
265
- "\r\n"
266
-
267
- expect(@parser.headers["Set-Cookie"]).to eq([
268
- "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com",
269
- "NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
270
- ])
271
- end
272
-
273
- it "should handle a single cookie using mixed" do
274
- @parser.header_value_type = :mixed
275
-
276
- @parser <<
277
- "GET / HTTP/1.0\r\n" +
278
- "Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
279
- "\r\n"
280
-
281
- expect(@parser.headers["Set-Cookie"]).to eq("PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com")
282
- end
283
-
284
- it "should support alternative api" do
285
- callbacks = double('callbacks')
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 }
290
-
291
- @parser = HTTP::Parser.new(callbacks)
292
- @parser << "GET / HTTP/1.0\r\n\r\n"
293
-
294
- expect(@started).to be true
295
- expect(@headers).to eq({})
296
- expect(@body).to eq('')
297
- expect(@done).to be true
298
- end
299
-
300
- it "should ignore extra content beyond specified length" do
301
- @parser <<
302
- "GET / HTTP/1.0\r\n" +
303
- "Content-Length: 5\r\n" +
304
- "\r\n" +
305
- "hello" +
306
- " \n"
307
-
308
- expect(@body).to eq('hello')
309
- expect(@done).to be true
310
- end
311
-
312
- it 'sets upgrade_data if available' do
313
- @parser <<
314
- "GET /demo HTTP/1.1\r\n" +
315
- "Connection: Upgrade\r\n" +
316
- "Upgrade: WebSocket\r\n\r\n" +
317
- "third key data"
318
-
319
- expect(@parser.upgrade?).to be true
320
- expect(@parser.upgrade_data).to eq('third key data')
321
- end
322
-
323
- it 'sets upgrade_data to blank if un-available' do
324
- @parser <<
325
- "GET /demo HTTP/1.1\r\n" +
326
- "Connection: Upgrade\r\n" +
327
- "Upgrade: WebSocket\r\n\r\n"
328
-
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)
347
- end
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
-
367
- %w[ request response ].each do |type|
368
- JSON.parse(File.read(File.expand_path("../support/#{type}s.json", __FILE__))).each do |test|
369
- test['headers'] ||= {}
370
- next if !defined?(JRUBY_VERSION) and HTTP::Parser.strict? != test['strict']
371
-
372
- it "should parse #{type}: #{test['name']}" do
373
- @parser << test['raw']
374
-
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
382
-
383
- expect(@parser.send("http_major")).to eq(test["http_major"])
384
- expect(@parser.send("http_minor")).to eq(test["http_minor"])
385
-
386
- if test['type'] == 'HTTP_REQUEST'
387
- expect(@parser.send("request_url")).to eq(test["request_url"].force_encoding(Encoding::BINARY))
388
- else
389
- expect(@parser.send("status_code")).to eq(test["status_code"])
390
- expect(@parser.send("status")).to eq(test["status"].force_encoding(Encoding::BINARY))
391
- end
392
-
393
- expect(@headers.size).to eq(test['num_headers'])
394
- expect(@headers).to eq(test['headers'])
395
-
396
- expect(@body).to eq(test['body'])
397
- expect(@body.size).to eq(test['body_size']) if test['body_size']
398
- end
399
- end
400
- end
401
- end
data/spec/spec_helper.rb DELETED
@@ -1 +0,0 @@
1
- require "http_parser"