tipi 0.43 → 0.45
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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/test.yml +1 -3
- data/CHANGELOG.md +12 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +14 -7
- data/README.md +184 -8
- data/Rakefile +1 -7
- data/benchmarks/bm_http1_parser.rb +1 -1
- data/bin/benchmark +0 -0
- data/bin/h1pd +0 -0
- data/bm.png +0 -0
- data/df/agent.rb +1 -1
- data/df/sample_agent.rb +2 -2
- data/df/server_utils.rb +1 -1
- data/examples/hello.rb +5 -0
- data/examples/http_server.js +1 -1
- data/examples/http_server_graceful.rb +1 -1
- data/examples/https_server.rb +41 -18
- data/examples/rack_server_forked.rb +26 -0
- data/examples/rack_server_https_forked.rb +1 -1
- data/examples/websocket_demo.rb +1 -1
- data/lib/tipi/acme.rb +46 -39
- data/lib/tipi/cli.rb +79 -16
- data/lib/tipi/config_dsl.rb +13 -13
- data/lib/tipi/configuration.rb +2 -2
- data/lib/tipi/controller/bare_polyphony.rb +0 -0
- data/lib/tipi/controller/bare_stock.rb +10 -0
- data/lib/tipi/controller/stock_http1_adapter.rb +15 -0
- data/lib/tipi/controller/web_polyphony.rb +351 -0
- data/lib/tipi/controller/web_stock.rb +631 -0
- data/lib/tipi/controller.rb +12 -0
- data/lib/tipi/digital_fabric/agent.rb +3 -3
- data/lib/tipi/digital_fabric/agent_proxy.rb +11 -5
- data/lib/tipi/digital_fabric/executive.rb +1 -1
- data/lib/tipi/digital_fabric/protocol.rb +1 -1
- data/lib/tipi/digital_fabric/service.rb +8 -8
- data/lib/tipi/handler.rb +2 -2
- data/lib/tipi/http1_adapter.rb +32 -27
- data/lib/tipi/http2_adapter.rb +10 -10
- data/lib/tipi/http2_stream.rb +14 -14
- data/lib/tipi/rack_adapter.rb +2 -2
- data/lib/tipi/response_extensions.rb +1 -1
- data/lib/tipi/supervisor.rb +75 -0
- data/lib/tipi/version.rb +1 -1
- data/lib/tipi/websocket.rb +3 -3
- data/lib/tipi.rb +4 -83
- data/test/coverage.rb +2 -2
- data/test/test_http_server.rb +14 -14
- data/tipi.gemspec +3 -2
- metadata +30 -5
data/lib/tipi.rb
CHANGED
@@ -17,7 +17,7 @@ end
|
|
17
17
|
module Tipi
|
18
18
|
ALPN_PROTOCOLS = %w[h2 http/1.1].freeze
|
19
19
|
H2_PROTOCOL = 'h2'
|
20
|
-
|
20
|
+
|
21
21
|
class << self
|
22
22
|
def serve(host, port, opts = {}, &handler)
|
23
23
|
opts[:alpn_protocols] = ALPN_PROTOCOLS
|
@@ -26,7 +26,7 @@ module Tipi
|
|
26
26
|
ensure
|
27
27
|
server&.close
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def listen(host, port, opts = {})
|
31
31
|
opts[:alpn_protocols] = ALPN_PROTOCOLS
|
32
32
|
Polyphony::Net.tcp_listen(host, port, opts).tap do |socket|
|
@@ -35,7 +35,7 @@ module Tipi
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def accept_loop(server, opts, &handler)
|
40
40
|
server.accept_loop do |client|
|
41
41
|
spin { client_loop(client, opts, &handler) }
|
@@ -43,7 +43,7 @@ module Tipi
|
|
43
43
|
# disregard
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
def client_loop(client, opts, &handler)
|
48
48
|
client.no_delay if client.respond_to?(:no_delay)
|
49
49
|
adapter = protocol_adapter(client, opts)
|
@@ -62,84 +62,5 @@ module Tipi
|
|
62
62
|
def route(&block)
|
63
63
|
proc { |req| req.route(&block) }
|
64
64
|
end
|
65
|
-
|
66
|
-
CERTIFICATE_STORE_DEFAULT_DIR = File.expand_path('~/.tipi')
|
67
|
-
CERTIFICATE_STORE_DEFAULT_DB_PATH = File.join(
|
68
|
-
CERTIFICATE_STORE_DEFAULT_DIR, 'certificates.db'
|
69
|
-
)
|
70
|
-
|
71
|
-
def default_certificate_store
|
72
|
-
FileUtils.mkdir(CERTIFICATE_STORE_DEFAULT_DIR) rescue nil
|
73
|
-
Tipi::ACME::SQLiteCertificateStore.new(CERTIFICATE_STORE_DEFAULT_DB_PATH)
|
74
|
-
end
|
75
|
-
|
76
|
-
def full_service(
|
77
|
-
http_port: 10080,
|
78
|
-
https_port: 10443,
|
79
|
-
certificate_store: default_certificate_store,
|
80
|
-
app: nil, &block
|
81
|
-
)
|
82
|
-
app ||= block
|
83
|
-
raise "No app given" unless app
|
84
|
-
|
85
|
-
http_handler = ->(r) { r.redirect("https://#{r.host}#{r.path}") }
|
86
|
-
|
87
|
-
ctx = OpenSSL::SSL::SSLContext.new
|
88
|
-
# ctx.ciphers = 'ECDH+aRSA'
|
89
|
-
Polyphony::Net.setup_alpn(ctx, Tipi::ALPN_PROTOCOLS)
|
90
|
-
|
91
|
-
challenge_handler = Tipi::ACME::HTTPChallengeHandler.new
|
92
|
-
certificate_manager = Tipi::ACME::CertificateManager.new(
|
93
|
-
master_ctx: ctx,
|
94
|
-
store: certificate_store,
|
95
|
-
challenge_handler: challenge_handler
|
96
|
-
)
|
97
|
-
|
98
|
-
http_listener = spin do
|
99
|
-
opts = {
|
100
|
-
reuse_addr: true,
|
101
|
-
reuse_port: true,
|
102
|
-
dont_linger: true,
|
103
|
-
}
|
104
|
-
puts "Listening for HTTP on localhost:#{http_port}"
|
105
|
-
server = Polyphony::Net.tcp_listen('0.0.0.0', http_port, opts)
|
106
|
-
wrapped_handler = certificate_manager.challenge_routing_app(http_handler)
|
107
|
-
server.accept_loop do |client|
|
108
|
-
spin do
|
109
|
-
Tipi.client_loop(client, opts, &wrapped_handler)
|
110
|
-
rescue => e
|
111
|
-
puts "Uncaught error in HTTP listener: #{e.inspect}"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
ensure
|
115
|
-
server.close
|
116
|
-
end
|
117
|
-
|
118
|
-
https_listener = spin do
|
119
|
-
opts = {
|
120
|
-
reuse_addr: true,
|
121
|
-
reuse_port: true,
|
122
|
-
dont_linger: true,
|
123
|
-
secure_context: ctx,
|
124
|
-
}
|
125
|
-
|
126
|
-
puts "Listening for HTTPS on localhost:#{https_port}"
|
127
|
-
server = Polyphony::Net.tcp_listen('0.0.0.0', https_port, opts)
|
128
|
-
loop do
|
129
|
-
client = server.accept
|
130
|
-
spin do
|
131
|
-
Tipi.client_loop(client, opts, &app)
|
132
|
-
rescue => e
|
133
|
-
puts "Uncaught error in HTTPS listener: #{e.inspect}"
|
134
|
-
end
|
135
|
-
rescue OpenSSL::SSL::SSLError, SystemCallError, TypeError
|
136
|
-
# ignore
|
137
|
-
end
|
138
|
-
ensure
|
139
|
-
server.close
|
140
|
-
end
|
141
|
-
|
142
|
-
Fiber.await(http_listener, https_listener)
|
143
|
-
end
|
144
65
|
end
|
145
66
|
end
|
data/test/coverage.rb
CHANGED
@@ -26,10 +26,10 @@ module Coverage
|
|
26
26
|
@result = {}
|
27
27
|
trace = TracePoint.new(:line) do |tp|
|
28
28
|
next if tp.path =~ /\(/
|
29
|
-
|
29
|
+
|
30
30
|
absolute = File.expand_path(tp.path)
|
31
31
|
next unless LIB_FILES.include?(absolute)# =~ /^#{LIB_DIR}/
|
32
|
-
|
32
|
+
|
33
33
|
@result[absolute] ||= relevant_lines_for_filename(absolute)
|
34
34
|
@result[absolute][tp.lineno - 1] = 1
|
35
35
|
end
|
data/test/test_http_server.rb
CHANGED
@@ -4,7 +4,7 @@ require_relative 'helper'
|
|
4
4
|
require 'tipi'
|
5
5
|
|
6
6
|
class String
|
7
|
-
def
|
7
|
+
def crlf_lines
|
8
8
|
gsub "\n", "\r\n"
|
9
9
|
end
|
10
10
|
end
|
@@ -33,7 +33,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
33
33
|
connection << "GET / HTTP/1.0\r\n\r\n"
|
34
34
|
|
35
35
|
response = connection.readpartial(8192)
|
36
|
-
expected = <<~HTTP.chomp.
|
36
|
+
expected = <<~HTTP.chomp.crlf_lines.chomp
|
37
37
|
HTTP/1.1 200
|
38
38
|
Content-Length: 13
|
39
39
|
|
@@ -51,7 +51,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
51
51
|
connection << "GET / HTTP/1.1\r\n\r\n"
|
52
52
|
|
53
53
|
response = connection.readpartial(8192)
|
54
|
-
expected = <<~HTTP.
|
54
|
+
expected = <<~HTTP.crlf_lines.chomp
|
55
55
|
HTTP/1.1 200
|
56
56
|
Content-Length: 13
|
57
57
|
|
@@ -73,7 +73,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
73
73
|
connection << "GET / HTTP/1.1\r\n\r\n"
|
74
74
|
response = connection.readpartial(8192)
|
75
75
|
assert !connection.eof?
|
76
|
-
expected = <<~HTTP.
|
76
|
+
expected = <<~HTTP.crlf_lines.chomp
|
77
77
|
HTTP/1.1 200
|
78
78
|
Content-Length: 2
|
79
79
|
|
@@ -100,7 +100,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
100
100
|
sleep 0.01
|
101
101
|
response = connection.readpartial(8192)
|
102
102
|
|
103
|
-
expected = <<~HTTP.
|
103
|
+
expected = <<~HTTP.crlf_lines.chomp
|
104
104
|
HTTP/1.1 200
|
105
105
|
Content-Length: 13
|
106
106
|
|
@@ -125,7 +125,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
125
125
|
req.finish
|
126
126
|
end
|
127
127
|
|
128
|
-
connection << <<~HTTP.
|
128
|
+
connection << <<~HTTP.crlf_lines
|
129
129
|
POST / HTTP/1.1
|
130
130
|
Transfer-Encoding: chunked
|
131
131
|
|
@@ -151,7 +151,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
151
151
|
|
152
152
|
response = connection.readpartial(8192)
|
153
153
|
|
154
|
-
expected = <<~HTTP.
|
154
|
+
expected = <<~HTTP.crlf_lines
|
155
155
|
HTTP/1.1 200
|
156
156
|
Transfer-Encoding: chunked
|
157
157
|
|
@@ -172,7 +172,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
172
172
|
upgrade: {
|
173
173
|
echo: lambda do |adapter, _headers|
|
174
174
|
conn = adapter.conn
|
175
|
-
conn << <<~HTTP.
|
175
|
+
conn << <<~HTTP.crlf_lines
|
176
176
|
HTTP/1.1 101 Switching Protocols
|
177
177
|
Upgrade: echo
|
178
178
|
Connection: Upgrade
|
@@ -192,7 +192,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
192
192
|
connection << "GET / HTTP/1.1\r\n\r\n"
|
193
193
|
response = connection.readpartial(8192)
|
194
194
|
assert !connection.eof?
|
195
|
-
expected = <<~HTTP.
|
195
|
+
expected = <<~HTTP.crlf_lines.chomp
|
196
196
|
HTTP/1.1 200
|
197
197
|
Content-Length: 2
|
198
198
|
|
@@ -200,7 +200,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
200
200
|
HTTP
|
201
201
|
assert_equal(expected, response)
|
202
202
|
|
203
|
-
connection << <<~HTTP.
|
203
|
+
connection << <<~HTTP.crlf_lines
|
204
204
|
GET / HTTP/1.1
|
205
205
|
Upgrade: echo
|
206
206
|
Connection: upgrade
|
@@ -210,7 +210,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
210
210
|
snooze
|
211
211
|
response = connection.readpartial(8192)
|
212
212
|
assert !connection.eof?
|
213
|
-
expected = <<~HTTP.
|
213
|
+
expected = <<~HTTP.crlf_lines
|
214
214
|
HTTP/1.1 101 Switching Protocols
|
215
215
|
Upgrade: echo
|
216
216
|
Connection: Upgrade
|
@@ -228,7 +228,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
228
228
|
|
229
229
|
connection.close
|
230
230
|
assert !done
|
231
|
-
|
231
|
+
|
232
232
|
sleep 0.01
|
233
233
|
assert done
|
234
234
|
end
|
@@ -251,7 +251,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
251
251
|
count = 0
|
252
252
|
|
253
253
|
connection << "GET / HTTP/1.1\r\n\r\n"
|
254
|
-
|
254
|
+
|
255
255
|
while (data = connection.read(chunk_size))
|
256
256
|
response << data
|
257
257
|
count += 1
|
@@ -259,7 +259,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
259
259
|
end
|
260
260
|
|
261
261
|
chunks = "#{chunk_size.to_s(16)}\n#{'*' * chunk_size}\n" * chunk_count
|
262
|
-
expected = <<~HTTP.
|
262
|
+
expected = <<~HTTP.crlf_lines
|
263
263
|
HTTP/1.1 200
|
264
264
|
Transfer-Encoding: chunked
|
265
265
|
|
data/tipi.gemspec
CHANGED
@@ -19,11 +19,12 @@ Gem::Specification.new do |s|
|
|
19
19
|
|
20
20
|
s.executables = ['tipi']
|
21
21
|
|
22
|
-
s.add_runtime_dependency 'polyphony', '~>0.
|
22
|
+
s.add_runtime_dependency 'polyphony', '~>0.71'
|
23
|
+
s.add_runtime_dependency 'ever', '~>0.1'
|
23
24
|
s.add_runtime_dependency 'qeweney', '~>0.14'
|
24
25
|
s.add_runtime_dependency 'extralite', '~>1.2'
|
25
26
|
s.add_runtime_dependency 'h1p', '~>0.2'
|
26
|
-
|
27
|
+
|
27
28
|
s.add_runtime_dependency 'http-2', '~>0.11'
|
28
29
|
s.add_runtime_dependency 'rack', '>=2.0.8', '<2.3.0'
|
29
30
|
s.add_runtime_dependency 'websocket', '~>1.2.8'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tipi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.45'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: polyphony
|
@@ -16,14 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.71'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.71'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ever
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.1'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: qeweney
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -234,6 +248,7 @@ extensions: []
|
|
234
248
|
extra_rdoc_files:
|
235
249
|
- README.md
|
236
250
|
files:
|
251
|
+
- ".github/FUNDING.yml"
|
237
252
|
- ".github/workflows/test.yml"
|
238
253
|
- ".gitignore"
|
239
254
|
- CHANGELOG.md
|
@@ -247,6 +262,7 @@ files:
|
|
247
262
|
- bin/benchmark
|
248
263
|
- bin/h1pd
|
249
264
|
- bin/tipi
|
265
|
+
- bm.png
|
250
266
|
- df/agent.rb
|
251
267
|
- df/etc_benchmark.rb
|
252
268
|
- df/multi_agent_supervisor.rb
|
@@ -263,6 +279,7 @@ files:
|
|
263
279
|
- examples/cuba.ru
|
264
280
|
- examples/full_service.rb
|
265
281
|
- examples/hanami-api.ru
|
282
|
+
- examples/hello.rb
|
266
283
|
- examples/hello.ru
|
267
284
|
- examples/http1_parser.rb
|
268
285
|
- examples/http_request_ws_server.rb
|
@@ -283,6 +300,7 @@ files:
|
|
283
300
|
- examples/https_server_forked.rb
|
284
301
|
- examples/https_wss_server.rb
|
285
302
|
- examples/rack_server.rb
|
303
|
+
- examples/rack_server_forked.rb
|
286
304
|
- examples/rack_server_https.rb
|
287
305
|
- examples/rack_server_https_forked.rb
|
288
306
|
- examples/routing_server.rb
|
@@ -298,6 +316,12 @@ files:
|
|
298
316
|
- lib/tipi/cli.rb
|
299
317
|
- lib/tipi/config_dsl.rb
|
300
318
|
- lib/tipi/configuration.rb
|
319
|
+
- lib/tipi/controller.rb
|
320
|
+
- lib/tipi/controller/bare_polyphony.rb
|
321
|
+
- lib/tipi/controller/bare_stock.rb
|
322
|
+
- lib/tipi/controller/stock_http1_adapter.rb
|
323
|
+
- lib/tipi/controller/web_polyphony.rb
|
324
|
+
- lib/tipi/controller/web_stock.rb
|
301
325
|
- lib/tipi/digital_fabric.rb
|
302
326
|
- lib/tipi/digital_fabric/agent.rb
|
303
327
|
- lib/tipi/digital_fabric/agent_proxy.rb
|
@@ -312,6 +336,7 @@ files:
|
|
312
336
|
- lib/tipi/http2_stream.rb
|
313
337
|
- lib/tipi/rack_adapter.rb
|
314
338
|
- lib/tipi/response_extensions.rb
|
339
|
+
- lib/tipi/supervisor.rb
|
315
340
|
- lib/tipi/version.rb
|
316
341
|
- lib/tipi/websocket.rb
|
317
342
|
- test/coverage.rb
|
@@ -345,7 +370,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
345
370
|
- !ruby/object:Gem::Version
|
346
371
|
version: '0'
|
347
372
|
requirements: []
|
348
|
-
rubygems_version: 3.1.
|
373
|
+
rubygems_version: 3.1.2
|
349
374
|
signing_key:
|
350
375
|
specification_version: 4
|
351
376
|
summary: Tipi - the All-in-one Web Server for Ruby Apps
|