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

Commit

Permalink
Remove response writing thunks into Reel::Request
Browse files Browse the repository at this point in the history
The Request object should keep track of its associated response, not the
connection. This should make pipelining cleaner.

We should still factor the connection state machine into its own class.
  • Loading branch information
tarcieri committed Oct 1, 2013
1 parent bf8aed8 commit 03241b0
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 30 deletions.
24 changes: 3 additions & 21 deletions lib/reel/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ class Connection
KEEP_ALIVE = 'Keep-Alive'.freeze
CLOSE = 'close'.freeze

attr_reader :socket, :parser
attr_reader :socket, :parser, :current_request
attr_accessor :request_state, :response_state

# Attempt to read this much data
BUFFER_SIZE = 16384
Expand All @@ -21,7 +22,6 @@ def initialize(socket, buffer_size = nil)
@keepalive = true
@buffer_size = buffer_size || BUFFER_SIZE
@parser = Request::Parser.new(self)
@writer = Response::Writer.new(socket)

reset_request
@response_state = :header
Expand All @@ -44,10 +44,6 @@ def readpartial(size = @buffer_size)
@parser.readpartial(size)
end

def current_request
@current_request
end

# Read a request object from the connection
def request
raise StateError, "already processing a request" if current_request
Expand Down Expand Up @@ -103,7 +99,7 @@ def respond(response, headers_or_body = {}, body = nil)
else raise TypeError, "invalid response: #{response.inspect}"
end

@writer.handle_response(response)
current_request.handle_response(response)

# Enable streaming mode
if response.chunked? and response.body.nil?
Expand All @@ -121,20 +117,6 @@ def respond(response, headers_or_body = {}, body = nil)
end
end

# Write body chunks directly to the connection
def write(chunk)
raise StateError, "not in chunked body mode" unless @response_state == :chunked_body
@writer.write(chunk)
end
alias_method :<<, :write

# Finish the response and reset the response state to header
def finish_response
raise StateError, "not in body state" if @response_state != :chunked_body
@writer.finish_response
@response_state = :header
end

# Close the connection
def close
raise StateError, "socket has been hijacked from this connection" unless @socket
Expand Down
35 changes: 27 additions & 8 deletions lib/reel/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@ class Request
extend Forwardable
include RequestMixin

def_delegators :@connection, :<<, :write, :remote_addr, :respond, :finish_response
def_delegators :@connection, :remote_addr, :respond
def_delegator :@response_writer, :handle_response
attr_reader :body

# request_info is a RequestInfo object including the headers and
# the url, method and http version.
#
# Access it through the RequestMixin methods.
def initialize(request_info, connection = nil)
@request_info = request_info
@connection = connection
@finished = false
@buffer = ""
@body = RequestBody.new(self)
@finished_read = false
@websocket = nil
@request_info = request_info
@connection = connection
@finished = false
@buffer = ""
@body = RequestBody.new(self)
@finished_read = false
@websocket = nil
@response_writer = Response::Writer.new(connection.socket)
end

# Returns true if request fully finished reading
Expand Down Expand Up @@ -79,6 +81,23 @@ def readpartial(length = nil)
slice && slice.length == 0 ? nil : slice
end

# Write body chunks directly to the connection
def write(chunk)
unless @connection.response_state == :chunked_body
raise StateError, "not in chunked body mode"
end

@response_writer.write(chunk)
end
alias_method :<<, :write

# Finish the response and reset the response state to header
def finish_response
raise StateError, "not in body state" if @connection.response_state != :chunked_body
@response_writer.finish_response
@connection.response_state = :header
end

# Can the current request be upgraded to a WebSocket?
def websocket?; @request_info.websocket_request?; end

Expand Down
9 changes: 8 additions & 1 deletion spec/reel/response_writer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@
writer.handle_response(response)
end

peer.readpartial(4096).should eq expected_response
buf = ""
begin
buf << peer.readpartial(4096)
rescue IOError
# End of body!
end

expect(buf).to eq expected_response
end
end
end

0 comments on commit 03241b0

Please sign in to comment.