# File src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb, line 69
      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
          env[HTTP_VERSION] = HTTP_1_1

          # Rails somehow modifies env['REQUEST_METHOD'], so we perform the comparison
          # before the Rack application object is called.
          is_head_request = env[REQUEST_METHOD] == HEAD

          begin
            status, headers, body = @app.call(env)
          rescue => e
            if !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)
              log_exception_to_union_station(env, e)
            end
            return false
          end

          # Application requested a full socket hijack.
          if env[RACK_HIJACK_IO]
            # Since the app hijacked the socket, we don't know what state we're
            # in and we don't know whether we can recover from it, so we don't
            # catch any exception here.
            #
            # The Rack specification doesn't specify whether the body should
            # be closed when the socket is hijacked. As of February 2 2015,
            # Puma and Thin close the body, while Unicorn does not.
            # However, Rack::Lock and possibly many other middlewares count
            # on the body being closed, as described here:
            # https://github.com/ngauthier/tubesock/issues/10#issuecomment-72539461
            # So we have chosen to close the body.
            body.close if body && body.respond_to?(:close)
            return true
          end

          # Application requested a partial socket hijack.
          if hijack_callback = headers[RACK_HIJACK]
            # We don't catch exceptions here. EPIPE is already handled
            # by ThreadHandler's #accept_and_process_next_request.
            # On any other exception, we don't know what state we're
            # in and we don't know whether we can recover from it.
            begin
              headers_output = generate_headers_array(status, headers)
              headers_output << CONNECTION_CLOSE_CRLF2
              connection.writev(headers_output)
              connection.flush
              hijacked_socket = env[RACK_HIJACK].call
              hijack_callback.call(hijacked_socket)
              return true
            ensure
              body.close if body && body.respond_to?(:close)
            end
          end

          begin
            process_body(env, connection, socket_wrapper, status.to_i, is_head_request,
              headers, body)
          rescue => e
            if !should_swallow_app_error?(e, socket_wrapper)
              print_exception("Rack response body object", e)
              log_exception_to_union_station(env, e)
            end
          ensure
            close_body(body, env, socket_wrapper)
          end
          false
        ensure
          rewindable_input.close
        end
      end