tipi 0.41 → 0.46

Sign up to get free protection for your applications and to get access to all the features.
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'