Skip to content

Commit

Permalink
Move (almost) everything back to Falcon::Environments.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Mar 23, 2024
1 parent fc8e9cb commit cb05b41
Show file tree
Hide file tree
Showing 14 changed files with 273 additions and 298 deletions.
6 changes: 3 additions & 3 deletions lib/falcon/command/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Released under the MIT License.
# Copyright, 2020-2023, by Samuel Williams.

require_relative '../service/proxy'
require_relative '../environments/proxy'
require_relative 'paths'

require 'samovar'
Expand Down Expand Up @@ -32,7 +32,7 @@ class Proxy < Samovar::Command
include Paths

def environment(**options)
Async::Service::Environment.new(Falcon::Service::Proxy::Environment).with(
Async::Service::Environment.new(Falcon::Environments::Proxy).with(
root: Dir.pwd,
verbose: self.parent&.verbose?,
url: @options[:bind],
Expand All @@ -45,7 +45,7 @@ def host_map(environments)
hosts = {}

environments.each do |environment|
next unless environment.implements?(Falcon::Service::Application::Environment)
next unless environment.implements?(Falcon::Environments::Application)
evaluator = environment.evaluator
hosts[evaluator.authority] = evaluator
end
Expand Down
6 changes: 3 additions & 3 deletions lib/falcon/command/redirect.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Released under the MIT License.
# Copyright, 2020-2023, by Samuel Williams.

require_relative '../service/redirect'
require_relative '../environments/redirect'
require_relative 'paths'

require 'samovar'
Expand All @@ -30,7 +30,7 @@ class Redirect < Samovar::Command
include Paths

def environment(**options)
Async::Service::Environment.new(Falcon::Service::Redirect::Environment).with(
Async::Service::Environment.new(Falcon::Environments::Redirect).with(
root: Dir.pwd,
verbose: self.parent&.verbose?,
url: @options[:bind],
Expand All @@ -44,7 +44,7 @@ def host_map(environments)
hosts = {}

environments.each do |environment|
next unless environment.implements?(Falcon::Service::Application::Environment)
next unless environment.implements?(Falcon::Environments::Application)
evaluator = environment.evaluator
hosts[evaluator.authority] = evaluator
end
Expand Down
2 changes: 1 addition & 1 deletion lib/falcon/command/serve.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def endpoint_options
end

def environment
Async::Service::Environment.new(Falcon::Service::Server::Environment).with(
Async::Service::Environment.new(Falcon::Environments::Server).with(
Falcon::Environments::Rackup,

root: Dir.pwd,
Expand Down
59 changes: 59 additions & 0 deletions lib/falcon/environments/application.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2019-2023, by Samuel Williams.
# Copyright, 2020, by Daniel Evans.

require_relative 'server'
require_relative '../proxy_endpoint'

module Falcon
module Environments
module Application
include Server

# The middleware stack for the application.
# @returns [Protocol::HTTP::Middleware]
def middleware
::Protocol::HTTP::Middleware::HelloWorld
end

# The scheme to use to communicate with the application.
# @returns [String]
def scheme
'https'
end

# The protocol to use to communicate with the application.
#
# Typically one of {Async::HTTP::Protocol::HTTP1} or {Async::HTTP::Protocl::HTTP2}.
#
# @returns [Async::HTTP::Protocol]
def protocol
Async::HTTP::Protocol::HTTP2
end

# The IPC path to use for communication with the application.
# @returns [String]
def ipc_path
::File.expand_path("application.ipc", root)
end

# The endpoint that will be used for communicating with the application server.
# @returns [Async::IO::Endpoint]
def endpoint
::Falcon::ProxyEndpoint.unix(ipc_path,
protocol: protocol,
scheme: scheme,
authority: authority
)
end

# Number of instances to start.
# @returns [Integer | nil]
def count
nil
end
end
end
end
105 changes: 105 additions & 0 deletions lib/falcon/environments/proxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2020-2023, by Samuel Williams.

require_relative 'server'
require_relative '../tls'
require_relative '../middleware/proxy'

module Falcon
module Environments
module Proxy
include Server

# The host that this proxy will receive connections for.
def url
"https://[::]:443"
end

# The default SSL session identifier.
def tls_session_id
"falcon"
end

# The services we will proxy to.
# @returns [Array(Async::Service::Environment)]
def environments
[]
end

def hosts
hosts = {}

environments.each do |environment|
evaluator = environment.evaluator

if evaluator.key?(:authority) and evaluator.key?(:ssl_context) and evaluator.key?(:endpoint)
Console.logger.info(self) {"Proxying #{self.url} to #{evaluator.authority} using #{evaluator.endpoint}"}
hosts[evaluator.authority] = evaluator

# Pre-cache the ssl contexts:
# It seems some OpenSSL objects don't like event-driven I/O.
# service.ssl_context
else
Console.logger.warn(self) {"Ignoring environment: #{environment}, missing authority, ssl_context, or endpoint."}
end
end

return hosts
end

# Look up the host context for the given hostname, and update the socket hostname if necessary.
# @parameter socket [OpenSSL::SSL::SSLSocket] The incoming connection.
# @parameter hostname [String] The negotiated hostname.
def host_context(socket, hostname)
hosts = self.hosts

if host = hosts[hostname]
Console.logger.debug(self) {"Resolving #{hostname} -> #{host}"}

socket.hostname = hostname

return host.ssl_context
else
Console.logger.warn(self, hosts: hosts.keys) {"Unable to resolve #{hostname}!"}

return nil
end
end

# 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: ::Falcon::TLS::SERVER_CIPHERS,
verify_mode: ::OpenSSL::SSL::VERIFY_NONE,
)

context.setup
end
end

# The endpoint the server will bind to.
def endpoint
super.with(
ssl_context: self.ssl_context,
)
end

def middleware
return Middleware::Proxy.new(Middleware::BadRequest, self.hosts)
end
end

LEGACY_ENVIRONMENTS[:proxy] = Proxy
end
end
4 changes: 2 additions & 2 deletions lib/falcon/environments/rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
# Released under the MIT License.
# Copyright, 2019-2023, by Samuel Williams.

require_relative '../service/application'
require_relative 'application'
require_relative 'rackup'

module Falcon
module Environments
module Rack
include Service::Application::Environment
include Application
include Rackup
end

Expand Down
33 changes: 33 additions & 0 deletions lib/falcon/environments/redirect.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2020-2023, by Samuel Williams.

require_relative 'server'
require_relative '../middleware/redirect'

module Falcon
module Environments
# A controller for redirecting requests.
module Redirect
include Server

def redirect_url
"https://[::]:443"
end

def redirect_endpoint
Async::HTTP::Endpoint.parse(redirect_url)
end

def hosts
{}
end

# Load the {Middleware::Redirect} application with the specified hosts.
def middleware
Middleware::Redirect.new(Middleware::NotFound, hosts, redirect_endpoint)
end
end
end
end
66 changes: 66 additions & 0 deletions lib/falcon/environments/server.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2020-2023, by Samuel Williams.

require 'async/service/generic'
require 'async/http/endpoint'

require_relative '../service/server'
require_relative '../server'

module Falcon
module Environments
module Server
# The service class to use for the proxy.
# @returns [Class]
def service_class
Service::Server
end

def name
"#{service_class.name} (#{url})"
end

# Options to use when creating the container.
def container_options
{restart: true}
end

# The host that this server will receive connections for.
def url
"http://[::]:9292"
end

def timeout
nil
end

# The upstream endpoint that will handle incoming requests.
# @returns [Async::HTTP::Endpoint]
def endpoint
::Async::HTTP::Endpoint.parse(url).with(
reuse_address: true,
timeout: timeout,
)
end

def verbose
false
end

def cache
false
end

def client_endpoint
::Async::HTTP::Endpoint.parse(url)
end

# Any scripts to preload before starting the server.
def preload
[]
end
end
end
end
Loading

0 comments on commit cb05b41

Please sign in to comment.