jls-http_parser.rb 0.5.3.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/.gitignore +11 -0
- data/.gitmodules +6 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +39 -0
- data/LICENSE-MIT +20 -0
- data/README.md +90 -0
- data/Rakefile +6 -0
- data/bench/standalone.rb +23 -0
- data/bench/thin.rb +58 -0
- data/ext/ruby_http_parser/.gitignore +1 -0
- data/ext/ruby_http_parser/RubyHttpParserService.java +18 -0
- data/ext/ruby_http_parser/ext_help.h +18 -0
- data/ext/ruby_http_parser/extconf.rb +24 -0
- data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +474 -0
- data/ext/ruby_http_parser/ruby_http_parser.c +546 -0
- data/ext/ruby_http_parser/vendor/.gitkeep +0 -0
- data/http_parser.rb.gemspec +27 -0
- data/lib/http/parser.rb +1 -0
- data/lib/http_parser.rb +21 -0
- data/spec/parser_spec.rb +326 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/requests.json +400 -0
- data/spec/support/responses.json +229 -0
- data/tasks/compile.rake +42 -0
- data/tasks/fixtures.rake +65 -0
- data/tasks/spec.rake +5 -0
- data/tasks/submodules.rake +7 -0
- metadata +172 -0
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "jls-http_parser.rb"
|
3
|
+
s.version = "0.5.3.1"
|
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"
|
6
|
+
|
7
|
+
s.authors = ["Marc-Andre Cournoyer", "Aman Gupta"]
|
8
|
+
s.email = ["macournoyer@gmail.com", "aman@tmm1.net"]
|
9
|
+
|
10
|
+
s.homepage = "http://github.com/tmm1/http_parser.rb"
|
11
|
+
s.files = `git ls-files`.split("\n") + Dir['ext/ruby_http_parser/vendor/**/*']
|
12
|
+
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
s.extensions = ["ext/ruby_http_parser/extconf.rb"]
|
15
|
+
|
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'
|
19
|
+
s.add_development_dependency 'benchmark_suite'
|
20
|
+
s.add_development_dependency 'ffi'
|
21
|
+
|
22
|
+
if RUBY_PLATFORM =~ /java/
|
23
|
+
s.add_development_dependency 'jruby-openssl'
|
24
|
+
else
|
25
|
+
s.add_development_dependency 'yajl-ruby', '>= 0.8.1'
|
26
|
+
end
|
27
|
+
end
|
data/lib/http/parser.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'http_parser'
|
data/lib/http_parser.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
$:.unshift File.expand_path('../', __FILE__)
|
2
|
+
require 'ruby_http_parser'
|
3
|
+
|
4
|
+
Http = HTTP
|
5
|
+
|
6
|
+
module HTTP
|
7
|
+
class Parser
|
8
|
+
class << self
|
9
|
+
attr_reader :default_header_value_type
|
10
|
+
|
11
|
+
def default_header_value_type=(val)
|
12
|
+
if (val != :mixed && val != :strings && val != :arrays)
|
13
|
+
raise ArgumentError, "Invalid header value type"
|
14
|
+
end
|
15
|
+
@default_header_value_type = val
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
HTTP::Parser.default_header_value_type = :mixed
|
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,326 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
describe HTTP::Parser do
|
5
|
+
before do
|
6
|
+
@parser = HTTP::Parser.new
|
7
|
+
|
8
|
+
@headers = nil
|
9
|
+
@body = ""
|
10
|
+
@started = false
|
11
|
+
@done = false
|
12
|
+
|
13
|
+
@parser.on_message_begin = proc{ @started = true }
|
14
|
+
@parser.on_headers_complete = proc { |e| @headers = e }
|
15
|
+
@parser.on_body = proc { |chunk| @body << chunk }
|
16
|
+
@parser.on_message_complete = proc{ @done = true }
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have initial state" do
|
20
|
+
@parser.headers.should be_nil
|
21
|
+
|
22
|
+
@parser.http_version.should be_nil
|
23
|
+
@parser.http_method.should be_nil
|
24
|
+
@parser.status_code.should be_nil
|
25
|
+
|
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
|
30
|
+
|
31
|
+
@parser.header_value_type.should == :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
|
+
@parser.header_value_type.should == type
|
38
|
+
|
39
|
+
parser_tmp = HTTP::Parser.new(nil, type)
|
40
|
+
parser_tmp.header_value_type.should == 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
|
+
parser.header_value_type.should == type
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
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)
|
55
|
+
end
|
56
|
+
|
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)
|
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
|
+
@started.should be_true
|
72
|
+
@done.should be_true
|
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
|
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
|
84
|
+
|
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'
|
88
|
+
|
89
|
+
@body.should == "World"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should raise errors on invalid data" do
|
93
|
+
proc{ @parser << "BLAH" }.should raise_error(HTTP::Parser::Error)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should abort parser via callback" do
|
97
|
+
@parser.on_headers_complete = proc { |e| @headers = e; :stop }
|
98
|
+
|
99
|
+
data =
|
100
|
+
"GET / HTTP/1.0\r\n" +
|
101
|
+
"Content-Length: 5\r\n" +
|
102
|
+
"\r\n" +
|
103
|
+
"World"
|
104
|
+
|
105
|
+
bytes = @parser << data
|
106
|
+
|
107
|
+
bytes.should == 37
|
108
|
+
data[bytes..-1].should == 'World'
|
109
|
+
|
110
|
+
@headers.should == {'Content-Length' => '5'}
|
111
|
+
@body.should be_empty
|
112
|
+
@done.should be_false
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should reset to initial state" do
|
116
|
+
@parser << "GET / HTTP/1.0\r\n\r\n"
|
117
|
+
|
118
|
+
@parser.http_method.should == 'GET'
|
119
|
+
@parser.http_version.should == [1,0]
|
120
|
+
|
121
|
+
@parser.request_url.should == '/'
|
122
|
+
@parser.request_path.should == '/'
|
123
|
+
@parser.query_string.should == ''
|
124
|
+
@parser.fragment.should == ''
|
125
|
+
|
126
|
+
@parser.reset!.should be_true
|
127
|
+
|
128
|
+
@parser.http_version.should be_nil
|
129
|
+
@parser.http_method.should be_nil
|
130
|
+
@parser.status_code.should be_nil
|
131
|
+
|
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
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should optionally reset parser state on no-body responses" do
|
139
|
+
@parser.reset!.should be_true
|
140
|
+
|
141
|
+
@head, @complete = 0, 0
|
142
|
+
@parser.on_headers_complete = proc {|h| @head += 1; :reset }
|
143
|
+
@parser.on_message_complete = proc { @complete += 1 }
|
144
|
+
@parser.on_body = proc {|b| fail }
|
145
|
+
|
146
|
+
head_response = "HTTP/1.1 200 OK\r\nContent-Length:10\r\n\r\n"
|
147
|
+
|
148
|
+
@parser << head_response
|
149
|
+
@head.should == 1
|
150
|
+
@complete.should == 1
|
151
|
+
|
152
|
+
@parser << head_response
|
153
|
+
@head.should == 2
|
154
|
+
@complete.should == 2
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should retain callbacks after reset" do
|
158
|
+
@parser.reset!.should be_true
|
159
|
+
|
160
|
+
@parser << "GET / HTTP/1.0\r\n\r\n"
|
161
|
+
@started.should be_true
|
162
|
+
@headers.should == {}
|
163
|
+
@done.should be_true
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should parse headers incrementally" do
|
167
|
+
request =
|
168
|
+
"GET / HTTP/1.0\r\n" +
|
169
|
+
"Header1: value 1\r\n" +
|
170
|
+
"Header2: value 2\r\n" +
|
171
|
+
"\r\n"
|
172
|
+
|
173
|
+
while chunk = request.slice!(0,2) and !chunk.empty?
|
174
|
+
@parser << chunk
|
175
|
+
end
|
176
|
+
|
177
|
+
@parser.headers.should == {
|
178
|
+
'Header1' => 'value 1',
|
179
|
+
'Header2' => 'value 2'
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should handle multiple headers using strings" do
|
184
|
+
@parser.header_value_type = :strings
|
185
|
+
|
186
|
+
@parser <<
|
187
|
+
"GET / HTTP/1.0\r\n" +
|
188
|
+
"Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
|
189
|
+
"Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
|
190
|
+
"\r\n"
|
191
|
+
|
192
|
+
@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"
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should handle multiple headers using strings" do
|
196
|
+
@parser.header_value_type = :arrays
|
197
|
+
|
198
|
+
@parser <<
|
199
|
+
"GET / HTTP/1.0\r\n" +
|
200
|
+
"Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
|
201
|
+
"Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
|
202
|
+
"\r\n"
|
203
|
+
|
204
|
+
@parser.headers["Set-Cookie"].should == [
|
205
|
+
"PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com",
|
206
|
+
"NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
|
207
|
+
]
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should handle multiple headers using mixed" do
|
211
|
+
@parser.header_value_type = :mixed
|
212
|
+
|
213
|
+
@parser <<
|
214
|
+
"GET / HTTP/1.0\r\n" +
|
215
|
+
"Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
|
216
|
+
"Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
|
217
|
+
"\r\n"
|
218
|
+
|
219
|
+
@parser.headers["Set-Cookie"].should == [
|
220
|
+
"PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com",
|
221
|
+
"NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
|
222
|
+
]
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should handle a single cookie using mixed" do
|
226
|
+
@parser.header_value_type = :mixed
|
227
|
+
|
228
|
+
@parser <<
|
229
|
+
"GET / HTTP/1.0\r\n" +
|
230
|
+
"Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
|
231
|
+
"\r\n"
|
232
|
+
|
233
|
+
@parser.headers["Set-Cookie"].should == "PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com"
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should support alternative api" do
|
237
|
+
callbacks = double('callbacks')
|
238
|
+
callbacks.stub(:on_message_begin){ @started = true }
|
239
|
+
callbacks.stub(:on_headers_complete){ |e| @headers = e }
|
240
|
+
callbacks.stub(:on_body){ |chunk| @body << chunk }
|
241
|
+
callbacks.stub(:on_message_complete){ @done = true }
|
242
|
+
|
243
|
+
@parser = HTTP::Parser.new(callbacks)
|
244
|
+
@parser << "GET / HTTP/1.0\r\n\r\n"
|
245
|
+
|
246
|
+
@started.should be_true
|
247
|
+
@headers.should == {}
|
248
|
+
@body.should == ''
|
249
|
+
@done.should be_true
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should ignore extra content beyond specified length" do
|
253
|
+
@parser <<
|
254
|
+
"GET / HTTP/1.0\r\n" +
|
255
|
+
"Content-Length: 5\r\n" +
|
256
|
+
"\r\n" +
|
257
|
+
"hello" +
|
258
|
+
" \n"
|
259
|
+
|
260
|
+
@body.should == 'hello'
|
261
|
+
@done.should be_true
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'sets upgrade_data if available' do
|
265
|
+
@parser <<
|
266
|
+
"GET /demo HTTP/1.1\r\n" +
|
267
|
+
"Connection: Upgrade\r\n" +
|
268
|
+
"Upgrade: WebSocket\r\n\r\n" +
|
269
|
+
"third key data"
|
270
|
+
|
271
|
+
@parser.upgrade?.should be_true
|
272
|
+
@parser.upgrade_data.should == 'third key data'
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'sets upgrade_data to blank if un-available' do
|
276
|
+
@parser <<
|
277
|
+
"GET /demo HTTP/1.1\r\n" +
|
278
|
+
"Connection: Upgrade\r\n" +
|
279
|
+
"Upgrade: WebSocket\r\n\r\n"
|
280
|
+
|
281
|
+
@parser.upgrade?.should be_true
|
282
|
+
@parser.upgrade_data.should == ''
|
283
|
+
end
|
284
|
+
|
285
|
+
%w[ request response ].each do |type|
|
286
|
+
JSON.parse(File.read(File.expand_path("../support/#{type}s.json", __FILE__))).each do |test|
|
287
|
+
test['headers'] ||= {}
|
288
|
+
|
289
|
+
it "should parse #{type}: #{test['name']}" do
|
290
|
+
@parser << test['raw']
|
291
|
+
|
292
|
+
@parser.keep_alive?.should == test['should_keep_alive']
|
293
|
+
@parser.upgrade?.should == (test['upgrade']==1)
|
294
|
+
@parser.http_method.should == test['method']
|
295
|
+
|
296
|
+
fields = %w[
|
297
|
+
http_major
|
298
|
+
http_minor
|
299
|
+
]
|
300
|
+
|
301
|
+
if test['type'] == 'HTTP_REQUEST'
|
302
|
+
fields += %w[
|
303
|
+
request_url
|
304
|
+
request_path
|
305
|
+
query_string
|
306
|
+
fragment
|
307
|
+
]
|
308
|
+
else
|
309
|
+
fields += %w[
|
310
|
+
status_code
|
311
|
+
]
|
312
|
+
end
|
313
|
+
|
314
|
+
fields.each do |field|
|
315
|
+
@parser.send(field).should == test[field]
|
316
|
+
end
|
317
|
+
|
318
|
+
@headers.size.should == test['num_headers']
|
319
|
+
@headers.should == test['headers']
|
320
|
+
|
321
|
+
@body.should == test['body']
|
322
|
+
@body.size.should == test['body_size'] if test['body_size']
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "http_parser"
|
@@ -0,0 +1,400 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"name": "curl get",
|
4
|
+
"type": "HTTP_REQUEST",
|
5
|
+
"raw": "GET /test HTTP/1.1\r\nUser-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\nHost: 0.0.0.0=5000\r\nAccept: */*\r\n\r\n",
|
6
|
+
"should_keep_alive": true,
|
7
|
+
"message_complete_on_eof": false,
|
8
|
+
"http_major": 1,
|
9
|
+
"http_minor": 1,
|
10
|
+
"method": "GET",
|
11
|
+
"query_string": "",
|
12
|
+
"fragment": "",
|
13
|
+
"request_path": "/test",
|
14
|
+
"request_url": "/test",
|
15
|
+
"num_headers": 3,
|
16
|
+
"headers": {
|
17
|
+
"User-Agent": "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1",
|
18
|
+
"Host": "0.0.0.0=5000",
|
19
|
+
"Accept": "*/*"
|
20
|
+
},
|
21
|
+
"body": ""
|
22
|
+
},
|
23
|
+
{
|
24
|
+
"name": "firefox get",
|
25
|
+
"type": "HTTP_REQUEST",
|
26
|
+
"raw": "GET /favicon.ico HTTP/1.1\r\nHost: 0.0.0.0=5000\r\nUser-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Encoding: gzip,deflate\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\n\r\n",
|
27
|
+
"should_keep_alive": true,
|
28
|
+
"message_complete_on_eof": false,
|
29
|
+
"http_major": 1,
|
30
|
+
"http_minor": 1,
|
31
|
+
"method": "GET",
|
32
|
+
"query_string": "",
|
33
|
+
"fragment": "",
|
34
|
+
"request_path": "/favicon.ico",
|
35
|
+
"request_url": "/favicon.ico",
|
36
|
+
"num_headers": 8,
|
37
|
+
"headers": {
|
38
|
+
"Host": "0.0.0.0=5000",
|
39
|
+
"User-Agent": "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0",
|
40
|
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
41
|
+
"Accept-Language": "en-us,en;q=0.5",
|
42
|
+
"Accept-Encoding": "gzip,deflate",
|
43
|
+
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
44
|
+
"Keep-Alive": "300",
|
45
|
+
"Connection": "keep-alive"
|
46
|
+
},
|
47
|
+
"body": ""
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"name": "dumbfuck",
|
51
|
+
"type": "HTTP_REQUEST",
|
52
|
+
"raw": "GET /dumbfuck HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n",
|
53
|
+
"should_keep_alive": true,
|
54
|
+
"message_complete_on_eof": false,
|
55
|
+
"http_major": 1,
|
56
|
+
"http_minor": 1,
|
57
|
+
"method": "GET",
|
58
|
+
"query_string": "",
|
59
|
+
"fragment": "",
|
60
|
+
"request_path": "/dumbfuck",
|
61
|
+
"request_url": "/dumbfuck",
|
62
|
+
"num_headers": 1,
|
63
|
+
"headers": {
|
64
|
+
"aaaaaaaaaaaaa": "++++++++++"
|
65
|
+
},
|
66
|
+
"body": ""
|
67
|
+
},
|
68
|
+
{
|
69
|
+
"name": "fragment in url",
|
70
|
+
"type": "HTTP_REQUEST",
|
71
|
+
"raw": "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n",
|
72
|
+
"should_keep_alive": true,
|
73
|
+
"message_complete_on_eof": false,
|
74
|
+
"http_major": 1,
|
75
|
+
"http_minor": 1,
|
76
|
+
"method": "GET",
|
77
|
+
"query_string": "page=1",
|
78
|
+
"fragment": "posts-17408",
|
79
|
+
"request_path": "/forums/1/topics/2375",
|
80
|
+
"request_url": "/forums/1/topics/2375?page=1#posts-17408",
|
81
|
+
"num_headers": 0,
|
82
|
+
"body": ""
|
83
|
+
},
|
84
|
+
{
|
85
|
+
"name": "get no headers no body",
|
86
|
+
"type": "HTTP_REQUEST",
|
87
|
+
"raw": "GET /get_no_headers_no_body/world HTTP/1.1\r\n\r\n",
|
88
|
+
"should_keep_alive": true,
|
89
|
+
"message_complete_on_eof": false,
|
90
|
+
"http_major": 1,
|
91
|
+
"http_minor": 1,
|
92
|
+
"method": "GET",
|
93
|
+
"query_string": "",
|
94
|
+
"fragment": "",
|
95
|
+
"request_path": "/get_no_headers_no_body/world",
|
96
|
+
"request_url": "/get_no_headers_no_body/world",
|
97
|
+
"num_headers": 0,
|
98
|
+
"body": ""
|
99
|
+
},
|
100
|
+
{
|
101
|
+
"name": "get one header no body",
|
102
|
+
"type": "HTTP_REQUEST",
|
103
|
+
"raw": "GET /get_one_header_no_body HTTP/1.1\r\nAccept: */*\r\n\r\n",
|
104
|
+
"should_keep_alive": true,
|
105
|
+
"message_complete_on_eof": false,
|
106
|
+
"http_major": 1,
|
107
|
+
"http_minor": 1,
|
108
|
+
"method": "GET",
|
109
|
+
"query_string": "",
|
110
|
+
"fragment": "",
|
111
|
+
"request_path": "/get_one_header_no_body",
|
112
|
+
"request_url": "/get_one_header_no_body",
|
113
|
+
"num_headers": 1,
|
114
|
+
"headers": {
|
115
|
+
"Accept": "*/*"
|
116
|
+
},
|
117
|
+
"body": ""
|
118
|
+
},
|
119
|
+
{
|
120
|
+
"name": "get funky content length body hello",
|
121
|
+
"type": "HTTP_REQUEST",
|
122
|
+
"raw": "GET /get_funky_content_length_body_hello HTTP/1.0\r\nconTENT-Length: 5\r\n\r\nHELLO",
|
123
|
+
"should_keep_alive": false,
|
124
|
+
"message_complete_on_eof": false,
|
125
|
+
"http_major": 1,
|
126
|
+
"http_minor": 0,
|
127
|
+
"method": "GET",
|
128
|
+
"query_string": "",
|
129
|
+
"fragment": "",
|
130
|
+
"request_path": "/get_funky_content_length_body_hello",
|
131
|
+
"request_url": "/get_funky_content_length_body_hello",
|
132
|
+
"num_headers": 1,
|
133
|
+
"headers": {
|
134
|
+
"conTENT-Length": "5"
|
135
|
+
},
|
136
|
+
"body": "HELLO"
|
137
|
+
},
|
138
|
+
{
|
139
|
+
"name": "post identity body world",
|
140
|
+
"type": "HTTP_REQUEST",
|
141
|
+
"raw": "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\nAccept: */*\r\nTransfer-Encoding: identity\r\nContent-Length: 5\r\n\r\nWorld",
|
142
|
+
"should_keep_alive": true,
|
143
|
+
"message_complete_on_eof": false,
|
144
|
+
"http_major": 1,
|
145
|
+
"http_minor": 1,
|
146
|
+
"method": "POST",
|
147
|
+
"query_string": "q=search",
|
148
|
+
"fragment": "hey",
|
149
|
+
"request_path": "/post_identity_body_world",
|
150
|
+
"request_url": "/post_identity_body_world?q=search#hey",
|
151
|
+
"num_headers": 3,
|
152
|
+
"headers": {
|
153
|
+
"Accept": "*/*",
|
154
|
+
"Transfer-Encoding": "identity",
|
155
|
+
"Content-Length": "5"
|
156
|
+
},
|
157
|
+
"body": "World"
|
158
|
+
},
|
159
|
+
{
|
160
|
+
"name": "post - chunked body: all your base are belong to us",
|
161
|
+
"type": "HTTP_REQUEST",
|
162
|
+
"raw": "POST /post_chunked_all_your_base HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n1e\r\nall your base are belong to us\r\n0\r\n\r\n",
|
163
|
+
"should_keep_alive": true,
|
164
|
+
"message_complete_on_eof": false,
|
165
|
+
"http_major": 1,
|
166
|
+
"http_minor": 1,
|
167
|
+
"method": "POST",
|
168
|
+
"query_string": "",
|
169
|
+
"fragment": "",
|
170
|
+
"request_path": "/post_chunked_all_your_base",
|
171
|
+
"request_url": "/post_chunked_all_your_base",
|
172
|
+
"num_headers": 1,
|
173
|
+
"headers": {
|
174
|
+
"Transfer-Encoding": "chunked"
|
175
|
+
},
|
176
|
+
"body": "all your base are belong to us"
|
177
|
+
},
|
178
|
+
{
|
179
|
+
"name": "two chunks ; triple zero ending",
|
180
|
+
"type": "HTTP_REQUEST",
|
181
|
+
"raw": "POST /two_chunks_mult_zero_end HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n6\r\n world\r\n000\r\n\r\n",
|
182
|
+
"should_keep_alive": true,
|
183
|
+
"message_complete_on_eof": false,
|
184
|
+
"http_major": 1,
|
185
|
+
"http_minor": 1,
|
186
|
+
"method": "POST",
|
187
|
+
"query_string": "",
|
188
|
+
"fragment": "",
|
189
|
+
"request_path": "/two_chunks_mult_zero_end",
|
190
|
+
"request_url": "/two_chunks_mult_zero_end",
|
191
|
+
"num_headers": 1,
|
192
|
+
"headers": {
|
193
|
+
"Transfer-Encoding": "chunked"
|
194
|
+
},
|
195
|
+
"body": "hello world"
|
196
|
+
},
|
197
|
+
{
|
198
|
+
"name": "chunked with trailing headers. blech.",
|
199
|
+
"type": "HTTP_REQUEST",
|
200
|
+
"raw": "POST /chunked_w_trailing_headers HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n6\r\n world\r\n0\r\nVary: *\r\nContent-Type: text/plain\r\n\r\n",
|
201
|
+
"should_keep_alive": true,
|
202
|
+
"message_complete_on_eof": false,
|
203
|
+
"http_major": 1,
|
204
|
+
"http_minor": 1,
|
205
|
+
"method": "POST",
|
206
|
+
"query_string": "",
|
207
|
+
"fragment": "",
|
208
|
+
"request_path": "/chunked_w_trailing_headers",
|
209
|
+
"request_url": "/chunked_w_trailing_headers",
|
210
|
+
"num_headers": 3,
|
211
|
+
"headers": {
|
212
|
+
"Transfer-Encoding": "chunked",
|
213
|
+
"Vary": "*",
|
214
|
+
"Content-Type": "text/plain"
|
215
|
+
},
|
216
|
+
"body": "hello world"
|
217
|
+
},
|
218
|
+
{
|
219
|
+
"name": "with bullshit after the length",
|
220
|
+
"type": "HTTP_REQUEST",
|
221
|
+
"raw": "POST /chunked_w_bullshit_after_length HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n6; blahblah; blah\r\n world\r\n0\r\n\r\n",
|
222
|
+
"should_keep_alive": true,
|
223
|
+
"message_complete_on_eof": false,
|
224
|
+
"http_major": 1,
|
225
|
+
"http_minor": 1,
|
226
|
+
"method": "POST",
|
227
|
+
"query_string": "",
|
228
|
+
"fragment": "",
|
229
|
+
"request_path": "/chunked_w_bullshit_after_length",
|
230
|
+
"request_url": "/chunked_w_bullshit_after_length",
|
231
|
+
"num_headers": 1,
|
232
|
+
"headers": {
|
233
|
+
"Transfer-Encoding": "chunked"
|
234
|
+
},
|
235
|
+
"body": "hello world"
|
236
|
+
},
|
237
|
+
{
|
238
|
+
"name": "with quotes",
|
239
|
+
"type": "HTTP_REQUEST",
|
240
|
+
"raw": "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n",
|
241
|
+
"should_keep_alive": true,
|
242
|
+
"message_complete_on_eof": false,
|
243
|
+
"http_major": 1,
|
244
|
+
"http_minor": 1,
|
245
|
+
"method": "GET",
|
246
|
+
"query_string": "foo=\"bar\"",
|
247
|
+
"fragment": "",
|
248
|
+
"request_path": "/with_\"stupid\"_quotes",
|
249
|
+
"request_url": "/with_\"stupid\"_quotes?foo=\"bar\"",
|
250
|
+
"num_headers": 0,
|
251
|
+
"headers": {
|
252
|
+
|
253
|
+
},
|
254
|
+
"body": ""
|
255
|
+
},
|
256
|
+
{
|
257
|
+
"name": "apachebench get",
|
258
|
+
"type": "HTTP_REQUEST",
|
259
|
+
"raw": "GET /test HTTP/1.0\r\nHost: 0.0.0.0:5000\r\nUser-Agent: ApacheBench/2.3\r\nAccept: */*\r\n\r\n",
|
260
|
+
"should_keep_alive": false,
|
261
|
+
"message_complete_on_eof": false,
|
262
|
+
"http_major": 1,
|
263
|
+
"http_minor": 0,
|
264
|
+
"method": "GET",
|
265
|
+
"query_string": "",
|
266
|
+
"fragment": "",
|
267
|
+
"request_path": "/test",
|
268
|
+
"request_url": "/test",
|
269
|
+
"num_headers": 3,
|
270
|
+
"headers": {
|
271
|
+
"Host": "0.0.0.0:5000",
|
272
|
+
"User-Agent": "ApacheBench/2.3",
|
273
|
+
"Accept": "*/*"
|
274
|
+
},
|
275
|
+
"body": ""
|
276
|
+
},
|
277
|
+
{
|
278
|
+
"name": "query url with question mark",
|
279
|
+
"type": "HTTP_REQUEST",
|
280
|
+
"raw": "GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n",
|
281
|
+
"should_keep_alive": true,
|
282
|
+
"message_complete_on_eof": false,
|
283
|
+
"http_major": 1,
|
284
|
+
"http_minor": 1,
|
285
|
+
"method": "GET",
|
286
|
+
"query_string": "foo=bar?baz",
|
287
|
+
"fragment": "",
|
288
|
+
"request_path": "/test.cgi",
|
289
|
+
"request_url": "/test.cgi?foo=bar?baz",
|
290
|
+
"num_headers": 0,
|
291
|
+
"headers": {
|
292
|
+
|
293
|
+
},
|
294
|
+
"body": ""
|
295
|
+
},
|
296
|
+
{
|
297
|
+
"name": "newline prefix get",
|
298
|
+
"type": "HTTP_REQUEST",
|
299
|
+
"raw": "\r\nGET /test HTTP/1.1\r\n\r\n",
|
300
|
+
"should_keep_alive": true,
|
301
|
+
"message_complete_on_eof": false,
|
302
|
+
"http_major": 1,
|
303
|
+
"http_minor": 1,
|
304
|
+
"method": "GET",
|
305
|
+
"query_string": "",
|
306
|
+
"fragment": "",
|
307
|
+
"request_path": "/test",
|
308
|
+
"request_url": "/test",
|
309
|
+
"num_headers": 0,
|
310
|
+
"headers": {
|
311
|
+
|
312
|
+
},
|
313
|
+
"body": ""
|
314
|
+
},
|
315
|
+
{
|
316
|
+
"name": "upgrade request",
|
317
|
+
"type": "HTTP_REQUEST",
|
318
|
+
"raw": "GET /demo HTTP/1.1\r\nHost: example.com\r\nConnection: Upgrade\r\nSec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\nSec-WebSocket-Protocol: sample\r\nUpgrade: WebSocket\r\nSec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\nOrigin: http://example.com\r\n\r\n",
|
319
|
+
"should_keep_alive": true,
|
320
|
+
"message_complete_on_eof": false,
|
321
|
+
"http_major": 1,
|
322
|
+
"http_minor": 1,
|
323
|
+
"method": "GET",
|
324
|
+
"query_string": "",
|
325
|
+
"fragment": "",
|
326
|
+
"request_path": "/demo",
|
327
|
+
"request_url": "/demo",
|
328
|
+
"num_headers": 7,
|
329
|
+
"upgrade": 1,
|
330
|
+
"headers": {
|
331
|
+
"Host": "example.com",
|
332
|
+
"Connection": "Upgrade",
|
333
|
+
"Sec-WebSocket-Key2": "12998 5 Y3 1 .P00",
|
334
|
+
"Sec-WebSocket-Protocol": "sample",
|
335
|
+
"Upgrade": "WebSocket",
|
336
|
+
"Sec-WebSocket-Key1": "4 @1 46546xW%0l 1 5",
|
337
|
+
"Origin": "http://example.com"
|
338
|
+
},
|
339
|
+
"body": ""
|
340
|
+
},
|
341
|
+
{
|
342
|
+
"name": "connect request",
|
343
|
+
"type": "HTTP_REQUEST",
|
344
|
+
"raw": "CONNECT home0.netscape.com:443 HTTP/1.0\r\nUser-agent: Mozilla/1.1N\r\nProxy-authorization: basic aGVsbG86d29ybGQ=\r\n\r\n",
|
345
|
+
"should_keep_alive": false,
|
346
|
+
"message_complete_on_eof": false,
|
347
|
+
"http_major": 1,
|
348
|
+
"http_minor": 0,
|
349
|
+
"method": "CONNECT",
|
350
|
+
"query_string": "",
|
351
|
+
"fragment": "",
|
352
|
+
"request_path": "",
|
353
|
+
"request_url": "home0.netscape.com:443",
|
354
|
+
"num_headers": 2,
|
355
|
+
"upgrade": 1,
|
356
|
+
"headers": {
|
357
|
+
"User-agent": "Mozilla/1.1N",
|
358
|
+
"Proxy-authorization": "basic aGVsbG86d29ybGQ="
|
359
|
+
},
|
360
|
+
"body": ""
|
361
|
+
},
|
362
|
+
{
|
363
|
+
"name": "report request",
|
364
|
+
"type": "HTTP_REQUEST",
|
365
|
+
"raw": "REPORT /test HTTP/1.1\r\n\r\n",
|
366
|
+
"should_keep_alive": true,
|
367
|
+
"message_complete_on_eof": false,
|
368
|
+
"http_major": 1,
|
369
|
+
"http_minor": 1,
|
370
|
+
"method": "REPORT",
|
371
|
+
"query_string": "",
|
372
|
+
"fragment": "",
|
373
|
+
"request_path": "/test",
|
374
|
+
"request_url": "/test",
|
375
|
+
"num_headers": 0,
|
376
|
+
"headers": {
|
377
|
+
|
378
|
+
},
|
379
|
+
"body": ""
|
380
|
+
},
|
381
|
+
{
|
382
|
+
"name": "request with no http version",
|
383
|
+
"type": "HTTP_REQUEST",
|
384
|
+
"raw": "GET /\r\n\r\n",
|
385
|
+
"should_keep_alive": false,
|
386
|
+
"message_complete_on_eof": false,
|
387
|
+
"http_major": 0,
|
388
|
+
"http_minor": 9,
|
389
|
+
"method": "GET",
|
390
|
+
"query_string": "",
|
391
|
+
"fragment": "",
|
392
|
+
"request_path": "/",
|
393
|
+
"request_url": "/",
|
394
|
+
"num_headers": 0,
|
395
|
+
"headers": {
|
396
|
+
|
397
|
+
},
|
398
|
+
"body": ""
|
399
|
+
}
|
400
|
+
]
|