falcon 0.36.3 → 0.37.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/lib/falcon/adapters/input.rb +32 -11
  3. data/lib/falcon/adapters/output.rb +20 -1
  4. data/lib/falcon/adapters/rack.rb +60 -39
  5. data/lib/falcon/adapters/response.rb +23 -1
  6. data/lib/falcon/adapters/rewindable.rb +10 -3
  7. data/lib/falcon/command.rb +2 -0
  8. data/lib/falcon/command/host.rb +13 -2
  9. data/lib/falcon/command/paths.rb +4 -0
  10. data/lib/falcon/command/proxy.rb +14 -0
  11. data/lib/falcon/command/redirect.rb +12 -0
  12. data/lib/falcon/command/serve.rb +22 -15
  13. data/lib/falcon/command/supervisor.rb +15 -1
  14. data/lib/falcon/command/top.rb +16 -0
  15. data/lib/falcon/command/virtual.rb +15 -0
  16. data/lib/falcon/configuration.rb +69 -7
  17. data/lib/falcon/controller/host.rb +12 -0
  18. data/lib/falcon/controller/proxy.rb +13 -0
  19. data/lib/falcon/controller/redirect.rb +7 -0
  20. data/lib/falcon/controller/serve.rb +17 -2
  21. data/lib/falcon/controller/virtual.rb +17 -0
  22. data/lib/falcon/endpoint.rb +8 -0
  23. data/lib/falcon/{configuration/proxy.rb → environments.rb} +9 -5
  24. data/lib/falcon/environments/application.rb +72 -0
  25. data/lib/falcon/{configuration/application.rb → environments/lets_encrypt_tls.rb} +21 -20
  26. data/lib/falcon/{configuration/lets_encrypt_tls.rb → environments/proxy.rb} +13 -6
  27. data/lib/falcon/{configuration → environments}/rack.rb +14 -2
  28. data/lib/falcon/{configuration → environments}/self_signed_tls.rb +9 -1
  29. data/lib/falcon/{configuration → environments}/supervisor.rb +19 -5
  30. data/lib/falcon/{configuration → environments}/tls.rb +39 -5
  31. data/lib/falcon/extensions/openssl.rb +1 -0
  32. data/lib/falcon/middleware/proxy.rb +26 -5
  33. data/lib/falcon/middleware/redirect.rb +11 -0
  34. data/lib/falcon/{verbose.rb → middleware/verbose.rb} +34 -26
  35. data/lib/falcon/proxy_endpoint.rb +21 -0
  36. data/lib/falcon/server.rb +8 -2
  37. data/lib/falcon/service/application.rb +24 -2
  38. data/lib/falcon/service/generic.rb +18 -0
  39. data/lib/falcon/service/proxy.rb +6 -0
  40. data/lib/falcon/service/supervisor.rb +13 -1
  41. data/lib/falcon/services.rb +21 -0
  42. data/lib/falcon/tls.rb +4 -2
  43. data/lib/falcon/version.rb +1 -1
  44. data/lib/rack/handler/falcon.rb +8 -2
  45. metadata +65 -122
  46. data/.editorconfig +0 -5
  47. data/.github/FUNDING.yml +0 -3
  48. data/.github/workflows/development.yml +0 -60
  49. data/.gitignore +0 -14
  50. data/.rspec +0 -3
  51. data/Gemfile +0 -17
  52. data/README.md +0 -316
  53. data/examples/beer/config.ru +0 -57
  54. data/examples/beer/falcon.rb +0 -8
  55. data/examples/benchmark/config.ru +0 -39
  56. data/examples/benchmark/falcon.rb +0 -6
  57. data/examples/csv/config.ru +0 -31
  58. data/examples/google/falcon.rb +0 -14
  59. data/examples/hello/config.ru +0 -22
  60. data/examples/hello/falcon.rb +0 -24
  61. data/examples/hello/preload.rb +0 -7
  62. data/examples/internet/config.ru +0 -54
  63. data/examples/memory/allocations.rb +0 -39
  64. data/examples/memory/config.ru +0 -14
  65. data/examples/push/client.rb +0 -29
  66. data/examples/push/config.ru +0 -28
  67. data/examples/push/index.html +0 -14
  68. data/examples/push/script.js +0 -2
  69. data/examples/push/style.css +0 -4
  70. data/examples/redis/Gemfile +0 -9
  71. data/examples/redis/config.ru +0 -28
  72. data/examples/sequel/Gemfile +0 -4
  73. data/examples/sequel/config.ru +0 -8
  74. data/examples/sequel/data.sqlite3 +0 -0
  75. data/examples/server/standalone.rb +0 -27
  76. data/examples/sinatra/Gemfile +0 -7
  77. data/examples/sinatra/Gemfile.lock +0 -53
  78. data/examples/sinatra/config.ru +0 -16
  79. data/examples/trailers/config.ru +0 -34
  80. data/examples/trailers/falcon.rb +0 -8
  81. data/falcon.gemspec +0 -45
  82. data/gems/rack1.gemfile +0 -4
  83. data/gems/rack3.gemfile +0 -4
  84. data/lib/falcon/adapters/early_hints.rb +0 -49
  85. data/logo-square.afdesign +0 -0
  86. data/logo.afdesign +0 -0
  87. data/logo.svg +0 -107
  88. data/server.rb +0 -21
  89. data/tasks/benchmark.rake +0 -103
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env falcon-host
2
- # frozen_string_literal: true
3
-
4
- load :rack, :self_signed_tls, :supervisor
5
-
6
- rack 'beer.localhost', :self_signed_tls
7
-
8
- supervisor
@@ -1,39 +0,0 @@
1
- #!/usr/bin/env falcon --verbose serve -c
2
- # frozen_string_literal: true
3
-
4
- class Benchmark
5
- def initialize(app)
6
- @app = app
7
- end
8
-
9
- PATH_INFO = 'PATH_INFO'.freeze
10
-
11
- SMALL = [200, {}, ["Hello World\n" * 10] * 10].freeze
12
-
13
- def small(env)
14
- SMALL
15
- end
16
-
17
- BIG = [200, {}, ["Hello World\n" * 1000] * 1000].freeze
18
-
19
- def big(env)
20
- BIG
21
- end
22
-
23
- def call(env)
24
- _, name, *path = env[PATH_INFO].split("/")
25
-
26
- method = name&.to_sym
27
-
28
- if method and self.respond_to?(method)
29
- self.send(method, env)
30
- else
31
- @app.call(env)
32
- end
33
- end
34
- end
35
-
36
- use Benchmark
37
-
38
- run lambda {|env| [200, {}, ["Hello World"]]}
39
-
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env -S ./bin/falcon virtual
2
- # frozen_string_literal: true
3
-
4
- load :rack, :self_signed_tls, :supervisor
5
-
6
- rack 'benchmark.local', :self_signed_tls
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env falcon --verbose serve -c
2
- # frozen_string_literal: true
3
-
4
- class MyApp
5
- def initialize(app)
6
- @app = app
7
-
8
- @words = File.readlines('/usr/share/dict/words', chomp: true).each_slice(3).to_a
9
- end
10
-
11
- def call(env)
12
- body = Async::HTTP::Body::Writable.new(queue: Async::LimitedQueue.new(8))
13
-
14
- Async do |task|
15
- @words.each do |words|
16
- Async.logger.debug("Sending #{words.inspect}")
17
- body.write(words.join(",") + "\n")
18
- task.sleep(1)
19
- end
20
- ensure
21
- body.close($!)
22
- end
23
-
24
- return [200, [], body]
25
- end
26
- end
27
-
28
- # Build the middleware stack:
29
- use MyApp
30
-
31
- run lambda {|env| [404, {}, []]}
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env falcon-host
2
- # frozen_string_literal: true
3
-
4
- load :proxy, :self_signed_tls, :supervisor
5
-
6
- supervisor
7
-
8
- proxy "google.localhost", :self_signed_tls do
9
- url 'https://www.google.com'
10
- end
11
-
12
- proxy "codeotaku.localhost", :self_signed_tls do
13
- url 'https://www.codeotaku.com'
14
- end
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env falcon --verbose serve -c
2
- # frozen_string_literal: true
3
-
4
- require 'async'
5
-
6
- class RequestLogger
7
- def initialize(app)
8
- @app = app
9
- end
10
-
11
- def call(env)
12
- logger = Async.logger.with(level: :debug)
13
-
14
- Async(logger: logger) do
15
- @app.call(env)
16
- end.wait
17
- end
18
- end
19
-
20
- # use RequestLogger
21
-
22
- run lambda {|env| [200, {'cache-control' => 'max-age=10, public'}, ["Hello World"]]}
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env falcon-host
2
- # frozen_string_literal: true
3
-
4
- load :rack, :self_signed_tls, :supervisor
5
-
6
- supervisor
7
-
8
- rack 'hello.localhost', :self_signed_tls do
9
- # scheme 'http'
10
- # protocol {Async::HTTP::Protocol::HTTP1}
11
- #
12
- # endpoint do
13
- # Async::HTTP::Endpoint.for(scheme, "localhost", port: 9292, protocol: protocol)
14
- # end
15
-
16
- append preload "preload.rb"
17
-
18
- # Process will connect to supervisor to report statistics periodically, otherwise it would be killed.
19
- # report :supervisor
20
- end
21
-
22
- # service 'jobs' do
23
- # shell ['rake', 'background:jobs:process']
24
- # end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- if GC.respond_to?(:compact)
4
- Async.logger.warn(self, "Compacting the mainframe...")
5
- GC.compact
6
- Async.logger.warn(self, "Compacting done...")
7
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'async'
4
- require 'async/http/internet'
5
-
6
- # Experimental.
7
- require 'kernel/sync'
8
-
9
- class Search
10
- def initialize(app)
11
- @internet = Async::HTTP::Internet.new
12
-
13
- @app = app
14
- end
15
-
16
- # This method uses the `Async` method to create a reactor if required, and then executes the contained code without waiting for the result. So even if the search query takes a long time (e.g. 100ms), it won't hold up the request processing.
17
- def async(close: !Async::Task.current?)
18
- Async do
19
- response = @internet.get("https://google.com/search?q=async+ruby")
20
-
21
- puts response.inspect
22
- ensure
23
- response&.finish
24
- end
25
- end
26
-
27
- # This method uses the experimental `Sync` method to create a reactor if required. If the code is already running in a reactor, it runs synchronously, otherwise it's effectively the same as `Async` and a blocking operation. This allow you to write efficient non-blocking code that works in both traditional web application servers, but gains additional scalability in `Async`-aware servers like Falcon.
28
- # You can achieve a similar result by calling `Async{}.wait`, but this is less efficient as it will allocate a sub-task even thought it's not needed.
29
- def sync(close: !Async::Task.current?)
30
- Sync do
31
- response = @internet.get("https://google.com/search?q=async+ruby")
32
-
33
- puts response.inspect
34
- ensure
35
- response&.finish
36
- end
37
- end
38
-
39
- # The only point of this is to invoke one of the above two methods.
40
- def call(env)
41
- case env['PATH_INFO']
42
- when '/sync'
43
- self.sync
44
- when '/async'
45
- self.async
46
- end
47
-
48
- return @app.call(env)
49
- end
50
- end
51
-
52
- use Search
53
-
54
- run lambda{|env| [404, [], []]}
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Allocations
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def allocations
9
- counts = Hash.new{|h,k| h[k] = 0}
10
-
11
- ObjectSpace.each_object do |object|
12
- counts[object.class] += 1
13
- end
14
-
15
- return counts
16
- end
17
-
18
- def print_allocations(minimum = 100)
19
- buffer = StringIO.new
20
-
21
- total = allocations.values.sum
22
-
23
- allocations.select{|k,v| v >= minimum}.sort_by{|k,v| -v}.each do |key, value|
24
- buffer.puts "#{key}: #{value} allocations"
25
- end
26
-
27
- buffer.puts "** Total: #{total} allocations."
28
-
29
- return buffer.string
30
- end
31
-
32
- def call(env)
33
- if env["PATH_INFO"] == "/allocations"
34
- return [200, [], [print_allocations]]
35
- else
36
- return @app.call(env)
37
- end
38
- end
39
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'allocations'
4
-
5
- use Allocations
6
-
7
- run lambda{|env| [404, [], []]}
8
-
9
- # % curl --insecure https://localhost:9292/allocations
10
- # String: 32179 allocations
11
- # Array: 10228 allocations
12
- # Hash: 1299 allocations
13
- # Class: 1118 allocations
14
- # ** Total: 50162 allocations.
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'async'
5
- require 'async/http/endpoint'
6
- require 'async/http/client'
7
-
8
- Async do
9
- endpoint = Async::HTTP::Endpoint.parse("https://localhost:9292")
10
- client = Async::HTTP::Client.new(endpoint, Async::HTTP::Protocol::HTTP2::WithPush)
11
-
12
- response = client.get("/index.html")
13
-
14
- puts response.status
15
- puts response.read
16
- puts
17
-
18
- while promise = response.promises.dequeue
19
- promise.wait
20
-
21
- puts "** Promise: #{promise.request.path} **"
22
- puts promise.read
23
- puts
24
- end
25
- ensure
26
- client.close
27
- end
28
-
29
- puts "Done"
@@ -1,28 +0,0 @@
1
- #!/usr/bin/env falcon --verbose serve --concurrency 1 --config
2
- # frozen_string_literal: true
3
-
4
- class EarlyHints
5
- def initialize(app)
6
- @app = app
7
- end
8
-
9
- def call(env)
10
- path = env['PATH_INFO']
11
- early_hints = early_hints = env['rack.early_hints']
12
-
13
- Async.logger.debug("path: #{path} #{early_hints}")
14
-
15
- if path == "/index.html" and early_hints
16
- early_hints.push("/style.css")
17
- early_hints.push("/script.js")
18
- end
19
-
20
- @app.call(env)
21
- end
22
- end
23
-
24
- use EarlyHints
25
-
26
- use Rack::Static, :urls => [""], :root => __dir__, :index => 'index.html'
27
-
28
- run lambda{|env| [404, [], ["Not Found"]]}
@@ -1,14 +0,0 @@
1
- <!doctype HTML>
2
- <html>
3
- <head>
4
- <title>Hello World</title>
5
-
6
- <link rel="stylesheet" href="/style.css" />
7
- <script type="text/javascript" src="script.js"></script>
8
- </head>
9
- <body>
10
- <h1>Early Hints</h1>
11
-
12
- <p>Check the developer tools to see if early hints worked!</p>
13
- </body>
14
- </html>
@@ -1,2 +0,0 @@
1
-
2
- console.log("Hello World")
@@ -1,4 +0,0 @@
1
-
2
- html {
3
- font-family: Helvetica;
4
- }
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # A sample Gemfile
4
- source "https://rubygems.org"
5
-
6
- gem "sinatra"
7
- gem "falcon"
8
-
9
- gem "async-redis", ">= 0.3.1"
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'sinatra/base'
4
- require 'async/redis'
5
- require 'async/clock'
6
-
7
- CLIENT = Async::Redis::Client.new(Async::Redis.local_endpoint)
8
-
9
- class MyApp < Sinatra::Base
10
- get "/" do
11
- puts "Starting BLPOP SLEEP..."
12
- duration = Async::Clock.measure do
13
- CLIENT.call "BLPOP", "SLEEP", 1
14
- end
15
- puts "Finished BLPOP SLEEP after #{duration.round(2)}s"
16
-
17
- "ok"
18
- end
19
- end
20
-
21
- use MyApp # Then, it will get to Sinatra.
22
- run lambda {|env| [404, {}, []]} # Bottom of the stack, give 404.
23
-
24
- # Start server like this:
25
- # falcon --verbose serve --threaded --count 1 --bind http://localhost:9292
26
-
27
- # Test server, e.g.:
28
- # time ab -n 64 -c 64 http://localhost:9292/
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'falcon'
4
- gem 'sequel'
@@ -1,8 +0,0 @@
1
- # config.ru
2
- require 'sequel'
3
-
4
- # Turn on single threaded mode
5
- Sequel.single_threaded = true
6
- DB = Sequel.sqlite('data.sqlite3')
7
-
8
- run(proc{|env| [200, {}, [DB[:user].get(:name)]]})
Binary file
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'async'
4
- require 'async/http/endpoint'
5
- require 'async/websocket/adapters/rack'
6
-
7
- require 'falcon'
8
-
9
- module WebSocketApp
10
- def self.call(env)
11
- Async::WebSocket::Adapters::Rack.open(env, protocols: %w[ws]) do |connection|
12
- while (message = connection.read)
13
- pp message
14
- end
15
- end or [200, [], ["Websocket only."]]
16
- end
17
- end
18
-
19
- Async do
20
- websocket_endpoint = Async::HTTP::Endpoint.parse('http://127.0.0.1:3000')
21
-
22
- app = Falcon::Server.middleware(WebSocketApp)
23
-
24
- server = Falcon::Server.new(app, websocket_endpoint)
25
-
26
- server.run.each(&:wait)
27
- end