puma 5.3.0-java → 5.5.0-java
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +78 -3
- data/README.md +24 -5
- data/docs/deployment.md +2 -17
- data/docs/systemd.md +1 -0
- data/ext/puma_http11/extconf.rb +18 -1
- data/ext/puma_http11/mini_ssl.c +16 -1
- data/lib/puma/app/status.rb +4 -4
- data/lib/puma/binder.rb +34 -3
- data/lib/puma/cli.rb +5 -0
- data/lib/puma/client.rb +50 -8
- data/lib/puma/cluster/worker.rb +9 -2
- data/lib/puma/cluster.rb +1 -3
- data/lib/puma/configuration.rb +2 -0
- data/lib/puma/const.rb +4 -2
- data/lib/puma/dsl.rb +21 -4
- data/lib/puma/{json.rb → json_serialization.rb} +1 -1
- data/lib/puma/launcher.rb +2 -0
- data/lib/puma/minissl.rb +5 -20
- data/lib/puma/plugin.rb +1 -1
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/rack/builder.rb +1 -1
- data/lib/puma/request.rb +17 -6
- data/lib/puma/server.rb +21 -12
- data/lib/puma/thread_pool.rb +6 -4
- data/lib/puma/util.rb +1 -1
- data/lib/puma.rb +2 -2
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 661cbffdacb6abddfeca2df52a317f8e3944290f9738e6500d718b6e99cd80d5
|
4
|
+
data.tar.gz: afd4a42aafc203919afac39161e564411cafbf08a4817171d0c8aa940922ce35
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f4f11d8ae7fc1c2f9b982dee9818bade60af588583d03ef56cb60965f87616008f961dc1ae179560ea2d263df65f4bb162465d47f029398bcecea79774e41a4
|
7
|
+
data.tar.gz: 0da863e974c4c9e2d91ff954c6c86621c1fc3ba0aa7a82c5d518e56edda289fabd110b1afb44937b327820ac84dd333d66a9b826c8152aab66ab124066a22f13
|
data/History.md
CHANGED
@@ -1,3 +1,46 @@
|
|
1
|
+
## 5.5.0 / 2021-09-19
|
2
|
+
|
3
|
+
* Features
|
4
|
+
* Automatic SSL certificate provisioning for localhost, via localhost gem ([#2610], [#2257])
|
5
|
+
* add support for the PROXY protocol (v1 only) ([#2654], [#2651])
|
6
|
+
* Add a semantic CLI option for no config file ([#2689])
|
7
|
+
|
8
|
+
* Bugfixes
|
9
|
+
* More elaborate exception handling - lets some dead pumas die. ([#2700], [#2699])
|
10
|
+
* allow multiple after_worker_fork hooks ([#2690])
|
11
|
+
* Preserve BUNDLE_APP_CONFIG on worker fork ([#2688], [#2687])
|
12
|
+
|
13
|
+
* Performance
|
14
|
+
* Fix performance of server-side SSL connection close. ([#2675])
|
15
|
+
|
16
|
+
## 5.4.0 / 2021-07-28
|
17
|
+
|
18
|
+
* Features
|
19
|
+
* Better/expanded names for threadpool threads ([#2657])
|
20
|
+
* Allow pkg_config for OpenSSL ([#2648], [#1412])
|
21
|
+
* Add `rack_url_scheme` to Puma::DSL, allows setting of `rack.url_scheme` header ([#2586], [#2569])
|
22
|
+
|
23
|
+
* Bugfixes
|
24
|
+
* `Binder#parse` - allow for symlinked unix path, add create_activated_fds debug ENV ([#2643], [#2638])
|
25
|
+
* Fix deprecation warning: minissl.c - Use Random.bytes if available ([#2642])
|
26
|
+
* Client certificates: set session id context while creating SSLContext ([#2633])
|
27
|
+
* Fix deadlock issue in thread pool ([#2656])
|
28
|
+
|
29
|
+
* Refactor
|
30
|
+
* Replace `IO.select` with `IO#wait_*` when checking a single IO ([#2666])
|
31
|
+
|
32
|
+
## 5.3.2 / 2021-05-21
|
33
|
+
|
34
|
+
* Bugfixes
|
35
|
+
* Gracefully handle Rack not accepting CLI options ([#2630], [#2626])
|
36
|
+
* Fix sigterm misbehavior ([#2629])
|
37
|
+
* Improvements to keepalive-connection shedding ([#2628])
|
38
|
+
|
39
|
+
## 5.3.1 / 2021-05-11
|
40
|
+
|
41
|
+
* Security
|
42
|
+
* Close keepalive connections after the maximum number of fast inlined requests (CVE-2021-29509) ([#2625])
|
43
|
+
|
1
44
|
## 5.3.0 / 2021-05-07
|
2
45
|
|
3
46
|
* Features
|
@@ -208,6 +251,11 @@
|
|
208
251
|
* Support parallel tests in verbose progress reporting ([#2223])
|
209
252
|
* Refactor error handling in server accept loop ([#2239])
|
210
253
|
|
254
|
+
## 4.3.8 / 2021-05-11
|
255
|
+
|
256
|
+
* Security
|
257
|
+
* Close keepalive connections after the maximum number of fast inlined requests (CVE-2021-29509) ([#2625])
|
258
|
+
|
211
259
|
## 4.3.7 / 2020-11-30
|
212
260
|
|
213
261
|
* Bugfixes
|
@@ -1736,6 +1784,33 @@ be added back in a future date when a java Puma::MiniSSL is added.
|
|
1736
1784
|
* Bugfixes
|
1737
1785
|
* Your bugfix goes here <Most recent on the top, like GitHub> (#Github Number)
|
1738
1786
|
|
1787
|
+
[#2610]:https://github.com/puma/puma/pull/2610 "PR by @ye-lin-aung, merged 2021-08-18"
|
1788
|
+
[#2257]:https://github.com/puma/puma/issues/2257 "Issue by @nateberkopec, closed 2021-08-18"
|
1789
|
+
[#2654]:https://github.com/puma/puma/pull/2654 "PR by @Roguelazer, merged 2021-09-07"
|
1790
|
+
[#2651]:https://github.com/puma/puma/issues/2651 "Issue by @Roguelazer, closed 2021-09-07"
|
1791
|
+
[#2689]:https://github.com/puma/puma/pull/2689 "PR by @jacobherrington, merged 2021-09-05"
|
1792
|
+
[#2700]:https://github.com/puma/puma/pull/2700 "PR by @ioquatix, merged 2021-09-16"
|
1793
|
+
[#2699]:https://github.com/puma/puma/issues/2699 "Issue by @ioquatix, closed 2021-09-16"
|
1794
|
+
[#2690]:https://github.com/puma/puma/pull/2690 "PR by @doits, merged 2021-09-06"
|
1795
|
+
[#2688]:https://github.com/puma/puma/pull/2688 "PR by @jdelStrother, merged 2021-09-03"
|
1796
|
+
[#2687]:https://github.com/puma/puma/issues/2687 "Issue by @jdelStrother, closed 2021-09-03"
|
1797
|
+
[#2675]:https://github.com/puma/puma/pull/2675 "PR by @devwout, merged 2021-09-08"
|
1798
|
+
[#2657]:https://github.com/puma/puma/pull/2657 "PR by @olivierbellone, merged 2021-07-13"
|
1799
|
+
[#2648]:https://github.com/puma/puma/pull/2648 "PR by @MSP-Greg, merged 2021-06-27"
|
1800
|
+
[#1412]:https://github.com/puma/puma/issues/1412 "Issue by @x-yuri, closed 2021-06-27"
|
1801
|
+
[#2586]:https://github.com/puma/puma/pull/2586 "PR by @MSP-Greg, merged 2021-05-26"
|
1802
|
+
[#2569]:https://github.com/puma/puma/issues/2569 "Issue by @tarragon, closed 2021-05-26"
|
1803
|
+
[#2643]:https://github.com/puma/puma/pull/2643 "PR by @MSP-Greg, merged 2021-06-27"
|
1804
|
+
[#2638]:https://github.com/puma/puma/issues/2638 "Issue by @gingerlime, closed 2021-06-27"
|
1805
|
+
[#2642]:https://github.com/puma/puma/pull/2642 "PR by @MSP-Greg, merged 2021-06-16"
|
1806
|
+
[#2633]:https://github.com/puma/puma/pull/2633 "PR by @onlined, merged 2021-06-04"
|
1807
|
+
[#2656]:https://github.com/puma/puma/pull/2656 "PR by @olivierbellone, merged 2021-07-07"
|
1808
|
+
[#2666]:https://github.com/puma/puma/pull/2666 "PR by @MSP-Greg, merged 2021-07-25"
|
1809
|
+
[#2630]:https://github.com/puma/puma/pull/2630 "PR by @seangoedecke, merged 2021-05-20"
|
1810
|
+
[#2626]:https://github.com/puma/puma/issues/2626 "Issue by @rorymckinley, closed 2021-05-20"
|
1811
|
+
[#2629]:https://github.com/puma/puma/pull/2629 "PR by @ye-lin-aung, merged 2021-05-20"
|
1812
|
+
[#2628]:https://github.com/puma/puma/pull/2628 "PR by @wjordan, merged 2021-05-20"
|
1813
|
+
[#2625]:https://github.com/puma/puma/issues/2625 "Issue by @jarthod, closed 2021-05-11"
|
1739
1814
|
[#2564]:https://github.com/puma/puma/pull/2564 "PR by @MSP-Greg, merged 2021-04-24"
|
1740
1815
|
[#2526]:https://github.com/puma/puma/issues/2526 "Issue by @nerdrew, closed 2021-04-24"
|
1741
1816
|
[#2559]:https://github.com/puma/puma/pull/2559 "PR by @ylecuyer, merged 2021-03-11"
|
@@ -1750,11 +1825,11 @@ be added back in a future date when a java Puma::MiniSSL is added.
|
|
1750
1825
|
[#2605]:https://github.com/puma/puma/pull/2605 "PR by @pascalbetz, merged 2021-04-26"
|
1751
1826
|
[#2584]:https://github.com/puma/puma/issues/2584 "Issue by @kaorihinata, closed 2021-04-26"
|
1752
1827
|
[#2607]:https://github.com/puma/puma/pull/2607 "PR by @calvinxiao, merged 2021-04-23"
|
1753
|
-
[#2552]:https://github.com/puma/puma/issues/2552 "Issue by @feliperaul,
|
1828
|
+
[#2552]:https://github.com/puma/puma/issues/2552 "Issue by @feliperaul, closed 2021-05-24"
|
1754
1829
|
[#2606]:https://github.com/puma/puma/pull/2606 "PR by @wjordan, merged 2021-04-20"
|
1755
1830
|
[#2574]:https://github.com/puma/puma/issues/2574 "Issue by @darkhelmet, closed 2021-04-20"
|
1756
|
-
[#2567]:https://github.com/puma/puma/pull/2567 "PR by @
|
1757
|
-
[#2566]:https://github.com/puma/puma/issues/2566 "Issue by @
|
1831
|
+
[#2567]:https://github.com/puma/puma/pull/2567 "PR by @kddnewton, merged 2021-04-19"
|
1832
|
+
[#2566]:https://github.com/puma/puma/issues/2566 "Issue by @kddnewton, closed 2021-04-19"
|
1758
1833
|
[#2596]:https://github.com/puma/puma/pull/2596 "PR by @MSP-Greg, merged 2021-04-18"
|
1759
1834
|
[#2588]:https://github.com/puma/puma/pull/2588 "PR by @dentarg, merged 2021-04-02"
|
1760
1835
|
[#2556]:https://github.com/puma/puma/issues/2556 "Issue by @gamecreature, closed 2021-04-02"
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
<img src="https://puma.io/images/logos/puma-logo-large.png">
|
3
3
|
</p>
|
4
4
|
|
5
|
-
# Puma: A Ruby Web Server Built For
|
5
|
+
# Puma: A Ruby Web Server Built For Parallelism
|
6
6
|
|
7
7
|
[![Actions MRI](https://github.com/puma/puma/workflows/MRI/badge.svg?branch=master)](https://github.com/puma/puma/actions?query=workflow%3AMRI)
|
8
8
|
[![Actions non MRI](https://github.com/puma/puma/workflows/non_MRI/badge.svg?branch=master)](https://github.com/puma/puma/actions?query=workflow%3Anon_MRI)
|
@@ -10,11 +10,11 @@
|
|
10
10
|
[![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=puma&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=puma&package-manager=bundler&version-scheme=semver)
|
11
11
|
[![StackOverflow](https://img.shields.io/badge/stackoverflow-Puma-blue.svg)]( https://stackoverflow.com/questions/tagged/puma )
|
12
12
|
|
13
|
-
Puma is a **simple, fast, multi-threaded, and highly
|
13
|
+
Puma is a **simple, fast, multi-threaded, and highly parallel HTTP 1.1 server for Ruby/Rack applications**.
|
14
14
|
|
15
|
-
## Built For Speed &
|
15
|
+
## Built For Speed & Parallelism
|
16
16
|
|
17
|
-
Puma processes requests using a C-optimized Ragel extension (inherited from Mongrel) that provides fast, accurate HTTP 1.1 protocol parsing in a portable way. Puma then serves the request using a thread pool. Each request is served in a separate thread, so truly
|
17
|
+
Puma processes requests using a C-optimized Ragel extension (inherited from Mongrel) that provides fast, accurate HTTP 1.1 protocol parsing in a portable way. Puma then serves the request using a thread pool. Each request is served in a separate thread, so truly parallel Ruby implementations (JRuby, Rubinius) will use all available CPU cores.
|
18
18
|
|
19
19
|
Originally designed as a server for [Rubinius](https://github.com/rubinius/rubinius), Puma also works well with Ruby (MRI) and JRuby.
|
20
20
|
|
@@ -187,6 +187,21 @@ Need a bit of security? Use SSL sockets:
|
|
187
187
|
```
|
188
188
|
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
|
189
189
|
```
|
190
|
+
#### Self-signed SSL certificates (via _localhost_ gem, for development use):
|
191
|
+
|
192
|
+
Puma supports [localhost](https://github.com/socketry/localhost) gem for self-signed certificates. This is particularly useful if you want to use Puma with SSL locally, and self-signed certificates will work for your use-case. Currently, `localhost-authority` can be used only in MRI. To use [localhost](https://github.com/socketry/localhost), you have to `require "localhost/authority"`:
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
# config.ru
|
196
|
+
require './app'
|
197
|
+
require 'localhost/authority'
|
198
|
+
run Sinatra::Application
|
199
|
+
|
200
|
+
...
|
201
|
+
|
202
|
+
$ puma -b 'ssl://localhost:9292' config.ru
|
203
|
+
```
|
204
|
+
|
190
205
|
|
191
206
|
#### Controlling SSL Cipher Suites
|
192
207
|
|
@@ -257,9 +272,13 @@ $ puma -C /path/to/config
|
|
257
272
|
|
258
273
|
If no configuration file is specified, Puma will look for a configuration file at `config/puma.rb`. If an environment is specified, either via the `-e` and `--environment` flags, or through the `RACK_ENV` or the `RAILS_ENV` environment variables, Puma first looks for configuration at `config/puma/<environment_name>.rb`, and then falls back to `config/puma.rb`.
|
259
274
|
|
260
|
-
If you want to prevent Puma from looking for a configuration file in those locations,
|
275
|
+
If you want to prevent Puma from looking for a configuration file in those locations, include the `--no-config` flag:
|
261
276
|
|
262
277
|
```
|
278
|
+
$ puma --no-config
|
279
|
+
|
280
|
+
# or
|
281
|
+
|
263
282
|
$ puma -C "-"
|
264
283
|
```
|
265
284
|
|
data/docs/deployment.md
CHANGED
@@ -97,20 +97,5 @@ and use `runit` or hell, even `monit`.
|
|
97
97
|
## Restarting
|
98
98
|
|
99
99
|
You probably will want to deploy some new code at some point, and you'd like
|
100
|
-
puma to start running that new code.
|
101
|
-
|
102
|
-
|
103
|
-
1. Don't use `preload!`. This dirties the master process and means it will have
|
104
|
-
to shutdown all the workers and re-exec itself to get your new code. It is not compatible with phased-restart and `prune_bundler` as well.
|
105
|
-
|
106
|
-
1. Use `prune_bundler`. This makes it so that the cluster master will detach itself
|
107
|
-
from a Bundler context on start. This allows the cluster workers to load your app
|
108
|
-
and start a brand new Bundler context within the worker only. This means your
|
109
|
-
master remains pristine and can live on between new releases of your code.
|
110
|
-
|
111
|
-
1. Use phased-restart (`SIGUSR1` or `pumactl phased-restart`). This tells the master
|
112
|
-
to kill off one worker at a time and restart them in your new code. This minimizes
|
113
|
-
downtime and staggers the restart nicely. **WARNING** This means that both your
|
114
|
-
old code and your new code will be running concurrently. Most deployment solutions
|
115
|
-
already cause that, but it's worth warning you about it again. Be careful with your
|
116
|
-
migrations, etc!
|
100
|
+
puma to start running that new code. There are a few options for restarting
|
101
|
+
puma, described separately in our [restart documentation](restart.md).
|
data/docs/systemd.md
CHANGED
data/ext/puma_http11/extconf.rb
CHANGED
@@ -11,9 +11,18 @@ end
|
|
11
11
|
unless ENV["DISABLE_SSL"]
|
12
12
|
dir_config("openssl")
|
13
13
|
|
14
|
-
|
14
|
+
found_ssl = if pkg_config 'openssl'
|
15
|
+
puts 'using OpenSSL pkgconfig (openssl.pc)'
|
16
|
+
true
|
17
|
+
elsif %w'crypto libeay32'.find {|crypto| have_library(crypto, 'BIO_read')} &&
|
15
18
|
%w'ssl ssleay32'.find {|ssl| have_library(ssl, 'SSL_CTX_new')}
|
19
|
+
true
|
20
|
+
else
|
21
|
+
puts '** Puma will be compiled without SSL support'
|
22
|
+
false
|
23
|
+
end
|
16
24
|
|
25
|
+
if found_ssl
|
17
26
|
have_header "openssl/bio.h"
|
18
27
|
|
19
28
|
# below is yes for 1.0.2 & later
|
@@ -25,6 +34,14 @@ unless ENV["DISABLE_SSL"]
|
|
25
34
|
|
26
35
|
have_func "X509_STORE_up_ref"
|
27
36
|
have_func("SSL_CTX_set_ecdh_auto(NULL, 0)", "openssl/ssl.h")
|
37
|
+
|
38
|
+
# Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
|
39
|
+
if Random.respond_to?(:bytes)
|
40
|
+
$defs.push("-DHAVE_RANDOM_BYTES")
|
41
|
+
puts "checking for Random.bytes... yes"
|
42
|
+
else
|
43
|
+
puts "checking for Random.bytes... no"
|
44
|
+
end
|
28
45
|
end
|
29
46
|
end
|
30
47
|
|
data/ext/puma_http11/mini_ssl.c
CHANGED
@@ -208,7 +208,7 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
208
208
|
#endif
|
209
209
|
int ssl_options;
|
210
210
|
VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1,
|
211
|
-
verification_flags;
|
211
|
+
verification_flags, session_id_bytes;
|
212
212
|
DH *dh;
|
213
213
|
|
214
214
|
#if OPENSSL_VERSION_NUMBER < 0x10002000L
|
@@ -309,6 +309,21 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
309
309
|
} else {
|
310
310
|
SSL_CTX_set_verify(ctx, NUM2INT(verify_mode), engine_verify_callback);
|
311
311
|
}
|
312
|
+
|
313
|
+
// Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
|
314
|
+
session_id_bytes = rb_funcall(
|
315
|
+
#ifdef HAVE_RANDOM_BYTES
|
316
|
+
rb_cRandom,
|
317
|
+
#else
|
318
|
+
rb_const_get(rb_cRandom, rb_intern_const("DEFAULT")),
|
319
|
+
#endif
|
320
|
+
rb_intern_const("bytes"),
|
321
|
+
1, ULL2NUM(SSL_MAX_SSL_SESSION_ID_LENGTH));
|
322
|
+
|
323
|
+
SSL_CTX_set_session_id_context(ctx,
|
324
|
+
(unsigned char *) RSTRING_PTR(session_id_bytes),
|
325
|
+
SSL_MAX_SSL_SESSION_ID_LENGTH);
|
326
|
+
|
312
327
|
// printf("\ninitialize end security_level %d\n", SSL_CTX_get_security_level(ctx));
|
313
328
|
rb_obj_freeze(self);
|
314
329
|
return self;
|
data/lib/puma/app/status.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'puma/
|
2
|
+
require 'puma/json_serialization'
|
3
3
|
|
4
4
|
module Puma
|
5
5
|
module App
|
@@ -46,17 +46,17 @@ module Puma
|
|
46
46
|
GC.start ; 200
|
47
47
|
|
48
48
|
when 'gc-stats'
|
49
|
-
Puma::
|
49
|
+
Puma::JSONSerialization.generate GC.stat
|
50
50
|
|
51
51
|
when 'stats'
|
52
|
-
Puma::
|
52
|
+
Puma::JSONSerialization.generate @launcher.stats
|
53
53
|
|
54
54
|
when 'thread-backtraces'
|
55
55
|
backtraces = []
|
56
56
|
@launcher.thread_status do |name, backtrace|
|
57
57
|
backtraces << { name: name, backtrace: backtrace }
|
58
58
|
end
|
59
|
-
Puma::
|
59
|
+
Puma::JSONSerialization.generate backtraces
|
60
60
|
|
61
61
|
else
|
62
62
|
return rack_response(404, "Unsupported action", 'text/plain')
|
data/lib/puma/binder.rb
CHANGED
@@ -41,6 +41,7 @@ module Puma
|
|
41
41
|
"rack.multithread".freeze => conf.options[:max_threads] > 1,
|
42
42
|
"rack.multiprocess".freeze => conf.options[:workers] >= 1,
|
43
43
|
"rack.run_once".freeze => false,
|
44
|
+
RACK_URL_SCHEME => conf.options[:rack_url_scheme],
|
44
45
|
"SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",
|
45
46
|
|
46
47
|
# I'd like to set a default CONTENT_TYPE here but some things
|
@@ -56,6 +57,7 @@ module Puma
|
|
56
57
|
|
57
58
|
@envs = {}
|
58
59
|
@ios = []
|
60
|
+
localhost_authority
|
59
61
|
end
|
60
62
|
|
61
63
|
attr_reader :ios
|
@@ -95,6 +97,7 @@ module Puma
|
|
95
97
|
# @version 5.0.0
|
96
98
|
#
|
97
99
|
def create_activated_fds(env_hash)
|
100
|
+
@events.debug "ENV['LISTEN_FDS'] #{ENV['LISTEN_FDS'].inspect} env_hash['LISTEN_PID'] #{env_hash['LISTEN_PID'].inspect}"
|
98
101
|
return [] unless env_hash['LISTEN_FDS'] && env_hash['LISTEN_PID'].to_i == $$
|
99
102
|
env_hash['LISTEN_FDS'].to_i.times do |index|
|
100
103
|
sock = TCPServer.for_fd(socket_activation_fd(index))
|
@@ -163,7 +166,7 @@ module Puma
|
|
163
166
|
ios_len = @ios.length
|
164
167
|
params = Util.parse_query uri.query
|
165
168
|
|
166
|
-
opt = params.key?('low_latency')
|
169
|
+
opt = params.key?('low_latency') && params['low_latency'] != 'false'
|
167
170
|
bak = params.fetch('backlog', 1024).to_i
|
168
171
|
|
169
172
|
io = add_tcp_listener uri.host, uri.port, opt, bak
|
@@ -188,7 +191,8 @@ module Puma
|
|
188
191
|
@unix_paths << path unless abstract
|
189
192
|
io = inherit_unix_listener path, fd
|
190
193
|
logger.log "* Inherited #{str}"
|
191
|
-
elsif sock = @activated_sockets.delete([ :unix, path ])
|
194
|
+
elsif sock = @activated_sockets.delete([ :unix, path ]) ||
|
195
|
+
@activated_sockets.delete([ :unix, File.realdirpath(path) ])
|
192
196
|
@unix_paths << path unless abstract || File.exist?(path)
|
193
197
|
io = inherit_unix_listener path, sock
|
194
198
|
logger.log "* Activated #{str}"
|
@@ -224,7 +228,13 @@ module Puma
|
|
224
228
|
raise "Puma compiled without SSL support" unless HAS_SSL
|
225
229
|
|
226
230
|
params = Util.parse_query uri.query
|
227
|
-
|
231
|
+
|
232
|
+
# If key and certs are not defined and localhost gem is required.
|
233
|
+
# localhost gem will be used for self signed
|
234
|
+
# Load localhost authority if not loaded.
|
235
|
+
ctx = localhost_authority && localhost_authority_context if params.empty?
|
236
|
+
|
237
|
+
ctx ||= MiniSSL::ContextBuilder.new(params, @events).context
|
228
238
|
|
229
239
|
if fd = @inherited_fds.delete(str)
|
230
240
|
logger.log "* Inherited #{str}"
|
@@ -282,6 +292,22 @@ module Puma
|
|
282
292
|
end
|
283
293
|
end
|
284
294
|
|
295
|
+
def localhost_authority
|
296
|
+
@localhost_authority ||= Localhost::Authority.fetch if defined?(Localhost::Authority) && !Puma::IS_JRUBY
|
297
|
+
end
|
298
|
+
|
299
|
+
def localhost_authority_context
|
300
|
+
return unless localhost_authority
|
301
|
+
|
302
|
+
key_path, crt_path = if [:key_path, :certificate_path].all? { |m| localhost_authority.respond_to?(m) }
|
303
|
+
[localhost_authority.key_path, localhost_authority.certificate_path]
|
304
|
+
else
|
305
|
+
local_certificates_path = File.expand_path("~/.localhost")
|
306
|
+
[File.join(local_certificates_path, "localhost.key"), File.join(local_certificates_path, "localhost.crt")]
|
307
|
+
end
|
308
|
+
MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @events).context
|
309
|
+
end
|
310
|
+
|
285
311
|
# Tell the server to listen on host +host+, port +port+.
|
286
312
|
# If +optimize_for_latency+ is true (the default) then clients connecting
|
287
313
|
# will be optimized for latency over throughput.
|
@@ -299,6 +325,7 @@ module Puma
|
|
299
325
|
|
300
326
|
host = host[1..-2] if host and host[0..0] == '['
|
301
327
|
tcp_server = TCPServer.new(host, port)
|
328
|
+
|
302
329
|
if optimize_for_latency
|
303
330
|
tcp_server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
304
331
|
end
|
@@ -320,6 +347,8 @@ module Puma
|
|
320
347
|
optimize_for_latency=true, backlog=1024)
|
321
348
|
|
322
349
|
raise "Puma compiled without SSL support" unless HAS_SSL
|
350
|
+
# Puma will try to use local authority context if context is supplied nil
|
351
|
+
ctx ||= localhost_authority_context
|
323
352
|
|
324
353
|
if host == "localhost"
|
325
354
|
loopback_addresses.each do |addr|
|
@@ -347,6 +376,8 @@ module Puma
|
|
347
376
|
|
348
377
|
def inherit_ssl_listener(fd, ctx)
|
349
378
|
raise "Puma compiled without SSL support" unless HAS_SSL
|
379
|
+
# Puma will try to use local authority context if context is supplied nil
|
380
|
+
ctx ||= localhost_authority_context
|
350
381
|
|
351
382
|
s = fd.kind_of?(::TCPServer) ? fd : ::TCPServer.for_fd(fd)
|
352
383
|
|
data/lib/puma/cli.rb
CHANGED
@@ -112,6 +112,11 @@ module Puma
|
|
112
112
|
file_config.load arg
|
113
113
|
end
|
114
114
|
|
115
|
+
# Identical to supplying --config "-", but more semantic
|
116
|
+
o.on "--no-config", "Prevent Puma from searching for a config file" do |arg|
|
117
|
+
file_config.load "-"
|
118
|
+
end
|
119
|
+
|
115
120
|
o.on "--control-url URL", "The bind url to use for the control server. Use 'auto' to use temp unix server" do |arg|
|
116
121
|
configure_control_url(arg)
|
117
122
|
end
|
data/lib/puma/client.rb
CHANGED
@@ -56,6 +56,7 @@ module Puma
|
|
56
56
|
@parser = HttpParser.new
|
57
57
|
@parsed_bytes = 0
|
58
58
|
@read_header = true
|
59
|
+
@read_proxy = false
|
59
60
|
@ready = false
|
60
61
|
|
61
62
|
@body = nil
|
@@ -69,7 +70,9 @@ module Puma
|
|
69
70
|
@hijacked = false
|
70
71
|
|
71
72
|
@peerip = nil
|
73
|
+
@listener = nil
|
72
74
|
@remote_addr_header = nil
|
75
|
+
@expect_proxy_proto = false
|
73
76
|
|
74
77
|
@body_remain = 0
|
75
78
|
|
@@ -81,7 +84,7 @@ module Puma
|
|
81
84
|
|
82
85
|
attr_writer :peerip
|
83
86
|
|
84
|
-
attr_accessor :remote_addr_header
|
87
|
+
attr_accessor :remote_addr_header, :listener
|
85
88
|
|
86
89
|
def_delegators :@io, :closed?
|
87
90
|
|
@@ -105,7 +108,7 @@ module Puma
|
|
105
108
|
|
106
109
|
# @!attribute [r] in_data_phase
|
107
110
|
def in_data_phase
|
108
|
-
|
111
|
+
!(@read_header || @read_proxy)
|
109
112
|
end
|
110
113
|
|
111
114
|
def set_timeout(val)
|
@@ -120,6 +123,7 @@ module Puma
|
|
120
123
|
def reset(fast_check=true)
|
121
124
|
@parser.reset
|
122
125
|
@read_header = true
|
126
|
+
@read_proxy = !!@expect_proxy_proto
|
123
127
|
@env = @proto_env.dup
|
124
128
|
@body = nil
|
125
129
|
@tempfile = nil
|
@@ -130,6 +134,8 @@ module Puma
|
|
130
134
|
@in_last_chunk = false
|
131
135
|
|
132
136
|
if @buffer
|
137
|
+
return false unless try_to_parse_proxy_protocol
|
138
|
+
|
133
139
|
@parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
|
134
140
|
|
135
141
|
if @parser.finished?
|
@@ -142,8 +148,7 @@ module Puma
|
|
142
148
|
return false
|
143
149
|
else
|
144
150
|
begin
|
145
|
-
if fast_check &&
|
146
|
-
IO.select([@to_io], nil, nil, FAST_TRACK_KA_TIMEOUT)
|
151
|
+
if fast_check && @to_io.wait_readable(FAST_TRACK_KA_TIMEOUT)
|
147
152
|
return try_to_finish
|
148
153
|
end
|
149
154
|
rescue IOError
|
@@ -161,8 +166,32 @@ module Puma
|
|
161
166
|
end
|
162
167
|
end
|
163
168
|
|
169
|
+
# If necessary, read the PROXY protocol from the buffer. Returns
|
170
|
+
# false if more data is needed.
|
171
|
+
def try_to_parse_proxy_protocol
|
172
|
+
if @read_proxy
|
173
|
+
if @expect_proxy_proto == :v1
|
174
|
+
if @buffer.include? "\r\n"
|
175
|
+
if md = PROXY_PROTOCOL_V1_REGEX.match(@buffer)
|
176
|
+
if md[1]
|
177
|
+
@peerip = md[1].split(" ")[0]
|
178
|
+
end
|
179
|
+
@buffer = md.post_match
|
180
|
+
end
|
181
|
+
# if the buffer has a \r\n but doesn't have a PROXY protocol
|
182
|
+
# request, this is just HTTP from a non-PROXY client; move on
|
183
|
+
@read_proxy = false
|
184
|
+
return @buffer.size > 0
|
185
|
+
else
|
186
|
+
return false
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
true
|
191
|
+
end
|
192
|
+
|
164
193
|
def try_to_finish
|
165
|
-
return read_body
|
194
|
+
return read_body if in_data_phase
|
166
195
|
|
167
196
|
begin
|
168
197
|
data = @io.read_nonblock(CHUNK_SIZE)
|
@@ -187,6 +216,8 @@ module Puma
|
|
187
216
|
@buffer = data
|
188
217
|
end
|
189
218
|
|
219
|
+
return false unless try_to_parse_proxy_protocol
|
220
|
+
|
190
221
|
@parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
|
191
222
|
|
192
223
|
if @parser.finished?
|
@@ -201,13 +232,13 @@ module Puma
|
|
201
232
|
|
202
233
|
def eagerly_finish
|
203
234
|
return true if @ready
|
204
|
-
return false unless
|
235
|
+
return false unless @to_io.wait_readable(0)
|
205
236
|
try_to_finish
|
206
237
|
end
|
207
238
|
|
208
239
|
def finish(timeout)
|
209
240
|
return if @ready
|
210
|
-
|
241
|
+
@to_io.wait_readable(timeout) || timeout! until try_to_finish
|
211
242
|
end
|
212
243
|
|
213
244
|
def timeout!
|
@@ -243,6 +274,17 @@ module Puma
|
|
243
274
|
@parsed_bytes == 0
|
244
275
|
end
|
245
276
|
|
277
|
+
def expect_proxy_proto=(val)
|
278
|
+
if val
|
279
|
+
if @read_header
|
280
|
+
@read_proxy = true
|
281
|
+
end
|
282
|
+
else
|
283
|
+
@read_proxy = false
|
284
|
+
end
|
285
|
+
@expect_proxy_proto = val
|
286
|
+
end
|
287
|
+
|
246
288
|
private
|
247
289
|
|
248
290
|
def setup_body
|
@@ -308,7 +350,7 @@ module Puma
|
|
308
350
|
|
309
351
|
@body_remain = remain
|
310
352
|
|
311
|
-
|
353
|
+
false
|
312
354
|
end
|
313
355
|
|
314
356
|
def read_body
|
data/lib/puma/cluster/worker.rb
CHANGED
@@ -33,9 +33,9 @@ module Puma
|
|
33
33
|
Signal.trap "SIGINT", "IGNORE"
|
34
34
|
Signal.trap "SIGCHLD", "DEFAULT"
|
35
35
|
|
36
|
-
|
36
|
+
Thread.new do
|
37
37
|
Puma.set_thread_name "worker check pipe"
|
38
|
-
|
38
|
+
@check_pipe.wait_readable
|
39
39
|
log "! Detected parent died, dying"
|
40
40
|
exit! 1
|
41
41
|
end
|
@@ -54,7 +54,14 @@ module Puma
|
|
54
54
|
# things in shape before booting the app.
|
55
55
|
@launcher.config.run_hooks :before_worker_boot, index, @launcher.events
|
56
56
|
|
57
|
+
begin
|
57
58
|
server = @server ||= start_server
|
59
|
+
rescue Exception => e
|
60
|
+
log "! Unable to start worker"
|
61
|
+
log e.backtrace[0]
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
58
65
|
restart_server = Queue.new << true << false
|
59
66
|
|
60
67
|
fork_worker = @options[:fork_worker] && index == 0
|
data/lib/puma/cluster.rb
CHANGED
@@ -426,9 +426,7 @@ module Puma
|
|
426
426
|
|
427
427
|
check_workers
|
428
428
|
|
429
|
-
|
430
|
-
|
431
|
-
if res
|
429
|
+
if read.wait_readable([0, @next_check - Time.now].max)
|
432
430
|
req = read.read_nonblock(1)
|
433
431
|
|
434
432
|
@next_check = Time.now if req == "!"
|
data/lib/puma/configuration.rb
CHANGED
@@ -343,6 +343,8 @@ module Puma
|
|
343
343
|
raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
|
344
344
|
|
345
345
|
rack_app, rack_options = rack_builder.parse_file(rackup)
|
346
|
+
rack_options = rack_options || {}
|
347
|
+
|
346
348
|
@options.file_options.merge!(rack_options)
|
347
349
|
|
348
350
|
config_ru_binds = []
|
data/lib/puma/const.rb
CHANGED
@@ -100,8 +100,8 @@ module Puma
|
|
100
100
|
# too taxing on performance.
|
101
101
|
module Const
|
102
102
|
|
103
|
-
PUMA_VERSION = VERSION = "5.
|
104
|
-
CODE_NAME = "
|
103
|
+
PUMA_VERSION = VERSION = "5.5.0".freeze
|
104
|
+
CODE_NAME = "Zawgyi".freeze
|
105
105
|
|
106
106
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
107
107
|
|
@@ -247,5 +247,7 @@ module Puma
|
|
247
247
|
|
248
248
|
# Banned keys of response header
|
249
249
|
BANNED_HEADER_KEY = /\A(rack\.|status\z)/.freeze
|
250
|
+
|
251
|
+
PROXY_PROTOCOL_V1_REGEX = /^PROXY (?:TCP4|TCP6|UNKNOWN) ([^\r]+)\r\n/.freeze
|
250
252
|
end
|
251
253
|
end
|
data/lib/puma/dsl.rb
CHANGED
@@ -201,7 +201,7 @@ module Puma
|
|
201
201
|
# * Set the socket backlog depth with +backlog+, default is 1024.
|
202
202
|
# * Set up an SSL certificate with +key+ & +cert+.
|
203
203
|
# * Set whether to optimize for low latency instead of throughput with
|
204
|
-
# +low_latency+, default is to optimize for low latency. This is done
|
204
|
+
# +low_latency+, default is to not optimize for low latency. This is done
|
205
205
|
# via +Socket::TCP_NODELAY+.
|
206
206
|
# * Set socket permissions with +umask+.
|
207
207
|
#
|
@@ -381,6 +381,13 @@ module Puma
|
|
381
381
|
@options[:rackup] ||= path.to_s
|
382
382
|
end
|
383
383
|
|
384
|
+
# Allows setting `env['rack.url_scheme']`.
|
385
|
+
# Only necessary if X-Forwarded-Proto is not being set by your proxy
|
386
|
+
# Normal values are 'http' or 'https'.
|
387
|
+
def rack_url_scheme(scheme=nil)
|
388
|
+
@options[:rack_url_scheme] = scheme
|
389
|
+
end
|
390
|
+
|
384
391
|
def early_hints(answer=true)
|
385
392
|
@options[:early_hints] = answer
|
386
393
|
end
|
@@ -578,7 +585,7 @@ module Puma
|
|
578
585
|
# end
|
579
586
|
def after_worker_fork(&block)
|
580
587
|
@options[:after_worker_fork] ||= []
|
581
|
-
@options[:after_worker_fork]
|
588
|
+
@options[:after_worker_fork] << block
|
582
589
|
end
|
583
590
|
|
584
591
|
alias_method :after_worker_boot, :after_worker_fork
|
@@ -811,7 +818,7 @@ module Puma
|
|
811
818
|
# a kernel syscall is required which for very fast rack handlers
|
812
819
|
# slows down the handling significantly.
|
813
820
|
#
|
814
|
-
# There are
|
821
|
+
# There are 5 possible values:
|
815
822
|
#
|
816
823
|
# 1. **:socket** (the default) - read the peername from the socket using the
|
817
824
|
# syscall. This is the normal behavior.
|
@@ -821,7 +828,10 @@ module Puma
|
|
821
828
|
# `set_remote_address header: "X-Real-IP"`.
|
822
829
|
# Only the first word (as separated by spaces or comma) is used, allowing
|
823
830
|
# headers such as X-Forwarded-For to be used as well.
|
824
|
-
# 4.
|
831
|
+
# 4. **proxy_protocol: :v1**- set the remote address to the value read from the
|
832
|
+
# HAproxy PROXY protocol, version 1. If the request does not have the PROXY
|
833
|
+
# protocol attached to it, will fall back to :socket
|
834
|
+
# 5. **\<Any string\>** - this allows you to hardcode remote address to any value
|
825
835
|
# you wish. Because Puma never uses this field anyway, it's format is
|
826
836
|
# entirely in your hands.
|
827
837
|
#
|
@@ -839,6 +849,13 @@ module Puma
|
|
839
849
|
if hdr = val[:header]
|
840
850
|
@options[:remote_address] = :header
|
841
851
|
@options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
|
852
|
+
elsif protocol_version = val[:proxy_protocol]
|
853
|
+
@options[:remote_address] = :proxy_protocol
|
854
|
+
protocol_version = protocol_version.downcase.to_sym
|
855
|
+
unless [:v1].include?(protocol_version)
|
856
|
+
raise "Invalid value for proxy_protocol - #{protocol_version.inspect}"
|
857
|
+
end
|
858
|
+
@options[:remote_address_proxy_protocol] = protocol_version
|
842
859
|
else
|
843
860
|
raise "Invalid value for set_remote_address - #{val.inspect}"
|
844
861
|
end
|
@@ -17,7 +17,7 @@ module Puma
|
|
17
17
|
# be particularly full-featured or fast. It just has to handle the few places
|
18
18
|
# where Puma relies on JSON serialization internally.
|
19
19
|
|
20
|
-
module
|
20
|
+
module JSONSerialization
|
21
21
|
QUOTE = /"/
|
22
22
|
BACKSLASH = /\\/
|
23
23
|
CONTROL_CHAR_TO_ESCAPE = /[\x00-\x1F]/ # As required by ECMA-404
|
data/lib/puma/launcher.rb
CHANGED
@@ -319,10 +319,12 @@ module Puma
|
|
319
319
|
log '* Pruning Bundler environment'
|
320
320
|
home = ENV['GEM_HOME']
|
321
321
|
bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
|
322
|
+
bundle_app_config = Bundler.original_env['BUNDLE_APP_CONFIG']
|
322
323
|
with_unbundled_env do
|
323
324
|
ENV['GEM_HOME'] = home
|
324
325
|
ENV['BUNDLE_GEMFILE'] = bundle_gemfile
|
325
326
|
ENV['PUMA_BUNDLER_PRUNED'] = '1'
|
327
|
+
ENV["BUNDLE_APP_CONFIG"] = bundle_app_config
|
326
328
|
args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':')] + @original_argv
|
327
329
|
# Ruby 2.0+ defaults to true which breaks socket activation
|
328
330
|
args += [{:close_others => false}]
|
data/lib/puma/minissl.rb
CHANGED
@@ -161,28 +161,13 @@ module Puma
|
|
161
161
|
@socket.flush
|
162
162
|
end
|
163
163
|
|
164
|
-
def read_and_drop(timeout = 1)
|
165
|
-
return :timeout unless IO.select([@socket], nil, nil, timeout)
|
166
|
-
case @socket.read_nonblock(1024, exception: false)
|
167
|
-
when nil
|
168
|
-
:eof
|
169
|
-
when :wait_readable
|
170
|
-
:eagain
|
171
|
-
else
|
172
|
-
:drop
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def should_drop_bytes?
|
177
|
-
@engine.init? || !@engine.shutdown
|
178
|
-
end
|
179
|
-
|
180
164
|
def close
|
181
165
|
begin
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
166
|
+
unless @engine.shutdown
|
167
|
+
while alert_data = @engine.extract
|
168
|
+
@socket.write alert_data
|
169
|
+
end
|
170
|
+
end
|
186
171
|
rescue IOError, SystemCallError
|
187
172
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
188
173
|
# nothing
|
data/lib/puma/plugin.rb
CHANGED
data/lib/puma/puma_http11.jar
CHANGED
Binary file
|
data/lib/puma/rack/builder.rb
CHANGED
data/lib/puma/request.rb
CHANGED
@@ -26,9 +26,10 @@ module Puma
|
|
26
26
|
# Finally, it'll return +true+ on keep-alive connections.
|
27
27
|
# @param client [Puma::Client]
|
28
28
|
# @param lines [Puma::IOBuffer]
|
29
|
+
# @param requests [Integer]
|
29
30
|
# @return [Boolean,:async]
|
30
31
|
#
|
31
|
-
def handle_request(client, lines)
|
32
|
+
def handle_request(client, lines, requests)
|
32
33
|
env = client.env
|
33
34
|
io = client.io # io may be a MiniSSL::Socket
|
34
35
|
|
@@ -50,7 +51,7 @@ module Puma
|
|
50
51
|
head = env[REQUEST_METHOD] == HEAD
|
51
52
|
|
52
53
|
env[RACK_INPUT] = body
|
53
|
-
env[RACK_URL_SCHEME]
|
54
|
+
env[RACK_URL_SCHEME] ||= default_server_port(env) == PORT_443 ? HTTPS : HTTP
|
54
55
|
|
55
56
|
if @early_hints
|
56
57
|
env[EARLY_HINTS] = lambda { |headers|
|
@@ -110,7 +111,7 @@ module Puma
|
|
110
111
|
|
111
112
|
cork_socket io
|
112
113
|
|
113
|
-
str_headers(env, status, headers, res_info, lines)
|
114
|
+
str_headers(env, status, headers, res_info, lines, requests, client)
|
114
115
|
|
115
116
|
line_ending = LINE_END
|
116
117
|
|
@@ -175,7 +176,7 @@ module Puma
|
|
175
176
|
after_reply.each { |o| o.call }
|
176
177
|
end
|
177
178
|
|
178
|
-
|
179
|
+
res_info[:keep_alive]
|
179
180
|
end
|
180
181
|
|
181
182
|
# @param env [Hash] see Puma::Client#env, from request
|
@@ -200,7 +201,7 @@ module Puma
|
|
200
201
|
begin
|
201
202
|
n = io.syswrite str
|
202
203
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
203
|
-
|
204
|
+
unless io.wait_writable WRITE_TIMEOUT
|
204
205
|
raise ConnectionError, "Socket timeout writing data"
|
205
206
|
end
|
206
207
|
|
@@ -367,9 +368,11 @@ module Puma
|
|
367
368
|
# @param headers [Hash] the headers returned by the Rack application
|
368
369
|
# @param res_info [Hash] used to pass info between this method and #handle_request
|
369
370
|
# @param lines [Puma::IOBuffer] modified inn place
|
371
|
+
# @param requests [Integer] number of inline requests handled
|
372
|
+
# @param client [Puma::Client]
|
370
373
|
# @version 5.0.3
|
371
374
|
#
|
372
|
-
def str_headers(env, status, headers, res_info, lines)
|
375
|
+
def str_headers(env, status, headers, res_info, lines, requests, client)
|
373
376
|
line_ending = LINE_END
|
374
377
|
colon = COLON
|
375
378
|
|
@@ -410,6 +413,14 @@ module Puma
|
|
410
413
|
# if running without request queueing
|
411
414
|
res_info[:keep_alive] &&= @queue_requests
|
412
415
|
|
416
|
+
# Close the connection after a reasonable number of inline requests
|
417
|
+
# if the server is at capacity and the listener has a new connection ready.
|
418
|
+
# This allows Puma to service connections fairly when the number
|
419
|
+
# of concurrent connections exceeds the size of the threadpool.
|
420
|
+
res_info[:keep_alive] &&= requests < @max_fast_inline ||
|
421
|
+
@thread_pool.busy_threads < @max_threads ||
|
422
|
+
!client.listener.to_io.wait_readable(0)
|
423
|
+
|
413
424
|
res_info[:response_hijack] = nil
|
414
425
|
|
415
426
|
headers.each do |k, vs|
|
data/lib/puma/server.rb
CHANGED
@@ -14,6 +14,7 @@ require 'puma/io_buffer'
|
|
14
14
|
require 'puma/request'
|
15
15
|
|
16
16
|
require 'socket'
|
17
|
+
require 'io/wait'
|
17
18
|
require 'forwardable'
|
18
19
|
|
19
20
|
module Puma
|
@@ -227,6 +228,7 @@ module Puma
|
|
227
228
|
@status = :run
|
228
229
|
|
229
230
|
@thread_pool = ThreadPool.new(
|
231
|
+
thread_name,
|
230
232
|
@min_threads,
|
231
233
|
@max_threads,
|
232
234
|
::Puma::IOBuffer,
|
@@ -321,6 +323,8 @@ module Puma
|
|
321
323
|
remote_addr_value = @options[:remote_address_value]
|
322
324
|
when :header
|
323
325
|
remote_addr_header = @options[:remote_address_header]
|
326
|
+
when :proxy_protocol
|
327
|
+
remote_addr_proxy_protocol = @options[:remote_address_proxy_protocol]
|
324
328
|
end
|
325
329
|
|
326
330
|
while @status == :run || (drain && shutting_down?)
|
@@ -341,15 +345,21 @@ module Puma
|
|
341
345
|
end
|
342
346
|
drain += 1 if shutting_down?
|
343
347
|
client = Client.new io, @binder.env(sock)
|
348
|
+
client.listener = sock
|
344
349
|
if remote_addr_value
|
345
350
|
client.peerip = remote_addr_value
|
346
351
|
elsif remote_addr_header
|
347
352
|
client.remote_addr_header = remote_addr_header
|
353
|
+
elsif remote_addr_proxy_protocol
|
354
|
+
client.expect_proxy_proto = remote_addr_proxy_protocol
|
348
355
|
end
|
349
356
|
pool << client
|
350
357
|
end
|
351
358
|
end
|
352
|
-
rescue
|
359
|
+
rescue IOError, Errno::EBADF
|
360
|
+
# In the case that any of the sockets are unexpectedly close.
|
361
|
+
raise
|
362
|
+
rescue StandardError => e
|
353
363
|
@events.unknown_error e, nil, "Listen loop"
|
354
364
|
end
|
355
365
|
end
|
@@ -395,7 +405,7 @@ module Puma
|
|
395
405
|
return true
|
396
406
|
end
|
397
407
|
|
398
|
-
|
408
|
+
false
|
399
409
|
end
|
400
410
|
|
401
411
|
# Given a connection on +client+, handle the incoming requests,
|
@@ -434,7 +444,7 @@ module Puma
|
|
434
444
|
|
435
445
|
while true
|
436
446
|
@requests_count += 1
|
437
|
-
case handle_request(client, buffer)
|
447
|
+
case handle_request(client, buffer, requests + 1)
|
438
448
|
when false
|
439
449
|
break
|
440
450
|
when :async
|
@@ -447,18 +457,17 @@ module Puma
|
|
447
457
|
|
448
458
|
requests += 1
|
449
459
|
|
450
|
-
|
460
|
+
# As an optimization, try to read the next request from the
|
461
|
+
# socket for a short time before returning to the reactor.
|
462
|
+
fast_check = @status == :run
|
451
463
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
# one once every max_fast_inline requests.
|
457
|
-
check_for_more_data = false
|
458
|
-
end
|
464
|
+
# Always pass the client back to the reactor after a reasonable
|
465
|
+
# number of inline requests if there are other requests pending.
|
466
|
+
fast_check = false if requests >= @max_fast_inline &&
|
467
|
+
@thread_pool.backlog > 0
|
459
468
|
|
460
469
|
next_request_ready = with_force_shutdown(client) do
|
461
|
-
client.reset(
|
470
|
+
client.reset(fast_check)
|
462
471
|
end
|
463
472
|
|
464
473
|
unless next_request_ready
|
data/lib/puma/thread_pool.rb
CHANGED
@@ -29,7 +29,7 @@ module Puma
|
|
29
29
|
# The block passed is the work that will be performed in each
|
30
30
|
# thread.
|
31
31
|
#
|
32
|
-
def initialize(min, max, *extra, &block)
|
32
|
+
def initialize(name, min, max, *extra, &block)
|
33
33
|
@not_empty = ConditionVariable.new
|
34
34
|
@not_full = ConditionVariable.new
|
35
35
|
@mutex = Mutex.new
|
@@ -39,6 +39,7 @@ module Puma
|
|
39
39
|
@spawned = 0
|
40
40
|
@waiting = 0
|
41
41
|
|
42
|
+
@name = name
|
42
43
|
@min = Integer(min)
|
43
44
|
@max = Integer(max)
|
44
45
|
@block = block
|
@@ -101,7 +102,7 @@ module Puma
|
|
101
102
|
@spawned += 1
|
102
103
|
|
103
104
|
th = Thread.new(@spawned) do |spawned|
|
104
|
-
Puma.set_thread_name 'threadpool %03i' % spawned
|
105
|
+
Puma.set_thread_name '%s threadpool %03i' % [@name, spawned]
|
105
106
|
todo = @todo
|
106
107
|
block = @block
|
107
108
|
mutex = @mutex
|
@@ -119,6 +120,7 @@ module Puma
|
|
119
120
|
@trim_requested -= 1
|
120
121
|
@spawned -= 1
|
121
122
|
@workers.delete th
|
123
|
+
not_full.signal
|
122
124
|
Thread.exit
|
123
125
|
end
|
124
126
|
|
@@ -318,12 +320,12 @@ module Puma
|
|
318
320
|
end
|
319
321
|
|
320
322
|
def auto_trim!(timeout=30)
|
321
|
-
@auto_trim = Automaton.new(self, timeout, "threadpool trimmer", :trim)
|
323
|
+
@auto_trim = Automaton.new(self, timeout, "#{@name} threadpool trimmer", :trim)
|
322
324
|
@auto_trim.start!
|
323
325
|
end
|
324
326
|
|
325
327
|
def auto_reap!(timeout=5)
|
326
|
-
@reaper = Automaton.new(self, timeout, "threadpool reaper", :reap)
|
328
|
+
@reaper = Automaton.new(self, timeout, "#{@name} threadpool reaper", :reap)
|
327
329
|
@reaper.start!
|
328
330
|
end
|
329
331
|
|
data/lib/puma/util.rb
CHANGED
data/lib/puma.rb
CHANGED
@@ -12,7 +12,7 @@ require 'thread'
|
|
12
12
|
|
13
13
|
require 'puma/puma_http11'
|
14
14
|
require 'puma/detect'
|
15
|
-
require 'puma/
|
15
|
+
require 'puma/json_serialization'
|
16
16
|
|
17
17
|
module Puma
|
18
18
|
autoload :Const, 'puma/const'
|
@@ -60,7 +60,7 @@ module Puma
|
|
60
60
|
|
61
61
|
# @!attribute [rw] stats_object
|
62
62
|
def self.stats
|
63
|
-
Puma::
|
63
|
+
Puma::JSONSerialization.generate @get_stats.stats
|
64
64
|
end
|
65
65
|
|
66
66
|
# @!attribute [r] stats_hash
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.5.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -24,9 +24,9 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.0'
|
27
|
-
description: Puma is a simple, fast, threaded, and highly
|
27
|
+
description: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server
|
28
28
|
for Ruby/Rack applications. Puma is intended for use in both development and production
|
29
|
-
environments. It's great for highly
|
29
|
+
environments. It's great for highly parallel Ruby implementations such as Rubinius
|
30
30
|
and JRuby as well as as providing process worker support to support CRuby well.
|
31
31
|
email:
|
32
32
|
- evan@phx.io
|
@@ -93,7 +93,7 @@ files:
|
|
93
93
|
- lib/puma/events.rb
|
94
94
|
- lib/puma/io_buffer.rb
|
95
95
|
- lib/puma/jruby_restart.rb
|
96
|
-
- lib/puma/
|
96
|
+
- lib/puma/json_serialization.rb
|
97
97
|
- lib/puma/launcher.rb
|
98
98
|
- lib/puma/minissl.rb
|
99
99
|
- lib/puma/minissl/context_builder.rb
|
@@ -143,6 +143,6 @@ requirements: []
|
|
143
143
|
rubygems_version: 3.1.6
|
144
144
|
signing_key:
|
145
145
|
specification_version: 4
|
146
|
-
summary: Puma is a simple, fast, threaded, and highly
|
146
|
+
summary: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server for
|
147
147
|
Ruby/Rack applications
|
148
148
|
test_files: []
|