Class: Reel::Connection
- Inherits:
-
Object
- Object
- Reel::Connection
- Includes:
- ConnectionMixin, HTTPVersionsMixin
- Defined in:
- lib/reel/connection.rb
Overview
A connection to the HTTP server
Constant Summary collapse
- CONNECTION =
'Connection'.freeze
- TRANSFER_ENCODING =
'Transfer-Encoding'.freeze
- KEEP_ALIVE =
'Keep-Alive'.freeze
- CLOSE =
'close'.freeze
- BUFFER_SIZE =
Attempt to read this much data
16384
Constants included from HTTPVersionsMixin
HTTPVersionsMixin::DEFAULT_HTTP_VERSION, HTTPVersionsMixin::HTTP_VERSION_1_0, HTTPVersionsMixin::HTTP_VERSION_1_1
Instance Attribute Summary collapse
-
#buffer_size ⇒ Object
readonly
Returns the value of attribute buffer_size.
-
#current_request ⇒ Object
readonly
Returns the value of attribute current_request.
-
#parser ⇒ Object
readonly
Returns the value of attribute parser.
-
#request_state ⇒ Object
Returns the value of attribute request_state.
-
#response_state ⇒ Object
Returns the value of attribute response_state.
-
#socket ⇒ Object
readonly
Raw access to the underlying socket.
Instance Method Summary collapse
-
#alive? ⇒ Boolean
Is the connection still active?.
-
#attached? ⇒ Boolean
Is the connection still attached to a Reel::Server?.
-
#close ⇒ Object
Close the connection.
-
#detach ⇒ Object
Detach this connection from the Reel::Server and manage it independently.
-
#each_request ⇒ Object
Enumerate the requests from this connection, since we might receive many if the client is using keep-alive.
-
#hijack_socket ⇒ Object
Hijack the socket from the connection.
-
#initialize(socket, buffer_size = nil) ⇒ Connection
constructor
A new instance of Connection.
- #readpartial(size = @buffer_size) ⇒ Object
-
#request ⇒ Object
Read a request object from the connection.
-
#respond(response, headers_or_body = {}, body = nil) ⇒ Object
Send a response back to the client Response can be a symbol indicating the status code or a Reel::Response.
Methods included from ConnectionMixin
Constructor Details
#initialize(socket, buffer_size = nil) ⇒ Connection
Returns a new instance of Connection.
21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/reel/connection.rb', line 21 def initialize(socket, buffer_size = nil) @attached = true @socket = socket @keepalive = true @buffer_size = buffer_size || BUFFER_SIZE @parser = Request::Parser.new(self) @request_fsm = Request::StateMachine.new(@socket) reset_request @response_state = :headers end |
Instance Attribute Details
#buffer_size ⇒ Object (readonly)
Returns the value of attribute buffer_size.
19 20 21 |
# File 'lib/reel/connection.rb', line 19 def buffer_size @buffer_size end |
#current_request ⇒ Object (readonly)
Returns the value of attribute current_request.
14 15 16 |
# File 'lib/reel/connection.rb', line 14 def current_request @current_request end |
#parser ⇒ Object (readonly)
Returns the value of attribute parser.
14 15 16 |
# File 'lib/reel/connection.rb', line 14 def parser @parser end |
#request_state ⇒ Object
Returns the value of attribute request_state.
15 16 17 |
# File 'lib/reel/connection.rb', line 15 def request_state @request_state end |
#response_state ⇒ Object
Returns the value of attribute response_state.
15 16 17 |
# File 'lib/reel/connection.rb', line 15 def response_state @response_state end |
#socket ⇒ Object (readonly)
Raw access to the underlying socket
155 156 157 |
# File 'lib/reel/connection.rb', line 155 def socket @socket end |
Instance Method Details
#alive? ⇒ Boolean
Is the connection still active?
34 |
# File 'lib/reel/connection.rb', line 34 def alive?; @keepalive; end |
#attached? ⇒ Boolean
Is the connection still attached to a Reel::Server?
37 |
# File 'lib/reel/connection.rb', line 37 def attached?; @attached; end |
#close ⇒ Object
Close the connection
132 133 134 135 136 137 |
# File 'lib/reel/connection.rb', line 132 def close raise StateError, "socket has been hijacked from this connection" unless @socket @keepalive = false @socket.close unless @socket.closed? end |
#detach ⇒ Object
Detach this connection from the Reel::Server and manage it independently
40 41 42 43 |
# File 'lib/reel/connection.rb', line 40 def detach @attached = false self end |
#each_request ⇒ Object
Enumerate the requests from this connection, since we might receive many if the client is using keep-alive
71 72 73 74 75 76 77 78 79 80 |
# File 'lib/reel/connection.rb', line 71 def each_request while req = request yield req # Websockets upgrade the connection to the Websocket protocol # Once we have finished processing a Websocket, we can't handle # additional requests break if req.websocket? end end |
#hijack_socket ⇒ Object
Hijack the socket from the connection
140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/reel/connection.rb', line 140 def hijack_socket # FIXME: this doesn't do a great job of ensuring we can hijack the socket # in its current state. Improve the state detection. if @request_fsm != :ready && @response_state != :headers raise StateError, "connection is not in a hijackable state" end @request_fsm.transition :hijacked @response_state = :hijacked socket = @socket @socket = nil socket end |
#readpartial(size = @buffer_size) ⇒ Object
45 46 47 48 49 50 51 |
# File 'lib/reel/connection.rb', line 45 def readpartial(size = @buffer_size) unless @request_fsm.state == :headers || @request_fsm.state == :body raise StateError, "can't read in the '#{@request_fsm.state}' request state" end @parser.readpartial(size) end |
#request ⇒ Object
Read a request object from the connection
54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/reel/connection.rb', line 54 def request raise StateError, "already processing a request" if current_request req = @parser.current_request @request_fsm.transition :headers @keepalive = false if req[CONNECTION] == CLOSE || req.version == HTTP_VERSION_1_0 @current_request = req req rescue IOError, Errno::ECONNRESET, Errno::EPIPE @request_fsm.transition :closed @keepalive = false nil end |
#respond(response, headers_or_body = {}, body = nil) ⇒ Object
Send a response back to the client Response can be a symbol indicating the status code or a Reel::Response
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/reel/connection.rb', line 84 def respond(response, headers_or_body = {}, body = nil) raise StateError, "not in header state" if @response_state != :headers if headers_or_body.is_a? Hash headers = headers_or_body else headers = {} body = headers_or_body end if @keepalive headers[CONNECTION] = KEEP_ALIVE else headers[CONNECTION] = CLOSE end case response when Symbol, Fixnum, Integer response = Response.new(response, headers, body) when Response else raise TypeError, "invalid response: #{response.inspect}" end if current_request current_request.handle_response(response) else raise RequestError end # Enable streaming mode if response.chunked? and response.body.nil? @response_state = :chunked_body elsif @keepalive reset_request else @current_request = nil @parser.reset @request_fsm.transition :closed end rescue IOError, SystemCallError, RequestError # The client disconnected early, or there is no request @keepalive = false @request_fsm.transition :closed @parser.reset @current_request = nil end |