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

Instance Method Summary collapse

Constructor Details

#initializeHosts

Returns a new instance of Hosts.



135
136
137
138
139
# File 'lib/falcon/hosts.rb', line 135

def initialize
  @named = {}
  @server_context = nil
  @server_endpoint = nil
end

Instance Method Details

#add(name, host = Host.new) {|host| ... } ⇒ Object

Yields:

  • (host)


177
178
179
180
181
182
183
# File 'lib/falcon/hosts.rb', line 177

def add(name, host = Host.new, &block)
  host = Host.new
  
  yield host if block_given?
  
  @named[name] = host.freeze
end

#call(controller) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/falcon/hosts.rb', line 199

def call(controller)
  self.each do |name, host|
    if container = host.start
      controller << container
    end
  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")
    
    server = Falcon::Server.new(
      proxy,
      Async::HTTP::URLEndpoint.parse(
        'https://0.0.0.0',
        reuse_address: true,
        ssl_context: hosts.ssl_context
      )
    )
    
    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
  end
end

#client_endpointsObject



185
186
187
188
189
# File 'lib/falcon/hosts.rb', line 185

def client_endpoints
  Hash[
    @named.collect{|name, host| [name, host.endpoint]}
  ]
end

#each(&block) ⇒ Object



141
142
143
# File 'lib/falcon/hosts.rb', line 141

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

#endpointObject



145
146
147
148
149
150
151
# File 'lib/falcon/hosts.rb', line 145

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

#host_context(socket, hostname) ⇒ Object



169
170
171
172
173
174
175
# File 'lib/falcon/hosts.rb', line 169

def host_context(socket, hostname)
  if host = @named[hostname]
    socket.hostname = hostname
    
    return host.ssl_context
  end
end

#proxyObject



191
192
193
# File 'lib/falcon/hosts.rb', line 191

def proxy
  Proxy.new(Falcon::BadRequest, self.client_endpoints)
end

#redirectionObject



195
196
197
# File 'lib/falcon/hosts.rb', line 195

def redirection
  Redirection.new(Falcon::BadRequest, self.client_endpoints)
end

#ssl_contextObject



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/falcon/hosts.rb', line 153

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
    
    context.setup
  end
end