# File lib/phusion_passenger/rack/thread_handler_extension.rb, line 54
        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] ||= connection
                        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)
                                        PhusionPassenger.log_request_exception(env, 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