Class: Thin::ReactorConnection
- Inherits:
-
Object
- Object
- Thin::ReactorConnection
- 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.
Constant Summary collapse
- CONTENT_LENGTH =
'Content-Length'.freeze
- TRANSFER_ENCODING =
'Transfer-Encoding'.freeze
- CHUNKED_REGEXP =
/\bchunked\b/i.freeze
- BUFFER_SIZE =
whenever we accumulate this buffer size we flush to the socket when flush is called the buffer is emptied (and the conn is blocked)
256*1024
Instance Attribute Summary collapse
-
#app ⇒ Object
Rack application (adapter) served by this connection.
-
#backend ⇒ Object
Backend to the server.
-
#fibered ⇒ Object
writeonly
Calling the application in a fiber allowing concurrent processing of requests.
-
#reactor ⇒ Object
writeonly
Sets the attribute reactor.
-
#request ⇒ Object
Current request served by the connection.
-
#response ⇒ Object
Next response sent through the connection.
-
#socket ⇒ Object
writeonly
Sets the attribute socket.
-
#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_connection(after_writing = false) ⇒ Object
- #close_connection_after_writing ⇒ Object
- #close_request_response ⇒ Object
- #flush_data ⇒ Object
-
#handle_error ⇒ Object
Logs catched exception and closes the connection.
-
#initialize(socket, reactor) ⇒ ReactorConnection
constructor
A new instance of ReactorConnection.
-
#persistent? ⇒ Boolean
Return
true
if the connection must be left open and ready to be reused for another request. - #post_init ⇒ Object
- #post_process(result) ⇒ Object
-
#pre_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.
- #send_data(data) ⇒ Object
- #terminate_request ⇒ Object
- #threaded? ⇒ Boolean
Methods included from Logging
#debug, debug, debug?, #log, log, #log_error, log_error, #silent, #silent=, silent?, #trace, trace, trace?
Constructor Details
#initialize(socket, reactor) ⇒ ReactorConnection
Returns a new instance of ReactorConnection.
41 42 43 44 45 46 47 48 49 |
# File 'lib/thin/connection.rb', line 41 def initialize(socket, reactor) @socket = socket @reactor = reactor @data = "" @sends = 0 @t = Time.now @request = Request.new @response = Response.new end |
Instance Attribute Details
#app ⇒ Object
Rack application (adapter) served by this connection.
20 21 22 |
# File 'lib/thin/connection.rb', line 20 def app @app end |
#backend ⇒ Object
Backend to the server
23 24 25 |
# File 'lib/thin/connection.rb', line 23 def backend @backend end |
#fibered=(value) ⇒ Object (writeonly)
Calling the application in a fiber allowing concurrent processing of requests.
37 38 39 |
# File 'lib/thin/connection.rb', line 37 def fibered=(value) @fibered = value end |
#reactor=(value) ⇒ Object (writeonly)
Sets the attribute reactor
38 39 40 |
# File 'lib/thin/connection.rb', line 38 def reactor=(value) @reactor = value end |
#request ⇒ Object
Current request served by the connection
26 27 28 |
# File 'lib/thin/connection.rb', line 26 def request @request end |
#response ⇒ Object
Next response sent through the connection
29 30 31 |
# File 'lib/thin/connection.rb', line 29 def response @response end |
#socket=(value) ⇒ Object (writeonly)
Sets the attribute socket
39 40 41 |
# File 'lib/thin/connection.rb', line 39 def socket=(value) @socket = value end |
#threaded=(value) ⇒ Object (writeonly)
Calling the application in a threaded allowing concurrent processing of requests.
33 34 35 |
# File 'lib/thin/connection.rb', line 33 def threaded=(value) @threaded = value end |
Instance Method Details
#can_persist! ⇒ Object
Allows this connection to be persistent.
155 156 |
# File 'lib/thin/connection.rb', line 155 def can_persist! end |
#can_persist? ⇒ Boolean
Return true
if this connection is allowed to stay open and be persistent.
159 160 161 |
# File 'lib/thin/connection.rb', line 159 def can_persist? false end |
#close_connection(after_writing = false) ⇒ Object
64 65 66 67 68 69 70 71 72 |
# File 'lib/thin/connection.rb', line 64 def close_connection(after_writing=false) unless after_writing @reactor.detach(:read, @socket) end if after_writing @reactor.detach(:read, @socket) unless @reactor.attached?(:read, @socket) @socket.close unless @socket.closed? end end |
#close_connection_after_writing ⇒ Object
74 75 76 |
# File 'lib/thin/connection.rb', line 74 def close_connection_after_writing close_connection(true) end |
#close_request_response ⇒ Object
144 145 146 147 |
# File 'lib/thin/connection.rb', line 144 def close_request_response @request.close rescue nil @response.close rescue nil end |
#flush_data ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/thin/connection.rb', line 83 def flush_data return if @data.blank? begin @socket.syswrite(@data) rescue Exception => e puts e close_connection return end @data = '' end |
#handle_error ⇒ Object
Logs catched exception and closes the connection.
138 139 140 141 142 |
# File 'lib/thin/connection.rb', line 138 def handle_error log "!! Unexpected error while processing request: #{$!.}" log_error close_connection rescue nil end |
#persistent? ⇒ Boolean
Return true
if the connection must be left open and ready to be reused for another request.
165 166 167 |
# File 'lib/thin/connection.rb', line 165 def persistent? false end |
#post_init ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/thin/connection.rb', line 51 def post_init @request = Request.new @response = Response.new @reactor.attach(:read, @socket) do |socket, reactor| begin receive_data(@socket.read_nonblock(8*1024)) rescue Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EINTR rescue Exception => e close_connection end end end |
#post_process(result) ⇒ Object
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/thin/connection.rb', line 116 def post_process(result) begin return unless result result = result.to_a # Set the Content-Length header if possible set_content_length(result) if need_content_length?(result) @response.status, @response.headers, @response.body = *result log "!! Rack application returned nil body. Probably you wanted it to be an empty string?" if @response.body.nil? # Send the response @response.each do |chunk| trace { chunk } send_data chunk end flush_data rescue Exception handle_error ensure terminate_request end end |
#pre_process ⇒ Object
Called when all data was received and the request is ready to be processed.
108 109 110 111 112 113 114 |
# File 'lib/thin/connection.rb', line 108 def pre_process @app.call(@request.env) rescue Exception handle_error terminate_request nil # Signal to post_process that the request could not be processed end |
#receive_data(data) ⇒ Object
Called when data is received from the client.
96 97 98 99 100 101 102 103 |
# File 'lib/thin/connection.rb', line 96 def receive_data(data) trace { data } post_process(pre_process) if @request.parse(data) rescue InvalidRequest => e log "!! Invalid request" log_error e close_connection end |
#remote_address ⇒ Object
IP Address of the remote client.
174 175 176 177 178 179 |
# File 'lib/thin/connection.rb', line 174 def remote_address @request.forwarded_for || socket_address rescue Exception log_error nil end |
#send_data(data) ⇒ Object
78 79 80 81 |
# File 'lib/thin/connection.rb', line 78 def send_data(data) @data << data flush_data if @data.length >= BUFFER_SIZE end |
#terminate_request ⇒ Object
149 150 151 152 |
# File 'lib/thin/connection.rb', line 149 def terminate_request close_connection_after_writing rescue nil close_request_response end |
#threaded? ⇒ Boolean
169 170 171 |
# File 'lib/thin/connection.rb', line 169 def threaded? false end |