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 65
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)
        PhusionPassenger.log_request_exception(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)
        PhusionPassenger.log_request_exception(env, e)
      end
    ensure
      begin
        body.close if body && body.respond_to?(:close)
      rescue => e
        if !should_swallow_app_error?(e, socket_wrapper)
          print_exception("Rack response body object's #close method", e)
          PhusionPassenger.log_request_exception(env, e)
        end
      end
    end
    false
  ensure
    rewindable_input.close
  end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.