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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/bake/falcon/supervisor.rb +3 -1
  4. data/changes.md +22 -0
  5. data/lib/falcon/command/host.rb +7 -50
  6. data/lib/falcon/command/paths.rb +2 -19
  7. data/lib/falcon/command/proxy.rb +21 -33
  8. data/lib/falcon/command/redirect.rb +22 -33
  9. data/lib/falcon/command/serve.rb +44 -82
  10. data/lib/falcon/command/supervisor.rb +2 -19
  11. data/lib/falcon/command/top.rb +2 -19
  12. data/lib/falcon/command/virtual.rb +16 -41
  13. data/lib/falcon/command.rb +3 -19
  14. data/lib/falcon/configuration.rb +28 -142
  15. data/lib/falcon/endpoint.rb +2 -19
  16. data/lib/falcon/environment/application.rb +60 -0
  17. data/lib/falcon/environment/lets_encrypt_tls.rb +34 -0
  18. data/lib/falcon/environment/proxy.rb +109 -0
  19. data/lib/falcon/environment/rack.rb +20 -0
  20. data/lib/falcon/environment/rackup.rb +26 -0
  21. data/lib/falcon/environment/redirect.rb +50 -0
  22. data/lib/falcon/environment/self_signed_tls.rb +45 -0
  23. data/lib/falcon/environment/server.rb +69 -0
  24. data/lib/falcon/environment/supervisor.rb +40 -0
  25. data/lib/falcon/environment/tls.rb +97 -0
  26. data/lib/falcon/environment.rb +13 -0
  27. data/lib/falcon/middleware/proxy.rb +3 -20
  28. data/lib/falcon/middleware/redirect.rb +2 -19
  29. data/lib/falcon/middleware/verbose.rb +2 -19
  30. data/lib/falcon/proxy_endpoint.rb +2 -19
  31. data/lib/falcon/railtie.rb +10 -0
  32. data/lib/falcon/server.rb +2 -19
  33. data/lib/falcon/service/server.rb +84 -0
  34. data/lib/falcon/service/supervisor.rb +5 -21
  35. data/lib/falcon/{controller → service}/virtual.rb +72 -36
  36. data/lib/falcon/tls.rb +2 -19
  37. data/lib/falcon/version.rb +3 -20
  38. data/lib/falcon.rb +5 -19
  39. data/lib/rack/handler/falcon.rb +4 -0
  40. data/lib/rackup/handler/falcon.rb +83 -0
  41. data/license.md +41 -0
  42. data/readme.md +60 -0
  43. data.tar.gz.sig +0 -0
  44. metadata +37 -117
  45. metadata.gz.sig +0 -0
  46. data/lib/.DS_Store +0 -0
  47. data/lib/falcon/controller/host.rb +0 -72
  48. data/lib/falcon/controller/proxy.rb +0 -126
  49. data/lib/falcon/controller/redirect.rb +0 -76
  50. data/lib/falcon/controller/serve.rb +0 -126
  51. data/lib/falcon/environments/application.rb +0 -72
  52. data/lib/falcon/environments/lets_encrypt_tls.rb +0 -47
  53. data/lib/falcon/environments/proxy.rb +0 -37
  54. data/lib/falcon/environments/rack.rb +0 -50
  55. data/lib/falcon/environments/self_signed_tls.rb +0 -55
  56. data/lib/falcon/environments/supervisor.rb +0 -51
  57. data/lib/falcon/environments/tls.rb +0 -103
  58. data/lib/falcon/environments.rb +0 -31
  59. data/lib/falcon/service/application.rb +0 -115
  60. data/lib/falcon/service/generic.rb +0 -78
  61. data/lib/falcon/service/proxy.rb +0 -66
  62. data/lib/falcon/services.rb +0 -99
@@ -1,26 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
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, 2019-2024, by Samuel Williams.
5
+ # Copyright, 2019, by Sho Ito.
22
6
 
23
- require 'build/environment'
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
- # Falcon provides default environments for different purposes. These are included in the gem, in the `environments/` directory. This method loads the code in those files into the current configuration.
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
- relative_path = File.join(__dir__, "environments", "#{feature}.rb")
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
- environment = merge(name, *parents, &block)
161
-
162
- environment[:root] = @root
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
- environment = merge(name, :proxy, *parents, &block)
173
-
174
- environment[:root] = @root
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
- environment = merge(name, :rack, *parents, &block)
185
-
186
- environment[:root] = @root
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
- # Adds `root` key.
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
- environment[:root] = @root
199
-
200
- @configuration.add(environment.flatten)
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(Build::Environment)]
95
+ # @parameter parents [Array(Symbol)]
208
96
  # @yields {...} The block that will generate the environment.
209
- def merge(name, *parents, &block)
210
- environments = parents.map{|name| @environments.fetch(name)}
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
- Build::Environment.new(parent, name: name, &block)
100
+ ::Async::Service::Environment.build(*facets, **initial, &block)
215
101
  end
216
102
  end
217
103
  end
@@ -1,24 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
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