tipi 0.41 → 0.46

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/test.yml +3 -1
  4. data/.gitignore +3 -1
  5. data/CHANGELOG.md +34 -0
  6. data/Gemfile +7 -1
  7. data/Gemfile.lock +53 -33
  8. data/README.md +184 -8
  9. data/Rakefile +1 -7
  10. data/benchmarks/bm_http1_parser.rb +85 -0
  11. data/bin/benchmark +37 -0
  12. data/bin/h1pd +6 -0
  13. data/bin/tipi +3 -21
  14. data/bm.png +0 -0
  15. data/df/agent.rb +1 -1
  16. data/df/sample_agent.rb +2 -2
  17. data/df/server.rb +3 -1
  18. data/df/server_utils.rb +48 -46
  19. data/examples/full_service.rb +13 -0
  20. data/examples/hello.rb +5 -0
  21. data/examples/hello.ru +3 -3
  22. data/examples/http1_parser.rb +10 -8
  23. data/examples/http_server.js +1 -1
  24. data/examples/http_server.rb +4 -1
  25. data/examples/http_server_graceful.rb +1 -1
  26. data/examples/https_server.rb +41 -15
  27. data/examples/rack_server_forked.rb +26 -0
  28. data/examples/rack_server_https_forked.rb +1 -1
  29. data/examples/servername_cb.rb +37 -0
  30. data/examples/websocket_demo.rb +1 -1
  31. data/lib/tipi/acme.rb +320 -0
  32. data/lib/tipi/cli.rb +93 -0
  33. data/lib/tipi/config_dsl.rb +13 -13
  34. data/lib/tipi/configuration.rb +2 -2
  35. data/lib/tipi/controller/bare_polyphony.rb +0 -0
  36. data/lib/tipi/controller/bare_stock.rb +10 -0
  37. data/lib/tipi/controller/extensions.rb +37 -0
  38. data/lib/tipi/controller/stock_http1_adapter.rb +15 -0
  39. data/lib/tipi/controller/web_polyphony.rb +353 -0
  40. data/lib/tipi/controller/web_stock.rb +635 -0
  41. data/lib/tipi/controller.rb +12 -0
  42. data/lib/tipi/digital_fabric/agent.rb +5 -5
  43. data/lib/tipi/digital_fabric/agent_proxy.rb +15 -8
  44. data/lib/tipi/digital_fabric/executive.rb +7 -3
  45. data/lib/tipi/digital_fabric/protocol.rb +3 -3
  46. data/lib/tipi/digital_fabric/request_adapter.rb +0 -4
  47. data/lib/tipi/digital_fabric/service.rb +17 -18
  48. data/lib/tipi/handler.rb +2 -2
  49. data/lib/tipi/http1_adapter.rb +85 -124
  50. data/lib/tipi/http2_adapter.rb +29 -16
  51. data/lib/tipi/http2_stream.rb +52 -57
  52. data/lib/tipi/rack_adapter.rb +2 -2
  53. data/lib/tipi/response_extensions.rb +1 -1
  54. data/lib/tipi/supervisor.rb +75 -0
  55. data/lib/tipi/version.rb +1 -1
  56. data/lib/tipi/websocket.rb +3 -3
  57. data/lib/tipi.rb +9 -7
  58. data/test/coverage.rb +2 -2
  59. data/test/helper.rb +60 -12
  60. data/test/test_http_server.rb +14 -41
  61. data/test/test_request.rb +2 -29
  62. data/tipi.gemspec +10 -10
  63. metadata +80 -54
  64. data/examples/automatic_certificate.rb +0 -193
  65. data/ext/tipi/extconf.rb +0 -12
  66. data/ext/tipi/http1_parser.c +0 -534
  67. data/ext/tipi/http1_parser.h +0 -18
  68. data/ext/tipi/tipi_ext.c +0 -5
  69. data/lib/tipi/http1_adapter_new.rb +0 -293
@@ -1,193 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/setup'
4
- require 'tipi'
5
- require 'openssl'
6
- require 'acme-client'
7
-
8
- # ::Exception.__disable_sanitized_backtrace__ = true
9
-
10
- class CertificateManager
11
- def initialize(store:, challenge_handler:)
12
- @store = store
13
- @challenge_handler = challenge_handler
14
- @workers = {}
15
- @contexts = {}
16
- end
17
-
18
- def [](name)
19
- worker = worker_for_name(name)
20
- p worker: worker
21
-
22
- worker << Fiber.current
23
- # cancel_after(30) { receive }
24
- receive.tap { |ctx| p got_ctx: ctx }
25
- rescue Exception => e
26
- p e
27
- puts e.backtrace.join("\n")
28
- nil
29
- end
30
-
31
- def worker_for_name(name)
32
- @workers[name] ||= spin { worker_loop(name) }
33
- end
34
-
35
- def worker_loop(name)
36
- while (client = receive)
37
- puts "get request for #{name} from #{client.inspect}"
38
- ctx = get_context(name)
39
- client << ctx rescue nil
40
- end
41
- end
42
-
43
- def get_context(name)
44
- @contexts[name] ||= setup_context(name)
45
- end
46
-
47
- CERTIFICATE_REGEXP = /(-----BEGIN CERTIFICATE-----\n[^-]+-----END CERTIFICATE-----\n)/.freeze
48
-
49
- def setup_context(name)
50
- certificate = get_certificate(name)
51
- ctx = OpenSSL::SSL::SSLContext.new
52
- chain = certificate.scan(CERTIFICATE_REGEXP).map { |p| OpenSSL::X509::Certificate.new(p.first) }
53
- cert = chain.shift
54
- puts "Certificate expires: #{cert.not_after.inspect}"
55
- ctx.add_certificate(cert, private_key, chain)
56
- Polyphony::Net.setup_alpn(ctx, Tipi::ALPN_PROTOCOLS)
57
- ctx
58
- end
59
-
60
- def get_certificate(name)
61
- @store[name] ||= provision_certificate(name)
62
- end
63
-
64
- def private_key
65
- @private_key ||= OpenSSL::PKey::RSA.new(4096)
66
- end
67
-
68
- ACME_DIRECTORY = 'https://acme-staging-v02.api.letsencrypt.org/directory'
69
-
70
- def acme_client
71
- @acme_client ||= setup_acme_client
72
- end
73
-
74
- def setup_acme_client
75
- client = Acme::Client.new(
76
- private_key: private_key,
77
- directory: ACME_DIRECTORY
78
- )
79
- p client: client
80
- account = client.new_account(
81
- contact: 'mailto:info@noteflakes.com',
82
- terms_of_service_agreed: true
83
- )
84
- p account: account.kid
85
- client
86
- end
87
-
88
- def provision_certificate(name)
89
- order = acme_client.new_order(identifiers: [name])
90
- p order: true
91
- authorization = order.authorizations.first
92
- p authorization: authorization
93
- challenge = authorization.http
94
- p challenge: challenge
95
-
96
- @challenge_handler.add(challenge)
97
- challenge.request_validation
98
- p challenge_status: challenge.status
99
- while challenge.status == 'pending'
100
- sleep(1)
101
- challenge.reload
102
- p challenge_status: challenge.status
103
- end
104
-
105
- csr = Acme::Client::CertificateRequest.new(private_key: @private_key, subject: { common_name: name })
106
- p csr: csr
107
- order.finalize(csr: csr)
108
- p order_status: order.status
109
- while order.status == 'processing'
110
- sleep(1)
111
- order.reload
112
- p order_status: order.status
113
- end
114
- order.certificate.tap { |c| p certificate: c } # => PEM-formatted certificate
115
- end
116
- end
117
-
118
- class AcmeHTTPChallengeHandler
119
- def initialize
120
- @challenges = {}
121
- end
122
-
123
- def add(challenge)
124
- path = "/.well-known/acme-challenge/#{challenge.token}"
125
- @challenges[path] = challenge
126
- end
127
-
128
- def call(req)
129
- # handle incoming request
130
- challenge = @challenges[req.path]
131
- return req.respond(nil, ':status' => 400) unless challenge
132
-
133
- req.respond(challenge.file_content, 'content-type' => challenge.content_type)
134
- @challenges.delete(req.path)
135
- end
136
- end
137
-
138
- challenge_handler = AcmeHTTPChallengeHandler.new
139
- certificate_manager = CertificateManager.new(
140
- store: {},
141
- challenge_handler: challenge_handler
142
- )
143
-
144
- http_handler = Tipi.route do |r|
145
- r.on('/.well-known/acme-challenge') { challenge_handler.call(r) }
146
- r.default { r.redirect "https://#{r.host}#{r.path}" }
147
- end
148
-
149
- https_handler = ->(r) { r.respond('Hello, world!') }
150
-
151
- http_listener = spin do
152
- opts = {
153
- reuse_addr: true,
154
- dont_linger: true,
155
- }
156
- puts 'Listening for HTTP on localhost:10080'
157
- Tipi.serve('0.0.0.0', 10080, opts, &http_handler)
158
- end
159
-
160
- https_listener = spin do
161
- ctx = OpenSSL::SSL::SSLContext.new
162
- ctx.servername_cb = proc { |_, name| p name: name; certificate_manager[name] }
163
- opts = {
164
- reuse_addr: true,
165
- dont_linger: true,
166
- secure_context: ctx,
167
- alpn_protocols: Tipi::ALPN_PROTOCOLS
168
- }
169
-
170
- puts 'Listening for HTTPS on localhost:10443'
171
- server = Polyphony::Net.tcp_listen('0.0.0.0', 10443, opts)
172
- server.accept_loop do |client|
173
- spin do
174
- service.incr_connection_count
175
- Tipi.client_loop(client, opts) { |req| service.http_request(req) }
176
- ensure
177
- service.decr_connection_count
178
- end
179
- rescue Exception => e
180
- puts "HTTPS accept_loop error: #{e.inspect}"
181
- puts e.backtrace.join("\n")
182
- end
183
- end
184
-
185
- begin
186
- Fiber.await(http_listener, https_listener)
187
- rescue Interrupt
188
- puts "Got SIGINT, terminating"
189
- rescue Exception => e
190
- puts '*' * 40
191
- p e
192
- puts e.backtrace.join("\n")
193
- end
data/ext/tipi/extconf.rb DELETED
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rubygems'
4
- require 'mkmf'
5
-
6
- $CFLAGS << " -Wno-pointer-arith"
7
-
8
- CONFIG['optflags'] << ' -fno-strict-aliasing' unless RUBY_PLATFORM =~ /mswin/
9
-
10
-
11
- dir_config 'tipi_ext'
12
- create_makefile 'tipi_ext'