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.