puma 2.2.0 → 8.0.2
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 +7 -0
- data/History.md +3334 -0
- data/LICENSE +23 -20
- data/README.md +387 -100
- data/bin/puma-wild +25 -0
- data/bin/pumactl +1 -1
- data/docs/5.0-Upgrade.md +98 -0
- data/docs/6.0-Upgrade.md +56 -0
- data/docs/7.0-Upgrade.md +52 -0
- data/docs/8.0-Upgrade.md +100 -0
- data/docs/architecture.md +74 -0
- data/docs/compile_options.md +55 -0
- data/docs/deployment.md +137 -0
- data/docs/fork_worker.md +41 -0
- data/docs/grpc.md +62 -0
- data/docs/images/favicon.svg +1 -0
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/images/running-puma.svg +1 -0
- data/docs/images/standard-logo.svg +1 -0
- data/docs/java_options.md +54 -0
- data/docs/jungle/README.md +9 -0
- data/docs/jungle/rc.d/README.md +74 -0
- data/docs/jungle/rc.d/puma +61 -0
- data/docs/jungle/rc.d/puma.conf +10 -0
- data/docs/kubernetes.md +73 -0
- data/docs/nginx.md +5 -5
- data/docs/plugins.md +42 -0
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +65 -0
- data/docs/signals.md +98 -0
- data/docs/stats.md +148 -0
- data/docs/systemd.md +253 -0
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/PumaHttp11Service.java +2 -2
- data/ext/puma_http11/extconf.rb +59 -2
- data/ext/puma_http11/http11_parser.c +319 -487
- data/ext/puma_http11/http11_parser.h +15 -13
- data/ext/puma_http11/http11_parser.java.rl +64 -94
- data/ext/puma_http11/http11_parser.rl +27 -24
- data/ext/puma_http11/http11_parser_common.rl +8 -8
- data/ext/puma_http11/mini_ssl.c +696 -38
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/EnvKey.java +241 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +241 -145
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +174 -221
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +413 -193
- data/ext/puma_http11/puma_http11.c +183 -175
- data/lib/puma/app/status.rb +77 -29
- data/lib/puma/binder.rb +349 -119
- data/lib/puma/cli.rb +163 -801
- data/lib/puma/client.rb +627 -144
- data/lib/puma/client_env.rb +171 -0
- data/lib/puma/cluster/worker.rb +183 -0
- data/lib/puma/cluster/worker_handle.rb +127 -0
- data/lib/puma/cluster.rb +634 -0
- data/lib/puma/cluster_accept_loop_delay.rb +91 -0
- data/lib/puma/commonlogger.rb +115 -0
- data/lib/puma/configuration.rb +420 -198
- data/lib/puma/const.rb +266 -115
- data/lib/puma/control_cli.rb +219 -120
- data/lib/puma/detect.rb +56 -2
- data/lib/puma/dsl.rb +1562 -0
- data/lib/puma/error_logger.rb +115 -0
- data/lib/puma/events.rb +44 -60
- data/lib/puma/io_buffer.rb +48 -5
- data/lib/puma/jruby_restart.rb +2 -51
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher/bundle_pruner.rb +102 -0
- data/lib/puma/launcher.rb +501 -0
- data/lib/puma/log_writer.rb +153 -0
- data/lib/puma/minissl/context_builder.rb +96 -0
- data/lib/puma/minissl.rb +355 -37
- data/lib/puma/null_io.rb +79 -12
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +36 -0
- data/lib/puma/plugin.rb +111 -0
- data/lib/puma/rack/builder.rb +297 -0
- data/lib/puma/rack/urlmap.rb +93 -0
- data/lib/puma/rack_default.rb +21 -4
- data/lib/puma/reactor.rb +102 -133
- data/lib/puma/response.rb +532 -0
- data/lib/puma/runner.rb +211 -0
- data/lib/puma/sd_notify.rb +146 -0
- data/lib/puma/server.rb +582 -445
- data/lib/puma/server_plugin_control.rb +32 -0
- data/lib/puma/single.rb +72 -0
- data/lib/puma/state_file.rb +69 -0
- data/lib/puma/thread_pool.rb +389 -57
- data/lib/puma/util.rb +125 -0
- data/lib/puma.rb +80 -6
- data/lib/rack/handler/puma.rb +125 -47
- data/tools/Dockerfile +26 -0
- data/tools/trickletest.rb +44 -0
- metadata +88 -148
- data/COPYING +0 -55
- data/Gemfile +0 -10
- data/History.txt +0 -302
- data/Manifest.txt +0 -60
- data/Rakefile +0 -165
- data/TODO +0 -5
- data/docs/config.md +0 -0
- data/ext/puma_http11/ext_help.h +0 -15
- data/ext/puma_http11/io_buffer.c +0 -154
- data/lib/puma/accept_nonblock.rb +0 -23
- data/lib/puma/capistrano.rb +0 -34
- data/lib/puma/compat.rb +0 -11
- data/lib/puma/daemon_ext.rb +0 -20
- data/lib/puma/delegation.rb +0 -11
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack_patch.rb +0 -25
- data/puma.gemspec +0 -45
- data/test/test_app_status.rb +0 -88
- data/test/test_cli.rb +0 -171
- data/test/test_config.rb +0 -16
- data/test/test_http10.rb +0 -27
- data/test/test_http11.rb +0 -126
- data/test/test_integration.rb +0 -154
- data/test/test_iobuffer.rb +0 -38
- data/test/test_minissl.rb +0 -25
- data/test/test_null_io.rb +0 -31
- data/test/test_persistent.rb +0 -238
- data/test/test_puma_server.rb +0 -224
- data/test/test_rack_handler.rb +0 -10
- data/test/test_rack_server.rb +0 -141
- data/test/test_thread_pool.rb +0 -146
- data/test/test_unix_socket.rb +0 -39
- data/test/test_ws.rb +0 -89
- data/tools/jungle/init.d/README.md +0 -54
- data/tools/jungle/init.d/puma +0 -332
- data/tools/jungle/init.d/run-puma +0 -3
- data/tools/jungle/upstart/README.md +0 -61
- data/tools/jungle/upstart/puma-manager.conf +0 -31
- data/tools/jungle/upstart/puma.conf +0 -52
data/test/test_puma_server.rb
DELETED
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
require "rbconfig"
|
|
2
|
-
require 'test/unit'
|
|
3
|
-
require 'socket'
|
|
4
|
-
require 'openssl'
|
|
5
|
-
|
|
6
|
-
require 'puma/minissl'
|
|
7
|
-
require 'puma/server'
|
|
8
|
-
|
|
9
|
-
require 'net/https'
|
|
10
|
-
|
|
11
|
-
class TestPumaServer < Test::Unit::TestCase
|
|
12
|
-
|
|
13
|
-
def setup
|
|
14
|
-
@port = 3212
|
|
15
|
-
@host = "127.0.0.1"
|
|
16
|
-
|
|
17
|
-
@app = lambda { |env| [200, {}, [env['rack.url_scheme']]] }
|
|
18
|
-
|
|
19
|
-
@events = Puma::Events.new STDOUT, STDERR
|
|
20
|
-
@server = Puma::Server.new @app, @events
|
|
21
|
-
|
|
22
|
-
if defined?(JRUBY_VERSION)
|
|
23
|
-
@ssl_key = File.expand_path "../../examples/puma/keystore.jks", __FILE__
|
|
24
|
-
@ssl_cert = @ssl_key
|
|
25
|
-
else
|
|
26
|
-
@ssl_key = File.expand_path "../../examples/puma/puma_keypair.pem", __FILE__
|
|
27
|
-
@ssl_cert = File.expand_path "../../examples/puma/cert_puma.pem", __FILE__
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def teardown
|
|
32
|
-
@server.stop(true)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def test_url_scheme_for_https
|
|
36
|
-
ctx = Puma::MiniSSL::Context.new
|
|
37
|
-
|
|
38
|
-
ctx.key = @ssl_key
|
|
39
|
-
ctx.cert = @ssl_cert
|
|
40
|
-
|
|
41
|
-
ctx.verify_mode = Puma::MiniSSL::VERIFY_NONE
|
|
42
|
-
|
|
43
|
-
@server.add_ssl_listener @host, @port, ctx
|
|
44
|
-
@server.run
|
|
45
|
-
|
|
46
|
-
http = Net::HTTP.new @host, @port
|
|
47
|
-
http.use_ssl = true
|
|
48
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
49
|
-
|
|
50
|
-
body = nil
|
|
51
|
-
http.start do
|
|
52
|
-
req = Net::HTTP::Get.new "/", {}
|
|
53
|
-
|
|
54
|
-
http.request(req) do |rep|
|
|
55
|
-
body = rep.body
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
assert_equal "https", body
|
|
60
|
-
end unless defined? JRUBY_VERSION
|
|
61
|
-
|
|
62
|
-
def test_proper_stringio_body
|
|
63
|
-
data = nil
|
|
64
|
-
|
|
65
|
-
@server.app = proc do |env|
|
|
66
|
-
data = env['rack.input'].read
|
|
67
|
-
[200, {}, ["ok"]]
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
@server.add_tcp_listener @host, @port
|
|
71
|
-
@server.run
|
|
72
|
-
|
|
73
|
-
fifteen = "1" * 15
|
|
74
|
-
|
|
75
|
-
sock = TCPSocket.new @host, @port
|
|
76
|
-
sock << "PUT / HTTP/1.0\r\nContent-Length: 30\r\n\r\n#{fifteen}"
|
|
77
|
-
sleep 0.1 # important so that the previous data is sent as a packet
|
|
78
|
-
sock << fifteen
|
|
79
|
-
|
|
80
|
-
sock.read
|
|
81
|
-
|
|
82
|
-
assert_equal "#{fifteen}#{fifteen}", data
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def test_puma_socket
|
|
86
|
-
body = "HTTP/1.1 750 Upgraded to Awesome\r\nDone: Yep!\r\n"
|
|
87
|
-
@server.app = proc do |env|
|
|
88
|
-
io = env['puma.socket']
|
|
89
|
-
|
|
90
|
-
io.write body
|
|
91
|
-
|
|
92
|
-
io.close
|
|
93
|
-
|
|
94
|
-
[-1, {}, []]
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
@server.add_tcp_listener @host, @port
|
|
98
|
-
@server.run
|
|
99
|
-
|
|
100
|
-
sock = TCPSocket.new @host, @port
|
|
101
|
-
sock << "PUT / HTTP/1.0\r\n\r\nHello"
|
|
102
|
-
|
|
103
|
-
assert_equal body, sock.read
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def test_very_large_return
|
|
107
|
-
giant = "x" * 2056610
|
|
108
|
-
|
|
109
|
-
@server.app = proc do |env|
|
|
110
|
-
[200, {}, [giant]]
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
@server.add_tcp_listener @host, @port
|
|
114
|
-
@server.run
|
|
115
|
-
|
|
116
|
-
sock = TCPSocket.new @host, @port
|
|
117
|
-
sock << "GET / HTTP/1.0\r\n\r\n"
|
|
118
|
-
|
|
119
|
-
while true
|
|
120
|
-
line = sock.gets
|
|
121
|
-
break if line == "\r\n"
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
out = sock.read
|
|
125
|
-
|
|
126
|
-
assert_equal giant.bytesize, out.bytesize
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def test_respect_x_forwarded_proto
|
|
130
|
-
@server.app = proc do |env|
|
|
131
|
-
[200, {}, [env['SERVER_PORT']]]
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
@server.add_tcp_listener @host, @port
|
|
135
|
-
@server.run
|
|
136
|
-
|
|
137
|
-
req = Net::HTTP::Get.new("/")
|
|
138
|
-
req['HOST'] = "example.com"
|
|
139
|
-
req['X_FORWARDED_PROTO'] = "https"
|
|
140
|
-
|
|
141
|
-
res = Net::HTTP.start @host, @port do |http|
|
|
142
|
-
http.request(req)
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
assert_equal "443", res.body
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def test_default_server_port
|
|
149
|
-
@server.app = proc do |env|
|
|
150
|
-
[200, {}, [env['SERVER_PORT']]]
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
@server.add_tcp_listener @host, @port
|
|
154
|
-
@server.run
|
|
155
|
-
|
|
156
|
-
req = Net::HTTP::Get.new("/")
|
|
157
|
-
req['HOST'] = "example.com"
|
|
158
|
-
|
|
159
|
-
res = Net::HTTP.start @host, @port do |http|
|
|
160
|
-
http.request(req)
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
assert_equal "80", res.body
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def test_HEAD_has_no_body
|
|
167
|
-
@server.app = proc { |env| [200, {"Foo" => "Bar"}, ["hello"]] }
|
|
168
|
-
|
|
169
|
-
@server.add_tcp_listener @host, @port
|
|
170
|
-
@server.run
|
|
171
|
-
|
|
172
|
-
sock = TCPSocket.new @host, @port
|
|
173
|
-
sock << "HEAD / HTTP/1.0\r\n\r\n"
|
|
174
|
-
|
|
175
|
-
data = sock.read
|
|
176
|
-
|
|
177
|
-
assert_equal "HTTP/1.0 200 OK\r\nFoo: Bar\r\n\r\n", data
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def test_GET_with_empty_body_has_sane_chunking
|
|
181
|
-
@server.app = proc { |env| [200, {}, [""]] }
|
|
182
|
-
|
|
183
|
-
@server.add_tcp_listener @host, @port
|
|
184
|
-
@server.run
|
|
185
|
-
|
|
186
|
-
sock = TCPSocket.new @host, @port
|
|
187
|
-
sock << "HEAD / HTTP/1.0\r\n\r\n"
|
|
188
|
-
|
|
189
|
-
data = sock.read
|
|
190
|
-
|
|
191
|
-
assert_equal "HTTP/1.0 200 OK\r\n\r\n", data
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def test_GET_with_no_body_has_sane_chunking
|
|
195
|
-
@server.app = proc { |env| [200, {}, [""]] }
|
|
196
|
-
|
|
197
|
-
@server.add_tcp_listener @host, @port
|
|
198
|
-
@server.run
|
|
199
|
-
|
|
200
|
-
sock = TCPSocket.new @host, @port
|
|
201
|
-
sock << "HEAD / HTTP/1.0\r\n\r\n"
|
|
202
|
-
|
|
203
|
-
data = sock.read
|
|
204
|
-
|
|
205
|
-
assert_equal "HTTP/1.0 200 OK\r\n\r\n", data
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
def test_doesnt_print_backtrace_in_production
|
|
209
|
-
@events = Puma::Events.strings
|
|
210
|
-
@server = Puma::Server.new @app, @events
|
|
211
|
-
|
|
212
|
-
@server.app = proc { |e| raise "don't leak me bro" }
|
|
213
|
-
@server.leak_stack_on_error = false
|
|
214
|
-
@server.add_tcp_listener @host, @port
|
|
215
|
-
@server.run
|
|
216
|
-
|
|
217
|
-
sock = TCPSocket.new @host, @port
|
|
218
|
-
sock << "GET / HTTP/1.0\r\n\r\n"
|
|
219
|
-
|
|
220
|
-
data = sock.read
|
|
221
|
-
|
|
222
|
-
assert_not_match(/don't leak me bro/, data)
|
|
223
|
-
end
|
|
224
|
-
end
|
data/test/test_rack_handler.rb
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
require 'test/unit'
|
|
2
|
-
|
|
3
|
-
class TestPumaUnixSocket < Test::Unit::TestCase
|
|
4
|
-
def test_handler
|
|
5
|
-
handler = Rack::Handler.get(:puma)
|
|
6
|
-
assert_equal Rack::Handler::Puma, handler
|
|
7
|
-
handler = Rack::Handler.get('Puma')
|
|
8
|
-
assert_equal Rack::Handler::Puma, handler
|
|
9
|
-
end
|
|
10
|
-
end
|
data/test/test_rack_server.rb
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
require 'test/unit'
|
|
2
|
-
require 'puma'
|
|
3
|
-
require 'rack/lint'
|
|
4
|
-
require 'test/testhelp'
|
|
5
|
-
require 'rack/commonlogger'
|
|
6
|
-
require 'puma/rack_patch'
|
|
7
|
-
|
|
8
|
-
class TestRackServer < Test::Unit::TestCase
|
|
9
|
-
|
|
10
|
-
class ErrorChecker
|
|
11
|
-
def initialize(app)
|
|
12
|
-
@app = app
|
|
13
|
-
@exception = nil
|
|
14
|
-
@env = nil
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
attr_reader :exception, :env
|
|
18
|
-
|
|
19
|
-
def call(env)
|
|
20
|
-
begin
|
|
21
|
-
@env = env
|
|
22
|
-
return @app.call(env)
|
|
23
|
-
rescue Exception => e
|
|
24
|
-
@exception = e
|
|
25
|
-
|
|
26
|
-
[
|
|
27
|
-
500,
|
|
28
|
-
{ "X-Exception" => e.message, "X-Exception-Class" => e.class.to_s },
|
|
29
|
-
["Error detected"]
|
|
30
|
-
]
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
class ServerLint < Rack::Lint
|
|
36
|
-
def call(env)
|
|
37
|
-
assert("No env given") { env }
|
|
38
|
-
check_env env
|
|
39
|
-
|
|
40
|
-
@app.call(env)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def setup
|
|
45
|
-
@valid_request = "GET / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
|
|
46
|
-
|
|
47
|
-
@simple = lambda { |env| [200, { "X-Header" => "Works" }, ["Hello"]] }
|
|
48
|
-
@server = Puma::Server.new @simple
|
|
49
|
-
@server.add_tcp_listener "127.0.0.1", 9998
|
|
50
|
-
|
|
51
|
-
@stopped = false
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def stop
|
|
55
|
-
@server.stop(true)
|
|
56
|
-
@stopped = true
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def teardown
|
|
60
|
-
@server.stop(true) unless @stopped
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def test_lint
|
|
64
|
-
@checker = ErrorChecker.new ServerLint.new(@simple)
|
|
65
|
-
@server.app = @checker
|
|
66
|
-
|
|
67
|
-
@server.run
|
|
68
|
-
|
|
69
|
-
hit(['http://127.0.0.1:9998/test'])
|
|
70
|
-
|
|
71
|
-
stop
|
|
72
|
-
|
|
73
|
-
if exc = @checker.exception
|
|
74
|
-
raise exc
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def test_large_post_body
|
|
79
|
-
@checker = ErrorChecker.new ServerLint.new(@simple)
|
|
80
|
-
@server.app = @checker
|
|
81
|
-
|
|
82
|
-
@server.run
|
|
83
|
-
|
|
84
|
-
big = "x" * (1024 * 16)
|
|
85
|
-
|
|
86
|
-
Net::HTTP.post_form URI.parse('http://127.0.0.1:9998/test'),
|
|
87
|
-
{ "big" => big }
|
|
88
|
-
|
|
89
|
-
stop
|
|
90
|
-
|
|
91
|
-
if exc = @checker.exception
|
|
92
|
-
raise exc
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def test_path_info
|
|
97
|
-
input = nil
|
|
98
|
-
@server.app = lambda { |env| input = env; @simple.call(env) }
|
|
99
|
-
@server.run
|
|
100
|
-
|
|
101
|
-
hit(['http://127.0.0.1:9998/test/a/b/c'])
|
|
102
|
-
|
|
103
|
-
stop
|
|
104
|
-
|
|
105
|
-
assert_equal "/test/a/b/c", input['PATH_INFO']
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def test_after_reply
|
|
109
|
-
closed = false
|
|
110
|
-
|
|
111
|
-
@server.app = lambda do |env|
|
|
112
|
-
env['rack.after_reply'] << lambda { closed = true }
|
|
113
|
-
@simple.call(env)
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
@server.run
|
|
117
|
-
|
|
118
|
-
hit(['http://127.0.0.1:9998/test'])
|
|
119
|
-
|
|
120
|
-
stop
|
|
121
|
-
|
|
122
|
-
assert_equal true, closed
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def test_common_logger
|
|
126
|
-
log = StringIO.new
|
|
127
|
-
|
|
128
|
-
logger = Rack::CommonLogger.new(@simple, log)
|
|
129
|
-
|
|
130
|
-
@server.app = logger
|
|
131
|
-
|
|
132
|
-
@server.run
|
|
133
|
-
|
|
134
|
-
hit(['http://127.0.0.1:9998/test'])
|
|
135
|
-
|
|
136
|
-
stop
|
|
137
|
-
|
|
138
|
-
assert_match %r!GET /test HTTP/1\.1!, log.string
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
end
|
data/test/test_thread_pool.rb
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
require 'test/unit'
|
|
2
|
-
|
|
3
|
-
require 'puma/thread_pool'
|
|
4
|
-
|
|
5
|
-
class TestThreadPool < Test::Unit::TestCase
|
|
6
|
-
|
|
7
|
-
def teardown
|
|
8
|
-
@pool.shutdown if @pool
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def new_pool(min, max, &blk)
|
|
12
|
-
blk = proc { } unless blk
|
|
13
|
-
@pool = Puma::ThreadPool.new(min, max, &blk)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def pause
|
|
17
|
-
sleep 0.2
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def test_append_spawns
|
|
21
|
-
saw = []
|
|
22
|
-
|
|
23
|
-
pool = new_pool(0, 1) do |work|
|
|
24
|
-
saw << work
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
pool << 1
|
|
28
|
-
|
|
29
|
-
pause
|
|
30
|
-
|
|
31
|
-
assert_equal [1], saw
|
|
32
|
-
assert_equal 1, pool.spawned
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def test_append_queues_on_max
|
|
36
|
-
finish = false
|
|
37
|
-
pool = new_pool(0, 1) { Thread.pass until finish }
|
|
38
|
-
|
|
39
|
-
pool << 1
|
|
40
|
-
pool << 2
|
|
41
|
-
pool << 3
|
|
42
|
-
|
|
43
|
-
pause
|
|
44
|
-
|
|
45
|
-
assert_equal 2, pool.backlog
|
|
46
|
-
|
|
47
|
-
finish = true
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def test_trim
|
|
51
|
-
pool = new_pool(0, 1)
|
|
52
|
-
|
|
53
|
-
pool << 1
|
|
54
|
-
|
|
55
|
-
pause
|
|
56
|
-
|
|
57
|
-
assert_equal 1, pool.spawned
|
|
58
|
-
pool.trim
|
|
59
|
-
|
|
60
|
-
pause
|
|
61
|
-
assert_equal 0, pool.spawned
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def test_trim_leaves_min
|
|
65
|
-
finish = false
|
|
66
|
-
pool = new_pool(1, 2) { Thread.pass until finish }
|
|
67
|
-
|
|
68
|
-
pool << 1
|
|
69
|
-
pool << 2
|
|
70
|
-
|
|
71
|
-
finish = true
|
|
72
|
-
|
|
73
|
-
pause
|
|
74
|
-
|
|
75
|
-
assert_equal 2, pool.spawned
|
|
76
|
-
pool.trim
|
|
77
|
-
pause
|
|
78
|
-
|
|
79
|
-
assert_equal 1, pool.spawned
|
|
80
|
-
pool.trim
|
|
81
|
-
pause
|
|
82
|
-
|
|
83
|
-
assert_equal 1, pool.spawned
|
|
84
|
-
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def test_force_trim_doesnt_overtrim
|
|
88
|
-
finish = false
|
|
89
|
-
pool = new_pool(1, 2) { Thread.pass until finish }
|
|
90
|
-
|
|
91
|
-
pool << 1
|
|
92
|
-
pool << 2
|
|
93
|
-
|
|
94
|
-
assert_equal 2, pool.spawned
|
|
95
|
-
pool.trim true
|
|
96
|
-
pool.trim true
|
|
97
|
-
|
|
98
|
-
finish = true
|
|
99
|
-
|
|
100
|
-
pause
|
|
101
|
-
|
|
102
|
-
assert_equal 1, pool.spawned
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def test_trim_is_ignored_if_no_waiting_threads
|
|
106
|
-
finish = false
|
|
107
|
-
pool = new_pool(1, 2) { Thread.pass until finish }
|
|
108
|
-
|
|
109
|
-
pool << 1
|
|
110
|
-
pool << 2
|
|
111
|
-
|
|
112
|
-
assert_equal 2, pool.spawned
|
|
113
|
-
pool.trim
|
|
114
|
-
pool.trim
|
|
115
|
-
|
|
116
|
-
assert_equal 0, pool.trim_requested
|
|
117
|
-
|
|
118
|
-
finish = true
|
|
119
|
-
|
|
120
|
-
pause
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def test_autotrim
|
|
124
|
-
finish = false
|
|
125
|
-
pool = new_pool(1, 2) { Thread.pass until finish }
|
|
126
|
-
|
|
127
|
-
pool << 1
|
|
128
|
-
pool << 2
|
|
129
|
-
|
|
130
|
-
assert_equal 2, pool.spawned
|
|
131
|
-
|
|
132
|
-
finish = true
|
|
133
|
-
|
|
134
|
-
pause
|
|
135
|
-
|
|
136
|
-
assert_equal 2, pool.spawned
|
|
137
|
-
|
|
138
|
-
pool.auto_trim! 1
|
|
139
|
-
|
|
140
|
-
sleep 1
|
|
141
|
-
|
|
142
|
-
pause
|
|
143
|
-
|
|
144
|
-
assert_equal 1, pool.spawned
|
|
145
|
-
end
|
|
146
|
-
end
|
data/test/test_unix_socket.rb
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
require "rbconfig"
|
|
2
|
-
require 'test/unit'
|
|
3
|
-
require 'puma/server'
|
|
4
|
-
|
|
5
|
-
require 'socket'
|
|
6
|
-
|
|
7
|
-
# UNIX sockets are not recommended on JRuby
|
|
8
|
-
# (or Windows)
|
|
9
|
-
unless defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
|
|
10
|
-
class TestPumaUnixSocket < Test::Unit::TestCase
|
|
11
|
-
|
|
12
|
-
App = lambda { |env| [200, {}, ["Works"]] }
|
|
13
|
-
|
|
14
|
-
Path = "test/puma.sock"
|
|
15
|
-
|
|
16
|
-
def setup
|
|
17
|
-
@server = Puma::Server.new App
|
|
18
|
-
@server.add_unix_listener Path
|
|
19
|
-
@server.run
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def teardown
|
|
23
|
-
@server.stop(true)
|
|
24
|
-
File.unlink Path if File.exists? Path
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def test_server
|
|
28
|
-
sock = UNIXSocket.new Path
|
|
29
|
-
|
|
30
|
-
sock << "GET / HTTP/1.0\r\nHost: blah.com\r\n\r\n"
|
|
31
|
-
|
|
32
|
-
expected = "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Length: 5\r\n\r\nWorks"
|
|
33
|
-
|
|
34
|
-
assert_equal expected, sock.read(expected.size)
|
|
35
|
-
|
|
36
|
-
sock.close
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
data/test/test_ws.rb
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2011 Evan Phoenix
|
|
2
|
-
# Copyright (c) 2005 Zed A. Shaw
|
|
3
|
-
|
|
4
|
-
require 'test/testhelp'
|
|
5
|
-
|
|
6
|
-
include Puma
|
|
7
|
-
|
|
8
|
-
class TestHandler
|
|
9
|
-
attr_reader :ran_test
|
|
10
|
-
|
|
11
|
-
def call(env)
|
|
12
|
-
@ran_test = true
|
|
13
|
-
|
|
14
|
-
[200, {"Content-Type" => "text/plain"}, ["hello!"]]
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
class WebServerTest < Test::Unit::TestCase
|
|
19
|
-
|
|
20
|
-
def setup
|
|
21
|
-
@valid_request = "GET / HTTP/1.1\r\nHost: www.zedshaw.com\r\nContent-Type: text/plain\r\n\r\n"
|
|
22
|
-
|
|
23
|
-
@tester = TestHandler.new
|
|
24
|
-
|
|
25
|
-
@server = Server.new @tester, Events.strings
|
|
26
|
-
@server.add_tcp_listener "127.0.0.1", 9998
|
|
27
|
-
|
|
28
|
-
@server.run
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def teardown
|
|
32
|
-
@server.stop(true)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def test_simple_server
|
|
36
|
-
hit(['http://127.0.0.1:9998/test'])
|
|
37
|
-
assert @tester.ran_test, "Handler didn't really run"
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def do_test(string, chunk, close_after=nil, shutdown_delay=0)
|
|
42
|
-
# Do not use instance variables here, because it needs to be thread safe
|
|
43
|
-
socket = TCPSocket.new("127.0.0.1", 9998);
|
|
44
|
-
request = StringIO.new(string)
|
|
45
|
-
chunks_out = 0
|
|
46
|
-
|
|
47
|
-
while data = request.read(chunk)
|
|
48
|
-
chunks_out += socket.write(data)
|
|
49
|
-
socket.flush
|
|
50
|
-
sleep 0.2
|
|
51
|
-
if close_after and chunks_out > close_after
|
|
52
|
-
socket.close
|
|
53
|
-
sleep 1
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
sleep(shutdown_delay)
|
|
57
|
-
socket.write(" ") # Some platforms only raise the exception on attempted write
|
|
58
|
-
socket.flush
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def test_trickle_attack
|
|
62
|
-
do_test(@valid_request, 3)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def test_close_client
|
|
66
|
-
assert_raises IOError do
|
|
67
|
-
do_test(@valid_request, 10, 20)
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def test_bad_client
|
|
72
|
-
do_test("GET /test HTTP/BAD", 3)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def test_header_is_too_long
|
|
76
|
-
long = "GET /test HTTP/1.1\r\n" + ("X-Big: stuff\r\n" * 15000) + "\r\n"
|
|
77
|
-
assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL, IOError do
|
|
78
|
-
do_test(long, long.length/2, 10)
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def test_file_streamed_request
|
|
83
|
-
body = "a" * (Puma::Const::MAX_BODY * 2)
|
|
84
|
-
long = "GET /test HTTP/1.1\r\nContent-length: #{body.length}\r\n\r\n" + body
|
|
85
|
-
do_test(long, (Puma::Const::CHUNK_SIZE * 2) - 400)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
end
|
|
89
|
-
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# Puma daemon service
|
|
2
|
-
|
|
3
|
-
Init script to manage multiple Puma servers on the same box using start-stop-daemon.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
# Copy the init script to services directory
|
|
8
|
-
sudo cp puma /etc/init.d
|
|
9
|
-
sudo chmod +x /etc/init.d/puma
|
|
10
|
-
|
|
11
|
-
# Make it start at boot time.
|
|
12
|
-
sudo update-rc.d -f puma defaults
|
|
13
|
-
|
|
14
|
-
# Copy the Puma runner to an accessible location
|
|
15
|
-
sudo cp run-puma /usr/local/bin
|
|
16
|
-
sudo chmod +x /usr/local/bin/run-puma
|
|
17
|
-
|
|
18
|
-
# Create an empty configuration file
|
|
19
|
-
sudo touch /etc/puma.conf
|
|
20
|
-
|
|
21
|
-
## Managing the jungle
|
|
22
|
-
|
|
23
|
-
Puma apps are held in /etc/puma.conf by default. It's mainly a CSV file and every line represents one app. Here's the syntax:
|
|
24
|
-
|
|
25
|
-
app-path,user,config-file-path,log-file-path
|
|
26
|
-
|
|
27
|
-
You can add an instance by editing the file or running the following command:
|
|
28
|
-
|
|
29
|
-
sudo /etc/init.d/puma add /path/to/app user /path/to/app/config/puma.rb /path/to/app/config/log/puma.log
|
|
30
|
-
|
|
31
|
-
The config and log paths are optional parameters and default to:
|
|
32
|
-
|
|
33
|
-
* config: /path/to/app/*config/puma.rb*
|
|
34
|
-
* log: /path/to/app/*config/puma.log*
|
|
35
|
-
|
|
36
|
-
To remove an app, simply delete the line from the config file or run:
|
|
37
|
-
|
|
38
|
-
sudo /etc/init.d/puma remove /path/to/app
|
|
39
|
-
|
|
40
|
-
The command will make sure the Puma instance stops before removing it from the jungle.
|
|
41
|
-
|
|
42
|
-
## Assumptions
|
|
43
|
-
|
|
44
|
-
* The script expects a temporary folder named /path/to/app/*tmp/puma* to exist. Create it if it's not there by default.
|
|
45
|
-
The pid and state files should live there and must be called: *tmp/puma/pid* and *tmp/puma/state*.
|
|
46
|
-
You can change those if you want but you'll have to adapt the script for it to work.
|
|
47
|
-
|
|
48
|
-
* Here's what a minimal app's config file should have:
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
pidfile "/path/to/app/tmp/puma/pid"
|
|
52
|
-
state_path "/path/to/app/tmp/puma/state"
|
|
53
|
-
activate_control_app
|
|
54
|
-
```
|