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

Commit

Permalink
Merge eb461c8 into 99474a4
Browse files Browse the repository at this point in the history
  • Loading branch information
digitalextremist committed Dec 11, 2013
2 parents 99474a4 + eb461c8 commit 82b4b58
Show file tree
Hide file tree
Showing 20 changed files with 127 additions and 177 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ traditional multithreaded blocking I/O support too.
[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
the Reel::Server thread ( handling HTTP, SSL, 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
Expand Down Expand Up @@ -132,7 +133,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,7 +164,7 @@ 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
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
2 changes: 1 addition & 1 deletion 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 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
2 changes: 1 addition & 1 deletion examples/ssl_hello_world.rb
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::SSL.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
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
6 changes: 5 additions & 1 deletion lib/reel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@
require 'reel/logger'
require 'reel/request'
require 'reel/response'

require 'reel/server'
require 'reel/ssl_server'
require 'reel/server/http'
require 'reel/server/ssl'
require 'reel/server/unix'

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

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
77 changes: 23 additions & 54 deletions lib/reel/server.rb
Original file line number Diff line number Diff line change
@@ -1,71 +1,34 @@
module Reel
# The Reel HTTP server class
# Base class for Reel servers.
#
# This class is a Celluloid::IO actor which provides a bareboens HTTP server
# For HTTPS support, use Reel::SSLServer
# This class is a Celluloid::IO actor which provides a barebones server
# which does not open a socket itself, it just begin handling connections once
# initialized with a specific kind of protocol-based server.

# For specific protocol support, use:

# Reel::Server::HTTP
# Reel::Server::SSL
# Reel::Server::SSL::UNIX

class Server
include Celluloid::IO

# How many connections to backlog in the TCP accept queue
DEFAULT_BACKLOG = 100

execute_block_on_receiver :initialize
finalizer :shutdown

# Allow the existing `new` to be called, even though we will
# replace it with a default version that creates HTTP servers over
# TCP sockets.
#
class << self
alias_method :_new, :new
protected :_new
end

# Create a new Reel HTTP server
#
# @param [String] host address to bind to
# @param [Fixnum] port to bind to
# @option options [Fixnum] backlog of requests to accept
# @option options [true] spy on the request
#
# @return [Reel::SSLServer] Reel HTTPS server actor
#
# ::new was overridden for backwards compatibility. The underlying
# #initialize method now accepts a `server` param that is
# responsible for having established the bi-directional
# communication channel. ::new uses the existing (sane) default of
# setting up the TCP channel for the user.
#
def self.new(host, port, options = {} , &callback)
server = Celluloid::IO::TCPServer.new(host, port)
backlog = options.fetch(:backlog, DEFAULT_BACKLOG)

# prevent TCP packets from being buffered
server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
server.listen(backlog)

self._new(server, options, &callback)
end

# Create a Reel HTTP server over a UNIX socket.
#
# @param [String] socket_path path to the UNIX socket
# @option options [true] spy on the request
#
def self.unix(socket_path, options = {}, &callback)
server = Celluloid::IO::UNIXServer.new(socket_path)

self._new(server, options, &callback)
end

def initialize(server, options = {}, &callback)
def initialize(server, options={}, &callback)
@spy = STDOUT if options[:spy]
@server = server
@options = options
@callback = callback
@server = server

async.run
end
@server.listen(options.fetch(:backlog, DEFAULT_BACKLOG))

async.run
end

def shutdown
@server.close if @server
Expand All @@ -75,6 +38,12 @@ def run
loop { async.handle_connection @server.accept }
end

def optimize(socket)
if socket.is_a? TCPSocket
socket.setsockopt( Socket::IPPROTO_TCP, :TCP_NODELAY, 1 )
end
end

def handle_connection(socket)
if @spy
require 'reel/spy'
Expand Down
20 changes: 20 additions & 0 deletions lib/reel/server/http.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Reel
class Server
class HTTP < Server

# Create a new Reel HTTPS server
#
# @param [String] host address to bind to
# @param [Fixnum] port to bind to
# @option options [Fixnum] backlog of requests to accept
#
# @return [Reel::Server::HTTP] Reel HTTP server actor
def initialize(host, port, options={}, &callback)
optimize server = Celluloid::IO::TCPServer.new(host, port)
options.merge!(host: host, port: port)
super(server, options, &callback)
end

end
end
end
57 changes: 57 additions & 0 deletions lib/reel/server/ssl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
module Reel
class Server
class SSL < Server

# Create a new Reel HTTPS server
#
# @param [String] host address to bind to
# @param [Fixnum] port to bind to
# @option options [Fixnum] backlog of requests to accept
# @option options [String] :cert the server's SSL certificate
# @option options [String] :key the server's SSL key
#
# @return [Reel::Server::SSL] Reel HTTPS server actor
def initialize(host, port, options={}, &callback)

# Ideally we can encapsulate this rather than making Ruby OpenSSL a
# mandatory part of the Reel API. It would be nice to support
# alternatives (e.g. Puma's MiniSSL)
ssl_context = OpenSSL::SSL::SSLContext.new
ssl_context.cert = OpenSSL::X509::Certificate.new options.fetch(:cert)
ssl_context.key = OpenSSL::PKey::RSA.new options.fetch(:key)

ssl_context.ca_file = options[:ca_file]
ssl_context.ca_path = options[:ca_path]

# if verify_mode isn't explicitly set, verify peers if we've
# been provided CA information that would enable us to do so
ssl_context.verify_mode = case
when options.include?(:verify_mode) then options[:verify_mode]
when options.include?(:ca_file) then OpenSSL::SSL::VERIFY_PEER
when options.include?(:ca_path) then OpenSSL::SSL::VERIFY_PEER
else OpenSSL::SSL::VERIFY_NONE
end

optimize @tcpserver = Celluloid::IO::TCPServer.new(host, port)

server = Celluloid::IO::SSLServer.new(@tcpserver, ssl_context)
options.merge!(host: host, port: port)

super(server, options, &callback)
end

def run
loop do
begin
socket = @server.accept
rescue OpenSSL::SSL::SSLError => ex
Logger.warn "Error accepting SSLSocket: #{ex.class}: #{ex.to_s}"
retry
end

async.handle_connection socket
end
end
end
end
end
Loading

0 comments on commit 82b4b58

Please sign in to comment.