Class: Thin::Connection
- Inherits:
-
EventMachine::Connection
- Object
- EventMachine::Connection
- Thin::Connection
- Includes:
- Logging
- Defined in:
- lib/thin/connection.rb
Overview
Connection between the server and client. This class is instanciated by EventMachine on each new connection that is opened.
Direct Known Subclasses
Constant Summary collapse
- AsyncResponse =
This is a template async response. N.B. Can’t use string for body on 1.9
[-1, {}, []].freeze
Instance Attribute Summary collapse
-
#app ⇒ Object
Rack application (adapter) served by this connection.
-
#backend ⇒ Object
Backend to the server.
-
#request ⇒ Object
Current request served by the connection.
-
#response ⇒ Object
Next response sent through the connection.
-
#threaded ⇒ Object
writeonly
Calling the application in a threaded allowing concurrent processing of requests.
Instance Method Summary collapse
-
#can_persist! ⇒ Object
Allows this connection to be persistent.
-
#can_persist? ⇒ Boolean
Return
true
if this connection is allowed to stay open and be persistent. - #close_request_response ⇒ Object
-
#idle? ⇒ Boolean
Return
true
if the connection is open but is not processing any user requests. -
#persistent? ⇒ Boolean
Return
true
if the connection must be left open and ready to be reused for another request. -
#post_init ⇒ Object
Get the connection ready to process a request.
- #post_process(result) ⇒ Object
- #pre_process ⇒ Object
-
#process ⇒ Object
Called when all data was received and the request is ready to be processed.
-
#receive_data(data) ⇒ Object
Called when data is received from the client.
-
#remote_address ⇒ Object
IP Address of the remote client.
- #ssl_verify_peer(cert) ⇒ Object
-
#terminate_request ⇒ Object
Does request and response cleanup (closes open IO streams and deletes created temporary files).
-
#threaded? ⇒ Boolean
true
ifapp.call
will be called inside a thread. -
#unbind ⇒ Object
Called when the connection is unbinded from the socket and can no longer be used to process requests.
-
#unexpected_error(e) ⇒ Object
Logs information about an unexpected exceptional condition.
Methods included from Logging
debug=, debug?, level, level=, #log, log_debug, #log_debug, log_error, #log_error, #log_info, log_info, log_msg, #silent, #silent=, silent=, silent?, #trace, trace, trace=, trace?, trace_msg
Instance Attribute Details
#app ⇒ Object
Rack application (adapter) served by this connection.
14 15 16 |
# File 'lib/thin/connection.rb', line 14 def app @app end |
#backend ⇒ Object
Backend to the server
17 18 19 |
# File 'lib/thin/connection.rb', line 17 def backend @backend end |
#request ⇒ Object
Current request served by the connection
20 21 22 |
# File 'lib/thin/connection.rb', line 20 def request @request end |
#response ⇒ Object
Next response sent through the connection
23 24 25 |
# File 'lib/thin/connection.rb', line 23 def response @response end |
#threaded=(value) ⇒ Object (writeonly)
Calling the application in a threaded allowing concurrent processing of requests.
27 28 29 |
# File 'lib/thin/connection.rb', line 27 def threaded=(value) @threaded = value end |
Instance Method Details
#can_persist! ⇒ Object
Allows this connection to be persistent.
172 173 174 |
# File 'lib/thin/connection.rb', line 172 def can_persist! @can_persist = true end |
#can_persist? ⇒ Boolean
Return true
if this connection is allowed to stay open and be persistent.
177 178 179 |
# File 'lib/thin/connection.rb', line 177 def can_persist? @can_persist end |
#close_request_response ⇒ Object
139 140 141 142 143 |
# File 'lib/thin/connection.rb', line 139 def close_request_response @request.async_close.succeed if @request.async_close @request.close rescue nil @response.close rescue nil end |
#idle? ⇒ Boolean
Return true
if the connection is open but is not processing any user requests
189 190 191 |
# File 'lib/thin/connection.rb', line 189 def idle? @idle end |
#persistent? ⇒ Boolean
Return true
if the connection must be left open and ready to be reused for another request.
183 184 185 |
# File 'lib/thin/connection.rb', line 183 def persistent? @can_persist && @response.persistent? end |
#post_init ⇒ Object
Get the connection ready to process a request.
30 31 32 33 |
# File 'lib/thin/connection.rb', line 30 def post_init @request = Request.new @response = Response.new end |
#post_process(result) ⇒ Object
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 130 131 132 |
# File 'lib/thin/connection.rb', line 95 def post_process(result) return unless result result = result.to_a # Status code -1 indicates that we're going to respond later (async). return if result.first == AsyncResponse.first @response.status, @response.headers, @response.body = *result log_error("Rack application returned nil body. " \ "Probably you wanted it to be an empty string?") if @response.body.nil? # HEAD requests should not return a body. @response.skip_body! if @request.head? # Make the response persistent if requested by the client @response.persistent! if @request.persistent? # Send the response @response.each do |chunk| trace chunk send_data chunk end rescue Exception => e unexpected_error(e) # Close connection since we can't handle response gracefully close_connection ensure # If the body is being deferred, then terminate afterward. if @response.body.respond_to?(:callback) && @response.body.respond_to?(:errback) @response.body.callback { terminate_request } @response.body.errback { terminate_request } else # Don't terminate the response if we're going async. terminate_request unless result && result.first == AsyncResponse.first end end |
#pre_process ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/thin/connection.rb', line 63 def pre_process # Add client info to the request env @request.remote_address = remote_address # Connection may be closed unless the App#call response was a [-1, ...] # It should be noted that connection objects will linger until this # callback is no longer referenced, so be tidy! @request.async_callback = method(:post_process) if @backend.ssl? @request.env["rack.url_scheme"] = "https" if cert = get_peer_cert @request.env['rack.peer_cert'] = cert end end # When we're under a non-async framework like rails, we can still spawn # off async responses using the callback info, so there's little point # in removing this. response = AsyncResponse catch(:async) do # Process the request calling the Rack adapter response = @app.call(@request.env) end response rescue Exception => e unexpected_error(e) # Pass through error response can_persist? && @request.persistent? ? Response::PERSISTENT_ERROR : Response::ERROR end |
#process ⇒ Object
Called when all data was received and the request is ready to be processed.
47 48 49 50 51 52 53 54 55 |
# File 'lib/thin/connection.rb', line 47 def process if threaded? @request.threaded = true EventMachine.defer { post_process(pre_process) } else @request.threaded = false post_process(pre_process) end end |
#receive_data(data) ⇒ Object
Called when data is received from the client.
36 37 38 39 40 41 42 43 |
# File 'lib/thin/connection.rb', line 36 def receive_data(data) @idle = false trace data process if @request.parse(data) rescue InvalidRequest => e log_error("Invalid request", e) post_process Response::BAD_REQUEST end |
#remote_address ⇒ Object
IP Address of the remote client.
201 202 203 204 205 206 |
# File 'lib/thin/connection.rb', line 201 def remote_address socket_address rescue Exception => e log_error('Could not infer remote address', e) nil end |
#ssl_verify_peer(cert) ⇒ Object
57 58 59 60 61 |
# File 'lib/thin/connection.rb', line 57 def ssl_verify_peer(cert) # In order to make the cert available later we have to have made at least # a show of verifying it. true end |
#terminate_request ⇒ Object
Does request and response cleanup (closes open IO streams and deletes created temporary files). Re-initializes response and request if client supports persistent connection.
149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/thin/connection.rb', line 149 def terminate_request unless persistent? close_connection_after_writing rescue nil close_request_response else close_request_response # Connection become idle but it's still open @idle = true # Prepare the connection for another request if the client # supports HTTP pipelining (persistent connection). post_init end end |
#threaded? ⇒ Boolean
true
if app.call
will be called inside a thread. You can set all requests as threaded setting Connection#threaded=true
or on a per-request case returning true
in app.deferred?
.
196 197 198 |
# File 'lib/thin/connection.rb', line 196 def threaded? @threaded || (@app.respond_to?(:deferred?) && @app.deferred?(@request.env)) end |
#unbind ⇒ Object
Called when the connection is unbinded from the socket and can no longer be used to process requests.
165 166 167 168 169 |
# File 'lib/thin/connection.rb', line 165 def unbind @request.async_close.succeed if @request.async_close @response.body.fail if @response.body.respond_to?(:fail) @backend.connection_finished(self) end |
#unexpected_error(e) ⇒ Object
Logs information about an unexpected exceptional condition
135 136 137 |
# File 'lib/thin/connection.rb', line 135 def unexpected_error(e) log_error("Unexpected error while processing request", e) end |