lib/falcon/adapters/rack.rb in falcon-0.36.4 vs lib/falcon/adapters/rack.rb in falcon-0.36.5

- old
+ new

@@ -29,53 +29,66 @@ require 'async/logger' module Falcon module Adapters class Rack - # CGI keys (https://tools.ietf.org/html/rfc3875#section-4.1) - HTTP_HOST = 'HTTP_HOST'.freeze - PATH_INFO = 'PATH_INFO'.freeze - REQUEST_METHOD = 'REQUEST_METHOD'.freeze - REQUEST_PATH = 'REQUEST_PATH'.freeze - REQUEST_URI = 'REQUEST_URI'.freeze - SCRIPT_NAME = 'SCRIPT_NAME'.freeze - QUERY_STRING = 'QUERY_STRING'.freeze - SERVER_PROTOCOL = 'SERVER_PROTOCOL'.freeze - SERVER_NAME = 'SERVER_NAME'.freeze - SERVER_PORT = 'SERVER_PORT'.freeze - REMOTE_ADDR = 'REMOTE_ADDR'.freeze - CONTENT_TYPE = 'CONTENT_TYPE'.freeze - CONTENT_LENGTH = 'CONTENT_LENGTH'.freeze + # CGI keys <https://tools.ietf.org/html/rfc3875#section-4.1>: - # Rack environment variables - RACK_VERSION = 'rack.version'.freeze - RACK_ERRORS = 'rack.errors'.freeze - RACK_LOGGER = 'rack.logger'.freeze - RACK_INPUT = 'rack.input'.freeze - RACK_MULTITHREAD = 'rack.multithread'.freeze - RACK_MULTIPROCESS = 'rack.multiprocess'.freeze - RACK_RUNONCE = 'rack.run_once'.freeze - RACK_URL_SCHEME = 'rack.url_scheme'.freeze - RACK_HIJACK = 'rack.hijack'.freeze - RACK_IS_HIJACK = 'rack.hijack?'.freeze - RACK_HIJACK_IO = 'rack.hijack_io'.freeze - RACK_EARLY_HINTS = "rack.early_hints".freeze + HTTP_HOST = 'HTTP_HOST' + PATH_INFO = 'PATH_INFO' + REQUEST_METHOD = 'REQUEST_METHOD' + REQUEST_PATH = 'REQUEST_PATH' + REQUEST_URI = 'REQUEST_URI' + SCRIPT_NAME = 'SCRIPT_NAME' + QUERY_STRING = 'QUERY_STRING' + SERVER_PROTOCOL = 'SERVER_PROTOCOL' + SERVER_NAME = 'SERVER_NAME' + SERVER_PORT = 'SERVER_PORT' + REMOTE_ADDR = 'REMOTE_ADDR' + CONTENT_TYPE = 'CONTENT_TYPE' + CONTENT_LENGTH = 'CONTENT_LENGTH' - ASYNC_HTTP_REQUEST = "async.http.request".freeze + # Rack environment variables: - # Header constants - HTTP_X_FORWARDED_PROTO = 'HTTP_X_FORWARDED_PROTO'.freeze + RACK_VERSION = 'rack.version' + RACK_ERRORS = 'rack.errors' + RACK_LOGGER = 'rack.logger' + RACK_INPUT = 'rack.input' + RACK_MULTITHREAD = 'rack.multithread' + RACK_MULTIPROCESS = 'rack.multiprocess' + RACK_RUNONCE = 'rack.run_once' + RACK_URL_SCHEME = 'rack.url_scheme' + RACK_HIJACK = 'rack.hijack' + RACK_IS_HIJACK = 'rack.hijack?' + RACK_HIJACK_IO = 'rack.hijack_io' + RACK_EARLY_HINTS = "rack.early_hints" + # Async::HTTP specific metadata: + + ASYNC_HTTP_REQUEST = "async.http.request" + + # Header constants: + + HTTP_X_FORWARDED_PROTO = 'HTTP_X_FORWARDED_PROTO' + + # Initialize the rack adaptor middleware. + # @parameter app [Object] The rack middleware. + # @parameter logger [Console::Logger] The logger to use. def initialize(app, logger = Async.logger) @app = app raise ArgumentError, "App must be callable!" unless @app.respond_to?(:call) @logger = logger end - # Rack separates multiple headers with the same key, into a single field with multiple "lines". + # Unwrap raw HTTP headers into the CGI-style expected by Rack middleware. + # + # Rack separates multiple headers with the same key, into a single field with multiple lines. + # + # @parameter headers [Protocol::HTTP::Headers] The raw HTTP request headers. + # @parameter env [Hash] The rack request `env`. def unwrap_headers(headers, env) headers.each do |key, value| http_key = "HTTP_#{key.upcase.tr('-', '_')}" if current_value = env[http_key] @@ -84,11 +97,19 @@ env[http_key] = value end end end - # Process the incoming request into a valid rack env. + # Process the incoming request into a valid rack `env`. + # + # - Set the `env['CONTENT_TYPE']` and `env['CONTENT_LENGTH']` based on the incoming request body. + # - Set the `env['HTTP_HOST']` header to the request authority. + # - Set the `env['HTTP_X_FORWARDED_PROTO']` header to the request scheme. + # - Set `env['REMOTE_ADDR']` to the request remote adress. + # + # @parameter request [Protocol::HTTP::Request] The incoming request. + # @parameter env [Hash] The rack `env`. def unwrap_request(request, env) if content_type = request.headers.delete('content-type') env[CONTENT_TYPE] = content_type end @@ -111,10 +132,13 @@ if remote_address = request.remote_address env[REMOTE_ADDR] = remote_address.ip_address if remote_address.ip? end end + # Build a rack `env` from the incoming request and apply it to the rack middleware. + # + # @parameter request [Protocol::HTTP::Request] The incoming request. def call(request) request_path, query_string = request.path.split('?', 2) server_name, server_port = (request.authority || '').split(':', 2) env = { @@ -192,9 +216,12 @@ @logger.error(self) {exception} return failure_response(exception) end + # Generate a suitable response for the given exception. + # @parameter exception [Exception] + # @returns [Protocol::HTTP::Response] def failure_response(exception) Protocol::HTTP::Response.for_exception(exception) end end end