Class/Module Index [+]

Quicksearch

PhusionPassenger::Rack::ThreadHandlerExtension

Public Instance Methods

process_request(env, connection, socket_wrapper, full_http_response) click to toggle source
# File lib/phusion_passenger/rack/thread_handler_extension.rb, line 53
def process_request(env, connection, socket_wrapper, full_http_response)
        rewindable_input = PhusionPassenger::Utils::TeeInput.new(connection, env)
        begin
                env[RACK_VERSION]      = RACK_VERSION_VALUE
                env[RACK_INPUT]        = rewindable_input
                env[RACK_ERRORS]       = STDERR
                env[RACK_MULTITHREAD]  = @request_handler.concurrency > 1
                env[RACK_MULTIPROCESS] = true
                env[RACK_RUN_ONCE]     = false
                if env[HTTPS] == YES || env[HTTPS] == ON || env[HTTPS] == ONE
                        env[RACK_URL_SCHEME] = HTTPS_DOWNCASE
                else
                        env[RACK_URL_SCHEME] = HTTP
                end
                env[RACK_HIJACK_P] = true
                env[RACK_HIJACK] = lambda do
                        env[RACK_HIJACK_IO] ||= begin
                                connection.stop_simulating_eof!
                                connection
                        end
                end
                
                begin
                        status, headers, body = @app.call(env)
                rescue => e
                        if should_reraise_app_error?(e, socket_wrapper)
                                raise e
                        elsif !should_swallow_app_error?(e, socket_wrapper)
                                # It's a good idea to catch application exceptions here because
                                # otherwise maliciously crafted responses can crash the app,
                                # forcing it to be respawned, and thereby effectively DoSing it.
                                print_exception("Rack application object", e)
                        end
                        return false
                end

                # Application requested a full socket hijack.
                return true if env[RACK_HIJACK_IO]

                begin
                        if full_http_response
                                connection.write("HTTP/1.1 #{status.to_i.to_s} Whatever#{CRLF}")
                                connection.write("Connection: close#{CRLF}")
                        end
                        headers_output = [
                                STATUS, status.to_i.to_s, CRLF
                        ]
                        headers.each do |key, values|
                                if values.is_a?(String)
                                        values = values.split(NEWLINE)
                                elsif key == RACK_HIJACK
                                        # We do not check for this key name in every loop
                                        # iteration as an optimization.
                                        next
                                end
                                values.each do |value|
                                        headers_output << key
                                        headers_output << NAME_VALUE_SEPARATOR
                                        headers_output << value
                                        headers_output << CRLF
                                end
                        end
                        headers_output << CRLF

                        if hijack_callback = headers[RACK_HIJACK]
                                # Application requested a partial socket hijack.
                                body = nil
                                connection.writev(headers_output)
                                connection.flush
                                hijacked_socket = env[RACK_HIJACK].call
                                hijack_callback.call(hijacked_socket)
                                return true
                        elsif body.is_a?(Array)
                                # The body may be an ActionController::StringCoercion::UglyBody
                                # object instead of a real Array, even when #is_a? claims so.
                                # Call #to_a just to be sure.
                                connection.writev2(headers_output, body.to_a)
                                return false
                        elsif body.is_a?(String)
                                headers_output << body
                                connection.writev(headers_output)
                                return false
                        else
                                connection.writev(headers_output)
                                if body
                                        begin
                                                body.each do |s|
                                                        connection.write(s)
                                                end
                                        rescue => e
                                                if should_reraise_app_error?(e, socket_wrapper)
                                                        raise e
                                                elsif !should_swallow_app_error?(e, socket_wrapper)
                                                        # Body objects can raise exceptions in #each.
                                                        print_exception("Rack body object #each method", e)
                                                end
                                                return false
                                        end
                                end
                                return false
                        end
                ensure
                        body.close if body && body.respond_to?(:close)
                end
        ensure
                rewindable_input.close
        end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.