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.
- checksums.yaml +7 -0
- data/.github/workflows/linux.yml +23 -0
- data/.github/workflows/windows.yml +23 -0
- data/.gitignore +5 -4
- data/.gitmodules +4 -4
- data/Gemfile +1 -1
- data/README.md +52 -47
- data/Rakefile +1 -0
- data/bench/standalone.rb +23 -0
- data/bench/thin.rb +1 -0
- data/ext/ruby_http_parser/extconf.rb +1 -1
- data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +139 -83
- data/ext/ruby_http_parser/ruby_http_parser.c +40 -41
- data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +5 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/README.md +133 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/TODO +6 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1202 -671
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +79 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +172 -51
- data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +22 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +41 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +8 -3
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +35 -102
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +6 -6
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +775 -682
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +8 -4
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +70 -20
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +1 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +2 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +6 -17
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +80 -9
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +2 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1637 -280
- data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
- data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +68 -0
- data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -1
- data/ext/ruby_http_parser/vendor/http-parser/README.md +113 -38
- data/ext/ruby_http_parser/vendor/http-parser/bench.c +128 -0
- data/ext/ruby_http_parser/vendor/http-parser/contrib/parsertrace.c +157 -0
- data/ext/ruby_http_parser/vendor/http-parser/contrib/url_parser.c +47 -0
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1576 -780
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +111 -0
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +308 -58
- data/ext/ruby_http_parser/vendor/http-parser/test.c +2964 -460
- data/http_parser.rb.gemspec +14 -7
- data/spec/parser_spec.rb +196 -102
- data/spec/support/requests.json +236 -24
- data/spec/support/responses.json +202 -36
- data/tasks/compile.rake +2 -2
- data/tasks/fixtures.rake +8 -2
- data/tasks/spec.rake +1 -1
- metadata +141 -134
- data/Gemfile.lock +0 -32
- data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +0 -1
- data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +0 -4
data/http_parser.rb.gemspec
CHANGED
@@ -1,25 +1,32 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "http_parser.rb"
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.7.0"
|
4
4
|
s.summary = "Simple callback-based HTTP request/response parser"
|
5
|
-
s.description = "Ruby bindings to
|
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 = "
|
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', '
|
17
|
-
s.add_development_dependency 'rspec', '
|
18
|
-
s.add_development_dependency 'json', '
|
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
|
-
|
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.
|
23
|
+
expect(@parser.headers).to be_nil
|
21
24
|
|
22
|
-
@parser.http_version.
|
23
|
-
@parser.http_method.
|
24
|
-
@parser.status_code.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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.
|
72
|
-
@done.
|
71
|
+
expect(@started).to be true
|
72
|
+
expect(@done).to be true
|
73
73
|
|
74
|
-
@parser.http_major.
|
75
|
-
@parser.http_minor.
|
76
|
-
@parser.http_version.
|
77
|
-
@parser.http_method.
|
78
|
-
@parser.status_code.
|
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.
|
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.
|
86
|
-
@parser.headers['User-Agent'].
|
87
|
-
@parser.headers['Host'].
|
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.
|
86
|
+
expect(@body).to eq("World")
|
90
87
|
end
|
91
88
|
|
92
89
|
it "should raise errors on invalid data" do
|
93
|
-
|
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.
|
108
|
-
data[bytes..-1].
|
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.
|
111
|
-
@body.
|
112
|
-
@done.
|
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.
|
119
|
-
@parser.http_version.
|
172
|
+
expect(@parser.http_method).to eq('GET')
|
173
|
+
expect(@parser.http_version).to eq([1,0])
|
120
174
|
|
121
|
-
@parser.request_url.
|
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
|
177
|
+
expect(@parser.reset!).to be true
|
127
178
|
|
128
|
-
@parser.http_version.
|
129
|
-
@parser.http_method.
|
130
|
-
@parser.status_code.
|
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.
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
206
|
+
expect(@parser.reset!).to be true
|
140
207
|
|
141
208
|
@parser << "GET / HTTP/1.0\r\n\r\n"
|
142
|
-
@started.
|
143
|
-
@headers.
|
144
|
-
@done.
|
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.
|
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"].
|
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"].
|
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"].
|
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"].
|
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.
|
220
|
-
callbacks.
|
221
|
-
callbacks.
|
222
|
-
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 }
|
223
290
|
|
224
291
|
@parser = HTTP::Parser.new(callbacks)
|
225
292
|
@parser << "GET / HTTP/1.0\r\n\r\n"
|
226
293
|
|
227
|
-
@started.
|
228
|
-
@headers.
|
229
|
-
@body.
|
230
|
-
@done.
|
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.
|
242
|
-
@done.
|
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
|
253
|
-
@parser.upgrade_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
|
263
|
-
@parser.upgrade_data.
|
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.
|
274
|
-
@parser.
|
275
|
-
|
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
|
-
|
278
|
-
|
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
|
-
|
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
|
-
|
291
|
-
|
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.
|
300
|
-
@headers.
|
393
|
+
expect(@headers.size).to eq(test['num_headers'])
|
394
|
+
expect(@headers).to eq(test['headers'])
|
301
395
|
|
302
|
-
@body.
|
303
|
-
@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
|