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