lib/falcon/hosts.rb in falcon-0.25.0 vs lib/falcon/hosts.rb in falcon-0.26.0
- old
+ new
@@ -21,123 +21,91 @@
require 'async/io/endpoint'
require_relative 'proxy'
require_relative 'redirection'
-require 'async/container/forked'
+require 'async/container'
+require 'async/container/controller'
+require 'async/http/url_endpoint'
module Falcon
class Host
- def initialize
- @app = nil
- @app_root = nil
- @config_path = "config.ru"
-
- @endpoint = nil
-
- @ssl_certificate = nil
- @ssl_key = nil
-
- @ssl_context = nil
+ def initialize(environment)
+ @environment = environment.flatten
+ @evaluator = @environment.evaluator
end
- attr_accessor :app
- attr_accessor :app_root
- attr_accessor :config_path
+ def name
+ "Falcon Host for #{self.authority}"
+ end
- attr_accessor :endpoint
-
- attr_accessor :ssl_certificate
- attr_accessor :ssl_key
-
- attr_accessor :ssl_context
-
- def freeze
- return if frozen?
-
- ssl_context
-
- super
+ def authority
+ @evaluator.authority
end
- def app?
- @app || @config_path
+ def endpoint
+ @evaluator.endpoint
end
- def load_app(verbose = false)
- return @app if @app
-
- if @config_path
- rack_app, options = Rack::Builder.parse_file(@config_path)
-
- return Server.middleware(rack_app, verbose: verbose)
- end
+ def ssl_context
+ @evaluator.ssl_context
end
- def self_signed!(hostname)
- authority = Localhost::Authority.fetch(hostname)
-
- @ssl_context = authority.server_context.tap do |context|
- context.alpn_select_cb = lambda do |protocols|
- if protocols.include? "h2"
- return "h2"
- elsif protocols.include? "http/1.1"
- return "http/1.1"
- elsif protocols.include? "http/1.0"
- return "http/1.0"
- else
- return nil
- end
- end
-
- context.session_id_context = "falcon"
- end
+ def root
+ @evaluator.root
end
- def ssl_certificate_path= path
- @ssl_certificate = OpenSSL::X509::Certificate.new(File.read(path))
+ def bound_endpoint
+ @evaluator.bound_endpoint
end
- def ssl_key_path= path
- @ssl_key = OpenSSL::PKey::RSA.new(File.read(path))
+ def to_s
+ "\#<#{self.class} #{@evaluator.authority}>"
end
- def ssl_context
- @ssl_context ||= OpenSSL::SSL::SSLContext.new.tap do |context|
- context.cert = @ssl_certificate
- context.key = @ssl_key
-
- context.session_id_context = "falcon"
-
- context.set_params
-
- context.setup
- end
+ def assume_privileges(path)
+ stat = File.stat(path)
+
+ Process::GID.change_privilege(stat.gid)
+ Process::UID.change_privilege(stat.uid)
end
- def start(*args)
- if self.app?
- Async::Container::Forked.new do
- Dir.chdir(@app_root) if @app_root
+ def run(container)
+ if @environment.include?(:server)
+ bound_endpoint = self.bound_endpoint
+
+ container.run(count: 1, name: self.name) do |task, instance|
+ Async.logger.info(self) {"Starting application server..."}
- app = self.load_app(*args)
+ if root = self.root
+ Dir.chdir(root)
+ end
- server = Falcon::Server.new(app, self.server_endpoint)
+ server = @evaluator.server
+ # Drop root privileges:
+ assume_privileges(root)
+
server.run
+
+ task.children.each(&:wait)
end
end
end
end
class Hosts
DEFAULT_ALPN_PROTOCOLS = ['h2', 'http/1.1'].freeze
- def initialize
+ def initialize(configuration)
@named = {}
@server_context = nil
@server_endpoint = nil
+
+ configuration.each do |environment|
+ add(Host.new(environment))
+ end
end
def each(&block)
@named.each(&block)
end
@@ -155,96 +123,66 @@
context.servername_cb = Proc.new do |socket, hostname|
self.host_context(socket, hostname)
end
context.session_id_context = "falcon"
-
context.alpn_protocols = DEFAULT_ALPN_PROTOCOLS
-
context.set_params
context.setup
end
end
def host_context(socket, hostname)
if host = @named[hostname]
+ Async.logger.debug(self) {"Resolving #{hostname} -> #{host}"}
+
socket.hostname = hostname
return host.ssl_context
+ else
+ Async.logger.warn(self) {"Unable to resolve #{hostname}!"}
+
+ return nil
end
end
- def add(name, host = Host.new, &block)
- host = Host.new
-
- yield host if block_given?
-
- @named[name] = host.freeze
+ def add(host)
+ @named[host.authority] = host
end
- def client_endpoints
- Hash[
- @named.collect{|name, host| [name, host.endpoint]}
- ]
- end
-
def proxy
- Proxy.new(Falcon::BadRequest, self.client_endpoints)
+ Proxy.new(Falcon::BadRequest, @named)
end
- def redirection
- Redirection.new(Falcon::BadRequest, self.client_endpoints)
+ def redirection(secure_endpoint)
+ Redirection.new(Falcon::BadRequest, @named, secure_endpoint)
end
- def call(controller)
- self.each do |name, host|
- if container = host.start
- controller << container
- end
+ def run(container = Async::Container::Forked.new, **options)
+ @named.each do |name, host|
+ host.run(container)
end
-
- proxy = hosts.proxy
- debug_trap = Async::IO::Trap.new(:USR1)
-
- profile = RubyProf::Profile.new(merge_fibers: true)
-
- controller << Async::Container::Forked.new do |task|
- Process.setproctitle("Falcon Proxy")
+
+ secure_endpoint = Async::HTTP::URLEndpoint.parse(options[:bind_secure], ssl_context: self.ssl_context)
+ insecure_endpoint = Async::HTTP::URLEndpoint.parse(options[:bind_insecure])
+
+ container.run(count: 1, name: "Falcon Proxy") do |task, instance|
+ proxy = self.proxy
- server = Falcon::Server.new(
- proxy,
- Async::HTTP::URLEndpoint.parse(
- 'https://0.0.0.0',
- reuse_address: true,
- ssl_context: hosts.ssl_context
- )
- )
+ proxy_server = Falcon::Server.new(proxy, secure_endpoint)
- Async::Reactor.run do |task|
- task.async do
- debug_trap.install!
- $stderr.puts "Send `kill -USR1 #{Process.pid}` for detailed status :)"
-
- debug_trap.trap do
- task.reactor.print_hierarchy($stderr)
- # Async.logger.level = Logger::DEBUG
- end
- end
-
- task.async do |task|
- start_time = Async::Clock.now
-
- while true
- task.sleep(600)
- duration = Async::Clock.now - start_time
- puts "Handled #{proxy.count} requests; #{(proxy.count.to_f / duration.to_f).round(1)} requests per second."
- end
- end
-
- $stderr.puts "Starting server"
- server.run
- end
+ proxy_server.run
end
+
+ container.run(count: 1, name: "Falcon Redirector") do |task, instance|
+ redirection = self.redirection(secure_endpoint)
+
+ redirection_server = Falcon::Server.new(redirection, insecure_endpoint)
+
+ redirection_server.run
+ end
+
+ return container
end
end
end