class Falcon::Controller::Proxy

A controller for proxying requests.

def endpoint

The endpoint the server will bind to.
def endpoint
	@command.endpoint.with(
		ssl_context: self.ssl_context,
		reuse_address: true,
	)
end

def host_context(socket, hostname)

@parameter hostname [String] The negotiated hostname.
@parameter socket [OpenSSL::SSL::SSLSocket] The incoming connection.
Look up the host context for the given hostname, and update the socket hostname if necessary.
def host_context(socket, hostname)
	if host = @hosts[hostname]
		Console.logger.debug(self) {"Resolving #{hostname} -> #{host}"}
		
		socket.hostname = hostname
		
		return host.ssl_context
	else
		Console.logger.warn(self) {"Unable to resolve #{hostname}!"}
		
		return nil
	end
end

def initialize(command, session_id: DEFAULT_SESSION_ID, **options)

@parameter session_id [String] The SSL session identifier to use for the session cache.
@parameter command [Command::Proxy] The user-specified command-line options.
Initialize the proxy controller.
def initialize(command, session_id: DEFAULT_SESSION_ID, **options)
	super(command, **options)
	
	@session_id = session_id
	@hosts = {}
end

def load_app

Load the {Middleware::Proxy} application with the specified hosts.
def load_app
	return Middleware::Proxy.new(Middleware::BadRequest, @hosts)
end

def name

The name of the controller which is used for the process title.
def name
	"Falcon Proxy Server"
end

def ssl_context

Generate an SSL context which delegates to {host_context} to multiplex based on hostname.
def ssl_context
	@server_context ||= OpenSSL::SSL::SSLContext.new.tap do |context|
		context.servername_cb = Proc.new do |socket, hostname|
			self.host_context(socket, hostname)
		end
		
		context.session_id_context = @session_id
		
		context.ssl_version = :TLSv1_2_server
		
		context.set_params(
			ciphers: TLS::SERVER_CIPHERS,
			verify_mode: OpenSSL::SSL::VERIFY_NONE,
		)
		
		context.setup
	end
end

def start

Builds a map of host redirections.
def start
	configuration = @command.configuration
	
	services = Services.new(configuration)
	
	@hosts = {}
	
	services.each do |service|
		if service.is_a?(Service::Proxy)
			Console.logger.info(self) {"Proxying #{service.authority} to #{service.endpoint}"}
			@hosts[service.authority] = service
			
			# Pre-cache the ssl contexts:
			# It seems some OpenSSL objects don't like event-driven I/O.
			service.ssl_context
		end
	end
	
	super
end