falcon 0.43.0 → 0.44.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/changes.md +22 -0
  4. data/lib/falcon/command/host.rb +6 -32
  5. data/lib/falcon/command/proxy.rb +20 -15
  6. data/lib/falcon/command/redirect.rb +21 -15
  7. data/lib/falcon/command/serve.rb +41 -65
  8. data/lib/falcon/command/top.rb +1 -1
  9. data/lib/falcon/command/virtual.rb +15 -23
  10. data/lib/falcon/configuration.rb +26 -124
  11. data/lib/falcon/environment/application.rb +60 -0
  12. data/lib/falcon/environment/lets_encrypt_tls.rb +34 -0
  13. data/lib/falcon/environment/proxy.rb +109 -0
  14. data/lib/falcon/environment/rack.rb +20 -0
  15. data/lib/falcon/environment/rackup.rb +26 -0
  16. data/lib/falcon/environment/redirect.rb +50 -0
  17. data/lib/falcon/environment/self_signed_tls.rb +45 -0
  18. data/lib/falcon/environment/server.rb +69 -0
  19. data/lib/falcon/environment/supervisor.rb +40 -0
  20. data/lib/falcon/environment/tls.rb +97 -0
  21. data/lib/falcon/{environments.rb → environment.rb} +3 -4
  22. data/lib/falcon/service/server.rb +84 -0
  23. data/lib/falcon/service/supervisor.rb +4 -3
  24. data/lib/falcon/{controller → service}/virtual.rb +71 -18
  25. data/lib/falcon/version.rb +2 -2
  26. data/license.md +2 -0
  27. data.tar.gz.sig +0 -0
  28. metadata +24 -26
  29. metadata.gz.sig +0 -0
  30. data/lib/.DS_Store +0 -0
  31. data/lib/falcon/controller/host.rb +0 -55
  32. data/lib/falcon/controller/proxy.rb +0 -109
  33. data/lib/falcon/controller/redirect.rb +0 -59
  34. data/lib/falcon/controller/serve.rb +0 -110
  35. data/lib/falcon/environments/application.rb +0 -56
  36. data/lib/falcon/environments/lets_encrypt_tls.rb +0 -30
  37. data/lib/falcon/environments/proxy.rb +0 -22
  38. data/lib/falcon/environments/rack.rb +0 -33
  39. data/lib/falcon/environments/self_signed_tls.rb +0 -38
  40. data/lib/falcon/environments/supervisor.rb +0 -34
  41. data/lib/falcon/environments/tls.rb +0 -86
  42. data/lib/falcon/service/application.rb +0 -99
  43. data/lib/falcon/service/generic.rb +0 -61
  44. data/lib/falcon/service/proxy.rb +0 -49
  45. data/lib/falcon/services.rb +0 -82
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2020-2023, by Samuel Williams.
5
-
6
- load(:tls)
7
-
8
- # A Lets Encrypt SSL context environment.
9
- #
10
- # Derived from {.tls}.
11
- #
12
- # @scope Falcon Environments
13
- # @name lets_encrypt_tls
14
- environment(:lets_encrypt_tls, :tls) do
15
- # The Lets Encrypt certificate store path.
16
- # @parameter [String]
17
- lets_encrypt_root '/etc/letsencrypt/live'
18
-
19
- # The public certificate path.
20
- # @attribute [String]
21
- ssl_certificate_path do
22
- File.join(lets_encrypt_root, authority, "fullchain.pem")
23
- end
24
-
25
- # The private key path.
26
- # @attribute [String]
27
- ssl_private_key_path do
28
- File.join(lets_encrypt_root, authority, "privkey.pem")
29
- end
30
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
5
-
6
- require_relative '../service/proxy'
7
-
8
- # A HTTP proxy environment.
9
- #
10
- # Derived from {.application}.
11
- #
12
- # @scope Falcon Environments
13
- # @name rack
14
- environment(:proxy) do
15
- # The upstream endpoint that will handle incoming requests.
16
- # @attribute [Async::HTTP::Endpoint]
17
- endpoint {::Async::HTTP::Endpoint.parse(url)}
18
-
19
- # The service class to use for the proxy.
20
- # @attribute [Class]
21
- service ::Falcon::Service::Proxy
22
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
5
-
6
- load :application
7
-
8
- # A rack application environment.
9
- #
10
- # Derived from {.application}.
11
- #
12
- # @scope Falcon Environments
13
- # @name rack
14
- environment(:rack, :application) do
15
- # The rack configuration path.
16
- # @attribute [String]
17
- config_path {::File.expand_path("config.ru", root)}
18
-
19
- # Whether to enable the application layer cache.
20
- # @attribute [String]
21
- cache false
22
-
23
- # The middleware stack for the rack application.
24
- # @attribute [Protocol::HTTP::Middleware]
25
- middleware do
26
- app, _ = ::Rack::Builder.parse_file(config_path)
27
-
28
- ::Falcon::Server.middleware(app,
29
- verbose: verbose,
30
- cache: cache
31
- )
32
- end
33
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
5
-
6
- require 'localhost/authority'
7
-
8
- # A self-signed SSL context environment.
9
- #
10
- # @scope Falcon Environments
11
- # @name self_signed_tls
12
- environment(:self_signed_tls) do
13
- # The default session identifier for the session cache.
14
- # @attribute [String]
15
- ssl_session_id {"falcon"}
16
-
17
- # The SSL context to use for incoming connections.
18
- # @attribute [OpenSSL::SSL::SSLContext]
19
- ssl_context do
20
- contexts = Localhost::Authority.fetch(authority)
21
-
22
- contexts.server_context.tap do |context|
23
- context.alpn_select_cb = lambda do |protocols|
24
- if protocols.include? "h2"
25
- return "h2"
26
- elsif protocols.include? "http/1.1"
27
- return "http/1.1"
28
- elsif protocols.include? "http/1.0"
29
- return "http/1.0"
30
- else
31
- return nil
32
- end
33
- end
34
-
35
- context.session_id_context = ssl_session_id
36
- end
37
- end
38
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
5
-
6
- require_relative '../service/supervisor'
7
-
8
- # A application process monitor environment.
9
- #
10
- # @scope Falcon Environments
11
- # @name supervisor
12
- environment(:supervisor) do
13
- # The name of the supervisor
14
- # @attribute [String]
15
- name "supervisor"
16
-
17
- # The IPC path to use for communication with the supervisor.
18
- # @attribute [String]
19
- ipc_path do
20
- ::File.expand_path("supervisor.ipc", root)
21
- end
22
-
23
- # The endpoint the supervisor will bind to.
24
- # @attribute [Async::IO::Endpoint]
25
- endpoint do
26
- Async::IO::Endpoint.unix(ipc_path)
27
- end
28
-
29
- # The service class to use for the supervisor.
30
- # @attribute [Class]
31
- service do
32
- ::Falcon::Service::Supervisor
33
- end
34
- end
@@ -1,86 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
5
-
6
- require_relative '../controller/proxy'
7
- require_relative '../tls'
8
-
9
- # A general SSL context environment.
10
- #
11
- # @scope Falcon Environments
12
- # @name tls
13
- environment(:tls) do
14
- # The default session identifier for the session cache.
15
- # @attribute [String]
16
- ssl_session_id "falcon"
17
-
18
- # The supported ciphers.
19
- # @attribute [Array(String)]
20
- ssl_ciphers Falcon::TLS::SERVER_CIPHERS
21
-
22
- # The public certificate path.
23
- # @attribute [String]
24
- ssl_certificate_path do
25
- File.expand_path("ssl/certificate.pem", root)
26
- end
27
-
28
- # The list of certificates loaded from that path.
29
- # @attribute [Array(OpenSSL::X509::Certificate)]
30
- ssl_certificates do
31
- OpenSSL::X509::Certificate.load_file(ssl_certificate_path)
32
- end
33
-
34
- # The main certificate.
35
- # @attribute [OpenSSL::X509::Certificate]
36
- ssl_certificate {ssl_certificates[0]}
37
-
38
- # The certificate chain.
39
- # @attribute [Array(OpenSSL::X509::Certificate)]
40
- ssl_certificate_chain {ssl_certificates[1..-1]}
41
-
42
- # The private key path.
43
- # @attribute [String]
44
- ssl_private_key_path do
45
- File.expand_path("ssl/private.key", root)
46
- end
47
-
48
- # The private key.
49
- # @attribute [OpenSSL::PKey::RSA]
50
- ssl_private_key do
51
- OpenSSL::PKey::RSA.new(File.read(ssl_private_key_path))
52
- end
53
-
54
- # The SSL context to use for incoming connections.
55
- # @attribute [OpenSSL::SSL::SSLContext]
56
- ssl_context do
57
- OpenSSL::SSL::SSLContext.new.tap do |context|
58
- context.add_certificate(ssl_certificate, ssl_private_key, ssl_certificate_chain)
59
-
60
- context.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT
61
- context.session_id_context = ssl_session_id
62
-
63
- context.alpn_select_cb = lambda do |protocols|
64
- if protocols.include? "h2"
65
- return "h2"
66
- elsif protocols.include? "http/1.1"
67
- return "http/1.1"
68
- elsif protocols.include? "http/1.0"
69
- return "http/1.0"
70
- else
71
- return nil
72
- end
73
- end
74
-
75
- # TODO Ruby 2.4 requires using ssl_version.
76
- context.ssl_version = :TLSv1_2_server
77
-
78
- context.set_params(
79
- ciphers: ssl_ciphers,
80
- verify_mode: OpenSSL::SSL::VERIFY_NONE,
81
- )
82
-
83
- context.setup
84
- end
85
- end
86
- end
@@ -1,99 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
5
- # Copyright, 2020, by Daniel Evans.
6
-
7
- require_relative 'proxy'
8
-
9
- require 'async/http/endpoint'
10
- require 'async/io/shared_endpoint'
11
-
12
- module Falcon
13
- module Service
14
- # Implements an application server using an internal clear-text proxy.
15
- class Application < Proxy
16
- def initialize(environment)
17
- super
18
-
19
- @bound_endpoint = nil
20
- end
21
-
22
- # The middleware that will be served by this application.
23
- # @returns [Protocol::HTTP::Middleware]
24
- def middleware
25
- # In a multi-threaded container, we don't want to modify the shared evaluator's cache, so we create a new evaluator:
26
- @environment.evaluator.middleware
27
- end
28
-
29
- # Number of instances to start.
30
- # @returns [Integer | nil]
31
- def count
32
- @environment.evaluator.count
33
- end
34
-
35
- # Preload any resources specified by the environment.
36
- def preload!
37
- if scripts = @evaluator.preload
38
- scripts.each do |path|
39
- Console.logger.info(self) {"Preloading #{path}..."}
40
- full_path = File.expand_path(path, self.root)
41
- load(full_path)
42
- end
43
- end
44
- end
45
-
46
- # Prepare the bound endpoint for the application instances.
47
- # Invoke {preload!} to load shared resources into the parent process.
48
- def start
49
- Console.logger.info(self) {"Binding to #{self.endpoint}..."}
50
-
51
- @bound_endpoint = Async::Reactor.run do
52
- Async::IO::SharedEndpoint.bound(self.endpoint)
53
- end.wait
54
-
55
- preload!
56
-
57
- super
58
- end
59
-
60
- # Setup instances of the application into the container.
61
- # @parameter container [Async::Container::Generic]
62
- def setup(container)
63
- protocol = self.protocol
64
- scheme = self.scheme
65
-
66
- run_options = {
67
- name: self.name,
68
- restart: true,
69
- }
70
-
71
- run_options[:count] = count unless count.nil?
72
-
73
- container.run(**run_options) do |instance|
74
- Async do |task|
75
- Console.logger.info(self) {"Starting application server for #{self.root}..."}
76
-
77
- server = Server.new(self.middleware, @bound_endpoint, protocol: protocol, scheme: scheme)
78
-
79
- server.run
80
-
81
- instance.ready!
82
-
83
- task.children.each(&:wait)
84
- end
85
- end
86
-
87
- super
88
- end
89
-
90
- # Close the bound endpoint.
91
- def stop
92
- @bound_endpoint&.close
93
- @bound_endpoint = nil
94
-
95
- super
96
- end
97
- end
98
- end
99
- end
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
5
-
6
- module Falcon
7
- module Service
8
- # Captures the stateful behaviour of a specific service.
9
- # Specifies the interfaces required by derived classes.
10
- #
11
- # Designed to be invoked within an {Async::Controller::Container}.
12
- class Generic
13
- # Convert the given environment into a service if possible.
14
- # @parameter environment [Build::Environment] The environment to use to construct the service.
15
- def self.wrap(environment)
16
- evaluator = environment.evaluator
17
- service = evaluator.service || self
18
-
19
- return service.new(environment)
20
- end
21
-
22
- # Initialize the service from the given environment.
23
- # @parameter environment [Build::Environment]
24
- def initialize(environment)
25
- @environment = environment
26
- @evaluator = @environment.evaluator
27
- end
28
-
29
- # Whether the service environment contains the specified keys.
30
- # This is used for matching environment configuration to service behaviour.
31
- def include?(keys)
32
- keys.all?{|key| @environment.include?(key)}
33
- end
34
-
35
- # The name of the service.
36
- # e.g. `myapp.com`.
37
- def name
38
- @evaluator.name
39
- end
40
-
41
- # The logger to use for this service.
42
- # @returns [Console::Logger]
43
- def logger
44
- return Console.logger # .with(name: name)
45
- end
46
-
47
- # Start the service.
48
- def start
49
- end
50
-
51
- # Setup the service into the specified container.
52
- # @parameter container [Async::Container::Generic]
53
- def setup(container)
54
- end
55
-
56
- # Stop the service.
57
- def stop
58
- end
59
- end
60
- end
61
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2020-2023, by Samuel Williams.
5
-
6
- require_relative 'generic'
7
-
8
- require 'async/http/endpoint'
9
- require 'async/io/shared_endpoint'
10
-
11
- module Falcon
12
- module Service
13
- class Proxy < Generic
14
- def name
15
- "#{self.class} for #{self.authority}"
16
- end
17
-
18
- # The host that this proxy will receive connections for.
19
- def authority
20
- @evaluator.authority
21
- end
22
-
23
- # The upstream endpoint that this proxy will connect to.
24
- def endpoint
25
- @evaluator.endpoint
26
- end
27
-
28
- # The {OpenSSL::SSL::SSLContext} that will be used for incoming connections.
29
- def ssl_context
30
- @evaluator.ssl_context
31
- end
32
-
33
- # The root
34
- def root
35
- @evaluator.root
36
- end
37
-
38
- # The protocol this proxy will use to talk to the upstream host.
39
- def protocol
40
- endpoint.protocol
41
- end
42
-
43
- # The scheme this proxy will use to talk to the upstream host.
44
- def scheme
45
- endpoint.scheme
46
- end
47
- end
48
- end
49
- end
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
5
-
6
- require_relative 'service/generic'
7
-
8
- module Falcon
9
- # Represents one or more services associated with a host.
10
- #
11
- # The services model allows falcon to manage one more more service associated with a given host. Some examples of services include:
12
- #
13
- # - Rack applications wrapped by {Service::Application}.
14
- # - Host supervisor implemented in {Service::Supervisor}.
15
- # - Proxy services wrapped by {Service::Proxy}.
16
- #
17
- # The list of services is typically generated from the user supplied `falcon.rb` configuration file, which is loaded into an immutable {Configuration} instance, which is mapped into a list of services.
18
- class Services
19
- # Initialize the services from the given configuration.
20
- #
21
- # @parameter configuration [Configuration]
22
- def initialize(configuration)
23
- @named = {}
24
-
25
- configuration.each(:service) do |environment|
26
- service = Service::Generic.wrap(environment)
27
-
28
- add(service)
29
- end
30
- end
31
-
32
- # Enumerate all named services.
33
- def each(&block)
34
- @named.each_value(&block)
35
- end
36
-
37
- # Add a named service.
38
- #
39
- # @parameter service [Service]
40
- def add(service)
41
- @named[service.name] = service
42
- end
43
-
44
- # Start all named services.
45
- def start
46
- @named.each do |name, service|
47
- Console.logger.debug(self) {"Starting #{name}..."}
48
- service.start
49
- end
50
- end
51
-
52
- # Setup all named services into the given container.
53
- #
54
- # @parameter container [Async::Container::Generic]
55
- def setup(container)
56
- @named.each do |name, service|
57
- Console.logger.debug(self) {"Setup #{name} into #{container}..."}
58
- service.setup(container)
59
- end
60
-
61
- return container
62
- end
63
-
64
- # Stop all named services.
65
- def stop
66
- failed = false
67
-
68
- @named.each do |name, service|
69
- Console.logger.debug(self) {"Stopping #{name}..."}
70
-
71
- begin
72
- service.stop
73
- rescue => error
74
- failed = true
75
- Console.logger.error(self, error)
76
- end
77
- end
78
-
79
- return failed
80
- end
81
- end
82
- end