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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 51c0dc865d430ed8c784c17406b7f949d52425b1
4
- data.tar.gz: f995592d1a542714360c99e20aadbc4281dee482
3
+ metadata.gz: b1a993a695b913f3274786678b7a8080749b5e2b
4
+ data.tar.gz: fcdccf97f738d01e317292f4f5499f8990d3948a
5
5
  SHA512:
6
- metadata.gz: c7d803b74e5e2b272fcb8affd947b1a0804e4b394945d680a38ebaf14ec95a7c994128e50ce95d38e656c68db1d655109c7179235fd3702d0c4eca3ced7cf9b8
7
- data.tar.gz: 4501a6d27b87a472529d1cbc3708cb950e8299c1aabae7a7565775450ab362f0f25674a417449c771dfa5b2a4cb500435619bf5f53146e875c6d02cbf24027c4
6
+ metadata.gz: a25fb72f593a8f05bae8272a4e5d3aeec408af15673ec05216b9abcaf2fae06f127e08f88b7cccc2f0c42f86a319e0ae2ae26bf6c22e7599c5da3fb52f4d8c76
7
+ data.tar.gz: 0707f29757b92d69e6b9c025702fc2da0823e8e19164c8b3a81f5347d4de3f2f71fb4b94f7000eb9c6dc4bb5d9609185b4a7df61e3211b86d789b0175658b16a
data/.rspec CHANGED
@@ -1,5 +1,4 @@
1
1
  --color
2
2
  --format documentation
3
3
  --backtrace
4
- --default_path spec
5
4
  --order random
@@ -1,18 +1,17 @@
1
1
  rvm:
2
2
  - 1.9.3
3
3
  - 2.0.0
4
- - 2.1.0
4
+ - 2.1.2
5
5
  - ruby-head
6
6
  - jruby
7
7
  - jruby-head
8
- - rbx
8
+ - rbx-2
9
9
 
10
10
  matrix:
11
11
  allow_failures:
12
12
  - rvm: ruby-head
13
- - rvm: jruby
14
13
  - rvm: jruby-head
15
- - rvm: rbx
14
+ - rvm: rbx-2
16
15
 
17
16
  notifications:
18
17
  irc: "irc.freenode.org#celluloid"
data/CHANGES.md CHANGED
@@ -1,5 +1,25 @@
1
+ 0.6.0 (2015-03-24)
2
+ -----
3
+ * Fix stack level too deep when writing to ChunkStream
4
+ * Use HTTP::Resonse::Status::REASONS table ( HTTP::Response::* deprecated in the HTTP gem )
5
+ * Use Timers 3.0.0 API
6
+ * Case-insensitivity for header field names ( i.e. in case a proxy downcases them )
7
+ * Catch when openssl sometimes fires ECONNRESET, EPIPE, ETIMEDOUT, EHOSTUNREACH and as an error
8
+ * Unused `optimize` socket modifications taken off all server implementations
9
+ * Fixed 404 error in roundtrip example
10
+ * Fixed "Reel::StateError: already processing a request" when client is killed
11
+ * Numerous updates to rspec.
12
+ * Switched to websocket/driver and improved websocket handling
13
+ * Implement DriverEnvironment to fix websocket example
14
+ * Refactored Server::HTTPS to be more idomatic
15
+ * Fixed jRuby related test failures
16
+ * Fixed "ArgumentError: Data object has already been freed" caused by underlying parser.
17
+ * FINALLY! Support for UNIX Socket servers across all RVM's, as of jRuby 1.7.19
18
+ * Unified Server#run removes need for duplication of #run across all Server implementations.
19
+ * Standardized method of rescuing exceptions unique to each type of Server in unified #run method.
20
+
1
21
  0.5.0 (2014-04-15)
2
- ------------------
22
+ -----
3
23
  * Reel::Server(::SSL) renamed to Reel::Server::HTTP and Reel::Server::HTTPS
4
24
  * New Reel::Spy API for observing requests and responses from the server
5
25
  * Fixes to chunked encoding handling
@@ -8,7 +28,7 @@
8
28
  * Ensure response bodies are always closed
9
29
  * Support for passing a fixnum status to Connection#respond
10
30
 
11
- 0.4.0
31
+ 0.4.0 (2013-09-14)
12
32
  -----
13
33
  * Rack adapter moved to the reel-rack project
14
34
  * Pipelining support
@@ -23,7 +43,7 @@
23
43
  * Remove Reel::App (unmaintained, sorry)
24
44
  * Reel::CODENAME added (0.4.0 is "Garbo")
25
45
 
26
- 0.3.0
46
+ 0.3.0 (2013-02-01)
27
47
  -----
28
48
  * Reel::App: Sinatra-like DSL for defining Reel apps using Octarine
29
49
  * Chunked upload support
@@ -33,12 +53,12 @@
33
53
  * Bugfix: Send CRLF after chunks
34
54
  * Bugfix: Increase TCP connection backlog to 1024
35
55
 
36
- 0.2.0
56
+ 0.2.0 (2012-09-03)
37
57
  -----
38
58
  * Initial WebSockets support via Reel::WebSocket
39
59
  * Experimental Rack adapter by Alberto Fernández-Capel
40
60
  * Octarine (Sinatra-like DSL) support by Grant Rodgers
41
61
 
42
- 0.1.0
62
+ 0.1.0 (2012-07-12)
43
63
  -----
44
64
  * Initial release
data/Gemfile CHANGED
@@ -1,8 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'celluloid', github: 'celluloid/celluloid'
4
- gem 'celluloid-io', github: 'celluloid/celluloid-io'
5
- gem 'http', github: 'tarcieri/http'
3
+ gem 'celluloid'
4
+ gem 'celluloid-io'
5
+ gem 'http'
6
6
 
7
7
  gem 'jruby-openssl' if defined? JRUBY_VERSION
8
8
  gem 'coveralls', require: false
data/Guardfile CHANGED
@@ -1,24 +1,14 @@
1
- # A sample Guardfile
2
- # More info at https://github.com/guard/guard#readme
3
-
4
- guard :rspec do
5
- watch(%r{^spec/.+_spec\.rb$})
6
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
- watch('spec/spec_helper.rb') { "spec" }
8
-
9
- # Rails example
10
- watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
- watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
- watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
- watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
- watch('config/routes.rb') { "spec/routing" }
15
- watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
-
17
- # Capybara features specs
18
- watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
-
20
- # Turnip features and steps
21
- watch(%r{^spec/acceptance/(.+)\.feature$})
22
- watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
1
+ guard :rspec, cmd: "bundle exec rspec" do
2
+ require "guard/rspec/dsl"
3
+ dsl = Guard::RSpec::Dsl.new(self)
4
+
5
+ # RSpec files
6
+ rspec = dsl.rspec
7
+ watch(rspec.spec_helper) { rspec.spec_dir }
8
+ watch(rspec.spec_support) { rspec.spec_dir }
9
+ watch(rspec.spec_files)
10
+
11
+ # Ruby files
12
+ ruby = dsl.ruby
13
+ dsl.watch_spec_files_for(ruby.lib_files)
23
14
  end
24
-
@@ -71,12 +71,22 @@ class WebServer < Reel::Server::HTTP
71
71
 
72
72
  def on_connection(connection)
73
73
  while request = connection.request
74
- case request
75
- when Reel::Request
76
- route_request connection, request
77
- when Reel::WebSocket
74
+ if request.websocket?
78
75
  info "Received a WebSocket connection"
79
- route_websocket request
76
+
77
+ # We're going to hand off this connection to another actor (Writer/Reader)
78
+ # However, initially Reel::Connections are "attached" to the
79
+ # Reel::Server::HTTP actor, meaning that the server manages the connection
80
+ # lifecycle (e.g. error handling) for us.
81
+ #
82
+ # If we want to hand this connection off to another actor, we first
83
+ # need to detach it from the Reel::Server (in this case, Reel::Server::HTTP)
84
+ connection.detach
85
+
86
+ route_websocket request.websocket
87
+ return
88
+ else
89
+ route_request connection, request
80
90
  end
81
91
  end
82
92
  end
@@ -14,6 +14,7 @@ require 'reel/response'
14
14
  require 'reel/server'
15
15
  require 'reel/server/http'
16
16
  require 'reel/server/https'
17
+ require 'reel/server/unix' unless defined? JRUBY_VERSION
17
18
 
18
19
  require 'reel/websocket'
19
20
  require 'reel/stream'
@@ -56,7 +56,7 @@ module Reel
56
56
 
57
57
  req = @parser.current_request
58
58
  @request_fsm.transition :headers
59
- @keepalive = false if req[CONNECTION] == CLOSE || req.version == HTTP_VERSION_1_0
59
+ @keepalive = false if req.nil? || req[CONNECTION] == CLOSE || req.version == HTTP_VERSION_1_0
60
60
  @current_request = req
61
61
 
62
62
  req
@@ -120,10 +120,12 @@ module Reel
120
120
  @parser.reset
121
121
  @request_fsm.transition :closed
122
122
  end
123
- rescue IOError, Errno::ECONNRESET, Errno::EPIPE, RequestError
123
+ rescue IOError, SystemCallError, RequestError
124
124
  # The client disconnected early, or there is no request
125
125
  @keepalive = false
126
126
  @request_fsm.transition :closed
127
+ @parser.reset
128
+ @current_request = nil
127
129
  end
128
130
 
129
131
  # Close the connection
@@ -112,8 +112,8 @@ module Reel
112
112
  # the underlying connection
113
113
  def websocket
114
114
  @websocket ||= begin
115
- raise StateError, "can't upgrade this request to a websocket" unless websocket?
116
- WebSocket.new(@request_info, @connection.hijack_socket)
115
+ raise StateError, "can't upgrade this request to a websocket" unless websocket?
116
+ WebSocket.new(self, @connection)
117
117
  end
118
118
  end
119
119
 
@@ -29,6 +29,10 @@ module Reel
29
29
  end
30
30
  end
31
31
 
32
+ def empty?
33
+ to_str.empty?
34
+ end
35
+
32
36
  # Eagerly consume the entire body as a string
33
37
  def to_str
34
38
  return @contents if @contents
@@ -1,13 +1,18 @@
1
1
  module Reel
2
2
  class Request
3
3
  class Info
4
+
5
+ CASE_INSENSITVE_HASH = Hash.new do |hash, key|
6
+ hash[hash.keys.find {|k| k =~ /#{key}/i}] if key
7
+ end
8
+
4
9
  attr_reader :http_method, :url, :http_version, :headers
5
10
 
6
11
  def initialize(http_method, url, http_version, headers)
7
12
  @http_method = http_method
8
13
  @url = url
9
14
  @http_version = http_version
10
- @headers = headers
15
+ @headers = CASE_INSENSITVE_HASH.merge headers
11
16
  end
12
17
 
13
18
  UPGRADE = 'Upgrade'.freeze
@@ -18,4 +23,4 @@ module Reel
18
23
  end
19
24
  end
20
25
  end
21
- end
26
+ end
@@ -43,7 +43,11 @@ module Reel
43
43
 
44
44
  def readpartial(size = @buffer_size)
45
45
  bytes = @socket.readpartial(size)
46
- @parser << bytes
46
+ begin
47
+ @parser << bytes
48
+ rescue ArgumentError
49
+ raise Errno::EPIPE
50
+ end
47
51
  end
48
52
 
49
53
  #
@@ -7,8 +7,8 @@ module Reel
7
7
  CHUNKED = 'chunked'.freeze
8
8
 
9
9
  # Use status code tables from the HTTP gem
10
- STATUS_CODES = HTTP::Response::STATUS_CODES
11
- SYMBOL_TO_STATUS_CODE = HTTP::Response::SYMBOL_TO_STATUS_CODE
10
+ STATUS_CODES = HTTP::Response::Status::REASONS
11
+ SYMBOL_TO_STATUS_CODE = Hash[STATUS_CODES.map { |k, v| [v.downcase.gsub(/\s|-/, '_').to_sym, k] }].freeze
12
12
 
13
13
  attr_reader :status # Status has a special setter to coerce symbol names
14
14
  attr_accessor :reason # Reason can be set explicitly if desired
@@ -12,7 +12,7 @@ module Reel
12
12
  chunk_header = chunk.bytesize.to_s(16)
13
13
  @socket << chunk_header + CRLF
14
14
  @socket << chunk + CRLF
15
- rescue IOError, Errno::EPIPE, Errno::ECONNRESET => ex
15
+ rescue IOError, SystemCallError => ex
16
16
  raise Reel::SocketError, ex.to_s
17
17
  end
18
18
 
@@ -2,14 +2,14 @@ module Reel
2
2
  # Base class for Reel servers.
3
3
  #
4
4
  # This class is a Celluloid::IO actor which provides a barebones server
5
- # which does not open a socket itself, it just begin handling connections once
6
- # initialized with a specific kind of protocol-based server.
5
+ # which does not open a socket itself, it just begin handling connections
6
+ # once initialized with a specific kind of protocol-based server.
7
7
 
8
8
  # For specific protocol support, use:
9
9
 
10
10
  # Reel::Server::HTTP
11
11
  # Reel::Server::HTTPS
12
- # Coming soon: Reel::Server::UNIX
12
+ # Reel::Server::UNIX ( not on jRuby yet )
13
13
 
14
14
  class Server
15
15
  include Celluloid::IO
@@ -25,6 +25,15 @@ module Reel
25
25
  @callback = callback
26
26
  @server = server
27
27
 
28
+ @options[:rescue] ||= []
29
+ @options[:rescue] += [
30
+ Errno::ECONNRESET,
31
+ Errno::EPIPE,
32
+ Errno::EINPROGRESS,
33
+ Errno::ETIMEDOUT,
34
+ Errno::EHOSTUNREACH
35
+ ]
36
+
28
37
  @server.listen(options.fetch(:backlog, DEFAULT_BACKLOG))
29
38
 
30
39
  async.run
@@ -35,13 +44,15 @@ module Reel
35
44
  end
36
45
 
37
46
  def run
38
- loop { async.handle_connection @server.accept }
39
- end
40
-
41
- def optimize(socket)
42
- if socket.is_a? TCPSocket
43
- socket.setsockopt(Socket::IPPROTO_TCP, :TCP_NODELAY, 1)
44
- end
47
+ loop {
48
+ begin
49
+ socket = @server.accept
50
+ rescue *@options[:rescue] => ex
51
+ Logger.warn "Error accepting socket: #{ex.class}: #{ex.to_s}"
52
+ next
53
+ end
54
+ async.handle_connection socket
55
+ }
45
56
  end
46
57
 
47
58
  def handle_connection(socket)
@@ -10,7 +10,7 @@ module Reel
10
10
  #
11
11
  # @return [Reel::Server::HTTP] Reel HTTP server actor
12
12
  def initialize(host, port, options={}, &callback)
13
- optimize server = Celluloid::IO::TCPServer.new(host, port)
13
+ server = Celluloid::IO::TCPServer.new(host, port)
14
14
  options.merge!(host: host, port: port)
15
15
  super(server, options, &callback)
16
16
  end
@@ -27,37 +27,25 @@ module Reel
27
27
 
28
28
  # if verify_mode isn't explicitly set, verify peers if we've
29
29
  # been provided CA information that would enable us to do so
30
- ssl_context.verify_mode = case
31
- when options.include?(:verify_mode)
30
+ ssl_context.verify_mode = if options.include?(:verify_mode)
32
31
  options[:verify_mode]
33
- when options.include?(:ca_file)
32
+ elsif options.include?(:ca_file)
34
33
  OpenSSL::SSL::VERIFY_PEER
35
- when options.include?(:ca_path)
34
+ elsif options.include?(:ca_path)
36
35
  OpenSSL::SSL::VERIFY_PEER
37
36
  else
38
37
  OpenSSL::SSL::VERIFY_NONE
39
38
  end
40
39
 
41
- optimize @tcpserver = Celluloid::IO::TCPServer.new(host, port)
40
+ @tcpserver = Celluloid::IO::TCPServer.new(host, port)
42
41
 
43
42
  server = Celluloid::IO::SSLServer.new(@tcpserver, ssl_context)
44
43
  options.merge!(host: host, port: port)
45
44
 
45
+ options[:rescue] = [ OpenSSL::SSL::SSLError ]
46
+
46
47
  super(server, options, &callback)
47
48
  end
48
-
49
- def run
50
- loop do
51
- begin
52
- socket = @server.accept
53
- rescue OpenSSL::SSL::SSLError => ex
54
- Logger.warn "Error accepting SSLSocket: #{ex.class}: #{ex.to_s}"
55
- retry
56
- end
57
-
58
- async.handle_connection socket
59
- end
60
- end
61
49
  end
62
50
  end
63
51
  end
@@ -0,0 +1,18 @@
1
+ module Reel
2
+ class Server
3
+ class UNIX < Server
4
+
5
+ # Create a new Reel HTTPS server
6
+ #
7
+ # @option options [String] socket path to bind to
8
+ # @option options [Fixnum] backlog of requests to accept
9
+ #
10
+ # @return [Reel::Server::UNIX] Reel UNIX server actor
11
+ def initialize(socket_path, options={}, &callback)
12
+ server = Celluloid::IO::UNIXServer.new(socket_path)
13
+ options[:socket_path] = socket_path
14
+ super(server, options, &callback)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -6,6 +6,7 @@ module Reel
6
6
  extend Forwardable
7
7
 
8
8
  def_delegators :@socket, :closed?
9
+ def_delegators :@socket, :addr, :peeraddr, :setsockopt, :getsockname
9
10
 
10
11
  def initialize(socket, logger = STDOUT)
11
12
  @socket, @logger = socket, logger
@@ -68,4 +69,4 @@ module Reel
68
69
  def gold(str); colorize(33, str); end
69
70
  end
70
71
  end
71
- end
72
+ end
@@ -64,8 +64,8 @@ module Reel
64
64
  class ChunkStream < Stream
65
65
  def write(chunk)
66
66
  chunk_header = chunk.bytesize.to_s(16)
67
- write chunk_header + Response::Writer::CRLF
68
- write chunk + Response::Writer::CRLF
67
+ super chunk_header + Response::Writer::CRLF
68
+ super chunk + Response::Writer::CRLF
69
69
  self
70
70
  end
71
71
  alias :<< :write