reel 0.5.0 → 0.6.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of reel might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.travis.yml +3 -4
- data/CHANGES.md +25 -5
- data/Gemfile +3 -3
- data/Guardfile +13 -23
- data/examples/roundtrip.rb +15 -5
- data/lib/reel.rb +1 -0
- data/lib/reel/connection.rb +4 -2
- data/lib/reel/request.rb +2 -2
- data/lib/reel/request/body.rb +4 -0
- data/lib/reel/request/info.rb +7 -2
- data/lib/reel/request/parser.rb +5 -1
- data/lib/reel/response.rb +2 -2
- data/lib/reel/response/writer.rb +1 -1
- data/lib/reel/server.rb +21 -10
- data/lib/reel/server/http.rb +1 -1
- data/lib/reel/server/https.rb +6 -18
- data/lib/reel/server/unix.rb +18 -0
- data/lib/reel/spy.rb +2 -1
- data/lib/reel/stream.rb +2 -2
- data/lib/reel/version.rb +2 -2
- data/lib/reel/websocket.rb +77 -44
- data/reel.gemspec +4 -1
- data/spec/reel/connection_spec.rb +85 -66
- data/spec/reel/http_server_spec.rb +8 -11
- data/spec/reel/https_server_spec.rb +22 -33
- data/spec/reel/response/writer_spec.rb +1 -1
- data/spec/reel/response_spec.rb +2 -2
- data/spec/reel/unix_server_spec.rb +41 -0
- data/spec/reel/websocket_spec.rb +95 -20
- data/spec/spec_helper.rb +26 -4
- data/spec/support/create_certs.rb +73 -0
- metadata +65 -43
- data/spec/fixtures/ca.crt +0 -27
- data/spec/fixtures/ca.key +0 -27
- data/spec/fixtures/client.crt +0 -83
- data/spec/fixtures/client.key +0 -27
- data/spec/fixtures/client.unsigned.crt +0 -22
- data/spec/fixtures/server.crt +0 -82
- data/spec/fixtures/server.key +0 -27
data/lib/reel/version.rb
CHANGED
data/lib/reel/websocket.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'forwardable'
|
2
|
-
require '
|
2
|
+
require 'websocket/driver'
|
3
|
+
require 'rack'
|
3
4
|
|
4
5
|
module Reel
|
5
6
|
class WebSocket
|
@@ -10,42 +11,32 @@ module Reel
|
|
10
11
|
attr_reader :socket
|
11
12
|
def_delegators :@socket, :addr, :peeraddr
|
12
13
|
|
13
|
-
def initialize(info,
|
14
|
+
def initialize(info, connection)
|
15
|
+
driver_env = DriverEnvironment.new(info, connection.socket)
|
16
|
+
|
17
|
+
@socket = connection.hijack_socket
|
14
18
|
@request_info = info
|
15
|
-
@socket = socket
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
response = handshake.accept_response
|
21
|
-
response.render(socket)
|
22
|
-
else
|
23
|
-
error = handshake.errors.first
|
24
|
-
|
25
|
-
response = Response.new(400)
|
26
|
-
response.reason = handshake.errors.first
|
27
|
-
response.render(@socket)
|
28
|
-
|
29
|
-
raise HandshakeError, "error during handshake: #{error}"
|
20
|
+
@driver = ::WebSocket::Driver.rack(driver_env)
|
21
|
+
@driver.on(:close) do
|
22
|
+
@socket.close
|
30
23
|
end
|
31
24
|
|
32
|
-
@
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
@socket << ::WebSocket::Message.close.to_data
|
38
|
-
close
|
39
|
-
end
|
25
|
+
@message_stream = MessageStream.new(@socket, @driver)
|
26
|
+
@driver.start
|
27
|
+
rescue EOFError
|
28
|
+
close
|
29
|
+
end
|
40
30
|
|
41
|
-
|
42
|
-
|
31
|
+
def on_message(&block)
|
32
|
+
@driver.on :message do |message|
|
33
|
+
block.(message.data)
|
43
34
|
end
|
44
35
|
end
|
45
36
|
|
46
|
-
[:
|
47
|
-
define_method meth do |&proc|
|
48
|
-
@
|
37
|
+
[:error, :close, :ping, :pong].each do |meth|
|
38
|
+
define_method "on_#{meth}" do |&proc|
|
39
|
+
@driver.send(:on, meth, &proc)
|
49
40
|
end
|
50
41
|
end
|
51
42
|
|
@@ -65,20 +56,21 @@ module Reel
|
|
65
56
|
alias read_frequency read_every
|
66
57
|
|
67
58
|
def read
|
68
|
-
@
|
69
|
-
msg
|
70
|
-
rescue
|
71
|
-
cancel_timer!
|
72
|
-
raise
|
59
|
+
@message_stream.read
|
73
60
|
end
|
74
61
|
|
75
|
-
def
|
76
|
-
|
62
|
+
def closed?
|
63
|
+
@socket.closed?
|
77
64
|
end
|
78
65
|
|
79
66
|
def write(msg)
|
80
|
-
|
81
|
-
|
67
|
+
if msg.is_a? String
|
68
|
+
@driver.text(msg)
|
69
|
+
elsif msg.is_a? Array
|
70
|
+
@driver.binary(msg)
|
71
|
+
else
|
72
|
+
raise "Can only send byte array or string over driver."
|
73
|
+
end
|
82
74
|
rescue IOError, Errno::ECONNRESET, Errno::EPIPE
|
83
75
|
cancel_timer!
|
84
76
|
raise SocketError, "error writing to socket"
|
@@ -88,18 +80,59 @@ module Reel
|
|
88
80
|
end
|
89
81
|
alias_method :<<, :write
|
90
82
|
|
91
|
-
def closed?
|
92
|
-
@socket.closed?
|
93
|
-
end
|
94
|
-
|
95
83
|
def close
|
96
|
-
|
97
|
-
@socket.close
|
84
|
+
@driver.close
|
85
|
+
@socket.close
|
98
86
|
end
|
99
87
|
|
100
88
|
def cancel_timer!
|
101
89
|
@timer && @timer.cancel
|
102
90
|
end
|
103
91
|
|
92
|
+
private
|
93
|
+
|
94
|
+
class DriverEnvironment
|
95
|
+
extend Forwardable
|
96
|
+
|
97
|
+
attr_reader :env, :url, :socket
|
98
|
+
|
99
|
+
def_delegators :socket, :write
|
100
|
+
|
101
|
+
def initialize(info, socket)
|
102
|
+
@url = info.url
|
103
|
+
|
104
|
+
env_hash = Hash[info.headers.map { |key, value| ['HTTP_' + key.upcase.gsub('-','_'),value ] }]
|
105
|
+
|
106
|
+
env_hash.merge!({
|
107
|
+
:method => info.method,
|
108
|
+
:input => info.body.to_s,
|
109
|
+
'REMOTE_ADDR' => info.remote_addr
|
110
|
+
})
|
111
|
+
|
112
|
+
@env = ::Rack::MockRequest.env_for(@url, env_hash)
|
113
|
+
|
114
|
+
@socket = socket
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class MessageStream
|
119
|
+
def initialize(socket, driver)
|
120
|
+
@socket = socket
|
121
|
+
@driver = driver
|
122
|
+
@message_buffer = []
|
123
|
+
|
124
|
+
@driver.on :message do |message|
|
125
|
+
@message_buffer.push(message.data)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def read
|
130
|
+
while @message_buffer.empty?
|
131
|
+
buffer = @socket.readpartial(Connection::BUFFER_SIZE)
|
132
|
+
@driver.parse(buffer)
|
133
|
+
end
|
134
|
+
@message_buffer.shift
|
135
|
+
end
|
136
|
+
end
|
104
137
|
end
|
105
138
|
end
|
data/reel.gemspec
CHANGED
@@ -19,8 +19,11 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.add_runtime_dependency 'celluloid-io', '>= 0.15.0'
|
20
20
|
gem.add_runtime_dependency 'http', '>= 0.6.0.pre'
|
21
21
|
gem.add_runtime_dependency 'http_parser.rb', '>= 0.6.0'
|
22
|
-
gem.add_runtime_dependency '
|
22
|
+
gem.add_runtime_dependency 'websocket-driver', '>= 0.5.1'
|
23
|
+
gem.add_runtime_dependency 'rack'
|
23
24
|
|
24
25
|
gem.add_development_dependency 'rake'
|
25
26
|
gem.add_development_dependency 'rspec', '>= 2.11.0'
|
27
|
+
gem.add_development_dependency 'certificate_authority'
|
28
|
+
gem.add_development_dependency 'websocket_parser', '>= 0.1.6'
|
26
29
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Reel::Connection do
|
3
|
+
RSpec.describe Reel::Connection do
|
4
4
|
let(:fixture_path) { File.expand_path("../../fixtures/example.txt", __FILE__) }
|
5
5
|
|
6
6
|
it "reads requests without bodies" do
|
@@ -9,16 +9,16 @@ describe Reel::Connection do
|
|
9
9
|
client << ExampleRequest.new.to_s
|
10
10
|
request = connection.request
|
11
11
|
|
12
|
-
request.url.
|
13
|
-
request.version.
|
12
|
+
expect(request.url).to eq "/"
|
13
|
+
expect(request.version).to eq "1.1"
|
14
14
|
|
15
|
-
request['Host'].
|
16
|
-
request['Connection'].
|
17
|
-
request['User-Agent'].
|
18
|
-
request['Accept'].
|
19
|
-
request['Accept-Encoding'].
|
20
|
-
request['Accept-Language'].
|
21
|
-
request['Accept-Charset'].
|
15
|
+
expect(request['Host']).to eq "www.example.com"
|
16
|
+
expect(request['Connection']).to eq "keep-alive"
|
17
|
+
expect(request['User-Agent']).to eq "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.78 S"
|
18
|
+
expect(request['Accept']).to eq "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
19
|
+
expect(request['Accept-Encoding']).to eq "gzip,deflate,sdch"
|
20
|
+
expect(request['Accept-Language']).to eq "en-US,en;q=0.8"
|
21
|
+
expect(request['Accept-Charset']).to eq "ISO-8859-1,utf-8;q=0.7,*;q=0.3"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -32,10 +32,10 @@ describe Reel::Connection do
|
|
32
32
|
client << example_request.to_s
|
33
33
|
request = connection.request
|
34
34
|
|
35
|
-
request.url.
|
36
|
-
request.version.
|
37
|
-
request['Content-Length'].
|
38
|
-
request.body.to_s.
|
35
|
+
expect(request.url).to eq "/"
|
36
|
+
expect(request.version).to eq "1.1"
|
37
|
+
expect(request['Content-Length']).to eq body.length.to_s
|
38
|
+
expect(request.body.to_s).to eq example_request.body
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -52,7 +52,7 @@ describe Reel::Connection do
|
|
52
52
|
end
|
53
53
|
|
54
54
|
response = client.read(4096)
|
55
|
-
response[(response.length - fixture_text.length)..-1].
|
55
|
+
expect(response[(response.length - fixture_text.length)..-1]).to eq fixture_text
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -64,12 +64,12 @@ describe Reel::Connection do
|
|
64
64
|
request_count = 0
|
65
65
|
connection.each_request do |request|
|
66
66
|
request_count += 1
|
67
|
-
request.url.
|
67
|
+
expect(request.url).to eq "/"
|
68
68
|
request.respond :ok
|
69
69
|
client.close
|
70
70
|
end
|
71
71
|
|
72
|
-
request_count.
|
72
|
+
expect(request_count).to eq 1
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -95,7 +95,7 @@ describe Reel::Connection do
|
|
95
95
|
|
96
96
|
crlf = "\r\n"
|
97
97
|
fixture = "5#{crlf}Hello#{crlf}5#{crlf}World#{crlf}0#{crlf*2}"
|
98
|
-
response[(response.length - fixture.length)..-1].
|
98
|
+
expect(response[(response.length - fixture.length)..-1]).to eq fixture
|
99
99
|
end
|
100
100
|
|
101
101
|
it "with keep-alive" do
|
@@ -148,14 +148,33 @@ describe Reel::Connection do
|
|
148
148
|
example_request = ExampleRequest.new(:get, "/", "1.1", {'Connection' => 'close'})
|
149
149
|
client << example_request
|
150
150
|
|
151
|
-
connection.request.
|
151
|
+
expect(connection.request).not_to be_nil
|
152
152
|
|
153
153
|
connection.respond :ok, "Response sent"
|
154
154
|
|
155
|
-
connection.request.
|
155
|
+
expect(connection.request).to be_nil
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
159
|
+
it "resets if client dropped connection" do
|
160
|
+
with_socket_pair do |client, peer|
|
161
|
+
connection = Reel::Connection.new(peer)
|
162
|
+
example_request = ExampleRequest.new
|
163
|
+
client << example_request
|
164
|
+
|
165
|
+
expect(connection.request).not_to be_nil
|
166
|
+
|
167
|
+
client.close # client drops connection
|
168
|
+
# now send more than the send buffer can hold, triggering a
|
169
|
+
# error (ECONNRESET or EPIPE)
|
170
|
+
connection.respond :ok, ("Some Big Response sent"*100000)
|
171
|
+
|
172
|
+
# connection should be at end
|
173
|
+
expect(connection.request).to be_nil
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
|
159
178
|
it "raises an error trying to read two pipelines without responding first" do
|
160
179
|
with_socket_pair do |client, peer|
|
161
180
|
connection = Reel::Connection.new(peer)
|
@@ -179,16 +198,16 @@ describe Reel::Connection do
|
|
179
198
|
3.times do
|
180
199
|
request = connection.request
|
181
200
|
|
182
|
-
request.url.
|
183
|
-
request.version.
|
201
|
+
expect(request.url).to eq "/"
|
202
|
+
expect(request.version).to eq "1.1"
|
184
203
|
|
185
|
-
request['Host'].
|
186
|
-
request['Connection'].
|
187
|
-
request['User-Agent'].
|
188
|
-
request['Accept'].
|
189
|
-
request['Accept-Encoding'].
|
190
|
-
request['Accept-Language'].
|
191
|
-
request['Accept-Charset'].
|
204
|
+
expect(request['Host']).to eq "www.example.com"
|
205
|
+
expect(request['Connection']).to eq "keep-alive"
|
206
|
+
expect(request['User-Agent']).to eq "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.78 S"
|
207
|
+
expect(request['Accept']).to eq "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
208
|
+
expect(request['Accept-Encoding']).to eq "gzip,deflate,sdch"
|
209
|
+
expect(request['Accept-Language']).to eq "en-US,en;q=0.8"
|
210
|
+
expect(request['Accept-Charset']).to eq "ISO-8859-1,utf-8;q=0.7,*;q=0.3"
|
192
211
|
connection.respond :ok, {}, ""
|
193
212
|
end
|
194
213
|
end
|
@@ -210,10 +229,10 @@ describe Reel::Connection do
|
|
210
229
|
request = connection.request
|
211
230
|
|
212
231
|
expected_body = "Hello, world number #{i}!"
|
213
|
-
request.url.
|
214
|
-
request.version.
|
215
|
-
request['Content-Length'].
|
216
|
-
request.body.to_s.
|
232
|
+
expect(request.url).to eq "/"
|
233
|
+
expect(request.version).to eq "1.1"
|
234
|
+
expect(request['Content-Length']).to eq expected_body.length.to_s
|
235
|
+
expect(request.body.to_s).to eq expected_body
|
217
236
|
|
218
237
|
connection.respond :ok, {}, ""
|
219
238
|
end
|
@@ -236,16 +255,16 @@ describe Reel::Connection do
|
|
236
255
|
request = connection.request
|
237
256
|
|
238
257
|
expected_body = "Hello, world number #{i}!"
|
239
|
-
request.url.
|
240
|
-
request.version.
|
241
|
-
request['Content-Length'].
|
242
|
-
request.
|
258
|
+
expect(request.url).to eq "/"
|
259
|
+
expect(request.version).to eq "1.1"
|
260
|
+
expect(request['Content-Length']).to eq expected_body.length.to_s
|
261
|
+
expect(request).not_to be_finished_reading
|
243
262
|
new_content = ""
|
244
263
|
while chunk = request.body.readpartial(1)
|
245
264
|
new_content << chunk
|
246
265
|
end
|
247
|
-
new_content.
|
248
|
-
request.
|
266
|
+
expect(new_content).to eq(expected_body)
|
267
|
+
expect(request).to be_finished_reading
|
249
268
|
|
250
269
|
connection.respond :ok, {}, ""
|
251
270
|
end
|
@@ -264,9 +283,9 @@ describe Reel::Connection do
|
|
264
283
|
client << example_request.to_s
|
265
284
|
|
266
285
|
request = connection.request
|
267
|
-
request.
|
286
|
+
expect(request).to be_a(Reel::Request)
|
268
287
|
client << content
|
269
|
-
request.body.to_s.
|
288
|
+
expect(request.body.to_s).to eq(content)
|
270
289
|
end
|
271
290
|
end
|
272
291
|
|
@@ -280,7 +299,7 @@ describe Reel::Connection do
|
|
280
299
|
client << example_request.to_s
|
281
300
|
|
282
301
|
request = connection.request
|
283
|
-
timers = Timers.new
|
302
|
+
timers = Timers::Group.new
|
284
303
|
timers.after(0.2){
|
285
304
|
client << content
|
286
305
|
}
|
@@ -291,8 +310,8 @@ describe Reel::Connection do
|
|
291
310
|
}
|
292
311
|
timers.wait
|
293
312
|
|
294
|
-
request.
|
295
|
-
read_body.
|
313
|
+
expect(request).to be_a(Reel::Request)
|
314
|
+
expect(read_body).to eq(content[0..7])
|
296
315
|
end
|
297
316
|
end
|
298
317
|
|
@@ -306,16 +325,16 @@ describe Reel::Connection do
|
|
306
325
|
client << example_request.to_s
|
307
326
|
|
308
327
|
request = connection.request
|
309
|
-
request.
|
310
|
-
request.
|
328
|
+
expect(request).to be_a(Reel::Request)
|
329
|
+
expect(request).not_to be_finished_reading
|
311
330
|
client << content
|
312
331
|
rebuilt = []
|
313
332
|
connection.readpartial(64) # Buffer some body
|
314
333
|
while chunk = request.read(8)
|
315
334
|
rebuilt << chunk
|
316
335
|
end
|
317
|
-
request.
|
318
|
-
rebuilt.
|
336
|
+
expect(request).to be_finished_reading
|
337
|
+
expect(rebuilt).to eq(["I'm data", " you can", " stream!"])
|
319
338
|
end
|
320
339
|
end
|
321
340
|
|
@@ -330,15 +349,15 @@ describe Reel::Connection do
|
|
330
349
|
client << example_request.to_s
|
331
350
|
|
332
351
|
request = connection.request
|
333
|
-
request.
|
334
|
-
request.
|
352
|
+
expect(request).to be_a(Reel::Request)
|
353
|
+
expect(request).not_to be_finished_reading
|
335
354
|
client << content
|
336
355
|
rebuilt = []
|
337
356
|
while chunk = request.body.readpartial(8)
|
338
357
|
rebuilt << chunk
|
339
358
|
end
|
340
|
-
request.
|
341
|
-
rebuilt.
|
359
|
+
expect(request).to be_finished_reading
|
360
|
+
expect(rebuilt).to eq(["I'm data", " you can", " stream!"])
|
342
361
|
end
|
343
362
|
end
|
344
363
|
end
|
@@ -364,14 +383,14 @@ describe Reel::Connection do
|
|
364
383
|
client << example_request.to_s
|
365
384
|
|
366
385
|
request = connection.request
|
367
|
-
request.
|
368
|
-
request.
|
386
|
+
expect(request).to be_a(Reel::Request)
|
387
|
+
expect(request).not_to be_finished_reading
|
369
388
|
client << content
|
370
389
|
|
371
390
|
data = ""
|
372
391
|
request.body.each { |chunk| data << chunk }
|
373
|
-
request.
|
374
|
-
data.
|
392
|
+
expect(request).to be_finished_reading
|
393
|
+
expect(data).to eq("I'm data you can stream!")
|
375
394
|
end
|
376
395
|
end
|
377
396
|
end
|
@@ -385,7 +404,7 @@ describe Reel::Connection do
|
|
385
404
|
client << example_request.to_s
|
386
405
|
request = connection.request
|
387
406
|
|
388
|
-
|
407
|
+
expect { request.read(-1) }.to raise_error(ArgumentError)
|
389
408
|
end
|
390
409
|
end
|
391
410
|
|
@@ -397,7 +416,7 @@ describe Reel::Connection do
|
|
397
416
|
client << example_request.to_s
|
398
417
|
request = connection.request
|
399
418
|
|
400
|
-
request.read(0).
|
419
|
+
expect(request.read(0)).to be_empty
|
401
420
|
end
|
402
421
|
end
|
403
422
|
|
@@ -406,12 +425,12 @@ describe Reel::Connection do
|
|
406
425
|
connection = Reel::Connection.new(peer, 4)
|
407
426
|
example_request = ExampleRequest.new
|
408
427
|
example_request.body = "Hello, world!"
|
409
|
-
connection.buffer_size.
|
428
|
+
expect(connection.buffer_size).to eq(4)
|
410
429
|
|
411
430
|
client << example_request.to_s
|
412
431
|
request = connection.request
|
413
432
|
|
414
|
-
request.read.
|
433
|
+
expect(request.read).to eq "Hello, world!"
|
415
434
|
end
|
416
435
|
end
|
417
436
|
|
@@ -425,7 +444,7 @@ describe Reel::Connection do
|
|
425
444
|
client << example_request.to_s
|
426
445
|
request = connection.request
|
427
446
|
|
428
|
-
request.read.
|
447
|
+
expect(request.read).to eq "Hello, world!"
|
429
448
|
end
|
430
449
|
end
|
431
450
|
|
@@ -439,8 +458,8 @@ describe Reel::Connection do
|
|
439
458
|
request = connection.request
|
440
459
|
|
441
460
|
buffer = ''
|
442
|
-
request.read(nil, buffer).
|
443
|
-
buffer.
|
461
|
+
expect(request.read(nil, buffer)).to eq "Hello, world!"
|
462
|
+
expect(buffer).to eq "Hello, world!"
|
444
463
|
end
|
445
464
|
end
|
446
465
|
|
@@ -453,7 +472,7 @@ describe Reel::Connection do
|
|
453
472
|
client << example_request.to_s
|
454
473
|
request = connection.request
|
455
474
|
|
456
|
-
request.read(1024).
|
475
|
+
expect(request.read(1024)).to eq "Hello, world!"
|
457
476
|
end
|
458
477
|
end
|
459
478
|
|
@@ -465,7 +484,7 @@ describe Reel::Connection do
|
|
465
484
|
client << example_request.to_s
|
466
485
|
request = connection.request
|
467
486
|
|
468
|
-
request.read(1024).
|
487
|
+
expect(request.read(1024)).to be_nil
|
469
488
|
end
|
470
489
|
end
|
471
490
|
|
@@ -477,7 +496,7 @@ describe Reel::Connection do
|
|
477
496
|
client << example_request.to_s
|
478
497
|
request = connection.request
|
479
498
|
|
480
|
-
request.read.
|
499
|
+
expect(request.read).to be_empty
|
481
500
|
end
|
482
501
|
end
|
483
502
|
end
|