class Falcon::Middleware::Proxy
Typically used for implementing virtual servers.
A HTTP middleware for proxying requests to a given set of hosts.
def call(request)
Proxy the request if the authority matches a specific host.
def call(request) if host = lookup(request) @count += 1 request = self.prepare_request(request, host) client = connect(host.endpoint) client.call(request) else super end rescue => error Console::Event::Failure.for(error).emit(self) return Protocol::HTTP::Response[502, {"content-type" => "text/plain"}, [error.class.name]] end
def call(request)
def call(request) attributes = { "authority" => request.authority, "method" => request.method, "path" => request.path, "version" => request.version, } Traces.trace("falcon.middleware.proxy.call", attributes: attributes) do super end end
def close
def close @clients.each_value(&:close) super end
def connect(endpoint)
Establish a connection to the specified upstream endpoint.
def connect(endpoint) @clients[endpoint] ||= Async::HTTP::Client.new(endpoint) end
def initialize(app, hosts)
@parameter app [Protocol::HTTP::Middleware] The middleware to use if a request can't be proxied.
Initialize the proxy middleware.
def initialize(app, hosts) super(app) @server_context = nil @hosts = hosts @clients = {} @count = 0 end
def lookup(request)
@parameter request [Protocol::HTTP::Request]
Lookup the appropriate host for the given request.
def lookup(request) # Trailing dot and port is ignored/normalized. if authority = request.authority&.sub(/(\.)?(:\d+)?$/, "") return @hosts[authority] end end
def prepare_headers(headers)
Prepare the headers to be sent to an upstream host.
def prepare_headers(headers) if connection = headers[CONNECTION] headers.extract(connection) end headers.extract(HOP_HEADERS) end
def prepare_request(request, host)
Prepare the request to be proxied to the specified host.
def prepare_request(request, host) forwarded = [] Console.debug(self) do |buffer| buffer.puts "Request authority: #{request.authority}" buffer.puts "Host authority: #{host.authority}" buffer.puts "Request: #{request.method} #{request.path} #{request.version}" buffer.puts "Request headers: #{request.headers.inspect}" end # The authority of the request must match the authority of the endpoint we are proxying to, otherwise SNI and other things won't work correctly. request.authority = host.authority if address = request.remote_address request.headers.add(X_FORWARDED_FOR, address.ip_address) forwarded << "for=#{address.ip_address}" end if scheme = request.scheme request.headers.add(X_FORWARDED_PROTO, scheme) forwarded << "proto=#{scheme}" end unless forwarded.empty? request.headers.add(FORWARDED, forwarded.join(";")) end request.headers.add(VIA, "#{request.version} #{self.class}") self.prepare_headers(request.headers) return request end