EventMachine::Connection
Connection between the server and client. This class is instanciated by EventMachine on each new connection that is opened.
This is a template async response. N.B. Can’t use string for body on 1.9
Allows this connection to be persistent.
# File lib/thin/connection.rb, line 159 159: def can_persist! 160: @can_persist = true 161: end
Return true if this connection is allowed to stay open and be persistent.
# File lib/thin/connection.rb, line 164 164: def can_persist? 165: @can_persist 166: end
# File lib/thin/connection.rb, line 128 128: def close_request_response 129: @request.async_close.succeed if @request.async_close 130: @request.close rescue nil 131: @response.close rescue nil 132: end
Logs catched exception and closes the connection.
# File lib/thin/connection.rb, line 122 122: def handle_error 123: log "!! Unexpected error while processing request: #{$!.message}" 124: log_error 125: close_connection rescue nil 126: end
Return true if the connection must be left open and ready to be reused for another request.
# File lib/thin/connection.rb, line 170 170: def persistent? 171: @can_persist && @response.persistent? 172: end
Get the connection ready to process a request.
# File lib/thin/connection.rb, line 34 34: def post_init 35: @request = Request.new 36: @response = Response.new 37: end
# File lib/thin/connection.rb, line 85 85: def post_process(result) 86: return unless result 87: result = result.to_a 88: 89: # Status code -1 indicates that we're going to respond later (async). 90: return if result.first == AsyncResponse.first 91: 92: # Set the Content-Length header if possible 93: set_content_length(result) if need_content_length?(result) 94: 95: @response.status, @response.headers, @response.body = *result 96: 97: log "!! Rack application returned nil body. Probably you wanted it to be an empty string?" if @response.body.nil? 98: 99: # Make the response persistent if requested by the client 100: @response.persistent! if @request.persistent? 101: 102: # Send the response 103: @response.each do |chunk| 104: trace { chunk } 105: send_data chunk 106: end 107: 108: rescue Exception 109: handle_error 110: ensure 111: # If the body is being deferred, then terminate afterward. 112: if @response.body.respond_to?(:callback) && @response.body.respond_to?(:errback) 113: @response.body.callback { terminate_request } 114: @response.body.errback { terminate_request } 115: else 116: # Don't terminate the response if we're going async. 117: terminate_request unless result && result.first == AsyncResponse.first 118: end 119: end
# File lib/thin/connection.rb, line 61 61: def pre_process 62: # Add client info to the request env 63: @request.remote_address = remote_address 64: 65: # Connection may be closed unless the App#call response was a [-1, ...] 66: # It should be noted that connection objects will linger until this 67: # callback is no longer referenced, so be tidy! 68: @request.async_callback = method(:post_process) 69: 70: # When we're under a non-async framework like rails, we can still spawn 71: # off async responses using the callback info, so there's little point 72: # in removing this. 73: response = AsyncResponse 74: catch(:async) do 75: # Process the request calling the Rack adapter 76: response = @app.call(@request.env) 77: end 78: response 79: rescue Exception 80: handle_error 81: terminate_request 82: nil # Signal to post_process that the request could not be processed 83: end
Called when all data was received and the request is ready to be processed.
# File lib/thin/connection.rb, line 51 51: def process 52: if threaded? 53: @request.threaded = true 54: EventMachine.defer(method(:pre_process), method(:post_process)) 55: else 56: @request.threaded = false 57: post_process(pre_process) 58: end 59: end
Called when data is received from the client.
# File lib/thin/connection.rb, line 40 40: def receive_data(data) 41: trace { data } 42: process if @request.parse(data) 43: rescue InvalidRequest => e 44: log "!! Invalid request" 45: log_error e 46: close_connection 47: end
IP Address of the remote client.
# File lib/thin/connection.rb, line 182 182: def remote_address 183: socket_address 184: rescue Exception 185: log_error 186: nil 187: end
Does request and response cleanup (closes open IO streams and deletes created temporary files). Re-initializes response and request if client supports persistent connection.
# File lib/thin/connection.rb, line 138 138: def terminate_request 139: unless persistent? 140: close_connection_after_writing rescue nil 141: close_request_response 142: else 143: close_request_response 144: # Prepare the connection for another request if the client 145: # supports HTTP pipelining (persistent connection). 146: post_init 147: end 148: end
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?.
# File lib/thin/connection.rb, line 177 177: def threaded? 178: @threaded || (@app.respond_to?(:deferred?) && @app.deferred?(@request.env)) 179: end
Called when the connection is unbinded from the socket and can no longer be used to process requests.
# File lib/thin/connection.rb, line 152 152: def unbind 153: @request.async_close.succeed if @request.async_close 154: @response.body.fail if @response.body.respond_to?(:fail) 155: @backend.connection_finished(self) 156: end
# File lib/thin/connection.rb, line 197 197: def need_content_length?(result) 198: status, headers, body = result 199: return false if status == 1 200: return false if headers.has_key?(CONTENT_LENGTH) 201: return false if (100..199).include?(status) || status == 204 || status == 304 202: return false if headers.has_key?(TRANSFER_ENCODING) && headers[TRANSFER_ENCODING] =~ CHUNKED_REGEXP 203: return false unless body.kind_of?(String) || body.kind_of?(Array) 204: true 205: end
# File lib/thin/connection.rb, line 207 207: def set_content_length(result) 208: headers, body = result[1..2] 209: case body 210: when String 211: # See http://redmine.ruby-lang.org/issues/show/203 212: headers[CONTENT_LENGTH] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s 213: when Array 214: bytes = 0 215: body.each do |p| 216: bytes += p.respond_to?(:bytesize) ? p.bytesize : p.size 217: end 218: headers[CONTENT_LENGTH] = bytes.to_s 219: end 220: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.