Class: Falcon::Hosts

Inherits:
Object
  • Object
show all
Defined in:
lib/falcon/hosts.rb

Constant Summary collapse

DEFAULT_ALPN_PROTOCOLS =
['h2', 'http/1.1'].freeze
SERVER_CIPHERS =
"EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5".freeze

Instance Method Summary collapse

Constructor Details

#initialize(configuration) ⇒ Hosts

Returns a new instance of Hosts.



36
37
38
39
40
41
42
43
44
# File 'lib/falcon/hosts.rb', line 36

def initialize(configuration)
  @named = {}
  @server_context = nil
  @server_endpoint = nil
  
  configuration.each(:authority) do |environment|
    add(Host.new(environment))
  end
end

Instance Method Details

#add(host) ⇒ Object



90
91
92
# File 'lib/falcon/hosts.rb', line 90

def add(host)
  @named[host.authority] = host
end

#each(&block) ⇒ Object



46
47
48
# File 'lib/falcon/hosts.rb', line 46

def each(&block)
  @named.each_value(&block)
end

#endpointObject



50
51
52
53
54
55
56
# File 'lib/falcon/hosts.rb', line 50

def endpoint
  @server_endpoint ||= Async::HTTP::Endpoint.parse(
    'https://[::]',
    ssl_context: self.ssl_context,
    reuse_address: true
  )
end

#host_context(socket, hostname) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/falcon/hosts.rb', line 76

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

#proxyObject



94
95
96
# File 'lib/falcon/hosts.rb', line 94

def proxy
  Proxy.new(Falcon::BadRequest, @named)
end

#redirection(secure_endpoint) ⇒ Object



98
99
100
# File 'lib/falcon/hosts.rb', line 98

def redirection(secure_endpoint)
  Redirection.new(Falcon::BadRequest, @named, secure_endpoint)
end

#run(container = Async::Container.new, **options) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/falcon/hosts.rb', line 102

def run(container = Async::Container.new, **options)
  secure_endpoint = Async::HTTP::Endpoint.parse(options[:bind_secure], ssl_context: self.ssl_context)
  insecure_endpoint = Async::HTTP::Endpoint.parse(options[:bind_insecure])
  
  secure_endpoint_bound = insecure_endpoint_bound = nil
  
  Async::Reactor.run do
    secure_endpoint_bound = Async::IO::SharedEndpoint.bound(secure_endpoint)
    insecure_endpoint_bound = Async::IO::SharedEndpoint.bound(insecure_endpoint)
  end.wait
  
  container.run(name: "Falcon Proxy", restart: true) do |task, instance|
    proxy = self.proxy
    
    proxy_server = Falcon::Server.new(proxy, secure_endpoint_bound, secure_endpoint.protocol, secure_endpoint.scheme)
    
    proxy_server.run
  end
  
  container.run(name: "Falcon Redirector", restart: true) do |task, instance|
    redirection = self.redirection(secure_endpoint)
    
    redirection_server = Falcon::Server.new(redirection, insecure_endpoint_bound, insecure_endpoint.protocol, insecure_endpoint.scheme)
    
    redirection_server.run
  end
  
  container.attach do
    secure_endpoint_bound.close
    insecure_endpoint_bound.close
  end
  
  return container
end

#ssl_contextObject



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/falcon/hosts.rb', line 58

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 = "falcon"
    context.alpn_protocols = DEFAULT_ALPN_PROTOCOLS
    
    context.set_params(
      ciphers: SERVER_CIPHERS,
      verify_mode: OpenSSL::SSL::VERIFY_NONE,
    )
    
    context.setup
  end
end