Class: Reel::Connection
- Inherits:
-
Object
- Object
- Reel::Connection
- Includes:
- ConnectionMixin, HTTPVersionsMixin
- Defined in:
- lib/reel/connection.rb
Overview
A connection to the HTTP server
Defined Under Namespace
Classes: StateError
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.
-
#parser ⇒ Object
readonly
Returns the value of attribute parser.
-
#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.
- #current_request ⇒ Object
-
#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.
-
#finish_response ⇒ Object
Finish the response and reset the response state to header.
-
#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.
-
#write(chunk) ⇒ Object
(also: #<<)
Write body chunks directly to the connection.
Methods included from ConnectionMixin
Constructor Details
#initialize(socket, buffer_size = nil) ⇒ Connection
Returns a new instance of Connection.
20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/reel/connection.rb', line 20 def initialize(socket, buffer_size = nil) @attached = true @socket = socket @keepalive = true @buffer_size = buffer_size || BUFFER_SIZE @parser = Request::Parser.new(self) @writer = Response::Writer.new(socket) reset_request @response_state = :header end |
Instance Attribute Details
#buffer_size ⇒ Object (readonly)
Returns the value of attribute buffer_size.
18 19 20 |
# File 'lib/reel/connection.rb', line 18 def buffer_size @buffer_size end |
#parser ⇒ Object (readonly)
Returns the value of attribute parser.
14 15 16 |
# File 'lib/reel/connection.rb', line 14 def parser @parser end |
#socket ⇒ Object (readonly)
Raw access to the underlying socket
163 164 165 |
# File 'lib/reel/connection.rb', line 163 def socket @socket end |
Instance Method Details
#alive? ⇒ Boolean
Is the connection still active?
33 |
# File 'lib/reel/connection.rb', line 33 def alive?; @keepalive; end |
#attached? ⇒ Boolean
Is the connection still attached to a Reel::Server?
36 |
# File 'lib/reel/connection.rb', line 36 def attached?; @attached; end |
#close ⇒ Object
Close the connection
141 142 143 144 145 146 |
# File 'lib/reel/connection.rb', line 141 def close raise StateError, "socket has been hijacked from this connection" unless @socket @keepalive = false @socket.close unless @socket.closed? end |
#current_request ⇒ Object
49 50 51 |
# File 'lib/reel/connection.rb', line 49 def current_request @current_request end |
#detach ⇒ Object
Detach this connection from the Reel::Server and manage it independently
39 40 41 42 |
# File 'lib/reel/connection.rb', line 39 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
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/reel/connection.rb', line 72 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 |
#finish_response ⇒ Object
Finish the response and reset the response state to header
134 135 136 137 138 |
# File 'lib/reel/connection.rb', line 134 def finish_response raise StateError, "not in body state" if @response_state != :chunked_body @writer.finish_response @response_state = :header end |
#hijack_socket ⇒ Object
Hijack the socket from the connection
149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/reel/connection.rb', line 149 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_state != :ready && @response_state != :header raise StateError, "connection is not in a hijackable state" end @request_state = @response_state = :hijacked socket = @socket @socket = nil socket end |
#readpartial(size = @buffer_size) ⇒ Object
44 45 46 47 |
# File 'lib/reel/connection.rb', line 44 def readpartial(size = @buffer_size) raise StateError, "can't read in the '#{@request_state}' request state" unless @request_state == :ready @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 68 |
# File 'lib/reel/connection.rb', line 54 def request raise StateError, "already processing a request" if current_request req = @parser.current_request @request_state = :ready @keepalive = false if req[CONNECTION] == CLOSE || req.version == HTTP_VERSION_1_0 @current_request = req req rescue IOError, Errno::ECONNRESET, Errno::EPIPE # The client is disconnected @request_state = :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
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 |
# File 'lib/reel/connection.rb', line 85 def respond(response, headers_or_body = {}, body = nil) raise StateError, "not in header state" if @response_state != :header 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 response = Response.new(response, headers, body) when Response else raise TypeError, "invalid response: #{response.inspect}" end @writer.handle_response(response) # Enable streaming mode if response.chunked? and response.body.nil? @response_state = :chunked_body end rescue IOError, Errno::ECONNRESET, Errno::EPIPE # The client disconnected early @keepalive = false ensure if @keepalive reset_request(:ready) else @socket.close unless @socket.closed? reset_request(:closed) end end |
#write(chunk) ⇒ Object Also known as: <<
Write body chunks directly to the connection
127 128 129 130 |
# File 'lib/reel/connection.rb', line 127 def write(chunk) raise StateError, "not in chunked body mode" unless @response_state == :chunked_body @writer.write(chunk) end |