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

Commit

Permalink
Merge 2bf6b37 into 2db2604
Browse files Browse the repository at this point in the history
  • Loading branch information
//de committed Apr 14, 2015
2 parents 2db2604 + 2bf6b37 commit 2712771
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 66 deletions.
30 changes: 25 additions & 5 deletions CHANGES.md
@@ -1,5 +1,25 @@
0.6.0 (2015-03-24)
-----
* Fix stack level too deep when writing to ChunkStream
* Use HTTP::Resonse::Status::REASONS table ( HTTP::Response::* deprecated in the HTTP gem )
* Use Timers 3.0.0 API
* Case-insensitivity for header field names ( i.e. in case a proxy downcases them )
* Catch when openssl sometimes fires ECONNRESET, EPIPE, ETIMEDOUT, EHOSTUNREACH and as an error
* Unused `optimize` socket modifications taken off all server implementations
* Fixed 404 error in roundtrip example
* Fixed "Reel::StateError: already processing a request" when client is killed
* Numerous updates to rspec.
* Switched to websocket/driver and improved websocket handling
* Implement DriverEnvironment to fix websocket example
* Refactored Server::HTTPS to be more idomatic
* Fixed jRuby related test failures
* Fixed "ArgumentError: Data object has already been freed" caused by underlying parser.
* FINALLY! Support for UNIX Socket servers across all RVM's, as of jRuby 1.7.19
* Unified Server#run removes need for duplication of #run across all Server implementations.
* Standardized method of rescuing exceptions unique to each type of Server in unified #run method.

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
Expand All @@ -8,7 +28,7 @@
* Ensure response bodies are always closed
* Support for passing a fixnum status to Connection#respond

0.4.0
0.4.0 (2013-09-14)
-----
* Rack adapter moved to the reel-rack project
* Pipelining support
Expand All @@ -23,7 +43,7 @@
* Remove Reel::App (unmaintained, sorry)
* Reel::CODENAME added (0.4.0 is "Garbo")

0.3.0
0.3.0 (2013-02-01)
-----
* Reel::App: Sinatra-like DSL for defining Reel apps using Octarine
* Chunked upload support
Expand All @@ -33,12 +53,12 @@
* Bugfix: Send CRLF after chunks
* Bugfix: Increase TCP connection backlog to 1024

0.2.0
0.2.0 (2012-09-03)
-----
* Initial WebSockets support via Reel::WebSocket
* Experimental Rack adapter by Alberto Fernández-Capel
* Octarine (Sinatra-like DSL) support by Grant Rodgers

0.1.0
0.1.0 (2012-07-12)
-----
* Initial release
1 change: 1 addition & 0 deletions lib/reel.rb
Expand Up @@ -14,6 +14,7 @@
require 'reel/server'
require 'reel/server/http'
require 'reel/server/https'
require 'reel/server/unix' unless defined? JRUBY_VERSION

require 'reel/websocket'
require 'reel/stream'
Expand Down
2 changes: 1 addition & 1 deletion lib/reel/connection.rb
Expand Up @@ -56,7 +56,7 @@ def request

req = @parser.current_request
@request_fsm.transition :headers
@keepalive = false if req[CONNECTION] == CLOSE || req.version == HTTP_VERSION_1_0
@keepalive = false if req.nil? || req[CONNECTION] == CLOSE || req.version == HTTP_VERSION_1_0
@current_request = req

req
Expand Down
6 changes: 5 additions & 1 deletion lib/reel/request/parser.rb
Expand Up @@ -43,7 +43,11 @@ def current_request

def readpartial(size = @buffer_size)
bytes = @socket.readpartial(size)
@parser << bytes
begin
@parser << bytes
rescue ArgumentError
raise Errno::EPIPE
end
end

#
Expand Down
25 changes: 21 additions & 4 deletions lib/reel/server.rb
Expand Up @@ -2,14 +2,14 @@ module Reel
# Base class for Reel servers.
#
# 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.
# 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::HTTPS
# Coming soon: Reel::Server::UNIX
# Reel::Server::UNIX ( not on jRuby yet )

class Server
include Celluloid::IO
Expand All @@ -25,6 +25,15 @@ def initialize(server, options={}, &callback)
@callback = callback
@server = server

@options[:rescue] ||= []
@options[:rescue] += [
Errno::ECONNRESET,
Errno::EPIPE,
Errno::EINPROGRESS,
Errno::ETIMEDOUT,
Errno::EHOSTUNREACH
]

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

async.run
Expand All @@ -35,7 +44,15 @@ def shutdown
end

def run
loop { async.handle_connection @server.accept }
loop {
begin
socket = @server.accept
rescue *@options[:rescue] => ex
Logger.warn "Error accepting socket: #{ex.class}: #{ex.to_s}"
next
end
async.handle_connection socket
}
end

def handle_connection(socket)
Expand Down
23 changes: 5 additions & 18 deletions lib/reel/server/https.rb
Expand Up @@ -27,12 +27,11 @@ def initialize(host, port, options={}, &callback)

# 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)
ssl_context.verify_mode = if options.include?(:verify_mode)
options[:verify_mode]
when options.include?(:ca_file)
elsif options.include?(:ca_file)
OpenSSL::SSL::VERIFY_PEER
when options.include?(:ca_path)
elsif options.include?(:ca_path)
OpenSSL::SSL::VERIFY_PEER
else
OpenSSL::SSL::VERIFY_NONE
Expand All @@ -43,22 +42,10 @@ def initialize(host, port, options={}, &callback)
server = Celluloid::IO::SSLServer.new(@tcpserver, ssl_context)
options.merge!(host: host, port: port)

options[:rescue] = [ OpenSSL::SSL::SSLError ]

super(server, options, &callback)
end

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

async.handle_connection socket
end
end
end
end
end
18 changes: 18 additions & 0 deletions lib/reel/server/unix.rb
@@ -0,0 +1,18 @@
module Reel
class Server
class UNIX < Server

# Create a new Reel HTTPS server
#
# @option options [String] socket path to bind to
# @option options [Fixnum] backlog of requests to accept
#
# @return [Reel::Server::UNIX] Reel UNIX server actor
def initialize(socket_path, options={}, &callback)
server = Celluloid::IO::UNIXServer.new(socket_path)
options[:socket_path] = socket_path
super(server, options, &callback)
end
end
end
end
2 changes: 1 addition & 1 deletion lib/reel/version.rb
@@ -1,4 +1,4 @@
module Reel
VERSION = "0.6.0"
VERSION = "0.6.0.pre2"
CODENAME = "Garland"
end
36 changes: 18 additions & 18 deletions lib/reel/websocket.rb
@@ -1,6 +1,5 @@
require 'forwardable'
require 'websocket/driver'
require 'rack'

module Reel
class WebSocket
Expand All @@ -10,10 +9,11 @@ class WebSocket

attr_reader :socket
def_delegators :@socket, :addr, :peeraddr
def_delegators :@driver, :ping

def initialize(info, connection)
driver_env = DriverEnvironment.new(info, connection.socket)
driver_env = DriverEnvironment.new(info, connection.socket)

@socket = connection.hijack_socket
@request_info = info

Expand Down Expand Up @@ -94,24 +94,24 @@ def cancel_timer!
class DriverEnvironment
extend Forwardable

attr_reader :env, :url, :socket

def_delegators :socket, :write

def initialize(info, socket)
@url = info.url
attr_reader :env, :socket

env_hash = Hash[info.headers.map { |key, value| ['HTTP_' + key.upcase.gsub('-','_'),value ] }]

env_hash.merge!({
:method => info.method,
:input => info.body.to_s,
'REMOTE_ADDR' => info.remote_addr
})
def_delegator :@info, :url
def_delegator :@socket, :write

@env = ::Rack::MockRequest.env_for(@url, env_hash)
RACK_HEADERS = {
'HTTP_ORIGIN' => 'Origin',
'HTTP_SEC_WEBSOCKET_KEY' => 'Sec-WebSocket-Key',
'HTTP_SEC_WEBSOCKET_KEY1' => 'Sec-WebSocket-Key1',
'HTTP_SEC_WEBSOCKET_KEY2' => 'Sec-WebSocket-Key2',
'HTTP_SEC_WEBSOCKET_EXTENSIONS' => 'Sec-WebSocket-Extensions',
'HTTP_SEC_WEBSOCKET_PROTOCOL' => 'Sec-WebSocket-Protocol',
'HTTP_SEC_WEBSOCKET_VERSION' => 'Sec-WebSocket-Version'
}.freeze

@socket = socket
def initialize(info, socket)
@info, @socket = info, socket
@env = Hash.new {|h,k| @info.headers[RACK_HEADERS[k]]}
end
end

Expand Down
1 change: 0 additions & 1 deletion reel.gemspec
Expand Up @@ -20,7 +20,6 @@ Gem::Specification.new do |gem|
gem.add_runtime_dependency 'http', '>= 0.6.0.pre'
gem.add_runtime_dependency 'http_parser.rb', '>= 0.6.0'
gem.add_runtime_dependency 'websocket-driver', '>= 0.5.1'
gem.add_runtime_dependency 'rack'

gem.add_development_dependency 'rake'
gem.add_development_dependency 'rspec', '>= 2.11.0'
Expand Down
3 changes: 0 additions & 3 deletions spec/reel/http_server_spec.rb
Expand Up @@ -14,9 +14,7 @@
expect(request.method).to eq 'GET'
expect(request.version).to eq "1.1"
expect(request.url).to eq example_path

connection.respond :ok, response_body
rescue => ex
end
end

Expand All @@ -36,7 +34,6 @@
request = connection.request
expect(request.method).to eq 'POST'
connection.respond :ok, request.body.to_s
rescue => ex
end
end

Expand Down
17 changes: 3 additions & 14 deletions spec/reel/https_server_spec.rb
Expand Up @@ -2,6 +2,7 @@
require 'net/http'

RSpec.describe Reel::Server::HTTPS do

let(:example_https_port) { example_port + 1 }
let(:example_url) { "https://#{example_addr}:#{example_https_port}#{example_path}" }
let(:endpoint) { URI(example_url) }
Expand All @@ -24,27 +25,23 @@
expect(request.method).to eq 'GET'
expect(request.version).to eq "1.1"
expect(request.url).to eq example_path

connection.respond :ok, response_body
rescue => ex
end
end

with_reel_https_server(handler) do
http = Net::HTTP.new(endpoint.host, endpoint.port)
http.use_ssl = true
http.ca_file = self.ca_file

request = Net::HTTP::Get.new(endpoint.path)
response = http.request(request)

expect(response.body).to eq response_body
end

raise ex if ex
end

it 'verifies client SSL certs when provided with a CA' do
it "verifies client SSL certs when provided with a CA" do
ex = nil

handler = proc do |connection|
Expand All @@ -53,9 +50,7 @@
expect(request.method).to eq 'GET'
expect(request.version).to eq '1.1'
expect(request.url).to eq example_path

connection.respond :ok, response_body
rescue => ex
end
end

Expand All @@ -65,17 +60,15 @@
http.ca_file = self.ca_file
http.cert = OpenSSL::X509::Certificate.new self.client_cert
http.key = OpenSSL::PKey::RSA.new self.client_key

request = Net::HTTP::Get.new(endpoint.path)
response = http.request(request)

expect(response.body).to eq response_body
end

raise ex if ex
end

it %{fails to verify client certificates that aren't signed} do
it "fails to verify client certificates that aren't signed" do
ex = nil

handler = proc do |connection|
Expand All @@ -84,9 +77,7 @@
expect(request.method).to eq 'GET'
expect(request.version).to eq '1.1'
expect(request.url).to eq example_path

connection.respond :ok, response_body
rescue => ex
end
end

Expand All @@ -96,9 +87,7 @@
http.ca_file = self.ca_file
http.cert = OpenSSL::X509::Certificate.new self.client_cert_unsigned
http.key = OpenSSL::PKey::RSA.new self.client_key

request = Net::HTTP::Get.new(endpoint.path)

expect { http.request(request) }.to raise_error(OpenSSL::SSL::SSLError)
end

Expand Down

0 comments on commit 2712771

Please sign in to comment.