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 167
167: def can_persist!
168: @can_persist = true
169: end
Return true if this connection is allowed to stay open and be persistent.
# File lib/thin/connection.rb, line 172
172: def can_persist?
173: @can_persist
174: end
# File lib/thin/connection.rb, line 136
136: def close_request_response
137: @request.async_close.succeed if @request.async_close
138: @request.close rescue nil
139: @response.close rescue nil
140: end
Logs catched exception and closes the connection.
# File lib/thin/connection.rb, line 130
130: def handle_error
131: log "!! Unexpected error while processing request: #{$!.message}"
132: log_error
133: close_connection rescue nil
134: end
Return true if the connection must be left open and ready to be reused for another request.
# File lib/thin/connection.rb, line 178
178: def persistent?
179: @can_persist && @response.persistent?
180: 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 93
93: def post_process(result)
94: return unless result
95: result = result.to_a
96:
97: # Status code -1 indicates that we're going to respond later (async).
98: return if result.first == AsyncResponse.first
99:
100: # Set the Content-Length header if possible
101: set_content_length(result) if need_content_length?(result)
102:
103: @response.status, @response.headers, @response.body = *result
104:
105: log "!! Rack application returned nil body. Probably you wanted it to be an empty string?" if @response.body.nil?
106:
107: # Make the response persistent if requested by the client
108: @response.persistent! if @request.persistent?
109:
110: # Send the response
111: @response.each do |chunk|
112: trace { chunk }
113: send_data chunk
114: end
115:
116: rescue Exception
117: handle_error
118: ensure
119: # If the body is being deferred, then terminate afterward.
120: if @response.body.respond_to?(:callback) && @response.body.respond_to?(:errback)
121: @response.body.callback { terminate_request }
122: @response.body.errback { terminate_request }
123: else
124: # Don't terminate the response if we're going async.
125: terminate_request unless result && result.first == AsyncResponse.first
126: end
127: 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: if @backend.ssl?
71: @request.env["rack.url_scheme"] = "https"
72:
73: if cert = get_peer_cert
74: @request.env['rack.peer_cert'] = cert
75: end
76: end
77:
78: # When we're under a non-async framework like rails, we can still spawn
79: # off async responses using the callback info, so there's little point
80: # in removing this.
81: response = AsyncResponse
82: catch(:async) do
83: # Process the request calling the Rack adapter
84: response = @app.call(@request.env)
85: end
86: response
87: rescue Exception
88: handle_error
89: terminate_request
90: nil # Signal to post_process that the request could not be processed
91: 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 190
190: def remote_address
191: socket_address
192: rescue Exception
193: log_error
194: nil
195: 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 146
146: def terminate_request
147: unless persistent?
148: close_connection_after_writing rescue nil
149: close_request_response
150: else
151: close_request_response
152: # Prepare the connection for another request if the client
153: # supports HTTP pipelining (persistent connection).
154: post_init
155: end
156: 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 185
185: def threaded?
186: @threaded || (@app.respond_to?(:deferred?) && @app.deferred?(@request.env))
187: 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 160
160: def unbind
161: @request.async_close.succeed if @request.async_close
162: @response.body.fail if @response.body.respond_to?(:fail)
163: @backend.connection_finished(self)
164: end
# File lib/thin/connection.rb, line 205
205: def need_content_length?(result)
206: status, headers, body = result
207: return false if status == 1
208: return false if headers.has_key?(CONTENT_LENGTH)
209: return false if (100..199).include?(status) || status == 204 || status == 304
210: return false if headers.has_key?(TRANSFER_ENCODING) && headers[TRANSFER_ENCODING] =~ CHUNKED_REGEXP
211: return false unless body.kind_of?(String) || body.kind_of?(Array)
212: true
213: end
# File lib/thin/connection.rb, line 215
215: def set_content_length(result)
216: headers, body = result[1..2]
217: case body
218: when String
219: # See http://redmine.ruby-lang.org/issues/show/203
220: headers[CONTENT_LENGTH] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
221: when Array
222: bytes = 0
223: body.each do |p|
224: bytes += p.respond_to?(:bytesize) ? p.bytesize : p.size
225: end
226: headers[CONTENT_LENGTH] = bytes.to_s
227: end
228: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.