falcon 0.36.3 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/falcon/adapters/input.rb +32 -11
- data/lib/falcon/adapters/output.rb +20 -1
- data/lib/falcon/adapters/rack.rb +60 -39
- data/lib/falcon/adapters/response.rb +23 -1
- data/lib/falcon/adapters/rewindable.rb +10 -3
- data/lib/falcon/command.rb +2 -0
- data/lib/falcon/command/host.rb +13 -2
- data/lib/falcon/command/paths.rb +4 -0
- data/lib/falcon/command/proxy.rb +14 -0
- data/lib/falcon/command/redirect.rb +12 -0
- data/lib/falcon/command/serve.rb +22 -15
- data/lib/falcon/command/supervisor.rb +15 -1
- data/lib/falcon/command/top.rb +16 -0
- data/lib/falcon/command/virtual.rb +15 -0
- data/lib/falcon/configuration.rb +69 -7
- data/lib/falcon/controller/host.rb +12 -0
- data/lib/falcon/controller/proxy.rb +13 -0
- data/lib/falcon/controller/redirect.rb +7 -0
- data/lib/falcon/controller/serve.rb +17 -2
- data/lib/falcon/controller/virtual.rb +17 -0
- data/lib/falcon/endpoint.rb +8 -0
- data/lib/falcon/{configuration/proxy.rb → environments.rb} +9 -5
- data/lib/falcon/environments/application.rb +72 -0
- data/lib/falcon/{configuration/application.rb → environments/lets_encrypt_tls.rb} +21 -20
- data/lib/falcon/{configuration/lets_encrypt_tls.rb → environments/proxy.rb} +13 -6
- data/lib/falcon/{configuration → environments}/rack.rb +14 -2
- data/lib/falcon/{configuration → environments}/self_signed_tls.rb +9 -1
- data/lib/falcon/{configuration → environments}/supervisor.rb +19 -5
- data/lib/falcon/{configuration → environments}/tls.rb +39 -5
- data/lib/falcon/extensions/openssl.rb +1 -0
- data/lib/falcon/middleware/proxy.rb +26 -5
- data/lib/falcon/middleware/redirect.rb +11 -0
- data/lib/falcon/{verbose.rb → middleware/verbose.rb} +34 -26
- data/lib/falcon/proxy_endpoint.rb +21 -0
- data/lib/falcon/server.rb +8 -2
- data/lib/falcon/service/application.rb +24 -2
- data/lib/falcon/service/generic.rb +18 -0
- data/lib/falcon/service/proxy.rb +6 -0
- data/lib/falcon/service/supervisor.rb +13 -1
- data/lib/falcon/services.rb +21 -0
- data/lib/falcon/tls.rb +4 -2
- data/lib/falcon/version.rb +1 -1
- data/lib/rack/handler/falcon.rb +8 -2
- metadata +65 -122
- data/.editorconfig +0 -5
- data/.github/FUNDING.yml +0 -3
- data/.github/workflows/development.yml +0 -60
- data/.gitignore +0 -14
- data/.rspec +0 -3
- data/Gemfile +0 -17
- data/README.md +0 -316
- data/examples/beer/config.ru +0 -57
- data/examples/beer/falcon.rb +0 -8
- data/examples/benchmark/config.ru +0 -39
- data/examples/benchmark/falcon.rb +0 -6
- data/examples/csv/config.ru +0 -31
- data/examples/google/falcon.rb +0 -14
- data/examples/hello/config.ru +0 -22
- data/examples/hello/falcon.rb +0 -24
- data/examples/hello/preload.rb +0 -7
- data/examples/internet/config.ru +0 -54
- data/examples/memory/allocations.rb +0 -39
- data/examples/memory/config.ru +0 -14
- data/examples/push/client.rb +0 -29
- data/examples/push/config.ru +0 -28
- data/examples/push/index.html +0 -14
- data/examples/push/script.js +0 -2
- data/examples/push/style.css +0 -4
- data/examples/redis/Gemfile +0 -9
- data/examples/redis/config.ru +0 -28
- data/examples/sequel/Gemfile +0 -4
- data/examples/sequel/config.ru +0 -8
- data/examples/sequel/data.sqlite3 +0 -0
- data/examples/server/standalone.rb +0 -27
- data/examples/sinatra/Gemfile +0 -7
- data/examples/sinatra/Gemfile.lock +0 -53
- data/examples/sinatra/config.ru +0 -16
- data/examples/trailers/config.ru +0 -34
- data/examples/trailers/falcon.rb +0 -8
- data/falcon.gemspec +0 -45
- data/gems/rack1.gemfile +0 -4
- data/gems/rack3.gemfile +0 -4
- data/lib/falcon/adapters/early_hints.rb +0 -49
- data/logo-square.afdesign +0 -0
- data/logo.afdesign +0 -0
- data/logo.svg +0 -107
- data/server.rb +0 -21
- data/tasks/benchmark.rake +0 -103
@@ -22,11 +22,23 @@
|
|
22
22
|
|
23
23
|
load :application
|
24
24
|
|
25
|
-
|
25
|
+
# A rack application environment.
|
26
|
+
#
|
27
|
+
# Derived from {.application}.
|
28
|
+
#
|
29
|
+
# @scope Falcon Environments
|
30
|
+
# @name rack
|
31
|
+
environment(:rack, :application) do
|
32
|
+
# The rack configuration path.
|
33
|
+
# @attribute [String]
|
26
34
|
config_path {::File.expand_path("config.ru", root)}
|
27
35
|
|
36
|
+
# Whether to enable the application layer cache.
|
37
|
+
# @attribute [String]
|
28
38
|
cache false
|
29
39
|
|
40
|
+
# The middleware stack for the rack application.
|
41
|
+
# @attribute [Protocol::HTTP::Middleware]
|
30
42
|
middleware do
|
31
43
|
app, _ = ::Rack::Builder.parse_file(config_path)
|
32
44
|
|
@@ -35,4 +47,4 @@ add(:rack, :application) do
|
|
35
47
|
cache: cache
|
36
48
|
)
|
37
49
|
end
|
38
|
-
end
|
50
|
+
end
|
@@ -22,9 +22,17 @@
|
|
22
22
|
|
23
23
|
require 'localhost/authority'
|
24
24
|
|
25
|
-
|
25
|
+
# A self-signed SSL context environment.
|
26
|
+
#
|
27
|
+
# @scope Falcon Environments
|
28
|
+
# @name self_signed_tls
|
29
|
+
environment(:self_signed_tls) do
|
30
|
+
# The default session identifier for the session cache.
|
31
|
+
# @attribute [String]
|
26
32
|
ssl_session_id {"falcon"}
|
27
33
|
|
34
|
+
# The SSL context to use for incoming connections.
|
35
|
+
# @attribute [OpenSSL::SSL::SSLContext]
|
28
36
|
ssl_context do
|
29
37
|
contexts = Localhost::Authority.fetch(authority)
|
30
38
|
|
@@ -22,15 +22,29 @@
|
|
22
22
|
|
23
23
|
require_relative '../service/supervisor'
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
# A application process monitor environment.
|
26
|
+
#
|
27
|
+
# @scope Falcon Environments
|
28
|
+
# @name supervisor
|
29
|
+
environment(:supervisor) do
|
30
|
+
# The name of the supervisor
|
31
|
+
# @attribute [String]
|
28
32
|
name "supervisor"
|
29
33
|
|
30
|
-
|
34
|
+
# The IPC path to use for communication with the supervisor.
|
35
|
+
# @attribute [String]
|
36
|
+
ipc_path do
|
37
|
+
::File.expand_path("supervisor.ipc", root)
|
38
|
+
end
|
31
39
|
|
32
|
-
endpoint
|
40
|
+
# The endpoint the supervisor will bind to.
|
41
|
+
# @attribute [Async::IO::Endpoint]
|
42
|
+
endpoint do
|
43
|
+
Async::IO::Endpoint.unix(ipc_path)
|
44
|
+
end
|
33
45
|
|
46
|
+
# The service class to use for the supervisor.
|
47
|
+
# @attribute [Class]
|
34
48
|
service do
|
35
49
|
::Falcon::Service::Supervisor
|
36
50
|
end
|
@@ -24,19 +24,53 @@ require_relative '../extensions/openssl'
|
|
24
24
|
require_relative '../controller/proxy'
|
25
25
|
require_relative '../tls'
|
26
26
|
|
27
|
-
|
27
|
+
# A general SSL context environment.
|
28
|
+
#
|
29
|
+
# @scope Falcon Environments
|
30
|
+
# @name tls
|
31
|
+
environment(:tls) do
|
32
|
+
# The default session identifier for the session cache.
|
33
|
+
# @attribute [String]
|
28
34
|
ssl_session_id "falcon"
|
35
|
+
|
36
|
+
# The supported ciphers.
|
37
|
+
# @attribute [Array(String)]
|
29
38
|
ssl_ciphers Falcon::TLS::SERVER_CIPHERS
|
30
39
|
|
31
|
-
|
32
|
-
|
40
|
+
# The public certificate path.
|
41
|
+
# @attribute [String]
|
42
|
+
ssl_certificate_path do
|
43
|
+
File.expand_path("ssl/certificate.pem", root)
|
44
|
+
end
|
45
|
+
|
46
|
+
# The list of certificates loaded from that path.
|
47
|
+
# @attribute [Array(OpenSSL::X509::Certificate)]
|
48
|
+
ssl_certificates do
|
49
|
+
OpenSSL::X509.load_certificates(ssl_certificate_path)
|
50
|
+
end
|
33
51
|
|
52
|
+
# The main certificate.
|
53
|
+
# @attribute [OpenSSL::X509::Certificate]
|
34
54
|
ssl_certificate {ssl_certificates[0]}
|
55
|
+
|
56
|
+
# The certificate chain.
|
57
|
+
# @attribute [Array(OpenSSL::X509::Certificate)]
|
35
58
|
ssl_certificate_chain {ssl_certificates[1..-1]}
|
36
59
|
|
37
|
-
|
38
|
-
|
60
|
+
# The private key path.
|
61
|
+
# @attribute [String]
|
62
|
+
ssl_private_key_path do
|
63
|
+
File.expand_path("ssl/private.key", root)
|
64
|
+
end
|
65
|
+
|
66
|
+
# The private key.
|
67
|
+
# @attribute [OpenSSL::PKey::RSA]
|
68
|
+
ssl_private_key do
|
69
|
+
OpenSSL::PKey::RSA.new(File.read(ssl_private_key_path))
|
70
|
+
end
|
39
71
|
|
72
|
+
# The SSL context to use for incoming connections.
|
73
|
+
# @attribute [OpenSSL::SSL::SSLContext]
|
40
74
|
ssl_context do
|
41
75
|
OpenSSL::SSL::SSLContext.new.tap do |context|
|
42
76
|
context.add_certificate(ssl_certificate, ssl_private_key, ssl_certificate_chain)
|
@@ -25,6 +25,7 @@ require 'openssl/x509'
|
|
25
25
|
module OpenSSL::X509
|
26
26
|
CERTIFICATE_PATTERN = /-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/m
|
27
27
|
|
28
|
+
# An extension to load an array of certificates from a file at the given path.
|
28
29
|
def self.load_certificates(path)
|
29
30
|
File.read(path).scan(CERTIFICATE_PATTERN).collect do |text|
|
30
31
|
Certificate.new(text)
|
@@ -26,6 +26,7 @@ require 'protocol/http/middleware'
|
|
26
26
|
|
27
27
|
module Falcon
|
28
28
|
module Middleware
|
29
|
+
# A static middleware which always returns a 400 bad request response.
|
29
30
|
module BadRequest
|
30
31
|
def self.call(request)
|
31
32
|
return Protocol::HTTP::Response[400, {}, []]
|
@@ -35,14 +36,17 @@ module Falcon
|
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
39
|
+
# A HTTP middleware for proxying requests to a given set of hosts.
|
40
|
+
# Typically used for implementing virtual servers.
|
38
41
|
class Proxy < Protocol::HTTP::Middleware
|
39
|
-
FORWARDED = 'forwarded'
|
40
|
-
X_FORWARDED_FOR = 'x-forwarded-for'
|
41
|
-
X_FORWARDED_PROTO = 'x-forwarded-proto'
|
42
|
+
FORWARDED = 'forwarded'
|
43
|
+
X_FORWARDED_FOR = 'x-forwarded-for'
|
44
|
+
X_FORWARDED_PROTO = 'x-forwarded-proto'
|
42
45
|
|
43
|
-
VIA = 'via'
|
44
|
-
CONNECTION = 'connection'
|
46
|
+
VIA = 'via'
|
47
|
+
CONNECTION = 'connection'
|
45
48
|
|
49
|
+
# HTTP hop headers which *should* not be passed through the proxy.
|
46
50
|
HOP_HEADERS = [
|
47
51
|
'connection',
|
48
52
|
'keep-alive',
|
@@ -52,6 +56,9 @@ module Falcon
|
|
52
56
|
'upgrade',
|
53
57
|
]
|
54
58
|
|
59
|
+
# Initialize the proxy middleware.
|
60
|
+
# @parameter app [Protocol::HTTP::Middleware] The middleware to use if a request can't be proxied.
|
61
|
+
# @parameter hosts [Array(Service::Proxy)] The host applications to proxy to.
|
55
62
|
def initialize(app, hosts)
|
56
63
|
super(app)
|
57
64
|
|
@@ -63,18 +70,26 @@ module Falcon
|
|
63
70
|
@count = 0
|
64
71
|
end
|
65
72
|
|
73
|
+
# The number of requests that have been proxied.
|
74
|
+
# @attribute [Integer]
|
66
75
|
attr :count
|
67
76
|
|
77
|
+
# Close all the connections to the upstream hosts.
|
68
78
|
def close
|
69
79
|
@clients.each_value(&:close)
|
70
80
|
|
71
81
|
super
|
72
82
|
end
|
73
83
|
|
84
|
+
# Establish a connection to the specified upstream endpoint.
|
85
|
+
# @parameter endpoint [Async::HTTP::Endpoint]
|
74
86
|
def connect(endpoint)
|
75
87
|
@clients[endpoint] ||= Async::HTTP::Client.new(endpoint)
|
76
88
|
end
|
77
89
|
|
90
|
+
# Lookup the appropriate host for the given request.
|
91
|
+
# @parameter request [Protocol::HTTP::Request]
|
92
|
+
# @returns [Service::Proxy]
|
78
93
|
def lookup(request)
|
79
94
|
# Trailing dot and port is ignored/normalized.
|
80
95
|
if authority = request.authority&.sub(/(\.)?(:\d+)?$/, '')
|
@@ -82,6 +97,8 @@ module Falcon
|
|
82
97
|
end
|
83
98
|
end
|
84
99
|
|
100
|
+
# Prepare the headers to be sent to an upstream host.
|
101
|
+
# In particular, we delete all connection and hop headers.
|
85
102
|
def prepare_headers(headers)
|
86
103
|
if connection = headers[CONNECTION]
|
87
104
|
headers.extract(connection)
|
@@ -90,6 +107,8 @@ module Falcon
|
|
90
107
|
headers.extract(HOP_HEADERS)
|
91
108
|
end
|
92
109
|
|
110
|
+
# Prepare the request to be proxied to the specified host.
|
111
|
+
# In particular, we set appropriate {VIA}, {FORWARDED}, {X_FORWARDED_FOR} and {X_FORWARDED_PROTO} headers.
|
93
112
|
def prepare_request(request, host)
|
94
113
|
forwarded = []
|
95
114
|
|
@@ -124,6 +143,8 @@ module Falcon
|
|
124
143
|
return request
|
125
144
|
end
|
126
145
|
|
146
|
+
# Proxy the request if the authority matches a specific host.
|
147
|
+
# @parameter request [Protocol::HTTP::Request]
|
127
148
|
def call(request)
|
128
149
|
if host = lookup(request)
|
129
150
|
@count += 1
|
@@ -24,6 +24,7 @@ require 'async/http/client'
|
|
24
24
|
|
25
25
|
module Falcon
|
26
26
|
module Middleware
|
27
|
+
# A static middleware which always returns a 404 not found response.
|
27
28
|
module NotFound
|
28
29
|
def self.call(request)
|
29
30
|
return Protocol::HTTP::Response[404, {}, []]
|
@@ -33,7 +34,13 @@ module Falcon
|
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
37
|
+
# A HTTP middleware for redirecting a given set of hosts to a different endpoint.
|
38
|
+
# Typically used for implementing HTTP -> HTTPS redirects.
|
36
39
|
class Redirect < Protocol::HTTP::Middleware
|
40
|
+
# Initialize the redirect middleware.
|
41
|
+
# @parameter app [Protocol::HTTP::Middleware] The middleware to wrap.
|
42
|
+
# @parameter hosts [Hash(String, Service::Proxy)] The map of hosts.
|
43
|
+
# @parameter endpoint [Endpoint] The template endpoint to use to build the redirect location.
|
37
44
|
def initialize(app, hosts, endpoint)
|
38
45
|
super(app)
|
39
46
|
|
@@ -41,6 +48,8 @@ module Falcon
|
|
41
48
|
@endpoint = endpoint
|
42
49
|
end
|
43
50
|
|
51
|
+
# Lookup the appropriate host for the given request.
|
52
|
+
# @parameter request [Protocol::HTTP::Request]
|
44
53
|
def lookup(request)
|
45
54
|
# Trailing dot and port is ignored/normalized.
|
46
55
|
if authority = request.authority&.sub(/(\.)?(:\d+)?$/, '')
|
@@ -48,6 +57,8 @@ module Falcon
|
|
48
57
|
end
|
49
58
|
end
|
50
59
|
|
60
|
+
# Redirect the request if the authority matches a specific host.
|
61
|
+
# @parameter request [Protocol::HTTP::Request]
|
51
62
|
def call(request)
|
52
63
|
if host = lookup(request)
|
53
64
|
if @endpoint.default_port?
|
@@ -24,36 +24,44 @@ require 'async/logger'
|
|
24
24
|
require 'async/http/statistics'
|
25
25
|
|
26
26
|
module Falcon
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
@
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
@logger.info(request) {"Headers: #{request.headers.to_h} from #{address.inspect}"}
|
39
|
-
|
40
|
-
task.annotate("#{request.method} #{request.path} from #{address.inspect}")
|
41
|
-
end
|
42
|
-
|
43
|
-
def call(request)
|
44
|
-
annotate(request)
|
45
|
-
|
46
|
-
statistics = Async::HTTP::Statistics.start
|
47
|
-
|
48
|
-
response = super
|
27
|
+
module Middleware
|
28
|
+
# A HTTP middleware for logging requests and responses.
|
29
|
+
class Verbose < Protocol::HTTP::Middleware
|
30
|
+
# Initialize the verbose middleware.
|
31
|
+
# @parameter app [Protocol::HTTP::Middleware] The middleware to wrap.
|
32
|
+
# @parameter logger [Console::Logger] The logger to use.
|
33
|
+
def initialize(app, logger = Async.logger)
|
34
|
+
super(app)
|
35
|
+
|
36
|
+
@logger = logger
|
37
|
+
end
|
49
38
|
|
50
|
-
|
51
|
-
|
39
|
+
# Log details of the incoming request.
|
40
|
+
def annotate(request)
|
41
|
+
task = Async::Task.current
|
42
|
+
address = request.remote_address
|
43
|
+
|
44
|
+
@logger.info(request) {"Headers: #{request.headers.to_h} from #{address.inspect}"}
|
52
45
|
|
53
|
-
|
46
|
+
task.annotate("#{request.method} #{request.path} from #{address.inspect}")
|
54
47
|
end
|
55
48
|
|
56
|
-
|
49
|
+
# Log details of the incoming request using {annotate} and wrap the response to log response details too.
|
50
|
+
def call(request)
|
51
|
+
annotate(request)
|
52
|
+
|
53
|
+
statistics = Async::HTTP::Statistics.start
|
54
|
+
|
55
|
+
response = super
|
56
|
+
|
57
|
+
statistics.wrap(response) do |statistics, error|
|
58
|
+
@logger.info(request) {"Responding with: #{response.status} #{response.headers.to_h}; #{statistics.inspect}"}
|
59
|
+
|
60
|
+
@logger.error(request) {"#{error.class}: #{error.message}"} if error
|
61
|
+
end
|
62
|
+
|
63
|
+
return response
|
64
|
+
end
|
57
65
|
end
|
58
66
|
end
|
59
67
|
end
|
@@ -23,7 +23,10 @@
|
|
23
23
|
require 'async/io/unix_endpoint'
|
24
24
|
|
25
25
|
module Falcon
|
26
|
+
# An endpoint suitable for proxing requests, typically via a unix pipe.
|
26
27
|
class ProxyEndpoint < Async::IO::Endpoint
|
28
|
+
# Initialize the proxy endpoint.
|
29
|
+
# @parameter endpoint [Async::IO::Endpoint] The endpoint which will be used for connecting/binding.
|
27
30
|
def initialize(endpoint, **options)
|
28
31
|
super(**options)
|
29
32
|
|
@@ -34,28 +37,44 @@ module Falcon
|
|
34
37
|
"\#<#{self.class} endpoint=#{@endpoint}>"
|
35
38
|
end
|
36
39
|
|
40
|
+
# The actual endpoint for I/O.
|
41
|
+
# @attribute [Async::IO::Endpoint]
|
37
42
|
attr :endpoint
|
38
43
|
|
44
|
+
# The protocol to use for this connection.
|
45
|
+
# @returns [Async::HTTP::Protocol] A specific protocol, e.g. {Async::HTTP::P}
|
39
46
|
def protocol
|
40
47
|
@options[:protocol]
|
41
48
|
end
|
42
49
|
|
50
|
+
# The scheme to use for this endpoint.
|
51
|
+
# e.g. `"http"`.
|
52
|
+
# @returns [String]
|
43
53
|
def scheme
|
44
54
|
@options[:scheme]
|
45
55
|
end
|
46
56
|
|
57
|
+
# The authority to use for this endpoint.
|
58
|
+
# e.g. `"myapp.com"`.
|
59
|
+
# @returns [String]
|
47
60
|
def authority
|
48
61
|
@options[:authority]
|
49
62
|
end
|
50
63
|
|
64
|
+
# Connect to the endpoint.
|
51
65
|
def connect(&block)
|
52
66
|
@endpoint.connect(&block)
|
53
67
|
end
|
54
68
|
|
69
|
+
# Bind to the endpoint.
|
55
70
|
def bind(&block)
|
56
71
|
@endpoint.bind(&block)
|
57
72
|
end
|
58
73
|
|
74
|
+
# Enumerate the endpoint.
|
75
|
+
# If the endpoint has multiple underlying endpoints, this will enumerate them individually.
|
76
|
+
# @yields {|endpoint| ...}
|
77
|
+
# @parameter endpoint [ProxyEndpoint]
|
59
78
|
def each
|
60
79
|
return to_enum unless block_given?
|
61
80
|
|
@@ -64,6 +83,8 @@ module Falcon
|
|
64
83
|
end
|
65
84
|
end
|
66
85
|
|
86
|
+
# Create a proxy unix endpoint with the specific path.
|
87
|
+
# @returns [ProxyEndpoint]
|
67
88
|
def self.unix(path, **options)
|
68
89
|
self.new(::Async::IO::Endpoint.unix(path), **options)
|
69
90
|
end
|
data/lib/falcon/server.rb
CHANGED
@@ -27,16 +27,22 @@ require 'protocol/http/content_encoding'
|
|
27
27
|
|
28
28
|
require 'async/http/cache'
|
29
29
|
|
30
|
-
require_relative 'verbose'
|
30
|
+
require_relative 'middleware/verbose'
|
31
|
+
|
31
32
|
require_relative 'adapters/rewindable'
|
32
33
|
require_relative 'adapters/rack'
|
33
34
|
|
34
35
|
module Falcon
|
36
|
+
# A server listening on a specific endpoint, hosting a specific middleware.
|
35
37
|
class Server < Async::HTTP::Server
|
38
|
+
# Wrap a rack application into a middleware suitable the server.
|
39
|
+
# @parameter rack_app [Proc | Object] A rack application/middleware.
|
40
|
+
# @parameter verbose [Boolean] Whether to add the {Verbose} middleware.
|
41
|
+
# @parameter cache [Boolean] Whether to add the {Async::HTTP::Cache} middleware.
|
36
42
|
def self.middleware(rack_app, verbose: false, cache: true)
|
37
43
|
::Protocol::HTTP::Middleware.build do
|
38
44
|
if verbose
|
39
|
-
use Verbose
|
45
|
+
use Middleware::Verbose
|
40
46
|
end
|
41
47
|
|
42
48
|
if cache
|
@@ -27,6 +27,7 @@ require 'async/io/shared_endpoint'
|
|
27
27
|
|
28
28
|
module Falcon
|
29
29
|
module Service
|
30
|
+
# Implements an application server using an internal clear-text proxy.
|
30
31
|
class Application < Proxy
|
31
32
|
def initialize(environment)
|
32
33
|
super
|
@@ -34,11 +35,20 @@ module Falcon
|
|
34
35
|
@bound_endpoint = nil
|
35
36
|
end
|
36
37
|
|
38
|
+
# The middleware that will be served by this application.
|
39
|
+
# @returns [Protocol::HTTP::Middleware]
|
37
40
|
def middleware
|
38
41
|
# In a multi-threaded container, we don't want to modify the shared evaluator's cache, so we create a new evaluator:
|
39
42
|
@environment.evaluator.middleware
|
40
43
|
end
|
41
44
|
|
45
|
+
# Number of instances to start.
|
46
|
+
# @returns [Integer | nil]
|
47
|
+
def count
|
48
|
+
@environment.evaluator.count
|
49
|
+
end
|
50
|
+
|
51
|
+
# Preload any resources specified by the environment.
|
42
52
|
def preload!
|
43
53
|
if scripts = @evaluator.preload
|
44
54
|
scripts.each do |path|
|
@@ -49,6 +59,8 @@ module Falcon
|
|
49
59
|
end
|
50
60
|
end
|
51
61
|
|
62
|
+
# Prepare the bound endpoint for the application instances.
|
63
|
+
# Invoke {preload!} to load shared resources into the parent process.
|
52
64
|
def start
|
53
65
|
Async.logger.info(self) {"Binding to #{self.endpoint}..."}
|
54
66
|
|
@@ -61,15 +73,24 @@ module Falcon
|
|
61
73
|
super
|
62
74
|
end
|
63
75
|
|
76
|
+
# Setup instances of the application into the container.
|
77
|
+
# @parameter container [Async::Container::Generic]
|
64
78
|
def setup(container)
|
65
79
|
protocol = self.protocol
|
66
80
|
scheme = self.scheme
|
67
81
|
|
68
|
-
|
82
|
+
run_options = {
|
83
|
+
name: self.name,
|
84
|
+
restart: true,
|
85
|
+
}
|
86
|
+
|
87
|
+
run_options[:count] = count unless count.nil?
|
88
|
+
|
89
|
+
container.run(**run_options) do |instance|
|
69
90
|
Async(logger: logger) do |task|
|
70
91
|
Async.logger.info(self) {"Starting application server for #{self.root}..."}
|
71
92
|
|
72
|
-
server = Server.new(self.middleware, @bound_endpoint, protocol, scheme)
|
93
|
+
server = Server.new(self.middleware, @bound_endpoint, protocol: protocol, scheme: scheme)
|
73
94
|
|
74
95
|
server.run
|
75
96
|
|
@@ -82,6 +103,7 @@ module Falcon
|
|
82
103
|
super
|
83
104
|
end
|
84
105
|
|
106
|
+
# Close the bound endpoint.
|
85
107
|
def stop
|
86
108
|
@bound_endpoint&.close
|
87
109
|
@bound_endpoint = nil
|