puma 6.4.0-java → 6.4.2-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 +66 -11
- data/README.md +1 -0
- data/docs/kubernetes.md +1 -1
- data/docs/restart.md +1 -0
- data/docs/systemd.md +2 -4
- data/ext/puma_http11/extconf.rb +5 -1
- data/ext/puma_http11/mini_ssl.c +5 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +2 -1
- data/lib/puma/client.rb +27 -0
- data/lib/puma/cluster.rb +69 -10
- data/lib/puma/configuration.rb +1 -3
- data/lib/puma/const.rb +1 -1
- data/lib/puma/detect.rb +3 -4
- data/lib/puma/dsl.rb +21 -8
- data/lib/puma/minissl/context_builder.rb +2 -0
- data/lib/puma/minissl.rb +5 -0
- data/lib/puma/null_io.rb +16 -2
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/runner.rb +1 -1
- data/lib/puma/server.rb +22 -1
- data/lib/puma/state_file.rb +2 -2
- data/tools/Dockerfile +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1736c6dd01c94d6cf6a109965156ec60ec8a9deb17b42bdabc198f79d1b72c1a
|
4
|
+
data.tar.gz: 58e70495466aa055fc76038a23cf394167ca393959ab7bfa8a55306a7506f1ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ee67bed8910a53a217a6d9f799cf7a64f145d5a80a0cbea224949e3ae2fe76ae31dc5e5991a7983f71cbe34836ef568cab41a6d0ae5ca7d21cf0f87b8fac09e
|
7
|
+
data.tar.gz: '0085fa5bd8492707be9c52b3618c0663a06a2aad62e5fe60b66521d51572f8159d22f5f14b265314c1a094bec0d506dabef74c514fb8813d9a31d9f5395bfd3d'
|
data/History.md
CHANGED
@@ -1,8 +1,37 @@
|
|
1
|
+
## 6.4.2 / 2024-01-08
|
2
|
+
|
3
|
+
* Security
|
4
|
+
* Limit the size of chunk extensions. Without this limit, an attacker could cause unbounded resource (CPU, network bandwidth) consumption. ([GHSA-c2f4-cvqm-65w2](https://github.com/puma/puma/security/advisories/GHSA-c2f4-cvqm-65w2))
|
5
|
+
|
6
|
+
## 6.4.1 / 2024-01-03
|
7
|
+
|
8
|
+
* Bugfixes
|
9
|
+
* DSL#warn_if_in_single_mode - fixup when workers set via CLI ([#3256])
|
10
|
+
* Fix `idle-timeout` not working in cluster mode ([#3235], [#3228], [#3282], [#3283])
|
11
|
+
* Fix worker 0 timing out during phased restart ([#3225], [#2786])
|
12
|
+
* context_builder.rb - require openssl if verify_mode != 'none' ([#3179])
|
13
|
+
* Make puma cluster process suitable as PID 1 ([#3255])
|
14
|
+
* Improve Puma::NullIO consistency with real IO ([#3276])
|
15
|
+
* extconf.rb - fixup to detect openssl info in Ruby build ([#3271], [#3266])
|
16
|
+
* MiniSSL.java - set serialVersionUID, fix RaiseException deprecation ([#3270])
|
17
|
+
* dsl.rb - fix warn_if_in_single_mode when WEB_CONCURRENCY is set ([#3265], [#3264])
|
18
|
+
|
19
|
+
* Maintenance
|
20
|
+
* LOTS of test refactoring to make tests more stable and easier to write - thanks to @MSP-Greg!
|
21
|
+
* Fix bug in tests re: TestPuma::HOST4 ([#3254])
|
22
|
+
* Dockerfile for minimal repros: use Ruby 3.2, expect bundler installed ([#3245])
|
23
|
+
* fix define_method calls, use Symbol parameter instead of String ([#3293])
|
24
|
+
|
25
|
+
* Docs
|
26
|
+
* README.md - add the puma-acme plugin ([#3301])
|
27
|
+
* Remove `--keep-file-descriptors` flag from systemd docs ([#3248])
|
28
|
+
* Note symlink mechanism in restart documentation for hot restart ([#3298])
|
29
|
+
|
1
30
|
## 6.4.0 / 2023-09-21
|
2
31
|
|
3
32
|
* Features
|
4
33
|
* on_thread_exit hook ([#2920])
|
5
|
-
* on_thread_start_hook ([#3195])
|
34
|
+
* on_thread_start_hook ([#3195])
|
6
35
|
* Shutdown on idle ([#3209], [#2580])
|
7
36
|
* New error message when control server port taken ([#3204])
|
8
37
|
|
@@ -12,13 +41,13 @@
|
|
12
41
|
|
13
42
|
* Bugfixes
|
14
43
|
* Bring the cert_pem: parameter into parity with the cert: parameter to ssl_bind. ([#3174])
|
15
|
-
* Fix using control server with IPv6 host ([#3181])
|
44
|
+
* Fix using control server with IPv6 host ([#3181])
|
16
45
|
* control_cli.rb - add require_relative 'log_writer' ([#3187])
|
17
46
|
* Fix cases where fallback Rack response wasn't sent to the client ([#3094])
|
18
|
-
|
47
|
+
|
19
48
|
## 6.3.1 / 2023-08-18
|
20
49
|
|
21
|
-
* Security
|
50
|
+
* Security
|
22
51
|
* Address HTTP request smuggling vulnerabilities with zero-length Content Length header and trailer fields ([GHSA-68xg-gqqm-vgj8](https://github.com/puma/puma/security/advisories/GHSA-68xg-gqqm-vgj8))
|
23
52
|
|
24
53
|
## 6.3.0 / 2023-05-31
|
@@ -92,12 +121,12 @@
|
|
92
121
|
* Refactor const.rb - freeze ([#3016])
|
93
122
|
|
94
123
|
## 6.0.1 / 2022-12-20
|
95
|
-
|
124
|
+
|
96
125
|
* Bugfixes
|
97
126
|
* Handle waking up a closed selector in Reactor#add ([#3005])
|
98
127
|
* Fixup response processing, enumerable bodies ([#3004], [#3000])
|
99
128
|
* Correctly close app body for all code paths ([#3002], [#2999])
|
100
|
-
* Refactor
|
129
|
+
* Refactor
|
101
130
|
* Add IOBuffer to Client, remove from ThreadPool thread instances ([#3013])
|
102
131
|
|
103
132
|
## 6.0.0 / 2022-10-14
|
@@ -126,12 +155,12 @@
|
|
126
155
|
* Allow header values to be arrays (Rack 3) ([#2936], [#2931])
|
127
156
|
* Export Puma/Ruby versions in /stats ([#2875])
|
128
157
|
* Allow configuring request uri max length & request path max length ([#2840])
|
129
|
-
* Add a couple of public accessors ([#2774])
|
158
|
+
* Add a couple of public accessors ([#2774])
|
130
159
|
* Log entire backtrace when worker start fails ([#2891])
|
131
160
|
* [jruby] Enable TLSv1.3 support ([#2886])
|
132
161
|
* [jruby] support setting TLS protocols + rename ssl_cipher_list ([#2899])
|
133
162
|
* [jruby] Support a truststore option ([#2849], [#2904], [#2884])
|
134
|
-
|
163
|
+
|
135
164
|
* Bugfixes
|
136
165
|
* Load the configuration before passing it to the binder ([#2897])
|
137
166
|
* Do not raise error raised on HTTP methods we don't recognize or support, like CONNECT ([#2932], [#1441])
|
@@ -144,9 +173,14 @@
|
|
144
173
|
* Ruby 3.2 will have native IO#wait_* methods, don't require io/wait ([#2903])
|
145
174
|
* Various internal API refactorings ([#2942], [#2921], [#2922], [#2955])
|
146
175
|
|
176
|
+
## 5.6.8 / 2024-01-08
|
177
|
+
|
178
|
+
* Security
|
179
|
+
* Limit the size of chunk extensions. Without this limit, an attacker could cause unbounded resource (CPU, network bandwidth) consumption. ([GHSA-c2f4-cvqm-65w2](https://github.com/puma/puma/security/advisories/GHSA-c2f4-cvqm-65w2))
|
180
|
+
|
147
181
|
## 5.6.7 / 2023-08-18
|
148
182
|
|
149
|
-
* Security
|
183
|
+
* Security
|
150
184
|
* Address HTTP request smuggling vulnerabilities with zero-length Content Length header and trailer fields ([GHSA-68xg-gqqm-vgj8](https://github.com/puma/puma/security/advisories/GHSA-68xg-gqqm-vgj8))
|
151
185
|
|
152
186
|
## 5.6.6 / 2023-06-21
|
@@ -2029,6 +2063,27 @@ be added back in a future date when a java Puma::MiniSSL is added.
|
|
2029
2063
|
* Bugfixes
|
2030
2064
|
* Your bugfix goes here <Most recent on the top, like GitHub> (#Github Number)
|
2031
2065
|
|
2066
|
+
[#3256]:https://github.com/puma/puma/pull/3256 "PR by @MSP-Greg, merged 2023-10-16"
|
2067
|
+
[#3235]:https://github.com/puma/puma/pull/3235 "PR by @joshuay03, merged 2023-10-03"
|
2068
|
+
[#3228]:https://github.com/puma/puma/issues/3228 "Issue by @davidalejandroaguilar, closed 2023-10-03"
|
2069
|
+
[#3282]:https://github.com/puma/puma/issues/3282 "Issue by @bensheldon, closed 2024-01-02"
|
2070
|
+
[#3283]:https://github.com/puma/puma/pull/3283 "PR by @joshuay03, merged 2024-01-02"
|
2071
|
+
[#3225]:https://github.com/puma/puma/pull/3225 "PR by @joshuay03, merged 2023-09-27"
|
2072
|
+
[#2786]:https://github.com/puma/puma/issues/2786 "Issue by @vitiokss, closed 2023-09-27"
|
2073
|
+
[#3179]:https://github.com/puma/puma/pull/3179 "PR by @MSP-Greg, merged 2023-09-26"
|
2074
|
+
[#3255]:https://github.com/puma/puma/pull/3255 "PR by @casperisfine, merged 2023-10-19"
|
2075
|
+
[#3276]:https://github.com/puma/puma/pull/3276 "PR by @casperisfine, merged 2023-11-16"
|
2076
|
+
[#3271]:https://github.com/puma/puma/pull/3271 "PR by @MSP-Greg, merged 2023-10-30"
|
2077
|
+
[#3266]:https://github.com/puma/puma/issues/3266 "Issue by @Dragonicity, closed 2023-10-30"
|
2078
|
+
[#3270]:https://github.com/puma/puma/pull/3270 "PR by @MSP-Greg, merged 2023-10-30"
|
2079
|
+
[#3265]:https://github.com/puma/puma/pull/3265 "PR by @MSP-Greg, merged 2023-10-25"
|
2080
|
+
[#3264]:https://github.com/puma/puma/issues/3264 "Issue by @dentarg, closed 2023-10-25"
|
2081
|
+
[#3254]:https://github.com/puma/puma/pull/3254 "PR by @casperisfine, merged 2023-10-11"
|
2082
|
+
[#3245]:https://github.com/puma/puma/pull/3245 "PR by @olleolleolle, merged 2023-10-02"
|
2083
|
+
[#3293]:https://github.com/puma/puma/pull/3293 "PR by @MSP-Greg, merged 2023-12-21"
|
2084
|
+
[#3301]:https://github.com/puma/puma/pull/3301 "PR by @benburkert, merged 2023-12-29"
|
2085
|
+
[#3248]:https://github.com/puma/puma/pull/3248 "PR by @dentarg, merged 2023-10-04"
|
2086
|
+
[#3298]:https://github.com/puma/puma/pull/3298 "PR by @til, merged 2023-12-26"
|
2032
2087
|
[#2920]:https://github.com/puma/puma/pull/2920 "PR by @biinari, merged 2023-07-11"
|
2033
2088
|
[#3195]:https://github.com/puma/puma/pull/3195 "PR by @binarygit, merged 2023-08-15"
|
2034
2089
|
[#3209]:https://github.com/puma/puma/pull/3209 "PR by @joshuay03, merged 2023-09-04"
|
@@ -2213,7 +2268,7 @@ be added back in a future date when a java Puma::MiniSSL is added.
|
|
2213
2268
|
[#2563]:https://github.com/puma/puma/pull/2563 "PR by @MSP-Greg, merged 2021-03-06"
|
2214
2269
|
[#2504]:https://github.com/puma/puma/issues/2504 "Issue by @fsateler, closed 2021-03-06"
|
2215
2270
|
[#2591]:https://github.com/puma/puma/pull/2591 "PR by @MSP-Greg, merged 2021-05-05"
|
2216
|
-
[#2572]:https://github.com/puma/puma/issues/2572 "Issue by @
|
2271
|
+
[#2572]:https://github.com/puma/puma/issues/2572 "Issue by @josef-krabath, closed 2021-05-05"
|
2217
2272
|
[#2613]:https://github.com/puma/puma/pull/2613 "PR by @smcgivern, merged 2021-04-27"
|
2218
2273
|
[#2605]:https://github.com/puma/puma/pull/2605 "PR by @pascalbetz, merged 2021-04-26"
|
2219
2274
|
[#2584]:https://github.com/puma/puma/issues/2584 "Issue by @kaorihinata, closed 2021-04-26"
|
@@ -2529,7 +2584,7 @@ be added back in a future date when a java Puma::MiniSSL is added.
|
|
2529
2584
|
[#1110]:https://github.com/puma/puma/pull/1110 "PR by @montdidier, merged 2016-12-12"
|
2530
2585
|
[#1135]:https://github.com/puma/puma/pull/1135 "PR by @jkraemer, merged 2016-11-19"
|
2531
2586
|
[#1081]:https://github.com/puma/puma/pull/1081 "PR by @frodsan, merged 2016-09-08"
|
2532
|
-
[#1138]:https://github.com/puma/puma/pull/1138 "PR by @
|
2587
|
+
[#1138]:https://github.com/puma/puma/pull/1138 "PR by @skull-squadron, merged 2016-12-13"
|
2533
2588
|
[#1118]:https://github.com/puma/puma/pull/1118 "PR by @hiroara, merged 2016-11-20"
|
2534
2589
|
[#1075]:https://github.com/puma/puma/issues/1075 "Issue by @pvalena, closed 2016-09-06"
|
2535
2590
|
[#932]:https://github.com/puma/puma/issues/932 "Issue by @everplays, closed 2016-07-24"
|
data/README.md
CHANGED
@@ -410,6 +410,7 @@ Community guides:
|
|
410
410
|
* [puma-plugin-statsd](https://github.com/yob/puma-plugin-statsd) — send Puma metrics to statsd
|
411
411
|
* [puma-plugin-systemd](https://github.com/sj26/puma-plugin-systemd) — deeper integration with systemd for notify, status and watchdog. Puma 5.1.0 integrated notify and watchdog, which probably conflicts with this plugin. Puma 6.1.0 added status support which obsoletes the plugin entirely.
|
412
412
|
* [puma-plugin-telemetry](https://github.com/babbel/puma-plugin-telemetry) - telemetry plugin for Puma offering various targets to publish
|
413
|
+
* [puma-acme](https://github.com/anchordotdev/puma-acme) - automatic SSL/HTTPS certificate provisioning and setup
|
413
414
|
|
414
415
|
### Monitoring
|
415
416
|
|
data/docs/kubernetes.md
CHANGED
@@ -69,7 +69,7 @@ More discussions and links to relevant articles can be found in https://github.c
|
|
69
69
|
|
70
70
|
With containerization, you will have to make a decision about how "big" to make each pod. Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make.
|
71
71
|
|
72
|
-
* Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes.
|
72
|
+
* Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
|
73
73
|
* Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50%) will lead to additional request queueing time (latency!) and additional memory usage.
|
74
74
|
* More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
|
75
75
|
* Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing, which means you will have to run more pods.
|
data/docs/restart.md
CHANGED
@@ -27,6 +27,7 @@ Any of the following will cause a Puma server to perform a hot restart:
|
|
27
27
|
|
28
28
|
### Additional notes
|
29
29
|
|
30
|
+
* The newly started Puma process changes its current working directory to the directory specified by the `directory` option. If `directory` is set to symlink, this is automatically re-evaluated, so this mechanism can be used to upgrade the application.
|
30
31
|
* Only one version of the application is running at a time.
|
31
32
|
* `on_restart` is invoked just before the server shuts down. This can be used to clean up resources (like long-lived database connections) gracefully. Since Ruby 2.0, it is not typically necessary to explicitly close file descriptors on restart. This is because any file descriptor opened by Ruby will have the `FD_CLOEXEC` flag set, meaning that file descriptors are closed on `exec`. `on_restart` is useful, though, if your application needs to perform any more graceful protocol-specific shutdown procedures before closing connections.
|
32
33
|
|
data/docs/systemd.md
CHANGED
@@ -51,7 +51,7 @@ ExecStart=/<FULLPATH>/bin/puma -C <YOUR_APP_PATH>/puma.rb
|
|
51
51
|
# Variant: Rails start.
|
52
52
|
# ExecStart=/<FULLPATH>/bin/puma -C <YOUR_APP_PATH>/config/puma.rb ../config.ru
|
53
53
|
|
54
|
-
# Variant: Use `bundle exec
|
54
|
+
# Variant: Use `bundle exec puma` instead of binstub
|
55
55
|
# Variant: Specify directives inline.
|
56
56
|
# ExecStart=/<FULLPATH>/puma -b tcp://0.0.0.0:9292 -b ssl://0.0.0.0:9293?key=key.pem&cert=cert.pem
|
57
57
|
|
@@ -76,9 +76,7 @@ compatible with both clustered mode and application preload.
|
|
76
76
|
|
77
77
|
**Note:** Any wrapper scripts which `exec`, or other indirections in `ExecStart`
|
78
78
|
may result in activated socket file descriptors being closed before reaching the
|
79
|
-
puma master process.
|
80
|
-
`--keep-file-descriptors` flag. `bundle exec` can be avoided by using a `puma`
|
81
|
-
executable generated by `bundle binstubs puma`. This is tracked in [#1499].
|
79
|
+
puma master process.
|
82
80
|
|
83
81
|
**Note:** Socket activation doesn't currently work on JRuby. This is tracked in
|
84
82
|
[#1367].
|
data/ext/puma_http11/extconf.rb
CHANGED
@@ -10,7 +10,11 @@ end
|
|
10
10
|
|
11
11
|
unless ENV["PUMA_DISABLE_SSL"]
|
12
12
|
# don't use pkg_config('openssl') if '--with-openssl-dir' is used
|
13
|
-
|
13
|
+
# also looks within the Ruby build for directory info
|
14
|
+
has_openssl_dir = dir_config('openssl').any? ||
|
15
|
+
RbConfig::CONFIG['configure_args']&.include?('openssl') ||
|
16
|
+
Dir.exist?("#{RbConfig::TOPDIR}/src/main/c/openssl") # TruffleRuby
|
17
|
+
|
14
18
|
found_pkg_config = !has_openssl_dir && pkg_config('openssl')
|
15
19
|
|
16
20
|
found_ssl = if !$mingw && found_pkg_config
|
data/ext/puma_http11/mini_ssl.c
CHANGED
@@ -546,7 +546,7 @@ NORETURN(void raise_error(SSL* ssl, int result));
|
|
546
546
|
|
547
547
|
void raise_error(SSL* ssl, int result) {
|
548
548
|
char buf[512];
|
549
|
-
char msg[
|
549
|
+
char msg[768];
|
550
550
|
const char* err_str;
|
551
551
|
int err = errno;
|
552
552
|
int mask = 4095;
|
@@ -804,6 +804,10 @@ void Init_mini_ssl(VALUE puma) {
|
|
804
804
|
|
805
805
|
rb_define_method(eng, "init?", engine_init, 0);
|
806
806
|
|
807
|
+
/* @!attribute [r] peercert
|
808
|
+
* Returns `nil` when `MiniSSL::Context#verify_mode` is set to `VERIFY_NONE`.
|
809
|
+
* @return [String, nil] DER encoded cert
|
810
|
+
*/
|
807
811
|
rb_define_method(eng, "peercert", engine_peercert, 0);
|
808
812
|
|
809
813
|
rb_define_method(eng, "ssl_vers_st", engine_ssl_vers_st, 0);
|
@@ -47,6 +47,7 @@ import static javax.net.ssl.SSLEngineResult.Status;
|
|
47
47
|
import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
48
48
|
|
49
49
|
public class MiniSSL extends RubyObject { // MiniSSL::Engine
|
50
|
+
private static final long serialVersionUID = -6903439483039141234L;
|
50
51
|
private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
51
52
|
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
52
53
|
return new MiniSSL(runtime, klass);
|
@@ -500,7 +501,7 @@ public class MiniSSL extends RubyObject { // MiniSSL::Engine
|
|
500
501
|
}
|
501
502
|
|
502
503
|
private static RaiseException newError(Ruby runtime, RubyClass errorClass, String message, Throwable cause) {
|
503
|
-
RaiseException ex =
|
504
|
+
RaiseException ex = RaiseException.from(runtime, errorClass, message);
|
504
505
|
ex.initCause(cause);
|
505
506
|
return ex;
|
506
507
|
}
|
data/lib/puma/client.rb
CHANGED
@@ -51,6 +51,14 @@ module Puma
|
|
51
51
|
CHUNK_VALID_ENDING = Const::LINE_END
|
52
52
|
CHUNK_VALID_ENDING_SIZE = CHUNK_VALID_ENDING.bytesize
|
53
53
|
|
54
|
+
# The maximum number of bytes we'll buffer looking for a valid
|
55
|
+
# chunk header.
|
56
|
+
MAX_CHUNK_HEADER_SIZE = 4096
|
57
|
+
|
58
|
+
# The maximum amount of excess data the client sends
|
59
|
+
# using chunk size extensions before we abort the connection.
|
60
|
+
MAX_CHUNK_EXCESS = 16 * 1024
|
61
|
+
|
54
62
|
# Content-Length header value validation
|
55
63
|
CONTENT_LENGTH_VALUE_INVALID = /[^\d]/.freeze
|
56
64
|
|
@@ -496,6 +504,7 @@ module Puma
|
|
496
504
|
@chunked_body = true
|
497
505
|
@partial_part_left = 0
|
498
506
|
@prev_chunk = ""
|
507
|
+
@excess_cr = 0
|
499
508
|
|
500
509
|
@body = Tempfile.new(Const::PUMA_TMP_BASE)
|
501
510
|
@body.unlink
|
@@ -577,6 +586,20 @@ module Puma
|
|
577
586
|
end
|
578
587
|
end
|
579
588
|
|
589
|
+
# Track the excess as a function of the size of the
|
590
|
+
# header vs the size of the actual data. Excess can
|
591
|
+
# go negative (and is expected to) when the body is
|
592
|
+
# significant.
|
593
|
+
# The additional of chunk_hex.size and 2 compensates
|
594
|
+
# for a client sending 1 byte in a chunked body over
|
595
|
+
# a long period of time, making sure that that client
|
596
|
+
# isn't accidentally eventually punished.
|
597
|
+
@excess_cr += (line.size - len - chunk_hex.size - 2)
|
598
|
+
|
599
|
+
if @excess_cr >= MAX_CHUNK_EXCESS
|
600
|
+
raise HttpParserError, "Maximum chunk excess detected"
|
601
|
+
end
|
602
|
+
|
580
603
|
len += 2
|
581
604
|
|
582
605
|
part = io.read(len)
|
@@ -604,6 +627,10 @@ module Puma
|
|
604
627
|
@partial_part_left = len - part.size
|
605
628
|
end
|
606
629
|
else
|
630
|
+
if @prev_chunk.size + chunk.size >= MAX_CHUNK_HEADER_SIZE
|
631
|
+
raise HttpParserError, "maximum size of chunk header exceeded"
|
632
|
+
end
|
633
|
+
|
607
634
|
@prev_chunk = line
|
608
635
|
return false
|
609
636
|
end
|
data/lib/puma/cluster.rb
CHANGED
@@ -85,9 +85,7 @@ module Puma
|
|
85
85
|
@workers << WorkerHandle.new(idx, pid, @phase, @options)
|
86
86
|
end
|
87
87
|
|
88
|
-
if @options[:fork_worker] &&
|
89
|
-
@workers.all? {|x| x.phase == @phase}
|
90
|
-
|
88
|
+
if @options[:fork_worker] && all_workers_in_phase?
|
91
89
|
@fork_writer << "0\n"
|
92
90
|
end
|
93
91
|
end
|
@@ -148,10 +146,22 @@ module Puma
|
|
148
146
|
idx
|
149
147
|
end
|
150
148
|
|
149
|
+
def worker_at(idx)
|
150
|
+
@workers.find { |w| w.index == idx }
|
151
|
+
end
|
152
|
+
|
151
153
|
def all_workers_booted?
|
152
154
|
@workers.count { |w| !w.booted? } == 0
|
153
155
|
end
|
154
156
|
|
157
|
+
def all_workers_in_phase?
|
158
|
+
@workers.all? { |w| w.phase == @phase }
|
159
|
+
end
|
160
|
+
|
161
|
+
def all_workers_idle_timed_out?
|
162
|
+
(@workers.map(&:pid) - idle_timed_out_worker_pids).empty?
|
163
|
+
end
|
164
|
+
|
155
165
|
def check_workers
|
156
166
|
return if @next_check >= Time.now
|
157
167
|
|
@@ -276,7 +286,7 @@ module Puma
|
|
276
286
|
|
277
287
|
# @version 5.0.0
|
278
288
|
def fork_worker!
|
279
|
-
if (worker =
|
289
|
+
if (worker = worker_at 0)
|
280
290
|
worker.phase += 1
|
281
291
|
end
|
282
292
|
phased_restart(true)
|
@@ -338,6 +348,8 @@ module Puma
|
|
338
348
|
def run
|
339
349
|
@status = :run
|
340
350
|
|
351
|
+
@idle_workers = {}
|
352
|
+
|
341
353
|
output_header "cluster"
|
342
354
|
|
343
355
|
# This is aligned with the output from Runner, see Runner#output_header
|
@@ -411,6 +423,8 @@ module Puma
|
|
411
423
|
|
412
424
|
@master_read, @worker_write = read, @wakeup
|
413
425
|
|
426
|
+
@options[:worker_write] = @worker_write
|
427
|
+
|
414
428
|
@config.run_hooks(:before_fork, nil, @log_writer)
|
415
429
|
|
416
430
|
spawn_workers
|
@@ -426,6 +440,11 @@ module Puma
|
|
426
440
|
|
427
441
|
while @status == :run
|
428
442
|
begin
|
443
|
+
if all_workers_idle_timed_out?
|
444
|
+
log "- All workers reached idle timeout"
|
445
|
+
break
|
446
|
+
end
|
447
|
+
|
429
448
|
if @phased_restart
|
430
449
|
start_phased_restart
|
431
450
|
@phased_restart = false
|
@@ -446,7 +465,7 @@ module Puma
|
|
446
465
|
|
447
466
|
if req == "b" || req == "f"
|
448
467
|
pid, idx = result.split(':').map(&:to_i)
|
449
|
-
w =
|
468
|
+
w = worker_at idx
|
450
469
|
w.pid = pid if w.pid.nil?
|
451
470
|
end
|
452
471
|
|
@@ -463,24 +482,37 @@ module Puma
|
|
463
482
|
when "t"
|
464
483
|
w.term unless w.term?
|
465
484
|
when "p"
|
466
|
-
|
485
|
+
status = result.sub(/^\d+/,'').chomp
|
486
|
+
w.ping!(status)
|
467
487
|
@events.fire(:ping!, w)
|
488
|
+
|
489
|
+
if in_phased_restart && workers_not_booted.positive? && w0 = worker_at(0)
|
490
|
+
w0.ping!(status)
|
491
|
+
@events.fire(:ping!, w0)
|
492
|
+
end
|
493
|
+
|
468
494
|
if !booted && @workers.none? {|worker| worker.last_status.empty?}
|
469
495
|
@events.fire_on_booted!
|
470
496
|
debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
|
471
497
|
booted = true
|
472
498
|
end
|
499
|
+
when "i"
|
500
|
+
if @idle_workers[pid]
|
501
|
+
@idle_workers.delete pid
|
502
|
+
else
|
503
|
+
@idle_workers[pid] = true
|
504
|
+
end
|
473
505
|
end
|
474
506
|
else
|
475
507
|
log "! Out-of-sync worker list, no #{pid} worker"
|
476
508
|
end
|
477
509
|
end
|
510
|
+
|
478
511
|
if in_phased_restart && workers_not_booted.zero?
|
479
512
|
@events.fire_on_booted!
|
480
513
|
debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
|
481
514
|
in_phased_restart = false
|
482
515
|
end
|
483
|
-
|
484
516
|
rescue Interrupt
|
485
517
|
@status = :stop
|
486
518
|
end
|
@@ -509,10 +541,28 @@ module Puma
|
|
509
541
|
# loops thru @workers, removing workers that exited, and calling
|
510
542
|
# `#term` if needed
|
511
543
|
def wait_workers
|
544
|
+
# Reap all children, known workers or otherwise.
|
545
|
+
# If puma has PID 1, as it's common in containerized environments,
|
546
|
+
# then it's responsible for reaping orphaned processes, so we must reap
|
547
|
+
# all our dead children, regardless of whether they are workers we spawned
|
548
|
+
# or some reattached processes.
|
549
|
+
reaped_children = {}
|
550
|
+
loop do
|
551
|
+
begin
|
552
|
+
pid, status = Process.wait2(-1, Process::WNOHANG)
|
553
|
+
break unless pid
|
554
|
+
reaped_children[pid] = status
|
555
|
+
rescue Errno::ECHILD
|
556
|
+
break
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
512
560
|
@workers.reject! do |w|
|
513
561
|
next false if w.pid.nil?
|
514
562
|
begin
|
515
|
-
|
563
|
+
# When `fork_worker` is enabled, some worker may not be direct children, but grand children.
|
564
|
+
# Because of this they won't be reaped by `Process.wait2(-1)`, so we need to check them individually)
|
565
|
+
if reaped_children.delete(w.pid) || (@options[:fork_worker] && Process.wait(w.pid, Process::WNOHANG))
|
516
566
|
true
|
517
567
|
else
|
518
568
|
w.term if w.term?
|
@@ -529,6 +579,11 @@ module Puma
|
|
529
579
|
end
|
530
580
|
end
|
531
581
|
end
|
582
|
+
|
583
|
+
# Log unknown children
|
584
|
+
reaped_children.each do |pid, status|
|
585
|
+
log "! reaped unknown child process pid=#{pid} status=#{status}"
|
586
|
+
end
|
532
587
|
end
|
533
588
|
|
534
589
|
# @version 5.0.0
|
@@ -536,14 +591,18 @@ module Puma
|
|
536
591
|
@workers.each do |w|
|
537
592
|
if !w.term? && w.ping_timeout <= Time.now
|
538
593
|
details = if w.booted?
|
539
|
-
"(
|
594
|
+
"(Worker #{w.index} failed to check in within #{@options[:worker_timeout]} seconds)"
|
540
595
|
else
|
541
|
-
"(
|
596
|
+
"(Worker #{w.index} failed to boot within #{@options[:worker_boot_timeout]} seconds)"
|
542
597
|
end
|
543
598
|
log "! Terminating timed out worker #{details}: #{w.pid}"
|
544
599
|
w.kill
|
545
600
|
end
|
546
601
|
end
|
547
602
|
end
|
603
|
+
|
604
|
+
def idle_timed_out_worker_pids
|
605
|
+
@idle_workers.keys
|
606
|
+
end
|
548
607
|
end
|
549
608
|
end
|
data/lib/puma/configuration.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require_relative 'rack/builder'
|
4
4
|
require_relative 'plugin'
|
5
5
|
require_relative 'const'
|
6
|
-
|
6
|
+
require_relative 'dsl'
|
7
7
|
|
8
8
|
module Puma
|
9
9
|
# A class used for storing "leveled" configuration options.
|
@@ -387,5 +387,3 @@ module Puma
|
|
387
387
|
end
|
388
388
|
end
|
389
389
|
end
|
390
|
-
|
391
|
-
require_relative 'dsl'
|
data/lib/puma/const.rb
CHANGED
@@ -100,7 +100,7 @@ module Puma
|
|
100
100
|
# too taxing on performance.
|
101
101
|
module Const
|
102
102
|
|
103
|
-
PUMA_VERSION = VERSION = "6.4.
|
103
|
+
PUMA_VERSION = VERSION = "6.4.2"
|
104
104
|
CODE_NAME = "The Eagle of Durango"
|
105
105
|
|
106
106
|
PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
|
data/lib/puma/detect.rb
CHANGED
@@ -12,15 +12,14 @@ module Puma
|
|
12
12
|
|
13
13
|
IS_JRUBY = Object.const_defined? :JRUBY_VERSION
|
14
14
|
|
15
|
-
IS_OSX =
|
15
|
+
IS_OSX = RUBY_DESCRIPTION.include? 'darwin'
|
16
16
|
|
17
|
-
IS_WINDOWS =
|
18
|
-
IS_JRUBY && RUBY_DESCRIPTION.include?('mswin')
|
17
|
+
IS_WINDOWS = RUBY_DESCRIPTION.match?(/mswin|ming|cygwin/)
|
19
18
|
|
20
19
|
IS_LINUX = !(IS_OSX || IS_WINDOWS)
|
21
20
|
|
22
21
|
# @version 5.2.0
|
23
|
-
IS_MRI =
|
22
|
+
IS_MRI = RUBY_ENGINE == 'ruby'
|
24
23
|
|
25
24
|
def self.jruby?
|
26
25
|
IS_JRUBY
|
data/lib/puma/dsl.rb
CHANGED
@@ -729,11 +729,15 @@ module Puma
|
|
729
729
|
process_hook :before_refork, key, block, 'on_refork'
|
730
730
|
end
|
731
731
|
|
732
|
-
#
|
733
|
-
#
|
732
|
+
# Provide a block to be executed just before a thread is added to the thread
|
733
|
+
# pool. Be careful: while the block executes, thread creation is delayed, and
|
734
|
+
# probably a request will have to wait too! The new thread will not be added to
|
735
|
+
# the threadpool until the provided block returns.
|
734
736
|
#
|
735
|
-
#
|
736
|
-
#
|
737
|
+
# Return values are ignored.
|
738
|
+
# Raising an exception will log a warning.
|
739
|
+
#
|
740
|
+
# This hook is useful for doing something when the thread pool grows.
|
737
741
|
#
|
738
742
|
# This can be called multiple times to add several hooks.
|
739
743
|
#
|
@@ -746,8 +750,15 @@ module Puma
|
|
746
750
|
@options[:before_thread_start] << block
|
747
751
|
end
|
748
752
|
|
749
|
-
#
|
750
|
-
#
|
753
|
+
# Provide a block to be executed after a thread is trimmed from the thread
|
754
|
+
# pool. Be careful: while this block executes, Puma's main loop is
|
755
|
+
# blocked, so no new requests will be picked up.
|
756
|
+
#
|
757
|
+
# This hook only runs when a thread in the threadpool is trimmed by Puma.
|
758
|
+
# It does not run when a thread dies due to exceptions or any other cause.
|
759
|
+
#
|
760
|
+
# Return values are ignored.
|
761
|
+
# Raising an exception will log a warning.
|
751
762
|
#
|
752
763
|
# This hook is useful for cleaning up thread local resources when a thread
|
753
764
|
# is trimmed.
|
@@ -1179,8 +1190,10 @@ module Puma
|
|
1179
1190
|
|
1180
1191
|
def warn_if_in_single_mode(hook_name)
|
1181
1192
|
return if @options[:silence_fork_callback_warning]
|
1182
|
-
|
1183
|
-
|
1193
|
+
# user_options (CLI) have precedence over config file
|
1194
|
+
workers_val = @config.options.user_options[:workers] || @options[:workers] ||
|
1195
|
+
@config.puma_default_options[:workers] || 0
|
1196
|
+
if workers_val == 0
|
1184
1197
|
log_string =
|
1185
1198
|
"Warning: You specified code to run in a `#{hook_name}` block, " \
|
1186
1199
|
"but Puma is not configured to run in cluster mode (worker count > 0 ), " \
|
data/lib/puma/minissl.rb
CHANGED
@@ -184,6 +184,11 @@ module Puma
|
|
184
184
|
@socket.peeraddr
|
185
185
|
end
|
186
186
|
|
187
|
+
# OpenSSL is loaded in `MiniSSL::ContextBuilder` when
|
188
|
+
# `MiniSSL::Context#verify_mode` is not `VERIFY_NONE`.
|
189
|
+
# When `VERIFY_NONE`, `MiniSSL::Engine#peercert` is nil, regardless of
|
190
|
+
# whether the client sends a cert.
|
191
|
+
# @return [OpenSSL::X509::Certificate, nil]
|
187
192
|
# @!attribute [r] peercert
|
188
193
|
def peercert
|
189
194
|
return @peercert if @peercert
|
data/lib/puma/null_io.rb
CHANGED
@@ -18,8 +18,22 @@ module Puma
|
|
18
18
|
|
19
19
|
# Mimics IO#read with no data.
|
20
20
|
#
|
21
|
-
def read(
|
22
|
-
|
21
|
+
def read(length = nil, buffer = nil)
|
22
|
+
if length.to_i < 0
|
23
|
+
raise ArgumentError, "(negative length #{length} given)"
|
24
|
+
end
|
25
|
+
|
26
|
+
buffer = if buffer.nil?
|
27
|
+
"".b
|
28
|
+
else
|
29
|
+
String.try_convert(buffer) or raise TypeError, "no implicit conversion of #{buffer.class} into String"
|
30
|
+
end
|
31
|
+
buffer.clear
|
32
|
+
if length.to_i > 0
|
33
|
+
nil
|
34
|
+
else
|
35
|
+
buffer
|
36
|
+
end
|
23
37
|
end
|
24
38
|
|
25
39
|
def rewind
|
data/lib/puma/puma_http11.jar
CHANGED
Binary file
|
data/lib/puma/runner.rb
CHANGED
@@ -70,7 +70,7 @@ module Puma
|
|
70
70
|
|
71
71
|
app = Puma::App::Status.new @launcher, token
|
72
72
|
|
73
|
-
# A Reactor is not created
|
73
|
+
# A Reactor is not created and nio4r is not loaded when 'queue_requests: false'
|
74
74
|
# Use `nil` for events, no hooks in control server
|
75
75
|
control = Puma::Server.new app, nil,
|
76
76
|
{ min_threads: 0, max_threads: 1, queue_requests: false, log_writer: @log_writer }
|
data/lib/puma/server.rb
CHANGED
@@ -81,6 +81,8 @@ module Puma
|
|
81
81
|
UserFileDefaultOptions.new(options, Configuration::DEFAULTS)
|
82
82
|
end
|
83
83
|
|
84
|
+
@clustered = (@options.fetch :workers, 0) > 0
|
85
|
+
@worker_write = @options[:worker_write]
|
84
86
|
@log_writer = @options.fetch :log_writer, LogWriter.stdio
|
85
87
|
@early_hints = @options[:early_hints]
|
86
88
|
@first_data_timeout = @options[:first_data_timeout]
|
@@ -117,6 +119,8 @@ module Puma
|
|
117
119
|
@precheck_closing = true
|
118
120
|
|
119
121
|
@requests_count = 0
|
122
|
+
|
123
|
+
@idle_timeout_reached = false
|
120
124
|
end
|
121
125
|
|
122
126
|
def inherit_binder(bind)
|
@@ -328,10 +332,26 @@ module Puma
|
|
328
332
|
begin
|
329
333
|
ios = IO.select sockets, nil, nil, (shutting_down? ? 0 : @idle_timeout)
|
330
334
|
unless ios
|
331
|
-
|
335
|
+
unless shutting_down?
|
336
|
+
@idle_timeout_reached = true
|
337
|
+
|
338
|
+
if @clustered
|
339
|
+
@worker_write << "i#{Process.pid}\n" rescue nil
|
340
|
+
next
|
341
|
+
else
|
342
|
+
@log_writer.log "- Idle timeout reached"
|
343
|
+
@status = :stop
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
332
347
|
break
|
333
348
|
end
|
334
349
|
|
350
|
+
if @idle_timeout_reached && @clustered
|
351
|
+
@idle_timeout_reached = false
|
352
|
+
@worker_write << "i#{Process.pid}\n" rescue nil
|
353
|
+
end
|
354
|
+
|
335
355
|
ios.first.each do |sock|
|
336
356
|
if sock == check
|
337
357
|
break if handle_check
|
@@ -367,6 +387,7 @@ module Puma
|
|
367
387
|
@queue_requests = false
|
368
388
|
@reactor.shutdown
|
369
389
|
end
|
390
|
+
|
370
391
|
graceful_shutdown if @status == :stop || @status == :restart
|
371
392
|
rescue Exception => e
|
372
393
|
@log_writer.unknown_error e, nil, "Exception handling servers"
|
data/lib/puma/state_file.rb
CHANGED
data/tools/Dockerfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Use this Dockerfile to create minimal reproductions of issues
|
2
2
|
|
3
|
-
FROM ruby:3.
|
3
|
+
FROM ruby:3.2
|
4
4
|
|
5
5
|
# throw errors if Gemfile has been modified since Gemfile.lock
|
6
6
|
RUN bundle config --global frozen 1
|
@@ -8,7 +8,7 @@ RUN bundle config --global frozen 1
|
|
8
8
|
WORKDIR /usr/src/app
|
9
9
|
|
10
10
|
COPY . .
|
11
|
-
|
11
|
+
|
12
12
|
RUN bundle install
|
13
13
|
RUN bundle exec rake compile
|
14
14
|
|
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: 6.4.
|
4
|
+
version: 6.4.2
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|