Skip to content
This repository has been archived by the owner on Dec 7, 2018. It is now read-only.

Commit

Permalink
Merge branch '0.6.0-update' into unix_server
Browse files Browse the repository at this point in the history
  • Loading branch information
//de committed Mar 24, 2015
2 parents df55c40 + 781f712 commit 8cf2294
Show file tree
Hide file tree
Showing 49 changed files with 677 additions and 758 deletions.
1 change: 0 additions & 1 deletion .rspec
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
--color
--format documentation
--backtrace
--default_path spec
--order random
6 changes: 4 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
rvm:
- 1.9.3
- 2.0.0
- 2.1.2
- ruby-head
- jruby-19mode
- jruby
- jruby-head
- rbx-19mode
- rbx-2

matrix:
allow_failures:
- rvm: ruby-head
- rvm: jruby-head
- rvm: rbx-2

notifications:
irc: "irc.freenode.org#celluloid"
10 changes: 10 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
0.5.0 (2014-04-15)
------------------
* Reel::Server(::SSL) renamed to Reel::Server::HTTP and Reel::Server::HTTPS
* New Reel::Spy API for observing requests and responses from the server
* Fixes to chunked encoding handling
* Update websocket_parser gem to 0.1.6
* Update to "The HTTP Gem" 0.6.0
* Ensure response bodies are always closed
* Support for passing a fixnum status to Connection#respond

0.4.0
-----
* Rack adapter moved to the reel-rack project
Expand Down
12 changes: 9 additions & 3 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
source 'https://rubygems.org'

gem 'celluloid', github: 'celluloid/celluloid'
gem 'celluloid-io', github: 'celluloid/celluloid-io'
gem 'http', github: 'tarcieri/http'
gem 'celluloid'
gem 'celluloid-io'
gem 'http'

gem 'jruby-openssl' if defined? JRUBY_VERSION
gem 'coveralls', require: false
Expand All @@ -14,3 +14,9 @@ group :development do
gem 'guard-rspec'
gem 'pry'
end

platforms :rbx do
gem 'racc'
gem 'rubinius-coverage'
gem 'rubysl', '~> 2.0'
end
36 changes: 13 additions & 23 deletions Guardfile
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme

guard :rspec do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }

# Rails example
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
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"] }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" }
watch('app/controllers/application_controller.rb') { "spec/controllers" }

# Capybara features specs
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }

# Turnip features and steps
watch(%r{^spec/acceptance/(.+)\.feature$})
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
guard :rspec, cmd: "bundle exec rspec" do
require "guard/rspec/dsl"
dsl = Guard::RSpec::Dsl.new(self)

# RSpec files
rspec = dsl.rspec
watch(rspec.spec_helper) { rspec.spec_dir }
watch(rspec.spec_support) { rspec.spec_dir }
watch(rspec.spec_files)

# Ruby files
ruby = dsl.ruby
dsl.watch_spec_files_for(ruby.lib_files)
end

27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,25 @@

> "A dizzying lifetime... reeling by on celluloid" _-- Rush / Between The Wheels_
Reel is a fast, non-blocking "evented" web server built on [http_parser.rb][parser],
[websocket_parser][websockets], [Celluloid::IO][celluloidio], and [nio4r][nio4r]. Thanks
to Celluloid, Reel also works great for multithreaded applications and provides
traditional multithreaded blocking I/O support too.
Reel is a fast, non-blocking "evented" web server
built on [http_parser.rb][parser], [websocket_parser][websockets],
[Celluloid::IO][celluloidio], and [nio4r][nio4r]. Thanks to Celluloid,
Reel also works great for multithreaded applications
and provides traditional multithreaded blocking I/O support too.

[parser]: https://github.com/tmm1/http_parser.rb
[websockets]: https://github.com/afcapel/websocket_parser
[celluloidio]: https://github.com/celluloid/celluloid-io
[nio4r]: https://github.com/celluloid/nio4r

Connections to Reel can be either non-blocking and handled entirely within
the Reel::Server thread, or the same connections can be dispatched to worker
threads where they will perform ordinary blocking IO. Reel provides no
built-in thread pool, however you can build one yourself using Celluloid.pool,
or because Celluloid already pools threads to begin with, you can simply use
an actor per connection.
the Reel::Server thread (handling HTTP, HTTPS, or UNIX sockets),
or the same connections can be dispatched to worker threads
where they will perform ordinary blocking IO.
Reel provides no built-in thread pool,
however you can build one yourself using Celluloid.pool,
or because Celluloid already pools threads to begin with,
you can simply use an actor per connection.

This gives you the best of both worlds: non-blocking I/O for when you're
primarily I/O bound, and threads for where you're compute bound.
Expand Down Expand Up @@ -132,7 +135,7 @@ Reel lets you pass a block to initialize which receives connections:
```ruby
require 'reel'

Reel::Server.supervise("0.0.0.0", 3000) do |connection|
Reel::Server::HTTP.supervise("0.0.0.0", 3000) do |connection|
# Support multiple keep-alive requests per connection
connection.each_request do |request|
# WebSocket support
Expand Down Expand Up @@ -163,15 +166,15 @@ You can also subclass Reel, which allows additional customizations:
```ruby
require 'reel'

class MyServer < Reel::Server
class MyServer < Reel::Server::HTTP
def initialize(host = "127.0.0.1", port = 3000)
super(host, port, &method(:on_connection))
end

def on_connection(connection)
connection.each_request do |request|
if request.websocket?
handle_websocket(request)
handle_websocket(request.websocket)
else
handle_request(request)
end
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/hello_reel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
addr, port = '127.0.0.1', 1234

puts "*** Starting server on #{addr}:#{port}"
Reel::Server.new(addr, port) do |connection|
Reel::Server::HTTP.new(addr, port) do |connection|
connection.respond :ok, "Hello World"
end

Expand Down
2 changes: 1 addition & 1 deletion benchmarks/reel_pool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def handle_request(request)

connectionPool = MyConnectionHandler.pool

Reel::Server.run('127.0.0.1', 3000) do |connection|
Reel::Server::HTTP.run('127.0.0.1', 3000) do |connection|
# We're handing this connection off to another actor, so
# we detach it first before handing it off
connection.detach
Expand Down
25 changes: 0 additions & 25 deletions examples/chunked.rb

This file was deleted.

2 changes: 1 addition & 1 deletion examples/hello_world.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
addr, port = '127.0.0.1', 1234

puts "*** Starting server on http://#{addr}:#{port}"
Reel::Server.run(addr, port) do |connection|
Reel::Server::HTTP.run(addr, port) do |connection|
# For keep-alive support
connection.each_request do |request|
# Ordinarily we'd route the request here, e.g.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}

puts "*** Starting server on #{addr}:#{port}"
Reel::SSLServer.supervise(addr, port, options) do |connection|
Reel::Server::HTTPS.supervise(addr, port, options) do |connection|
# For keep-alive support
connection.each_request do |request|
# Ordinarily we'd route the request here, e.g.
Expand Down
22 changes: 16 additions & 6 deletions examples/roundtrip.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def new_message(topic)
end
end

class WebServer < Reel::Server
class WebServer < Reel::Server::HTTP
include Celluloid::Logger

def initialize(host = "0.0.0.0", port = 9000)
Expand All @@ -71,12 +71,22 @@ def initialize(host = "0.0.0.0", port = 9000)

def on_connection(connection)
while request = connection.request
case request
when Reel::Request
route_request connection, request
when Reel::WebSocket
if request.websocket?
info "Received a WebSocket connection"
route_websocket request

# We're going to hand off this connection to another actor (Writer/Reader)
# However, initially Reel::Connections are "attached" to the
# Reel::Server::HTTP actor, meaning that the server manages the connection
# lifecycle (e.g. error handling) for us.
#
# If we want to hand this connection off to another actor, we first
# need to detach it from the Reel::Server (in this case, Reel::Server::HTTP)
connection.detach

route_websocket request.websocket
return
else
route_request connection, request
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion examples/server_sent_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
require 'reel'


class ServerSentEvents < Reel::Server
class ServerSentEvents < Reel::Server::HTTP
include Celluloid::Logger

def initialize(ip = '127.0.0.1', port = 63310)
Expand Down
2 changes: 1 addition & 1 deletion examples/spy_hello_world.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
addr, port = '127.0.0.1', 1234

puts "*** Starting server on http://#{addr}:#{port}"
Reel::Server.run(addr, port, spy: true) do |connection|
Reel::Server::HTTP.run(addr, port, spy: true) do |connection|
# For keep-alive support
connection.each_request do |request|
# Ordinarily we'd route the request here, e.g.
Expand Down
6 changes: 3 additions & 3 deletions examples/websockets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def notify_time_change(topic, new_time)
end
end

class WebServer < Reel::Server
class WebServer < Reel::Server::HTTP
include Celluloid::Logger

def initialize(host = "127.0.0.1", port = 1234)
Expand All @@ -53,11 +53,11 @@ def on_connection(connection)

# We're going to hand off this connection to another actor (TimeClient)
# However, initially Reel::Connections are "attached" to the
# Reel::Server actor, meaning that the server manages the connection
# Reel::Server::HTTP actor, meaning that the server manages the connection
# lifecycle (e.g. error handling) for us.
#
# If we want to hand this connection off to another actor, we first
# need to detach it from the Reel::Server
# need to detach it from the Reel::Server (in this case, Reel::Server::HTTP)
connection.detach

route_websocket request.websocket
Expand Down
7 changes: 5 additions & 2 deletions lib/reel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
require 'reel/logger'
require 'reel/request'
require 'reel/response'

require 'reel/server'
require 'reel/ssl_server' # will be deleted by #121
require 'reel/server/unix' #required by #123 after #121
require 'reel/server/http'
require 'reel/server/https'
require 'reel/server/unix'

require 'reel/websocket'
require 'reel/stream'

Expand Down
14 changes: 8 additions & 6 deletions lib/reel/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def initialize(socket, buffer_size = nil)
@request_fsm = Request::StateMachine.new(@socket)

reset_request
@response_state = :header
@response_state = :headers
end

# Is the connection still active?
Expand Down Expand Up @@ -82,7 +82,7 @@ def each_request
# Send a response back to the client
# Response can be a symbol indicating the status code or a Reel::Response
def respond(response, headers_or_body = {}, body = nil)
raise StateError, "not in header state" if @response_state != :header
raise StateError, "not in header state" if @response_state != :headers

if headers_or_body.is_a? Hash
headers = headers_or_body
Expand All @@ -98,7 +98,7 @@ def respond(response, headers_or_body = {}, body = nil)
end

case response
when Symbol
when Symbol, Fixnum, Integer
response = Response.new(response, headers, body)
when Response
else raise TypeError, "invalid response: #{response.inspect}"
Expand All @@ -120,10 +120,12 @@ def respond(response, headers_or_body = {}, body = nil)
@parser.reset
@request_fsm.transition :closed
end
rescue IOError, Errno::ECONNRESET, Errno::EPIPE, RequestError
rescue IOError, SystemCallError, RequestError
# The client disconnected early, or there is no request
@keepalive = false
@request_fsm.transition :closed
@parser.reset
@current_request = nil
end

# Close the connection
Expand All @@ -138,7 +140,7 @@ def close
def hijack_socket
# FIXME: this doesn't do a great job of ensuring we can hijack the socket
# in its current state. Improve the state detection.
if @request_fsm != :ready && @response_state != :header
if @request_fsm != :ready && @response_state != :headers
raise StateError, "connection is not in a hijackable state"
end

Expand All @@ -165,7 +167,7 @@ def reset_request

# Set response state for the connection.
def response_state=(state)
if state == :header
if state == :headers
reset_request
end
@response_state = state
Expand Down
4 changes: 3 additions & 1 deletion lib/reel/mixins.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def remote_host
# NOTE: Celluloid::IO does not yet support non-blocking reverse DNS
socket.peeraddr(true)[2]
end

end

module RequestMixin
Expand All @@ -31,7 +32,7 @@ def headers
@request_info.headers
end

def [] header
def [](header)
headers[header]
end

Expand Down Expand Up @@ -60,4 +61,5 @@ def fragment
end

end

end

0 comments on commit 8cf2294

Please sign in to comment.