reel 0.0.0 → 0.0.1

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.

data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format documentation
3
+ --backtrace
4
+ --default_path spec
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+ - ruby-head
5
+ - jruby-19mode
6
+ - jruby-head
7
+
8
+ # Rubies I would like to support, but they deadlock
9
+ # - rbx-18mode
10
+ # - rbx-19mode
data/Gemfile CHANGED
@@ -1,6 +1,9 @@
1
- source 'https://rubygems.org'
1
+ source :rubygems
2
+
3
+ gem 'celluloid', :git => 'https://github.com/celluloid/celluloid.git'
4
+ gem 'celluloid-io', :git => 'https://github.com/celluloid/celluloid-io.git'
5
+ gem 'jruby-openssl' if defined? JRUBY_VERSION
2
6
 
3
7
  # Specify your gem's dependencies in reel.gemspec
4
8
  gemspec
5
9
 
6
- gem 'celluloid-io', :git => 'https://github.com/tarcieri/celluloid-io.git'
File without changes
data/README.md CHANGED
@@ -1,29 +1,90 @@
1
- # Reel
1
+ ![Reel](https://github.com/celluloid/reel/raw/master/logo.png)
2
+ =======
3
+ [![Build Status](https://secure.travis-ci.org/celluloid/reel.png?branch=master)](http://travis-ci.org/celluloid/reel)
2
4
 
3
- TODO: Write a gem description
5
+ Reel is a fast, non-blocking "evented" web server built on [http_parser.rb][parser],
6
+ [Celluloid::IO][celluloidio], and [nio4r][nio4r]. It's probably most similar to
7
+ [Goliath][goliath], but thanks to Celluloid also works great for multithreaded
8
+ applications and provides traditional multithreaded blocking I/O support too.
4
9
 
5
- ## Installation
10
+ [parser]: https://github.com/tmm1/http_parser.rb
11
+ [celluloidio]: https://github.com/celluloid/celluloid-io
12
+ [nio4r]: https://github.com/tarcieri/nio4r
13
+ [Goliath]: http://postrank-labs.github.com/goliath/
6
14
 
7
- Add this line to your application's Gemfile:
15
+ Connections to Reel can be either non-blocking and handled entirely within
16
+ the Reel::Server thread, or the same connections can be dispatched to worker
17
+ threads where they will perform ordinary blocking IO. Reel provides no
18
+ built-in thread pool, however you can build one yourself using Celluloid::Pool,
19
+ or because Celluloid already pools threads to begin with, you can simply use
20
+ an actor per connection.
8
21
 
9
- gem 'reel'
22
+ This gives you the best of both worlds: non-blocking I/O for when you're
23
+ primarily I/O bound, and threads for where you're compute bound.
10
24
 
11
- And then execute:
25
+ ### Is It Good?
12
26
 
13
- $ bundle
27
+ Yes, but it has room for improvement. A "hello world" web server benchmark,
28
+ run on a 2GHz i7 (OS X 10.7.3). All servers used in a single-threaded mode.
14
29
 
15
- Or install it yourself as:
30
+ Reel performance on various Ruby VMs:
16
31
 
17
- $ gem install reel
32
+ ```
33
+ # httperf --num-conns=50 --num-calls=1000
18
34
 
19
- ## Usage
35
+ Ruby Version Throughput Latency
36
+ ------------ ---------- -------
37
+ JRuby HEAD 5650 reqs/s (0.2 ms/req)
38
+ Ruby 1.9.3 5263 reqs/s (0.2 ms/req)
39
+ JRuby 1.6.7 4303 reqs/s (0.2 ms/req)
40
+ rbx HEAD 2288 reqs/s (0.4 ms/req)
41
+ ```
20
42
 
21
- TODO: Write usage instructions here
43
+ Comparison with other web servers:
22
44
 
23
- ## Contributing
45
+ ```
46
+ Web Server Throughput Latency
47
+ ---------- ---------- -------
48
+ Goliath (0.9.4) 2058 reqs/s (0.5 ms/req)
49
+ Thin (1.2.11) 7502 reqs/s (0.1 ms/req)
50
+ Node.js (0.6.5) 11735 reqs/s (0.1 ms/req)
51
+ ```
24
52
 
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Added some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
53
+ All Ruby benchmarks done on Ruby 1.9.3. Latencies given are average-per-request
54
+ and are not amortized across all concurrent requests.
55
+
56
+ Usage
57
+ -----
58
+
59
+ Reel provides an extremely simple API:
60
+
61
+ ```ruby
62
+ require 'reel'
63
+
64
+ Reel::Server.supervise("0.0.0.0", 3000) do |connection|
65
+ request = connection.request
66
+ puts "Client requested: #{request.method} #{request.url}"
67
+ connection.respond :ok, "hello, world"
68
+ end
69
+ ```
70
+
71
+ Status
72
+ ------
73
+
74
+ Reel is still in an extremely early stage of development and may be
75
+ missing a lot of features. It seems to be doing a rudimentary job of
76
+ speaking HTTP and has basic keep-alive support.
77
+
78
+ Contributing
79
+ ------------
80
+
81
+ * Fork this repository on github
82
+ * Make your changes and send me a pull request
83
+ * If I like them I'll merge them
84
+ * If I've accepted a patch, feel free to ask for commit access
85
+
86
+ License
87
+ -------
88
+
89
+ Copyright (c) 2012 Tony Arcieri. Distributed under the MIT License. See
90
+ LICENSE.txt for further details.
data/Rakefile CHANGED
@@ -1,2 +1,6 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
+
4
+ Dir[File.expand_path("../tasks/**/*.rake", __FILE__)].each { |task| load task }
5
+
6
+ task :default => :spec
@@ -0,0 +1,11 @@
1
+ # Run with: ruby hello_goliath.rb -sv -e production
2
+ require 'goliath'
3
+
4
+ class Hello < Goliath::API
5
+ # default to JSON output, allow Yaml as secondary
6
+ use Goliath::Rack::Render, ['json', 'yaml']
7
+
8
+ def response(env)
9
+ [200, {}, "Hello World"]
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ /* Run with: node hello_node.js */
2
+
3
+ var http = require('http');
4
+ http.createServer(function (req, res) {
5
+ res.writeHead(200, {'Content-Type': 'text/plain'});
6
+ res.end('Hello World\n');
7
+ }).listen(1337, "127.0.0.1");
8
+ console.log('Server running at http://127.0.0.1:1337/');
@@ -0,0 +1,5 @@
1
+ # Run with: thin -e production -R hello_rack.ru start
2
+ require 'rack'
3
+
4
+ body = "Hello World"
5
+ run proc { |env| [200, {}, body] }
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'reel'
4
+
5
+ addr, port = '127.0.0.1', 1234
6
+
7
+ puts "*** Starting server on #{addr}:#{port}"
8
+ Reel::Server.new(addr, port) do |connection|
9
+ connection.respond :ok, "Hello World"
10
+ end
11
+
12
+ sleep
data/bin/reel ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'reel'
4
+
5
+ host, port = "0.0.0.0", 3000
6
+
7
+ Reel::Logger.info "A Reel good HTTP server!"
8
+ Reel::Logger.info "Listening on #{host}:#{port}"
9
+
10
+ Reel::Server.supervise("0.0.0.0", 3000) do |connection|
11
+ p connection
12
+ end
13
+
14
+ sleep
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'reel'
4
+
5
+ addr, port = '127.0.0.1', 1234
6
+
7
+ puts "*** Starting server on #{addr}:#{port}"
8
+ Reel::Server.new(addr, port) do |connection|
9
+ connection.respond :ok, "hello, world!"
10
+ end
11
+
12
+ sleep
data/lib/reel.rb CHANGED
@@ -1,5 +1,18 @@
1
- require "reel/version"
1
+ require 'http/parser'
2
+ require 'http'
3
+ require 'celluloid/io'
2
4
 
5
+ require 'reel/version'
6
+
7
+ require 'reel/connection'
8
+ require 'reel/logger'
9
+ require 'reel/request'
10
+ require 'reel/request/parser'
11
+ require 'reel/response'
12
+ require 'reel/server'
13
+
14
+ # A Reel good HTTP server
3
15
  module Reel
4
- # Your code goes here...
16
+ # The method given was not understood
17
+ class UnsupportedMethodError < ArgumentError; end
5
18
  end
@@ -0,0 +1,103 @@
1
+ module Reel
2
+ # A connection to the HTTP server
3
+ class Connection
4
+ class StateError < RuntimeError; end # wrong state for a given request
5
+
6
+ attr_reader :request
7
+
8
+ # Attempt to read this much data
9
+ BUFFER_SIZE = 4096
10
+
11
+ def initialize(socket)
12
+ @socket = socket
13
+ @keepalive = true
14
+ reset
15
+
16
+ @response_state = :header
17
+ @body_remaining = nil
18
+ end
19
+
20
+ # Is the connection still active?
21
+ def alive?; @keepalive; end
22
+
23
+ def read_request
24
+ raise StateError, "can't read header" unless @request_state == :header
25
+
26
+ begin
27
+ until @parser.headers
28
+ @parser << @socket.readpartial(BUFFER_SIZE)
29
+ end
30
+ rescue IOError, Errno::ECONNRESET, Errno::EPIPE
31
+ @keepalive = false
32
+ @socket.close unless @socket.closed?
33
+ return
34
+ end
35
+
36
+ @request_state = :body
37
+
38
+ headers = {}
39
+ @parser.headers.each do |header, value|
40
+ headers[Http.canonicalize_header(header)] = value
41
+ end
42
+
43
+ if headers['Connection']
44
+ @keepalive = false if headers['Connection'] == 'close'
45
+ elsif @parser.http_version == "1.0"
46
+ @keepalive = false
47
+ end
48
+
49
+ @body_remaining = Integer(headers['Content-Length']) if headers['Content-Length']
50
+ @request = Request.new(@parser.http_method, @parser.url, @parser.http_version, headers, self)
51
+ end
52
+
53
+ def readpartial(size = BUFFER_SIZE)
54
+ if @body_remaining and @body_remaining > 0
55
+ chunk = @parser.chunk
56
+ unless chunk
57
+ @parser << @socket.readpartial(size)
58
+ chunk = @parser.chunk
59
+ return unless chunk
60
+ end
61
+
62
+ @body_remaining -= chunk.length
63
+ @body_remaining = nil if @body_remaining < 1
64
+
65
+ chunk
66
+ end
67
+ end
68
+
69
+ def respond(response, body = nil)
70
+ if @keepalive
71
+ headers = {'Connection' => 'Keep-Alive'}
72
+ else
73
+ headers = {'Connection' => 'close'}
74
+ end
75
+
76
+ case response
77
+ when Symbol
78
+ response = Response.new(response, headers, body)
79
+ when Response
80
+ else raise TypeError, "invalid response: #{response.inspect}"
81
+ end
82
+
83
+ response.render(@socket)
84
+ rescue IOError, Errno::ECONNRESET, Errno::EPIPE
85
+ # The client disconnected early
86
+ @keepalive = false
87
+ ensure
88
+ if @keepalive
89
+ reset
90
+ @request_state = :header
91
+ else
92
+ @socket.close unless @socket.closed?
93
+ @request_state = :closed
94
+ end
95
+ end
96
+
97
+ def reset
98
+ @request_state = :header
99
+ @parser = Request::Parser.new
100
+ @request = nil
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,21 @@
1
+ require 'logger'
2
+
3
+ module Reel
4
+ module Logger
5
+ @logger = ::Logger.new STDERR
6
+ module_function
7
+
8
+ def logger=(logger)
9
+ @logger = logger
10
+ end
11
+
12
+ def logger
13
+ @logger
14
+ end
15
+
16
+ def debug(msg); @logger.debug(msg); end
17
+ def info(msg); @logger.info(msg); end
18
+ def warn(msg); @logger.warn(msg); end
19
+ def error(msg); @logger.error(msg); end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ module Reel
2
+ class Request
3
+ attr_accessor :method, :version, :url
4
+ METHODS = [:get, :head, :post, :put, :delete, :trace, :options, :connect, :patch]
5
+
6
+ def initialize(method, url, version = "1.1", headers = {}, connection = nil)
7
+ @method = method.to_s.downcase.to_sym
8
+ raise UnsupportedArgumentError, "unknown method: #{method}" unless METHODS.include? @method
9
+
10
+ @url, @version, @headers, @connection = url, version, headers, connection
11
+ end
12
+
13
+ def [](header)
14
+ @headers[header]
15
+ end
16
+
17
+ def body
18
+ @body ||= begin
19
+ raise "no connection given" unless @connection
20
+
21
+ body = "" unless block_given?
22
+ while (chunk = @connection.readpartial)
23
+ if block_given?
24
+ yield chunk
25
+ else
26
+ body << chunk
27
+ end
28
+ end
29
+ body unless block_given?
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,63 @@
1
+ module Reel
2
+ # Parses incoming HTTP requests
3
+ class Request
4
+ class Parser
5
+ attr_reader :headers
6
+
7
+ def initialize
8
+ @parser = Http::Parser.new(self)
9
+ @headers = nil
10
+ @finished = false
11
+ @chunk = nil
12
+ end
13
+
14
+ def add(data)
15
+ @parser << data
16
+ end
17
+ alias_method :<<, :add
18
+
19
+ def headers?
20
+ !!@headers
21
+ end
22
+
23
+ def http_method
24
+ @parser.http_method.downcase.to_sym
25
+ end
26
+
27
+ def http_version
28
+ @parser.http_version.join(".")
29
+ end
30
+
31
+ def url
32
+ @parser.request_url
33
+ end
34
+
35
+ #
36
+ # Http::Parser callbacks
37
+ #
38
+
39
+ def on_headers_complete(headers)
40
+ @headers = headers
41
+ end
42
+
43
+ def on_body(chunk)
44
+ if @chunk
45
+ @chunk << chunk
46
+ else
47
+ @chunk = chunk
48
+ end
49
+ end
50
+
51
+ def chunk
52
+ if (chunk = @chunk)
53
+ @chunk = nil
54
+ chunk
55
+ end
56
+ end
57
+
58
+ def on_message_complete
59
+ @finished = true
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,68 @@
1
+ module Reel
2
+ class Response
3
+ # Use status code tables from the Http gem
4
+ STATUS_CODES = Http::Response::STATUS_CODES
5
+ SYMBOL_TO_STATUS_CODE = Http::Response::SYMBOL_TO_STATUS_CODE
6
+ CRLF = "\r\n"
7
+
8
+ attr_reader :status # Status has a special setter to coerce symbol names
9
+ attr_accessor :reason
10
+
11
+ def initialize(status, body_or_headers = nil, body = nil)
12
+ self.status = status
13
+
14
+ if body_or_headers and not body
15
+ @body = body_or_headers
16
+ @headers = {}
17
+ else
18
+ @body = body
19
+ @headers = body_or_headers
20
+ end
21
+
22
+ if @body
23
+ @headers['Content-Length'] ||= @body.length
24
+ end
25
+
26
+ # FIXME: real HTTP versioning
27
+ @version = "HTTP/1.1"
28
+ end
29
+
30
+ # Set the status
31
+ def status=(status, reason=nil)
32
+ case status
33
+ when Integer
34
+ @status = status
35
+ @reason ||= STATUS_CODES[status]
36
+ when Symbol
37
+ if code = SYMBOL_TO_STATUS_CODE[status]
38
+ self.status = code
39
+ else
40
+ raise ArgumentError, "unrecognized status symbol: #{status}"
41
+ end
42
+ else
43
+ raise TypeError, "invalid status type: #{status.inspect}"
44
+ end
45
+ end
46
+
47
+ # Write the response out to the wire
48
+ def render(socket)
49
+ socket << render_header
50
+ socket << @body
51
+ end
52
+
53
+ # Convert headers into a string
54
+ # FIXME: this should probably be factored elsewhere, SRP and all
55
+ def render_header
56
+ response_header = "#{@version} #{@status} #{@reason}#{CRLF}"
57
+
58
+ unless @headers.empty?
59
+ response_header << @headers.map do |header, value|
60
+ "#{header}: #{value}"
61
+ end.join(CRLF) << CRLF
62
+ end
63
+
64
+ response_header << CRLF
65
+ end
66
+ private :render_header
67
+ end
68
+ end
@@ -0,0 +1,31 @@
1
+ module Reel
2
+ class Server
3
+ include Celluloid::IO
4
+
5
+ def initialize(host, port, &callback)
6
+ # This is actually an evented Celluloid::IO::TCPServer
7
+ @server = TCPServer.new(host, port)
8
+ @callback = callback
9
+ run!
10
+ end
11
+
12
+ def finalize
13
+ @server.close
14
+ end
15
+
16
+ def run
17
+ loop { handle_connection! @server.accept }
18
+ end
19
+
20
+ def handle_connection(socket)
21
+ connection = Connection.new(socket)
22
+ begin
23
+ connection.read_request
24
+ @callback[connection]
25
+ end while connection.alive?
26
+ rescue EOFError
27
+ # Client disconnected prematurely
28
+ # FIXME: should probably do something here
29
+ end
30
+ end
31
+ end
data/lib/reel/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Reel
2
- VERSION = "0.0.0"
2
+ VERSION = "0.0.1"
3
3
  end
data/logo.png ADDED
Binary file
data/reel.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |gem|
6
6
  gem.email = ["tony.arcieri@gmail.com"]
7
7
  gem.description = "A Celluloid::IO-powered HTTP server"
8
8
  gem.summary = "A reel good HTTP server"
9
- gem.homepage = "https://github.com/tarcieri/reel"
9
+ gem.homepage = "https://github.com/celluloid/reel"
10
10
 
11
11
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
12
  gem.files = `git ls-files`.split("\n")
@@ -15,9 +15,10 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Reel::VERSION
17
17
 
18
- gem.add_dependency 'celluloid-io', '>= 0.8.0'
19
- gem.add_dependency 'http_parser'
18
+ gem.add_dependency 'celluloid-io', '>= 0.8.0'
19
+ gem.add_dependency 'http', '>= 0.2.0'
20
+ gem.add_dependency 'http_parser.rb', '>= 0.5.3'
20
21
 
21
22
  gem.add_development_dependency 'rake'
22
- gem.add_development_dependency 'rspec', '~> 2.7.0'
23
+ gem.add_development_dependency 'rspec'
23
24
  end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe Reel::Connection do
4
+ it "reads requests without bodies" do
5
+ with_socket_pair do |client, connection|
6
+ client << ExampleRequest.new.to_s
7
+ request = connection.read_request
8
+
9
+ request.url.should eq "/"
10
+ request.version.should eq "1.1"
11
+
12
+ request['Host'].should eq "www.example.com"
13
+ request['Connection'].should eq "keep-alive"
14
+ 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"
15
+ request['Accept'].should eq "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
16
+ request['Accept-Encoding'].should eq "gzip,deflate,sdch"
17
+ request['Accept-Language'].should eq "en-US,en;q=0.8"
18
+ request['Accept-Charset'].should eq "ISO-8859-1,utf-8;q=0.7,*;q=0.3"
19
+ end
20
+ end
21
+
22
+ it "reads requests with bodies" do
23
+ with_socket_pair do |client, connection|
24
+ body = "Hello, world!"
25
+ example_request = ExampleRequest.new
26
+ example_request.body = body
27
+
28
+ client << example_request.to_s
29
+ request = connection.read_request
30
+
31
+ request.url.should eq "/"
32
+ request.version.should eq "1.1"
33
+ request['Content-Length'].should == body.length.to_s
34
+ request.body.should == example_request.body
35
+ end
36
+ end
37
+
38
+ def with_socket_pair
39
+ host = '127.0.0.1'
40
+ port = 10103
41
+
42
+ server = TCPServer.new(host, port)
43
+ client = TCPSocket.new(host, port)
44
+ peer = server.accept
45
+
46
+ yield client, Reel::Connection.new(peer)
47
+
48
+ server.close
49
+ client.close
50
+ peer.close
51
+ end
52
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+ require 'net/http'
3
+
4
+ describe Reel::Server do
5
+ let(:endpoint) { URI("http://#{example_addr}:#{example_port}#{example_url}") }
6
+ let(:response_body) { "ohai thar" }
7
+
8
+ it "receives HTTP requests and sends responses" do
9
+ handler_called = false
10
+ handler = proc do |connection|
11
+ handler_called = true
12
+ request = connection.request
13
+ request.method.should eq :get
14
+ request.version.should eq "1.1"
15
+ request.url.should eq example_url
16
+
17
+ connection.respond :ok, response_body
18
+ end
19
+
20
+ with_reel(handler) do
21
+ response = Net::HTTP.get endpoint
22
+ response.should eq response_body
23
+ end
24
+
25
+ handler_called.should be_true
26
+ end
27
+
28
+ it "echoes request bodies as response bodies" do
29
+ handler_called = false
30
+ handler = proc do |connection|
31
+ handler_called = true
32
+ request = connection.request
33
+ request.method.should eq :post
34
+ connection.respond :ok, request.body
35
+ end
36
+
37
+ with_reel(handler) do
38
+ http = Net::HTTP.new(endpoint.host, endpoint.port)
39
+ request = Net::HTTP::Post.new(endpoint.request_uri)
40
+ request['connection'] = 'close'
41
+ request.body = response_body
42
+ response = http.request(request)
43
+ response.should be_a Net::HTTPOK
44
+ response.body.should == response_body
45
+ end
46
+
47
+ handler_called.should be_true
48
+ end
49
+ end
@@ -0,0 +1,46 @@
1
+ require 'bundler/setup'
2
+ require 'reel'
3
+
4
+ def example_addr; '127.0.0.1'; end
5
+ def example_port; 1234; end
6
+ def example_url; "/example"; end
7
+
8
+ def with_reel(handler)
9
+ server = Reel::Server.new(example_addr, example_port, &handler)
10
+ yield server
11
+ ensure
12
+ server.terminate
13
+ end
14
+
15
+ class ExampleRequest
16
+ extend Forwardable
17
+ def_delegators :@headers, :[], :[]=
18
+ attr_accessor :path, :version, :body
19
+
20
+ def initialize(verb = :get, path = "/", version = "1.1", headers = {}, body = nil)
21
+ @verb = verb.to_s.upcase
22
+ @path = path
23
+ @version = "1.1"
24
+ @headers = {
25
+ 'Host' => 'www.example.com',
26
+ 'Connection' => 'keep-alive',
27
+ 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.78 S',
28
+ 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
29
+ 'Accept-Encoding' => 'gzip,deflate,sdch',
30
+ 'Accept-Language' => 'en-US,en;q=0.8',
31
+ 'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3'
32
+ }.merge(headers)
33
+
34
+ @body = nil
35
+ end
36
+
37
+ def to_s
38
+ if @body && !@headers['Content-Length']
39
+ @headers['Content-Length'] = @body.length
40
+ end
41
+
42
+ "#{@verb} #{@path} HTTP/#{@version}\r\n" <<
43
+ @headers.map { |k, v| "#{k}: #{v}" }.join("\r\n") << "\r\n\r\n" <<
44
+ (@body ? @body : '')
45
+ end
46
+ end
data/tasks/rspec.rake ADDED
@@ -0,0 +1,7 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new
4
+
5
+ RSpec::Core::RakeTask.new(:rcov) do |task|
6
+ task.rcov = true
7
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-30 00:00:00.000000000 Z
12
+ date: 2012-03-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: celluloid-io
16
- requirement: &70178153658100 !ruby/object:Gem::Requirement
16
+ requirement: &70219946901960 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,21 +21,32 @@ dependencies:
21
21
  version: 0.8.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70178153658100
24
+ version_requirements: *70219946901960
25
25
  - !ruby/object:Gem::Dependency
26
- name: http_parser
27
- requirement: &70178153657640 !ruby/object:Gem::Requirement
26
+ name: http
27
+ requirement: &70219946917780 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
31
31
  - !ruby/object:Gem::Version
32
- version: '0'
32
+ version: 0.2.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70219946917780
36
+ - !ruby/object:Gem::Dependency
37
+ name: http_parser.rb
38
+ requirement: &70219946917260 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 0.5.3
33
44
  type: :runtime
34
45
  prerelease: false
35
- version_requirements: *70178153657640
46
+ version_requirements: *70219946917260
36
47
  - !ruby/object:Gem::Dependency
37
48
  name: rake
38
- requirement: &70178153657160 !ruby/object:Gem::Requirement
49
+ requirement: &70219946916780 !ruby/object:Gem::Requirement
39
50
  none: false
40
51
  requirements:
41
52
  - - ! '>='
@@ -43,34 +54,54 @@ dependencies:
43
54
  version: '0'
44
55
  type: :development
45
56
  prerelease: false
46
- version_requirements: *70178153657160
57
+ version_requirements: *70219946916780
47
58
  - !ruby/object:Gem::Dependency
48
59
  name: rspec
49
- requirement: &70178153656660 !ruby/object:Gem::Requirement
60
+ requirement: &70219946916200 !ruby/object:Gem::Requirement
50
61
  none: false
51
62
  requirements:
52
- - - ~>
63
+ - - ! '>='
53
64
  - !ruby/object:Gem::Version
54
- version: 2.7.0
65
+ version: '0'
55
66
  type: :development
56
67
  prerelease: false
57
- version_requirements: *70178153656660
68
+ version_requirements: *70219946916200
58
69
  description: A Celluloid::IO-powered HTTP server
59
70
  email:
60
71
  - tony.arcieri@gmail.com
61
- executables: []
72
+ executables:
73
+ - reel
62
74
  extensions: []
63
75
  extra_rdoc_files: []
64
76
  files:
65
77
  - .gitignore
78
+ - .rspec
79
+ - .travis.yml
66
80
  - Gemfile
67
- - LICENSE
81
+ - LICENSE.txt
68
82
  - README.md
69
83
  - Rakefile
84
+ - benchmarks/hello_goliath.rb
85
+ - benchmarks/hello_node.js
86
+ - benchmarks/hello_rack.ru
87
+ - benchmarks/hello_reel.rb
88
+ - bin/reel
89
+ - examples/hello_world.rb
70
90
  - lib/reel.rb
91
+ - lib/reel/connection.rb
92
+ - lib/reel/logger.rb
93
+ - lib/reel/request.rb
94
+ - lib/reel/request/parser.rb
95
+ - lib/reel/response.rb
96
+ - lib/reel/server.rb
71
97
  - lib/reel/version.rb
98
+ - logo.png
72
99
  - reel.gemspec
73
- homepage: https://github.com/tarcieri/reel
100
+ - spec/reel/connection_spec.rb
101
+ - spec/reel/server_spec.rb
102
+ - spec/spec_helper.rb
103
+ - tasks/rspec.rake
104
+ homepage: https://github.com/celluloid/reel
74
105
  licenses: []
75
106
  post_install_message:
76
107
  rdoc_options: []
@@ -94,5 +125,8 @@ rubygems_version: 1.8.10
94
125
  signing_key:
95
126
  specification_version: 3
96
127
  summary: A reel good HTTP server
97
- test_files: []
128
+ test_files:
129
+ - spec/reel/connection_spec.rb
130
+ - spec/reel/server_spec.rb
131
+ - spec/spec_helper.rb
98
132
  has_rdoc: