falcon 0.42.3 → 0.44.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
- checksums.yaml.gz.sig +0 -0
- data/bake/falcon/supervisor.rb +3 -1
- data/changes.md +22 -0
- data/lib/falcon/command/host.rb +7 -50
- data/lib/falcon/command/paths.rb +2 -19
- data/lib/falcon/command/proxy.rb +21 -33
- data/lib/falcon/command/redirect.rb +22 -33
- data/lib/falcon/command/serve.rb +44 -82
- data/lib/falcon/command/supervisor.rb +2 -19
- data/lib/falcon/command/top.rb +2 -19
- data/lib/falcon/command/virtual.rb +16 -41
- data/lib/falcon/command.rb +3 -19
- data/lib/falcon/configuration.rb +28 -142
- data/lib/falcon/endpoint.rb +2 -19
- data/lib/falcon/environment/application.rb +60 -0
- data/lib/falcon/environment/lets_encrypt_tls.rb +34 -0
- data/lib/falcon/environment/proxy.rb +109 -0
- data/lib/falcon/environment/rack.rb +20 -0
- data/lib/falcon/environment/rackup.rb +26 -0
- data/lib/falcon/environment/redirect.rb +50 -0
- data/lib/falcon/environment/self_signed_tls.rb +45 -0
- data/lib/falcon/environment/server.rb +69 -0
- data/lib/falcon/environment/supervisor.rb +40 -0
- data/lib/falcon/environment/tls.rb +97 -0
- data/lib/falcon/environment.rb +13 -0
- data/lib/falcon/middleware/proxy.rb +3 -20
- data/lib/falcon/middleware/redirect.rb +2 -19
- data/lib/falcon/middleware/verbose.rb +2 -19
- data/lib/falcon/proxy_endpoint.rb +2 -19
- data/lib/falcon/railtie.rb +10 -0
- data/lib/falcon/server.rb +2 -19
- data/lib/falcon/service/server.rb +84 -0
- data/lib/falcon/service/supervisor.rb +5 -21
- data/lib/falcon/{controller → service}/virtual.rb +72 -36
- data/lib/falcon/tls.rb +2 -19
- data/lib/falcon/version.rb +3 -20
- data/lib/falcon.rb +5 -19
- data/lib/rack/handler/falcon.rb +4 -0
- data/lib/rackup/handler/falcon.rb +83 -0
- data/license.md +41 -0
- data/readme.md +60 -0
- data.tar.gz.sig +0 -0
- metadata +37 -117
- metadata.gz.sig +0 -0
- data/lib/.DS_Store +0 -0
- data/lib/falcon/controller/host.rb +0 -72
- data/lib/falcon/controller/proxy.rb +0 -126
- data/lib/falcon/controller/redirect.rb +0 -76
- data/lib/falcon/controller/serve.rb +0 -126
- data/lib/falcon/environments/application.rb +0 -72
- data/lib/falcon/environments/lets_encrypt_tls.rb +0 -47
- data/lib/falcon/environments/proxy.rb +0 -37
- data/lib/falcon/environments/rack.rb +0 -50
- data/lib/falcon/environments/self_signed_tls.rb +0 -55
- data/lib/falcon/environments/supervisor.rb +0 -51
- data/lib/falcon/environments/tls.rb +0 -103
- data/lib/falcon/environments.rb +0 -31
- data/lib/falcon/service/application.rb +0 -115
- data/lib/falcon/service/generic.rb +0 -78
- data/lib/falcon/service/proxy.rb +0 -66
- data/lib/falcon/services.rb +0 -99
data/lib/falcon/configuration.rb
CHANGED
@@ -1,26 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2024, by Samuel Williams.
|
5
|
+
# Copyright, 2019, by Sho Ito.
|
22
6
|
|
23
|
-
require '
|
7
|
+
require 'async/service'
|
24
8
|
|
25
9
|
module Falcon
|
26
10
|
# Manages environments which describes how to host a specific application.
|
@@ -41,177 +25,79 @@ module Falcon
|
|
41
25
|
# end
|
42
26
|
# ~~~
|
43
27
|
#
|
44
|
-
class Configuration
|
45
|
-
# Initialize an empty configuration.
|
46
|
-
def initialize
|
47
|
-
@environments = {}
|
48
|
-
end
|
49
|
-
|
50
|
-
# The map of named environments.
|
51
|
-
# @attribute [Hash(String, Build::Environment)]
|
52
|
-
attr :environments
|
53
|
-
|
54
|
-
# Enumerate all environments that have the specified key.
|
55
|
-
# @parameter key [Symbol] Filter environments that don't have this key.
|
56
|
-
def each(key = :authority)
|
57
|
-
return to_enum(key) unless block_given?
|
58
|
-
|
59
|
-
@environments.each do |name, environment|
|
60
|
-
environment = environment.flatten
|
61
|
-
|
62
|
-
if environment.include?(key)
|
63
|
-
yield environment
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Add the named environment to the configuration.
|
69
|
-
def add(environment)
|
70
|
-
name = environment.name
|
71
|
-
|
72
|
-
unless name
|
73
|
-
raise ArgumentError, "Environment name is nil #{environment.inspect}"
|
74
|
-
end
|
75
|
-
|
76
|
-
environment = environment.flatten
|
77
|
-
|
78
|
-
raise KeyError.new("#{name.inspect} is already set", key: name) if @environments.key?(name)
|
79
|
-
|
80
|
-
@environments[name] = environment
|
81
|
-
end
|
82
|
-
|
28
|
+
class Configuration < ::Async::Service::Configuration
|
83
29
|
# Load the specified configuration file. See {Loader#load_file} for more details.
|
84
30
|
def load_file(path)
|
85
31
|
Loader.load_file(self, path)
|
86
32
|
end
|
87
33
|
|
88
34
|
# The domain specific language for loading configuration files.
|
89
|
-
class Loader
|
90
|
-
# Initialize the loader, attached to a specific configuration instance.
|
91
|
-
# Any environments generated by the loader will be added to the configuration.
|
92
|
-
# @parameter configuration [Configuration]
|
93
|
-
# @parameter root [String] The file-system root path for relative path computations.
|
94
|
-
def initialize(configuration, root = nil)
|
95
|
-
@loaded = {}
|
96
|
-
@configuration = configuration
|
97
|
-
@environments = {}
|
98
|
-
@root = root
|
99
|
-
end
|
100
|
-
|
101
|
-
# The file-system root path which is injected into the environments as required.
|
102
|
-
# @attribute [String]
|
103
|
-
attr :root
|
104
|
-
|
105
|
-
# The attached configuration instance.
|
106
|
-
# @attribute [Configuration]
|
107
|
-
attr :configuration
|
108
|
-
|
109
|
-
# Load the specified file into the given configuration.
|
110
|
-
# @parameter configuration [Configuration]
|
111
|
-
# @oaram path [String] The path to the configuration file, e.g. `falcon.rb`.
|
112
|
-
def self.load_file(configuration, path)
|
113
|
-
path = File.realpath(path)
|
114
|
-
root = File.dirname(path)
|
115
|
-
|
116
|
-
loader = self.new(configuration, root)
|
117
|
-
|
118
|
-
loader.instance_eval(File.read(path), path)
|
119
|
-
end
|
120
|
-
|
35
|
+
class Loader < ::Async::Service::Loader
|
121
36
|
# Load specific features into the current configuration.
|
122
37
|
#
|
123
|
-
#
|
124
|
-
#
|
38
|
+
# @deprecated Use `require` instead.
|
125
39
|
# @parameter features [Array(Symbol)] The features to load.
|
126
40
|
def load(*features)
|
127
41
|
features.each do |feature|
|
128
|
-
next if @loaded.include?(feature)
|
129
|
-
|
130
42
|
case feature
|
131
43
|
when Symbol
|
132
|
-
|
133
|
-
|
134
|
-
self.instance_eval(File.read(relative_path), relative_path)
|
135
|
-
|
136
|
-
@loaded[feature] = relative_path
|
137
|
-
when Module
|
138
|
-
feature.load(self)
|
139
|
-
|
140
|
-
@loaded[feature] = feature
|
44
|
+
require File.join(__dir__, "environment", "#{feature}.rb")
|
141
45
|
else
|
142
46
|
raise LoadError, "Unsure about how to load #{feature}!"
|
143
47
|
end
|
144
48
|
end
|
145
49
|
end
|
146
50
|
|
147
|
-
# Add the named environment, with zero or more parent environments, defined using the specified `block`.
|
148
|
-
# @parameter name [String] The name of the environment.
|
149
|
-
# @parameter parents [Array(Symbol)] The names of the parent environments to inherit.
|
150
|
-
# @yields {...} The block that will generate the environment.
|
151
|
-
def environment(name, *parents, &block)
|
152
|
-
raise KeyError.new("#{name} is already set", key: name) if @environments.key?(name)
|
153
|
-
@environments[name] = merge(name, *parents, &block)
|
154
|
-
end
|
155
|
-
|
156
51
|
# Define a host with the specified name.
|
157
52
|
# Adds `root` and `authority` keys.
|
53
|
+
# @deprecated Use `service` and `include Falcon::Environment::Server` instead.
|
158
54
|
# @parameter name [String] The name of the environment, usually a hostname.
|
159
55
|
def host(name, *parents, &block)
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
environment[:authority] = name
|
164
|
-
|
165
|
-
@configuration.add(environment.flatten)
|
56
|
+
@configuration.add(
|
57
|
+
merge(*parents, name: name, root: @root, authority: name, &block)
|
58
|
+
)
|
166
59
|
end
|
167
60
|
|
168
61
|
# Define a proxy with the specified name.
|
169
62
|
# Adds `root` and `authority` keys.
|
63
|
+
# @deprecated Use `service` and `include Falcon::Environment::Proxy` instead.
|
170
64
|
# @parameter name [String] The name of the environment, usually a hostname.
|
171
65
|
def proxy(name, *parents, &block)
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
environment[:authority] = name
|
176
|
-
|
177
|
-
@configuration.add(environment.flatten)
|
66
|
+
@configuration.add(
|
67
|
+
merge(:proxy, *parents, name: name, root: @root, authority: name, &block)
|
68
|
+
)
|
178
69
|
end
|
179
70
|
|
180
71
|
# Define a rack application with the specified name.
|
181
72
|
# Adds `root` and `authority` keys.
|
73
|
+
# @deprecated Use `service` and `include Falcon::Environment::Rack` instead.
|
182
74
|
# @parameter name [String] The name of the environment, usually a hostname.
|
183
75
|
def rack(name, *parents, &block)
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
environment[:authority] = name
|
188
|
-
|
189
|
-
@configuration.add(environment.flatten)
|
76
|
+
@configuration.add(
|
77
|
+
merge(:rack, *parents, name: name, root: @root, authority: name, &block)
|
78
|
+
)
|
190
79
|
end
|
191
80
|
|
192
81
|
# Define a supervisor instance
|
193
|
-
#
|
82
|
+
# @deprecated Use `service` and `include Falcon::Environment::Supervisor` instead.
|
194
83
|
def supervisor(&block)
|
195
84
|
name = File.join(@root, "supervisor")
|
196
|
-
environment = merge(name, :supervisor, &block)
|
197
85
|
|
198
|
-
|
199
|
-
|
200
|
-
|
86
|
+
@configuration.add(
|
87
|
+
merge(:supervisor, name: name, root: @root, &block)
|
88
|
+
)
|
201
89
|
end
|
202
90
|
|
203
91
|
private
|
204
92
|
|
205
93
|
# Build a new environment with the specified name and the given parents.
|
206
94
|
# @parameter name [String]
|
207
|
-
# @parameter parents [Array(
|
95
|
+
# @parameter parents [Array(Symbol)]
|
208
96
|
# @yields {...} The block that will generate the environment.
|
209
|
-
def merge(
|
210
|
-
|
211
|
-
|
212
|
-
parent = Build::Environment.combine(*environments)
|
97
|
+
def merge(*parents, **initial, &block)
|
98
|
+
facets = parents.map{|parent| Environment::LEGACY_ENVIRONMENTS.fetch(parent)}
|
213
99
|
|
214
|
-
|
100
|
+
::Async::Service::Environment.build(*facets, **initial, &block)
|
215
101
|
end
|
216
102
|
end
|
217
103
|
end
|
data/lib/falcon/endpoint.rb
CHANGED
@@ -1,24 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2018-2023, by Samuel Williams.
|
22
5
|
|
23
6
|
require 'async/http/endpoint'
|
24
7
|
require 'localhost/authority'
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2024, by Samuel Williams.
|
5
|
+
# Copyright, 2020, by Daniel Evans.
|
6
|
+
|
7
|
+
require_relative 'server'
|
8
|
+
require_relative '../proxy_endpoint'
|
9
|
+
|
10
|
+
module Falcon
|
11
|
+
module Environment
|
12
|
+
# Provides an environment for hosting a web application that uses TLS.
|
13
|
+
module Application
|
14
|
+
include Server
|
15
|
+
|
16
|
+
# The middleware stack for the application.
|
17
|
+
# @returns [Protocol::HTTP::Middleware]
|
18
|
+
def middleware
|
19
|
+
::Protocol::HTTP::Middleware::HelloWorld
|
20
|
+
end
|
21
|
+
|
22
|
+
# The scheme to use to communicate with the application.
|
23
|
+
# @returns [String]
|
24
|
+
def scheme
|
25
|
+
'https'
|
26
|
+
end
|
27
|
+
|
28
|
+
# The protocol to use to communicate with the application.
|
29
|
+
#
|
30
|
+
# Typically one of {Async::HTTP::Protocol::HTTP1} or {Async::HTTP::Protocl::HTTP2}.
|
31
|
+
#
|
32
|
+
# @returns [Async::HTTP::Protocol]
|
33
|
+
def protocol
|
34
|
+
Async::HTTP::Protocol::HTTP2
|
35
|
+
end
|
36
|
+
|
37
|
+
# The IPC path to use for communication with the application.
|
38
|
+
# @returns [String]
|
39
|
+
def ipc_path
|
40
|
+
::File.expand_path("application.ipc", root)
|
41
|
+
end
|
42
|
+
|
43
|
+
# The endpoint that will be used for communicating with the application server.
|
44
|
+
# @returns [Async::IO::Endpoint]
|
45
|
+
def endpoint
|
46
|
+
::Falcon::ProxyEndpoint.unix(ipc_path,
|
47
|
+
protocol: protocol,
|
48
|
+
scheme: scheme,
|
49
|
+
authority: authority
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Number of instances to start.
|
54
|
+
# @returns [Integer | nil]
|
55
|
+
def count
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2020-2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative 'tls'
|
7
|
+
require_relative '../environment'
|
8
|
+
|
9
|
+
module Falcon
|
10
|
+
module Environment
|
11
|
+
# Provides an environment that uses "Lets Encrypt" for TLS.
|
12
|
+
module LetsEncryptTLS
|
13
|
+
# The Lets Encrypt certificate store path.
|
14
|
+
# @parameter [String]
|
15
|
+
def lets_encrypt_root
|
16
|
+
'/etc/letsencrypt/live'
|
17
|
+
end
|
18
|
+
|
19
|
+
# The public certificate path.
|
20
|
+
# @attribute [String]
|
21
|
+
def ssl_certificate_path
|
22
|
+
File.join(lets_encrypt_root, authority, "fullchain.pem")
|
23
|
+
end
|
24
|
+
|
25
|
+
# The private key path.
|
26
|
+
# @attribute [String]
|
27
|
+
def ssl_private_key_path
|
28
|
+
File.join(lets_encrypt_root, authority, "privkey.pem")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
LEGACY_ENVIRONMENTS[:tls] = TLS
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative 'server'
|
7
|
+
require_relative '../tls'
|
8
|
+
require_relative '../middleware/proxy'
|
9
|
+
require_relative '../environment'
|
10
|
+
|
11
|
+
module Falcon
|
12
|
+
module Environment
|
13
|
+
# Provides an environment for hosting a TLS-capable reverse proxy using SNI.
|
14
|
+
module Proxy
|
15
|
+
include Server
|
16
|
+
|
17
|
+
# The host that this proxy will receive connections for.
|
18
|
+
def url
|
19
|
+
"https://[::]:443"
|
20
|
+
end
|
21
|
+
|
22
|
+
# The default SSL session identifier.
|
23
|
+
def tls_session_id
|
24
|
+
"falcon"
|
25
|
+
end
|
26
|
+
|
27
|
+
# The services we will proxy to.
|
28
|
+
# @returns [Array(Async::Service::Environment)]
|
29
|
+
def environments
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
|
33
|
+
# The hosts we will proxy to. This is a hash of SNI authority -> evaluator.
|
34
|
+
# @returns [Hash(String, Async::Service::Environment::Evaluator)]
|
35
|
+
def hosts
|
36
|
+
hosts = {}
|
37
|
+
|
38
|
+
environments.each do |environment|
|
39
|
+
evaluator = environment.evaluator
|
40
|
+
|
41
|
+
# next unless environment.implements?(Falcon::Environment::Application)
|
42
|
+
if evaluator.key?(:authority) and evaluator.key?(:ssl_context) and evaluator.key?(:endpoint)
|
43
|
+
Console.info(self) {"Proxying #{self.url} to #{evaluator.authority} using #{evaluator.endpoint}"}
|
44
|
+
hosts[evaluator.authority] = evaluator
|
45
|
+
|
46
|
+
if RUBY_VERSION < '3.1'
|
47
|
+
# Ensure the SSL context is set up before forking - it's buggy on Ruby < 3.1:
|
48
|
+
evaluator.ssl_context
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
return hosts
|
54
|
+
end
|
55
|
+
|
56
|
+
# Look up the host context for the given hostname, and update the socket hostname if necessary.
|
57
|
+
# @parameter socket [OpenSSL::SSL::SSLSocket] The incoming connection.
|
58
|
+
# @parameter hostname [String] The negotiated hostname.
|
59
|
+
def host_context(socket, hostname)
|
60
|
+
hosts = self.hosts
|
61
|
+
|
62
|
+
if host = hosts[hostname]
|
63
|
+
Console.logger.debug(self) {"Resolving #{hostname} -> #{host}"}
|
64
|
+
|
65
|
+
socket.hostname = hostname
|
66
|
+
|
67
|
+
return host.ssl_context
|
68
|
+
else
|
69
|
+
Console.logger.warn(self, hosts: hosts.keys) {"Unable to resolve #{hostname}!"}
|
70
|
+
|
71
|
+
return nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Generate an SSL context which delegates to {host_context} to multiplex based on hostname.
|
76
|
+
def ssl_context
|
77
|
+
@server_context ||= OpenSSL::SSL::SSLContext.new.tap do |context|
|
78
|
+
context.servername_cb = Proc.new do |socket, hostname|
|
79
|
+
self.host_context(socket, hostname)
|
80
|
+
end
|
81
|
+
|
82
|
+
context.session_id_context = @session_id
|
83
|
+
|
84
|
+
context.ssl_version = :TLSv1_2_server
|
85
|
+
|
86
|
+
context.set_params(
|
87
|
+
ciphers: ::Falcon::TLS::SERVER_CIPHERS,
|
88
|
+
verify_mode: ::OpenSSL::SSL::VERIFY_NONE,
|
89
|
+
)
|
90
|
+
|
91
|
+
context.setup
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# The endpoint the server will bind to.
|
96
|
+
def endpoint
|
97
|
+
super.with(
|
98
|
+
ssl_context: self.ssl_context,
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
def middleware
|
103
|
+
return Middleware::Proxy.new(Middleware::BadRequest, self.hosts)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
LEGACY_ENVIRONMENTS[:proxy] = Proxy
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative 'application'
|
7
|
+
require_relative 'rackup'
|
8
|
+
require_relative '../environment'
|
9
|
+
|
10
|
+
module Falcon
|
11
|
+
module Environment
|
12
|
+
# Provides an environment for hosting a web application that use a Rackup `config.ru` file.
|
13
|
+
module Rack
|
14
|
+
include Application
|
15
|
+
include Rackup
|
16
|
+
end
|
17
|
+
|
18
|
+
LEGACY_ENVIRONMENTS[:rack] = Rack
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'rack/builder'
|
7
|
+
require_relative '../server'
|
8
|
+
|
9
|
+
module Falcon
|
10
|
+
module Environment
|
11
|
+
# Provides an environment for hosting loading a Rackup `config.ru` file.
|
12
|
+
module Rackup
|
13
|
+
def rackup_path
|
14
|
+
'config.ru'
|
15
|
+
end
|
16
|
+
|
17
|
+
def rack_app
|
18
|
+
::Rack::Builder.parse_file(rackup_path)
|
19
|
+
end
|
20
|
+
|
21
|
+
def middleware
|
22
|
+
::Falcon::Server.middleware(rack_app, verbose: verbose, cache: cache)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2020-2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative 'server'
|
7
|
+
require_relative '../middleware/redirect'
|
8
|
+
|
9
|
+
module Falcon
|
10
|
+
module Environment
|
11
|
+
# Provides an environment for redirecting insecure web traffic to a secure endpoint.
|
12
|
+
module Redirect
|
13
|
+
include Server
|
14
|
+
|
15
|
+
def redirect_url
|
16
|
+
"https://[::]:443"
|
17
|
+
end
|
18
|
+
|
19
|
+
def redirect_endpoint
|
20
|
+
Async::HTTP::Endpoint.parse(redirect_url)
|
21
|
+
end
|
22
|
+
|
23
|
+
# The services we will redirect to.
|
24
|
+
# @returns [Array(Async::Service::Environment)]
|
25
|
+
def environments
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
|
29
|
+
def hosts
|
30
|
+
hosts = {}
|
31
|
+
|
32
|
+
environments.each do |environment|
|
33
|
+
evaluator = environment.evaluator
|
34
|
+
|
35
|
+
if environment.implements?(Falcon::Environment::Application)
|
36
|
+
Console.info(self) {"Redirecting #{self.url} to #{evaluator.authority}"}
|
37
|
+
hosts[evaluator.authority] = evaluator
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
return hosts
|
42
|
+
end
|
43
|
+
|
44
|
+
# Load the {Middleware::Redirect} application with the specified hosts.
|
45
|
+
def middleware
|
46
|
+
Middleware::Redirect.new(Middleware::NotFound, hosts, redirect_endpoint)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'localhost/authority'
|
7
|
+
require_relative 'tls'
|
8
|
+
require_relative '../environment'
|
9
|
+
|
10
|
+
module Falcon
|
11
|
+
module Environment
|
12
|
+
# Provides an environment that exposes a self-signed TLS certificate using the `localhost` gem.
|
13
|
+
module SelfSignedTLS
|
14
|
+
# The default session identifier for the session cache.
|
15
|
+
# @returns [String]
|
16
|
+
def ssl_session_id
|
17
|
+
"falcon"
|
18
|
+
end
|
19
|
+
|
20
|
+
# The SSL context to use for incoming connections.
|
21
|
+
# @returns [OpenSSL::SSL::SSLContext]
|
22
|
+
def ssl_context
|
23
|
+
contexts = Localhost::Authority.fetch(authority)
|
24
|
+
|
25
|
+
contexts.server_context.tap do |context|
|
26
|
+
context.alpn_select_cb = lambda do |protocols|
|
27
|
+
if protocols.include? "h2"
|
28
|
+
return "h2"
|
29
|
+
elsif protocols.include? "http/1.1"
|
30
|
+
return "http/1.1"
|
31
|
+
elsif protocols.include? "http/1.0"
|
32
|
+
return "http/1.0"
|
33
|
+
else
|
34
|
+
return nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context.session_id_context = ssl_session_id
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
LEGACY_ENVIRONMENTS[:self_signed_tls] = SelfSignedTLS
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'async/service/generic'
|
7
|
+
require 'async/http/endpoint'
|
8
|
+
|
9
|
+
require_relative '../service/server'
|
10
|
+
require_relative '../server'
|
11
|
+
|
12
|
+
module Falcon
|
13
|
+
module Environment
|
14
|
+
# Provides an environment for hosting a web application that uses a Falcon server.
|
15
|
+
module Server
|
16
|
+
# The service class to use for the proxy.
|
17
|
+
# @returns [Class]
|
18
|
+
def service_class
|
19
|
+
Service::Server
|
20
|
+
end
|
21
|
+
|
22
|
+
# The server authority. Defaults to the server name.
|
23
|
+
# @returns [String]
|
24
|
+
def authority
|
25
|
+
self.name
|
26
|
+
end
|
27
|
+
|
28
|
+
# Options to use when creating the container.
|
29
|
+
def container_options
|
30
|
+
{restart: true}
|
31
|
+
end
|
32
|
+
|
33
|
+
# The host that this server will receive connections for.
|
34
|
+
def url
|
35
|
+
"http://[::]:9292"
|
36
|
+
end
|
37
|
+
|
38
|
+
def timeout
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
# The upstream endpoint that will handle incoming requests.
|
43
|
+
# @returns [Async::HTTP::Endpoint]
|
44
|
+
def endpoint
|
45
|
+
::Async::HTTP::Endpoint.parse(url).with(
|
46
|
+
reuse_address: true,
|
47
|
+
timeout: timeout,
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def verbose
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
def cache
|
56
|
+
false
|
57
|
+
end
|
58
|
+
|
59
|
+
def client_endpoint
|
60
|
+
::Async::HTTP::Endpoint.parse(url)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Any scripts to preload before starting the server.
|
64
|
+
def preload
|
65
|
+
[]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|