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.
- checksums.yaml +5 -13
- data/.github/workflows/linux.yml +23 -0
- data/.github/workflows/windows.yml +23 -0
- data/.gitignore +5 -4
- data/.gitmodules +2 -2
- data/README.md +2 -2
- data/Rakefile +1 -0
- data/ext/ruby_http_parser/extconf.rb +1 -1
- data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +22 -1
- data/ext/ruby_http_parser/ruby_http_parser.c +31 -5
- data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +37 -1
- data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -5
- data/ext/ruby_http_parser/vendor/http-parser/README.md +105 -37
- 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 +892 -510
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +34 -2
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +198 -77
- data/ext/ruby_http_parser/vendor/http-parser/test.c +1781 -201
- data/http_parser.rb.gemspec +13 -9
- data/spec/parser_spec.rb +149 -98
- data/spec/support/requests.json +2 -2
- data/spec/support/responses.json +20 -0
- data/tasks/spec.rake +1 -1
- metadata +64 -63
- data/Gemfile.lock +0 -39
- data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +0 -4
data/http_parser.rb.gemspec
CHANGED
@@ -1,28 +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
9
|
s.license = 'MIT'
|
10
10
|
|
11
|
-
s.homepage = "
|
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', '
|
18
|
-
s.add_development_dependency 'rspec', '
|
19
|
-
s.add_development_dependency 'json', '
|
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
|
-
|
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.
|
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.
|
29
|
+
expect(@parser.request_url).to be_nil
|
27
30
|
|
28
|
-
@parser.header_value_type.
|
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.
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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.
|
69
|
-
@done.
|
71
|
+
expect(@started).to be true
|
72
|
+
expect(@done).to be true
|
70
73
|
|
71
|
-
@parser.http_major.
|
72
|
-
@parser.http_minor.
|
73
|
-
@parser.http_version.
|
74
|
-
@parser.http_method.
|
75
|
-
@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
|
76
79
|
|
77
|
-
@parser.request_url.
|
80
|
+
expect(@parser.request_url).to eq('/test?ok=1')
|
78
81
|
|
79
|
-
@parser.headers.
|
80
|
-
@parser.headers['User-Agent'].
|
81
|
-
@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')
|
82
85
|
|
83
|
-
@body.
|
86
|
+
expect(@body).to eq("World")
|
84
87
|
end
|
85
88
|
|
86
89
|
it "should raise errors on invalid data" do
|
87
|
-
|
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.
|
102
|
-
data[bytes..-1].
|
104
|
+
expect(bytes).to eq(37)
|
105
|
+
expect(data[bytes..-1]).to eq('World')
|
103
106
|
|
104
|
-
@headers.
|
105
|
-
@body.
|
106
|
-
@done.
|
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.
|
113
|
-
@parser.http_version.
|
172
|
+
expect(@parser.http_method).to eq('GET')
|
173
|
+
expect(@parser.http_version).to eq([1,0])
|
114
174
|
|
115
|
-
@parser.request_url.
|
175
|
+
expect(@parser.request_url).to eq('/')
|
116
176
|
|
117
|
-
@parser.reset
|
177
|
+
expect(@parser.reset!).to be true
|
118
178
|
|
119
|
-
@parser.http_version.
|
120
|
-
@parser.http_method.
|
121
|
-
@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
|
122
182
|
|
123
|
-
@parser.request_url.
|
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
|
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.
|
138
|
-
@complete.
|
197
|
+
expect(@head).to eq(1)
|
198
|
+
expect(@complete).to eq(1)
|
139
199
|
|
140
200
|
@parser << head_response
|
141
|
-
@head.
|
142
|
-
@complete.
|
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
|
206
|
+
expect(@parser.reset!).to be true
|
147
207
|
|
148
208
|
@parser << "GET / HTTP/1.0\r\n\r\n"
|
149
|
-
@started.
|
150
|
-
@headers.
|
151
|
-
@done.
|
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.
|
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"].
|
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"].
|
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"].
|
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"].
|
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.
|
227
|
-
callbacks.
|
228
|
-
callbacks.
|
229
|
-
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 }
|
230
290
|
|
231
291
|
@parser = HTTP::Parser.new(callbacks)
|
232
292
|
@parser << "GET / HTTP/1.0\r\n\r\n"
|
233
293
|
|
234
|
-
@started.
|
235
|
-
@headers.
|
236
|
-
@body.
|
237
|
-
@done.
|
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.
|
249
|
-
@done.
|
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
|
260
|
-
@parser.upgrade_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
|
270
|
-
@parser.upgrade_data.
|
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
|
285
|
-
@parser.upgrade_data.
|
286
|
-
offset.
|
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
|
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.
|
302
|
-
@complete.
|
303
|
-
@body.
|
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.
|
316
|
-
@parser.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
|
320
|
-
@parser.upgrade_data.
|
379
|
+
expect(@parser.upgrade?).to be true
|
380
|
+
expect(@parser.upgrade_data).to eq(test['upgrade'])
|
321
381
|
end
|
322
382
|
|
323
|
-
|
324
|
-
|
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
|
-
|
330
|
-
request_url
|
331
|
-
]
|
387
|
+
expect(@parser.send("request_url")).to eq(test["request_url"].force_encoding(Encoding::BINARY))
|
332
388
|
else
|
333
|
-
|
334
|
-
|
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.
|
343
|
-
@headers.
|
393
|
+
expect(@headers.size).to eq(test['num_headers'])
|
394
|
+
expect(@headers).to eq(test['headers'])
|
344
395
|
|
345
|
-
@body.
|
346
|
-
@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
|