This repository has been archived by the owner on Dec 7, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial support for the full HTTP request cycle
- Loading branch information
Showing
12 changed files
with
184 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--color | ||
--format documentation | ||
--backtrace | ||
--default_path spec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,6 @@ | ||
#!/usr/bin/env rake | ||
require "bundler/gem_tasks" | ||
|
||
Dir[File.expand_path("../tasks/**/*.rake", __FILE__)].each { |task| load task } | ||
|
||
task :default => :spec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,32 @@ | ||
module Reel | ||
# A connection to the HTTP server | ||
class Connection | ||
attr_reader :request | ||
|
||
# Attempt to read this much data | ||
BUFFER_SIZE = 4096 | ||
|
||
def initialize(socket) | ||
@socket = socket | ||
@parser = RequestParser.new | ||
@request = nil | ||
end | ||
|
||
def read_header | ||
while data = @socket.readpartial(4096) | ||
@parser << data | ||
def read_request | ||
return if @request | ||
|
||
until @parser.headers | ||
@parser << @socket.readpartial(BUFFER_SIZE) | ||
end | ||
|
||
@request = Request.new(@parser.http_method, @parser.url, @parser.http_version, @parser.headers) | ||
end | ||
|
||
def respond(response) | ||
response.render(@socket) | ||
ensure | ||
# FIXME: Keep-Alive support | ||
@socket.close | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
module Reel | ||
class Request | ||
attr_accessor :method, :version, :url | ||
METHODS = [:get, :post, :put, :delete, :trace, :options, :connect, :patch] | ||
|
||
def initialize(method, url, version = "1.1", headers = {}) | ||
@method = method.to_s.downcase.to_sym | ||
raise UnsupportedArgumentError, "unknown method: #{method}" unless METHODS.include? @method | ||
|
||
@url, @version, @headers = url, version, headers | ||
end | ||
|
||
def [](header) | ||
@headers[header] | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,49 @@ | ||
module Reel | ||
# Parses incoming HTTP requests | ||
class RequestParser | ||
attr_reader :headers | ||
|
||
def initialize | ||
@parser = Http::Parser.new(self) | ||
@headers = nil | ||
@read_body = false | ||
end | ||
|
||
def add(data) | ||
@parser << data | ||
end | ||
alias_method :<<, :add | ||
|
||
def on_headers_complete(headers) | ||
puts "Got headers: #{headers.inspect}" | ||
def headers? | ||
!!@headers | ||
end | ||
|
||
def http_method | ||
@parser.http_method.downcase.to_sym | ||
end | ||
|
||
def http_version | ||
@parser.http_version.join(".") | ||
end | ||
|
||
def url | ||
@parser.request_url | ||
end | ||
|
||
# | ||
# Http::Parser callbacks | ||
# | ||
|
||
def on_headers_complete(headers) | ||
@headers = headers | ||
end | ||
|
||
def on_body(chunk) | ||
puts "[BODY] #{chunk}" | ||
# FIXME: handle request bodies | ||
end | ||
|
||
def on_message_complete | ||
puts "DONE!" | ||
@read_body = true | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
module Reel | ||
class Response | ||
attr_reader :status | ||
|
||
def initialize(status, body = '') | ||
self.status = status | ||
@body = body | ||
@headers = {} | ||
|
||
# hax | ||
@version = "HTTP/1.1" | ||
end | ||
|
||
# Set the status | ||
def set_status(status, reason = nil) | ||
case status | ||
when Integer | ||
@status = status | ||
@reason = reason | ||
when Symbol | ||
# hax! | ||
if status == :ok | ||
@status = 200 | ||
@reason = reason || "OK" | ||
else | ||
raise ArgumentError, "unrecognized status symbol :/" | ||
end | ||
else | ||
raise ArgumentError, "invalid status: #{status}" | ||
end | ||
end | ||
alias_method :status=, :set_status | ||
|
||
# Write the response out to the wire | ||
def render(socket) | ||
socket << render_header | ||
socket << @body | ||
end | ||
|
||
####### | ||
private | ||
####### | ||
|
||
# Convert headers into a string | ||
# FIXME: this should probably be factored elsewhere, SRP and all | ||
def render_header | ||
header = "#{@version} #{@status} #{@reason}\r\n" | ||
header << @headers.map do |header, value| | ||
"#{header}: #{value}" | ||
end.join("\r\n") | ||
header << "\r\n" | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require 'spec_helper' | ||
require 'net/http' | ||
|
||
describe Reel::Server do | ||
let(:endpoint) { "http://#{example_addr}:#{example_port}#{example_url}" } | ||
let(:response_body) { "ohai thar" } | ||
|
||
it "receives HTTP requests and sends responses" do | ||
handler_called = false | ||
handler = proc do |connection| | ||
request = connection.request | ||
request.method.should eq :get | ||
request.version.should eq "1.1" | ||
request.url.should eq example_url | ||
|
||
connection.respond Reel::Response.new(:ok, response_body) | ||
handler_called = true | ||
end | ||
|
||
with_reel(handler) do | ||
response = Net::HTTP.get URI(endpoint) | ||
response.should eq response_body | ||
handler_called.should be_true | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
require 'bundler/setup' | ||
require 'reel' | ||
|
||
def example_addr; '127.0.0.1'; end | ||
def example_port; 1234; end | ||
def example_url; "/example"; end | ||
|
||
def with_reel(handler) | ||
server = Reel::Server.new(example_addr, example_port, &handler) | ||
yield server | ||
ensure | ||
server.terminate | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
require 'rspec/core/rake_task' | ||
|
||
RSpec::Core::RakeTask.new | ||
|
||
RSpec::Core::RakeTask.new(:rcov) do |task| | ||
task.rcov = true | ||
end |