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.

@@ -1,4 +1,4 @@
1
1
  module Reel
2
- VERSION = "0.5.0"
3
- CODENAME = "Bette"
2
+ VERSION = "0.6.0.pre1"
3
+ CODENAME = "Garland"
4
4
  end
@@ -1,5 +1,6 @@
1
1
  require 'forwardable'
2
- require 'websocket_parser'
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, socket)
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
- handshake = ::WebSocket::ClientHandshake.new(:get, url, headers)
18
-
19
- if handshake.valid?
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
- @parser = ::WebSocket::Parser.new
33
-
34
- @parser.on_close do |status, reason|
35
- # According to the spec the server must respond with another
36
- # close message before closing the connection
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
- @parser.on_ping do |payload|
42
- @socket << ::WebSocket::Message.pong(payload).to_data
31
+ def on_message(&block)
32
+ @driver.on :message do |message|
33
+ block.(message.data)
43
34
  end
44
35
  end
45
36
 
46
- [:next_message, :next_messages, :on_message, :on_error, :on_close, :on_ping, :on_pong].each do |meth|
47
- define_method meth do |&proc|
48
- @parser.send __method__, &proc
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
- @parser.append @socket.readpartial(Connection::BUFFER_SIZE) until msg = @parser.next_message
69
- msg
70
- rescue
71
- cancel_timer!
72
- raise
59
+ @message_stream.read
73
60
  end
74
61
 
75
- def body
76
- nil
62
+ def closed?
63
+ @socket.closed?
77
64
  end
78
65
 
79
66
  def write(msg)
80
- @socket << ::WebSocket::Message.new(msg).to_data
81
- msg
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
- cancel_timer!
97
- @socket.close unless closed?
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
@@ -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 'websocket_parser', '>= 0.1.6'
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.should eq "/"
13
- request.version.should eq "1.1"
12
+ expect(request.url).to eq "/"
13
+ expect(request.version).to eq "1.1"
14
14
 
15
- request['Host'].should eq "www.example.com"
16
- request['Connection'].should eq "keep-alive"
17
- request['User-Agent'].should 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
- request['Accept'].should eq "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
19
- request['Accept-Encoding'].should eq "gzip,deflate,sdch"
20
- request['Accept-Language'].should eq "en-US,en;q=0.8"
21
- request['Accept-Charset'].should eq "ISO-8859-1,utf-8;q=0.7,*;q=0.3"
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.should eq "/"
36
- request.version.should eq "1.1"
37
- request['Content-Length'].should eq body.length.to_s
38
- request.body.to_s.should eq example_request.body
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].should eq fixture_text
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.should eq "/"
67
+ expect(request.url).to eq "/"
68
68
  request.respond :ok
69
69
  client.close
70
70
  end
71
71
 
72
- request_count.should eq 1
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].should eq fixture
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.should_not be_nil
151
+ expect(connection.request).not_to be_nil
152
152
 
153
153
  connection.respond :ok, "Response sent"
154
154
 
155
- connection.request.should be_nil
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.should eq "/"
183
- request.version.should eq "1.1"
201
+ expect(request.url).to eq "/"
202
+ expect(request.version).to eq "1.1"
184
203
 
185
- request['Host'].should eq "www.example.com"
186
- request['Connection'].should eq "keep-alive"
187
- request['User-Agent'].should eq "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.78 S"
188
- request['Accept'].should eq "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
189
- request['Accept-Encoding'].should eq "gzip,deflate,sdch"
190
- request['Accept-Language'].should eq "en-US,en;q=0.8"
191
- request['Accept-Charset'].should eq "ISO-8859-1,utf-8;q=0.7,*;q=0.3"
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.should eq "/"
214
- request.version.should eq "1.1"
215
- request['Content-Length'].should eq expected_body.length.to_s
216
- request.body.to_s.should eq expected_body
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.should eq "/"
240
- request.version.should eq "1.1"
241
- request['Content-Length'].should eq expected_body.length.to_s
242
- request.should_not be_finished_reading
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.should == expected_body
248
- request.should be_finished_reading
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.should be_a(Reel::Request)
286
+ expect(request).to be_a(Reel::Request)
268
287
  client << content
269
- request.body.to_s.should == content
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.should be_a(Reel::Request)
295
- read_body.should == content[0..7]
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.should be_a(Reel::Request)
310
- request.should_not be_finished_reading
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.should be_finished_reading
318
- rebuilt.should == ["I'm data", " you can", " stream!"]
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.should be_a(Reel::Request)
334
- request.should_not be_finished_reading
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.should be_finished_reading
341
- rebuilt.should == ["I'm data", " you can", " stream!"]
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.should be_a(Reel::Request)
368
- request.should_not be_finished_reading
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.should be_finished_reading
374
- data.should == "I'm data you can stream!"
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
- lambda { request.read(-1) }.should raise_error(ArgumentError)
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).should be_empty
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.should == 4
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.should eq "Hello, world!"
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.should eq "Hello, world!"
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).should eq "Hello, world!"
443
- buffer.should eq "Hello, world!"
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).should eq "Hello, world!"
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).should be_nil
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.should be_empty
499
+ expect(request.read).to be_empty
481
500
  end
482
501
  end
483
502
  end