puma 5.6.4 → 5.6.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +68 -3
  3. data/LICENSE +0 -0
  4. data/README.md +0 -0
  5. data/bin/puma-wild +0 -0
  6. data/docs/architecture.md +0 -0
  7. data/docs/compile_options.md +0 -0
  8. data/docs/deployment.md +0 -0
  9. data/docs/fork_worker.md +0 -0
  10. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  11. data/docs/images/puma-connection-flow.png +0 -0
  12. data/docs/images/puma-general-arch.png +0 -0
  13. data/docs/jungle/README.md +0 -0
  14. data/docs/jungle/rc.d/README.md +0 -0
  15. data/docs/jungle/rc.d/puma.conf +0 -0
  16. data/docs/kubernetes.md +0 -0
  17. data/docs/nginx.md +0 -0
  18. data/docs/plugins.md +0 -0
  19. data/docs/rails_dev_mode.md +0 -0
  20. data/docs/restart.md +0 -0
  21. data/docs/signals.md +0 -0
  22. data/docs/stats.md +0 -0
  23. data/docs/systemd.md +0 -0
  24. data/ext/puma_http11/PumaHttp11Service.java +0 -0
  25. data/ext/puma_http11/ext_help.h +0 -0
  26. data/ext/puma_http11/extconf.rb +8 -3
  27. data/ext/puma_http11/http11_parser.c +0 -0
  28. data/ext/puma_http11/http11_parser.h +0 -0
  29. data/ext/puma_http11/http11_parser.java.rl +0 -0
  30. data/ext/puma_http11/http11_parser.rl +0 -0
  31. data/ext/puma_http11/http11_parser_common.rl +0 -0
  32. data/ext/puma_http11/mini_ssl.c +28 -10
  33. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
  34. data/ext/puma_http11/org/jruby/puma/Http11.java +2 -0
  35. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +0 -0
  36. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +10 -12
  37. data/ext/puma_http11/puma_http11.c +0 -0
  38. data/lib/puma/app/status.rb +3 -0
  39. data/lib/puma/binder.rb +1 -1
  40. data/lib/puma/cli.rb +0 -0
  41. data/lib/puma/client.rb +42 -8
  42. data/lib/puma/cluster/worker.rb +0 -0
  43. data/lib/puma/cluster/worker_handle.rb +0 -0
  44. data/lib/puma/cluster.rb +0 -0
  45. data/lib/puma/commonlogger.rb +0 -0
  46. data/lib/puma/configuration.rb +0 -0
  47. data/lib/puma/const.rb +9 -1
  48. data/lib/puma/control_cli.rb +18 -12
  49. data/lib/puma/detect.rb +0 -0
  50. data/lib/puma/dsl.rb +6 -2
  51. data/lib/puma/error_logger.rb +0 -0
  52. data/lib/puma/events.rb +0 -0
  53. data/lib/puma/io_buffer.rb +0 -0
  54. data/lib/puma/jruby_restart.rb +0 -0
  55. data/lib/puma/json_serialization.rb +0 -0
  56. data/lib/puma/launcher.rb +11 -0
  57. data/lib/puma/minissl/context_builder.rb +0 -0
  58. data/lib/puma/minissl.rb +9 -4
  59. data/lib/puma/null_io.rb +5 -0
  60. data/lib/puma/plugin/tmp_restart.rb +0 -0
  61. data/lib/puma/plugin.rb +0 -0
  62. data/lib/puma/queue_close.rb +0 -0
  63. data/lib/puma/rack/builder.rb +0 -0
  64. data/lib/puma/rack/urlmap.rb +0 -0
  65. data/lib/puma/rack_default.rb +0 -0
  66. data/lib/puma/reactor.rb +0 -0
  67. data/lib/puma/request.rb +21 -4
  68. data/lib/puma/runner.rb +0 -0
  69. data/lib/puma/server.rb +2 -0
  70. data/lib/puma/single.rb +0 -0
  71. data/lib/puma/state_file.rb +1 -0
  72. data/lib/puma/systemd.rb +0 -0
  73. data/lib/puma/thread_pool.rb +0 -0
  74. data/lib/puma/util.rb +12 -3
  75. data/lib/puma.rb +5 -3
  76. data/lib/rack/handler/puma.rb +0 -0
  77. data/lib/rack/version_restriction.rb +15 -0
  78. data/tools/Dockerfile +0 -0
  79. data/tools/trickletest.rb +0 -0
  80. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff9f4c8b81e1bfced36da8ecfe60912bd6bb37a2f989f2f8489d31cbe1a5947a
4
- data.tar.gz: 6821bc93adc639fea1ed82559b0e67c70bfd86fa0b0ec641eed65e020fb53440
3
+ metadata.gz: 869ae34fc3a993b7bc996c0053a647afc12fb908e6d5224a841bdafb23974bef
4
+ data.tar.gz: e65a1e6e579b8c8b4d52a77ee9bf4710be1a26f5e4934f96d4502f2b1afa98af
5
5
  SHA512:
6
- metadata.gz: 7b3eafbc651e03214851f79a89cb92637f7966f7d645446e15ac29e118d3b564aa28222ef54c1ea02f946da813172cf24bf9fb3b4c9d9b14dc1dadbc20754579
7
- data.tar.gz: 760c958a8c56ee5ec7b2208e5d1d9e0ef31c09975d058cd535f42382895f76f0854a18c68f671b37736e1588a372bc752a676cbbd1a896a08bd97962642dc0b7
6
+ metadata.gz: b9e1cb266acced0292dc12e0b825344de6cf128a42246625bf166f8042497b75195d354cda77123c5ae8049d062465b58b19395d31cc922e32196072d94ad45c
7
+ data.tar.gz: 522578ae4fc289ff7bd2c71704e7c8b22dcf0bf59db414bc2d5a730243e6daac027d2f4b106e9913f881a53749c75b41fd5c77982b8bfca3768b62f25abde150
data/History.md CHANGED
@@ -1,3 +1,41 @@
1
+ ## 5.6.9 / 2024-09-19
2
+
3
+ * Security
4
+ * Discards any headers using underscores if the non-underscore version also exists. Without this, an attacker could overwrite values set by intermediate proxies (e.g. X-Forwarded-For). ([CVE-2024-45614](https://github.com/puma/puma/security/advisories/GHSA-9hf4-67fc-4vf4)/GHSA-9hf4-67fc-4vf4)
5
+
6
+ ## 5.6.8 / 2024-01-08
7
+
8
+ * Security
9
+ * 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))
10
+
11
+ ## 5.6.7 / 2023-08-18
12
+
13
+ * Security
14
+ * 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))
15
+
16
+ ## 5.6.6 / 2023-06-21
17
+
18
+ * Bugfix
19
+ * Allow Puma to be loaded with Rack 3 ([#3166])
20
+
21
+ ## 5.6.5 / 2022-08-23
22
+
23
+ * Feature
24
+ * Puma::ControlCLI - allow refork command to be sent as a request ([#2868], [#2866])
25
+
26
+ * Bugfixes
27
+ * NullIO#closed should return false ([#2883])
28
+ * [jruby] Fix TLS verification hang ([#2890], [#2729])
29
+ * extconf.rb - don't use pkg_config('openssl') if '--with-openssl-dir' is used ([#2885], [#2839])
30
+ * MiniSSL - detect SSL_CTX_set_dh_auto ([#2864], [#2863])
31
+ * Fix rack.after_reply exceptions breaking connections ([#2861], [#2856])
32
+ * Escape SSL cert and filenames ([#2855])
33
+ * Fail hard if SSL certs or keys are invalid ([#2848])
34
+ * Fail hard if SSL certs or keys cannot be read by user ([#2847])
35
+ * Fix build with Opaque DH in LibreSSL 3.5. ([#2838])
36
+ * Pre-existing socket file removed when TERM is issued after USR2 (if puma is running in cluster mode) ([#2817])
37
+ * Fix Puma::StateFile#load incompatibility ([#2810])
38
+
1
39
  ## 5.6.4 / 2022-03-30
2
40
 
3
41
  * Security
@@ -1845,6 +1883,33 @@ be added back in a future date when a java Puma::MiniSSL is added.
1845
1883
  * Bugfixes
1846
1884
  * Your bugfix goes here <Most recent on the top, like GitHub> (#Github Number)
1847
1885
 
1886
+ [#3166]:https://github.com/puma/puma/issues/3166 "Issue by @JoeDupuis, merged 2023-06-08"
1887
+ [#2883]:https://github.com/puma/puma/pull/2883 "PR by @MSP-Greg, merged 2022-06-02"
1888
+ [#2868]:https://github.com/puma/puma/pull/2868 "PR by @MSP-Greg, merged 2022-06-02"
1889
+ [#2866]:https://github.com/puma/puma/issues/2866 "Issue by @slondr, closed 2022-06-02"
1890
+ [#2888]:https://github.com/puma/puma/pull/2888 "PR by @MSP-Greg, merged 2022-06-01"
1891
+ [#2890]:https://github.com/puma/puma/pull/2890 "PR by @kares, merged 2022-06-01"
1892
+ [#2729]:https://github.com/puma/puma/issues/2729 "Issue by @kares, closed 2022-06-01"
1893
+ [#2885]:https://github.com/puma/puma/pull/2885 "PR by @MSP-Greg, merged 2022-05-30"
1894
+ [#2839]:https://github.com/puma/puma/issues/2839 "Issue by @wlipa, closed 2022-05-30"
1895
+ [#2882]:https://github.com/puma/puma/pull/2882 "PR by @MSP-Greg, merged 2022-05-19"
1896
+ [#2864]:https://github.com/puma/puma/pull/2864 "PR by @MSP-Greg, merged 2022-04-26"
1897
+ [#2863]:https://github.com/puma/puma/issues/2863 "Issue by @eradman, closed 2022-04-26"
1898
+ [#2861]:https://github.com/puma/puma/pull/2861 "PR by @BlakeWilliams, merged 2022-04-17"
1899
+ [#2856]:https://github.com/puma/puma/issues/2856 "Issue by @nateberkopec, closed 2022-04-17"
1900
+ [#2855]:https://github.com/puma/puma/pull/2855 "PR by @stanhu, merged 2022-04-09"
1901
+ [#2848]:https://github.com/puma/puma/pull/2848 "PR by @stanhu, merged 2022-04-02"
1902
+ [#2847]:https://github.com/puma/puma/pull/2847 "PR by @stanhu, merged 2022-04-02"
1903
+ [#2838]:https://github.com/puma/puma/pull/2838 "PR by @epsilon-0, merged 2022-03-03"
1904
+ [#2817]:https://github.com/puma/puma/pull/2817 "PR by @khustochka, merged 2022-02-20"
1905
+ [#2810]:https://github.com/puma/puma/pull/2810 "PR by @kzkn, merged 2022-01-27"
1906
+ [#2899]:https://github.com/puma/puma/pull/2899 "PR by @kares, merged 2022-07-04"
1907
+ [#2891]:https://github.com/puma/puma/pull/2891 "PR by @gingerlime, merged 2022-06-02"
1908
+ [#2886]:https://github.com/puma/puma/pull/2886 "PR by @kares, merged 2022-05-30"
1909
+ [#2884]:https://github.com/puma/puma/pull/2884 "PR by @kares, merged 2022-05-30"
1910
+ [#2875]:https://github.com/puma/puma/pull/2875 "PR by @ylecuyer, merged 2022-05-19"
1911
+ [#2840]:https://github.com/puma/puma/pull/2840 "PR by @LukaszMaslej, merged 2022-04-13"
1912
+ [#2849]:https://github.com/puma/puma/pull/2849 "PR by @kares, merged 2022-04-09"
1848
1913
  [#2809]:https://github.com/puma/puma/pull/2809 "PR by @dentarg, merged 2022-01-26"
1849
1914
  [#2764]:https://github.com/puma/puma/pull/2764 "PR by @dentarg, merged 2022-01-18"
1850
1915
  [#2708]:https://github.com/puma/puma/issues/2708 "Issue by @erikaxel, closed 2022-01-18"
@@ -1930,7 +1995,7 @@ be added back in a future date when a java Puma::MiniSSL is added.
1930
1995
  [#2519]:https://github.com/puma/puma/pull/2519 "PR by @MSP-Greg, merged 2021-01-26"
1931
1996
  [#2522]:https://github.com/puma/puma/pull/2522 "PR by @jcmfernandes, merged 2021-01-12"
1932
1997
  [#2490]:https://github.com/puma/puma/pull/2490 "PR by @Bonias, merged 2020-12-07"
1933
- [#2486]:https://github.com/puma/puma/pull/2486 "PR by @ccverak, merged 2020-12-02"
1998
+ [#2486]:https://github.com/puma/puma/pull/2486 "PR by @karloscodes, merged 2020-12-02"
1934
1999
  [#2535]:https://github.com/puma/puma/pull/2535 "PR by @MSP-Greg, merged 2021-01-27"
1935
2000
  [#2529]:https://github.com/puma/puma/pull/2529 "PR by @MSP-Greg, merged 2021-01-24"
1936
2001
  [#2533]:https://github.com/puma/puma/pull/2533 "PR by @MSP-Greg, merged 2021-01-24"
@@ -1940,7 +2005,7 @@ be added back in a future date when a java Puma::MiniSSL is added.
1940
2005
  [#2521]:https://github.com/puma/puma/pull/2521 "PR by @ojab, merged 2021-01-04"
1941
2006
  [#2531]:https://github.com/puma/puma/pull/2531 "PR by @wjordan, merged 2021-01-19"
1942
2007
  [#2510]:https://github.com/puma/puma/pull/2510 "PR by @micke, merged 2020-12-10"
1943
- [#2472]:https://github.com/puma/puma/pull/2472 "PR by @ccverak, merged 2020-11-02"
2008
+ [#2472]:https://github.com/puma/puma/pull/2472 "PR by @karloscodes, merged 2020-11-02"
1944
2009
  [#2438]:https://github.com/puma/puma/pull/2438 "PR by @ekohl, merged 2020-10-26"
1945
2010
  [#2406]:https://github.com/puma/puma/pull/2406 "PR by @fdel15, merged 2020-10-19"
1946
2011
  [#2449]:https://github.com/puma/puma/pull/2449 "PR by @MSP-Greg, merged 2020-10-28"
@@ -2367,7 +2432,7 @@ be added back in a future date when a java Puma::MiniSSL is added.
2367
2432
  [#709]:https://github.com/puma/puma/pull/709 "PR by @lian, merged 2015-06-10"
2368
2433
  [#711]:https://github.com/puma/puma/pull/711 "PR by @julik, merged 2015-06-10"
2369
2434
  [#712]:https://github.com/puma/puma/pull/712 "PR by @chewi, merged 2015-07-14"
2370
- [#715]:https://github.com/puma/puma/pull/715 "PR by @0RaymondJiang0, merged 2015-07-14"
2435
+ [#715]:https://github.com/puma/puma/pull/715 "PR by @raymondmars, merged 2015-07-14"
2371
2436
  [#725]:https://github.com/puma/puma/pull/725 "PR by @rwz, merged 2015-07-14"
2372
2437
  [#726]:https://github.com/puma/puma/pull/726 "PR by @jshafton, merged 2015-07-14"
2373
2438
  [#729]:https://github.com/puma/puma/pull/729 "PR by @allaire, merged 2015-07-14"
data/LICENSE CHANGED
File without changes
data/README.md CHANGED
File without changes
data/bin/puma-wild CHANGED
File without changes
data/docs/architecture.md CHANGED
File without changes
File without changes
data/docs/deployment.md CHANGED
File without changes
data/docs/fork_worker.md CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
data/docs/kubernetes.md CHANGED
File without changes
data/docs/nginx.md CHANGED
File without changes
data/docs/plugins.md CHANGED
File without changes
File without changes
data/docs/restart.md CHANGED
File without changes
data/docs/signals.md CHANGED
File without changes
data/docs/stats.md CHANGED
File without changes
data/docs/systemd.md CHANGED
File without changes
File without changes
File without changes
@@ -9,9 +9,11 @@ if $mingw && RUBY_VERSION >= '2.4'
9
9
  end
10
10
 
11
11
  unless ENV["DISABLE_SSL"]
12
- dir_config("openssl")
12
+ # don't use pkg_config('openssl') if '--with-openssl-dir' is used
13
+ has_openssl_dir = dir_config('openssl').any?
14
+ found_pkg_config = !has_openssl_dir && pkg_config('openssl')
13
15
 
14
- found_ssl = if (!$mingw || RUBY_VERSION >= '2.4') && (t = pkg_config 'openssl')
16
+ found_ssl = if (!$mingw || RUBY_VERSION >= '2.4') && found_pkg_config
15
17
  puts 'using OpenSSL pkgconfig (openssl.pc)'
16
18
  true
17
19
  elsif %w'crypto libeay32'.find {|crypto| have_library(crypto, 'BIO_read')} &&
@@ -35,7 +37,10 @@ unless ENV["DISABLE_SSL"]
35
37
  have_func "X509_STORE_up_ref"
36
38
  have_func "SSL_CTX_set_ecdh_auto(NULL, 0)" , "openssl/ssl.h"
37
39
 
38
- # below are yes for 3.0.0 & later, use for OpenSSL 3 detection
40
+ # below exists in 1.1.0 and later, but isn't documented until 3.0.0
41
+ have_func "SSL_CTX_set_dh_auto(NULL, 0)" , "openssl/ssl.h"
42
+
43
+ # below is yes for 3.0.0 & later
39
44
  have_func "SSL_get1_peer_certificate" , "openssl/ssl.h"
40
45
 
41
46
  # Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -30,6 +30,12 @@ typedef struct {
30
30
 
31
31
  VALUE eError;
32
32
 
33
+ NORETURN(void raise_file_error(const char* caller, const char *filename));
34
+
35
+ void raise_file_error(const char* caller, const char *filename) {
36
+ rb_raise(eError, "%s: error in file '%s': %s", caller, filename, ERR_error_string(ERR_get_error(), NULL));
37
+ }
38
+
33
39
  void engine_free(void *ptr) {
34
40
  ms_conn *conn = ptr;
35
41
  ms_cert_buf* cert_buf = (ms_cert_buf*)SSL_get_app_data(conn->ssl);
@@ -49,7 +55,7 @@ const rb_data_type_t engine_data_type = {
49
55
  0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
50
56
  };
51
57
 
52
- #ifndef HAVE_SSL_GET1_PEER_CERTIFICATE
58
+ #ifndef HAVE_SSL_CTX_SET_DH_AUTO
53
59
  DH *get_dh2048(void) {
54
60
  /* `openssl dhparam -C 2048`
55
61
  * -----BEGIN DH PARAMETERS-----
@@ -92,13 +98,13 @@ DH *get_dh2048(void) {
92
98
  static unsigned char dh2048_g[] = { 0x02 };
93
99
 
94
100
  DH *dh;
95
- #if !(OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER))
101
+ #if !(OPENSSL_VERSION_NUMBER < 0x10100005L)
96
102
  BIGNUM *p, *g;
97
103
  #endif
98
104
 
99
105
  dh = DH_new();
100
106
 
101
- #if OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER)
107
+ #if OPENSSL_VERSION_NUMBER < 0x10100005L
102
108
  dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
103
109
  dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
104
110
 
@@ -211,7 +217,7 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
211
217
  int ssl_options;
212
218
  VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1,
213
219
  verification_flags, session_id_bytes, cert_pem, key_pem;
214
- #ifndef HAVE_SSL_GET1_PEER_CERTIFICATE
220
+ #ifndef HAVE_SSL_CTX_SET_DH_AUTO
215
221
  DH *dh;
216
222
  #endif
217
223
  BIO *bio;
@@ -244,12 +250,18 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
244
250
 
245
251
  if (!NIL_P(cert)) {
246
252
  StringValue(cert);
247
- SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
253
+
254
+ if (SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert)) != 1) {
255
+ raise_file_error("SSL_CTX_use_certificate_chain_file", RSTRING_PTR(cert));
256
+ }
248
257
  }
249
258
 
250
259
  if (!NIL_P(key)) {
251
260
  StringValue(key);
252
- SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM);
261
+
262
+ if (SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM) != 1) {
263
+ raise_file_error("SSL_CTX_use_PrivateKey_file", RSTRING_PTR(key));
264
+ }
253
265
  }
254
266
 
255
267
  if (!NIL_P(cert_pem)) {
@@ -257,7 +269,9 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
257
269
  BIO_puts(bio, RSTRING_PTR(cert_pem));
258
270
  x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
259
271
 
260
- SSL_CTX_use_certificate(ctx, x509);
272
+ if (SSL_CTX_use_certificate(ctx, x509) != 1) {
273
+ raise_file_error("SSL_CTX_use_certificate", RSTRING_PTR(cert_pem));
274
+ }
261
275
  }
262
276
 
263
277
  if (!NIL_P(key_pem)) {
@@ -265,7 +279,9 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
265
279
  BIO_puts(bio, RSTRING_PTR(key_pem));
266
280
  pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
267
281
 
268
- SSL_CTX_use_PrivateKey(ctx, pkey);
282
+ if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
283
+ raise_file_error("SSL_CTX_use_PrivateKey", RSTRING_PTR(key_pem));
284
+ }
269
285
  }
270
286
 
271
287
  verification_flags = rb_funcall(mini_ssl_ctx, rb_intern_const("verification_flags"), 0);
@@ -278,7 +294,9 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
278
294
 
279
295
  if (!NIL_P(ca)) {
280
296
  StringValue(ca);
281
- SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
297
+ if (SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL) != 1) {
298
+ raise_file_error("SSL_CTX_load_verify_locations", RSTRING_PTR(ca));
299
+ }
282
300
  }
283
301
 
284
302
  ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
@@ -355,7 +373,7 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
355
373
 
356
374
  // printf("\ninitialize end security_level %d\n", SSL_CTX_get_security_level(ctx));
357
375
 
358
- #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
376
+ #ifdef HAVE_SSL_CTX_SET_DH_AUTO
359
377
  // https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_dh_auto.html
360
378
  SSL_CTX_set_dh_auto(ctx, 1);
361
379
  #else
File without changes
@@ -99,6 +99,8 @@ public class Http11 extends RubyObject {
99
99
  int bite = b.get(i) & 0xFF;
100
100
  if(bite == '-') {
101
101
  b.set(i, (byte)'_');
102
+ } else if(bite == '_') {
103
+ b.set(i, (byte)',');
102
104
  } else {
103
105
  b.set(i, (byte)Character.toUpperCase(bite));
104
106
  }
File without changes
@@ -279,14 +279,6 @@ public class MiniSSL extends RubyObject {
279
279
  }
280
280
  }
281
281
 
282
- // after each op, run any delegated tasks if needed
283
- if(res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
284
- Runnable runnable;
285
- while ((runnable = engine.getDelegatedTask()) != null) {
286
- runnable.run();
287
- }
288
- }
289
-
290
282
  return res;
291
283
  }
292
284
 
@@ -304,11 +296,12 @@ public class MiniSSL extends RubyObject {
304
296
 
305
297
  HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
306
298
  boolean done = false;
307
- SSLEngineResult res = null;
308
299
  while (!done) {
300
+ SSLEngineResult res;
309
301
  switch (handshakeStatus) {
310
302
  case NEED_WRAP:
311
303
  res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
304
+ handshakeStatus = res.getHandshakeStatus();
312
305
  break;
313
306
  case NEED_UNWRAP:
314
307
  res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
@@ -316,13 +309,18 @@ public class MiniSSL extends RubyObject {
316
309
  // need more data before we can shake more hands
317
310
  done = true;
318
311
  }
312
+ handshakeStatus = res.getHandshakeStatus();
313
+ break;
314
+ case NEED_TASK:
315
+ Runnable runnable;
316
+ while ((runnable = engine.getDelegatedTask()) != null) {
317
+ runnable.run();
318
+ }
319
+ handshakeStatus = engine.getHandshakeStatus();
319
320
  break;
320
321
  default:
321
322
  done = true;
322
323
  }
323
- if (!done) {
324
- handshakeStatus = res.getHandshakeStatus();
325
- }
326
324
  }
327
325
 
328
326
  if (inboundNetData.hasRemaining()) {
File without changes
@@ -39,6 +39,9 @@ module Puma
39
39
  when 'phased-restart'
40
40
  @launcher.phased_restart ? 200 : 404
41
41
 
42
+ when 'refork'
43
+ @launcher.refork ? 200 : 404
44
+
42
45
  when 'reload-worker-directory'
43
46
  @launcher.send(:reload_worker_directory) ? 200 : 404
44
47
 
data/lib/puma/binder.rb CHANGED
@@ -189,7 +189,7 @@ module Puma
189
189
  end
190
190
 
191
191
  if fd = @inherited_fds.delete(str)
192
- @unix_paths << path unless abstract
192
+ @unix_paths << path unless abstract || File.exist?(path)
193
193
  io = inherit_unix_listener path, fd
194
194
  logger.log "* Inherited #{str}"
195
195
  elsif sock = @activated_sockets.delete([ :unix, path ]) ||
data/lib/puma/cli.rb CHANGED
File without changes
data/lib/puma/client.rb CHANGED
@@ -45,7 +45,16 @@ module Puma
45
45
 
46
46
  # chunked body validation
47
47
  CHUNK_SIZE_INVALID = /[^\h]/.freeze
48
- CHUNK_VALID_ENDING = "\r\n".freeze
48
+ CHUNK_VALID_ENDING = Const::LINE_END
49
+ CHUNK_VALID_ENDING_SIZE = CHUNK_VALID_ENDING.bytesize
50
+
51
+ # The maximum number of bytes we'll buffer looking for a valid
52
+ # chunk header.
53
+ MAX_CHUNK_HEADER_SIZE = 4096
54
+
55
+ # The maximum amount of excess data the client sends
56
+ # using chunk size extensions before we abort the connection.
57
+ MAX_CHUNK_EXCESS = 16 * 1024
49
58
 
50
59
  # Content-Length header value validation
51
60
  CONTENT_LENGTH_VALUE_INVALID = /[^\d]/.freeze
@@ -347,8 +356,8 @@ module Puma
347
356
  cl = @env[CONTENT_LENGTH]
348
357
 
349
358
  if cl
350
- # cannot contain characters that are not \d
351
- if cl =~ CONTENT_LENGTH_VALUE_INVALID
359
+ # cannot contain characters that are not \d, or be empty
360
+ if cl =~ CONTENT_LENGTH_VALUE_INVALID || cl.empty?
352
361
  raise HttpParserError, "Invalid Content-Length: #{cl.inspect}"
353
362
  end
354
363
  else
@@ -459,6 +468,7 @@ module Puma
459
468
  @chunked_body = true
460
469
  @partial_part_left = 0
461
470
  @prev_chunk = ""
471
+ @excess_cr = 0
462
472
 
463
473
  @body = Tempfile.new(Const::PUMA_TMP_BASE)
464
474
  @body.unlink
@@ -509,7 +519,7 @@ module Puma
509
519
 
510
520
  while !io.eof?
511
521
  line = io.gets
512
- if line.end_with?("\r\n")
522
+ if line.end_with?(CHUNK_VALID_ENDING)
513
523
  # Puma doesn't process chunk extensions, but should parse if they're
514
524
  # present, which is the reason for the semicolon regex
515
525
  chunk_hex = line.strip[/\A[^;]+/]
@@ -521,19 +531,39 @@ module Puma
521
531
  @in_last_chunk = true
522
532
  @body.rewind
523
533
  rest = io.read
524
- last_crlf_size = "\r\n".bytesize
525
- if rest.bytesize < last_crlf_size
534
+ if rest.bytesize < CHUNK_VALID_ENDING_SIZE
526
535
  @buffer = nil
527
- @partial_part_left = last_crlf_size - rest.bytesize
536
+ @partial_part_left = CHUNK_VALID_ENDING_SIZE - rest.bytesize
528
537
  return false
529
538
  else
530
- @buffer = rest[last_crlf_size..-1]
539
+ # if the next character is a CRLF, set buffer to everything after that CRLF
540
+ start_of_rest = if rest.start_with?(CHUNK_VALID_ENDING)
541
+ CHUNK_VALID_ENDING_SIZE
542
+ else # we have started a trailer section, which we do not support. skip it!
543
+ rest.index(CHUNK_VALID_ENDING*2) + CHUNK_VALID_ENDING_SIZE*2
544
+ end
545
+
546
+ @buffer = rest[start_of_rest..-1]
531
547
  @buffer = nil if @buffer.empty?
532
548
  set_ready
533
549
  return true
534
550
  end
535
551
  end
536
552
 
553
+ # Track the excess as a function of the size of the
554
+ # header vs the size of the actual data. Excess can
555
+ # go negative (and is expected to) when the body is
556
+ # significant.
557
+ # The additional of chunk_hex.size and 2 compensates
558
+ # for a client sending 1 byte in a chunked body over
559
+ # a long period of time, making sure that that client
560
+ # isn't accidentally eventually punished.
561
+ @excess_cr += (line.size - len - chunk_hex.size - 2)
562
+
563
+ if @excess_cr >= MAX_CHUNK_EXCESS
564
+ raise HttpParserError, "Maximum chunk excess detected"
565
+ end
566
+
537
567
  len += 2
538
568
 
539
569
  part = io.read(len)
@@ -561,6 +591,10 @@ module Puma
561
591
  @partial_part_left = len - part.size
562
592
  end
563
593
  else
594
+ if @prev_chunk.size + chunk.size >= MAX_CHUNK_HEADER_SIZE
595
+ raise HttpParserError, "maximum size of chunk header exceeded"
596
+ end
597
+
564
598
  @prev_chunk = line
565
599
  return false
566
600
  end
File without changes
File without changes
data/lib/puma/cluster.rb CHANGED
File without changes
File without changes
File without changes
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 = "5.6.4".freeze
103
+ PUMA_VERSION = VERSION = "5.6.9".freeze
104
104
  CODE_NAME = "Birdie's Version".freeze
105
105
 
106
106
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
@@ -244,6 +244,14 @@ module Puma
244
244
  # header values can contain HTAB?
245
245
  ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
246
246
 
247
+ # The keys of headers that should not be convert to underscore
248
+ # normalized versions. These headers are ignored at the request reading layer,
249
+ # but if we normalize them after reading, it's just confusing for the application.
250
+ UNMASKABLE_HEADERS = {
251
+ "HTTP_TRANSFER,ENCODING" => true,
252
+ "HTTP_CONTENT,LENGTH" => true,
253
+ }
254
+
247
255
  # Banned keys of response header
248
256
  BANNED_HEADER_KEY = /\A(rack\.|status\z)/.freeze
249
257
 
@@ -17,26 +17,30 @@ module Puma
17
17
  CMD_PATH_SIG_MAP = {
18
18
  'gc' => nil,
19
19
  'gc-stats' => nil,
20
- 'halt' => 'SIGQUIT',
21
- 'phased-restart' => 'SIGUSR1',
22
- 'refork' => 'SIGURG',
20
+ 'halt' => 'SIGQUIT',
21
+ 'info' => 'SIGINFO',
22
+ 'phased-restart' => 'SIGUSR1',
23
+ 'refork' => 'SIGURG',
23
24
  'reload-worker-directory' => nil,
24
- 'restart' => 'SIGUSR2',
25
+ 'reopen-log' => 'SIGHUP',
26
+ 'restart' => 'SIGUSR2',
25
27
  'start' => nil,
26
28
  'stats' => nil,
27
29
  'status' => '',
28
- 'stop' => 'SIGTERM',
29
- 'thread-backtraces' => nil
30
+ 'stop' => 'SIGTERM',
31
+ 'thread-backtraces' => nil,
32
+ 'worker-count-down' => 'SIGTTOU',
33
+ 'worker-count-up' => 'SIGTTIN'
30
34
  }.freeze
31
35
 
32
36
  # @deprecated 6.0.0
33
37
  COMMANDS = CMD_PATH_SIG_MAP.keys.freeze
34
38
 
35
39
  # commands that cannot be used in a request
36
- NO_REQ_COMMANDS = %w{refork}.freeze
40
+ NO_REQ_COMMANDS = %w[info reopen-log worker-count-down worker-count-up].freeze
37
41
 
38
42
  # @version 5.0.0
39
- PRINTABLE_COMMANDS = %w{gc-stats stats thread-backtraces}.freeze
43
+ PRINTABLE_COMMANDS = %w[gc-stats stats thread-backtraces].freeze
40
44
 
41
45
  def initialize(argv, stdout=STDOUT, stderr=STDERR)
42
46
  @state = nil
@@ -185,8 +189,6 @@ module Puma
185
189
 
186
190
  if @command == 'status'
187
191
  message 'Puma is started'
188
- elsif NO_REQ_COMMANDS.include? @command
189
- raise "Invalid request command: #{@command}"
190
192
  else
191
193
  url = "/#{@command}"
192
194
 
@@ -242,7 +244,11 @@ module Puma
242
244
  @stdout.flush unless @stdout.sync
243
245
  return
244
246
  elsif sig.start_with? 'SIG'
245
- Process.kill sig, @pid
247
+ if Signal.list.key? sig.sub(/\ASIG/, '')
248
+ Process.kill sig, @pid
249
+ else
250
+ raise "Signal '#{sig}' not available'"
251
+ end
246
252
  elsif @command == 'status'
247
253
  begin
248
254
  Process.kill 0, @pid
@@ -268,7 +274,7 @@ module Puma
268
274
  return start if @command == 'start'
269
275
  prepare_configuration
270
276
 
271
- if Puma.windows? || @control_url
277
+ if Puma.windows? || @control_url && !NO_REQ_COMMANDS.include?(@command)
272
278
  send_request
273
279
  else
274
280
  send_signal
data/lib/puma/detect.rb CHANGED
File without changes
data/lib/puma/dsl.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'puma/const'
4
+ require 'puma/util'
4
5
 
5
6
  module Puma
6
7
  # The methods that are available for use inside the configuration file.
@@ -46,7 +47,7 @@ module Puma
46
47
  else ''
47
48
  end
48
49
 
49
- ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
50
+ ca_additions = "&ca=#{Puma::Util.escape(opts[:ca])}" if ['peer', 'force_peer'].include?(verify)
50
51
 
51
52
  backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
52
53
 
@@ -65,7 +66,10 @@ module Puma
65
66
  v_flags = (ary = opts[:verification_flags]) ?
66
67
  "&verification_flags=#{Array(ary).join ','}" : nil
67
68
 
68
- "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}" \
69
+ cert_flags = (cert = opts[:cert]) ? "cert=#{Puma::Util.escape(opts[:cert])}" : nil
70
+ key_flags = (cert = opts[:key]) ? "&key=#{Puma::Util.escape(opts[:key])}" : nil
71
+
72
+ "ssl://#{host}:#{port}?#{cert_flags}#{key_flags}" \
69
73
  "#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}#{backlog_str}"
70
74
  end
71
75
  end
File without changes
data/lib/puma/events.rb CHANGED
File without changes
File without changes
File without changes
File without changes
data/lib/puma/launcher.rb CHANGED
@@ -159,6 +159,17 @@ module Puma
159
159
  true
160
160
  end
161
161
 
162
+ # Begin a refork if supported
163
+ def refork
164
+ if clustered? && @runner.respond_to?(:fork_worker!) && @options[:fork_worker]
165
+ @runner.fork_worker!
166
+ true
167
+ else
168
+ log "* refork called but not available."
169
+ false
170
+ end
171
+ end
172
+
162
173
  # Run the server. This blocks until the server is stopped
163
174
  def run
164
175
  previous_env =
File without changes
data/lib/puma/minissl.rb CHANGED
@@ -214,6 +214,11 @@ module Puma
214
214
  @cert_pem = nil
215
215
  end
216
216
 
217
+ def check_file(file, desc)
218
+ raise ArgumentError, "#{desc} file '#{file}' does not exist" unless File.exist? file
219
+ raise ArgumentError, "#{desc} file '#{file}' is not readable" unless File.readable? file
220
+ end
221
+
217
222
  if IS_JRUBY
218
223
  # jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
219
224
  attr_reader :keystore
@@ -221,7 +226,7 @@ module Puma
221
226
  attr_accessor :ssl_cipher_list
222
227
 
223
228
  def keystore=(keystore)
224
- raise ArgumentError, "No such keystore file '#{keystore}'" unless File.exist? keystore
229
+ check_file keystore, 'Keystore'
225
230
  @keystore = keystore
226
231
  end
227
232
 
@@ -240,17 +245,17 @@ module Puma
240
245
  attr_accessor :verification_flags
241
246
 
242
247
  def key=(key)
243
- raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
248
+ check_file key, 'Key'
244
249
  @key = key
245
250
  end
246
251
 
247
252
  def cert=(cert)
248
- raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
253
+ check_file cert, 'Cert'
249
254
  @cert = cert
250
255
  end
251
256
 
252
257
  def ca=(ca)
253
- raise ArgumentError, "No such ca file '#{ca}'" unless File.exist? ca
258
+ check_file ca, 'ca'
254
259
  @ca = ca
255
260
  end
256
261
 
data/lib/puma/null_io.rb CHANGED
@@ -52,5 +52,10 @@ module Puma
52
52
  def flush
53
53
  self
54
54
  end
55
+
56
+ # This is used as singleton class, so can't have state.
57
+ def closed?
58
+ false
59
+ end
55
60
  end
56
61
  end
File without changes
data/lib/puma/plugin.rb CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
data/lib/puma/reactor.rb CHANGED
File without changes
data/lib/puma/request.rb CHANGED
@@ -178,7 +178,11 @@ module Puma
178
178
  res_body.close if res_body.respond_to? :close
179
179
  end
180
180
 
181
- after_reply.each { |o| o.call }
181
+ begin
182
+ after_reply.each { |o| o.call }
183
+ rescue StandardError => e
184
+ @log_writer.debug_error e
185
+ end
182
186
  end
183
187
 
184
188
  res_info[:keep_alive]
@@ -314,6 +318,11 @@ module Puma
314
318
  # compatibility, we'll convert them back. This code is written to
315
319
  # avoid allocation in the common case (ie there are no headers
316
320
  # with `,` in their names), that's why it has the extra conditionals.
321
+ #
322
+ # @note If a normalized version of a `,` header already exists, we ignore
323
+ # the `,` version. This prevents clobbering headers managed by proxies
324
+ # but not by clients (Like X-Forwarded-For).
325
+ #
317
326
  # @param env [Hash] see Puma::Client#env, from request, modifies in place
318
327
  # @version 5.0.3
319
328
  #
@@ -322,23 +331,31 @@ module Puma
322
331
  to_add = nil
323
332
 
324
333
  env.each do |k,v|
325
- if k.start_with?("HTTP_") and k.include?(",") and k != "HTTP_TRANSFER,ENCODING"
334
+ if k.start_with?("HTTP_") && k.include?(",") && !UNMASKABLE_HEADERS.key?(k)
326
335
  if to_delete
327
336
  to_delete << k
328
337
  else
329
338
  to_delete = [k]
330
339
  end
331
340
 
341
+ new_k = k.tr(",", "_")
342
+ if env.key?(new_k)
343
+ next
344
+ end
345
+
332
346
  unless to_add
333
347
  to_add = {}
334
348
  end
335
349
 
336
- to_add[k.tr(",", "_")] = v
350
+ to_add[new_k] = v
337
351
  end
338
352
  end
339
353
 
340
- if to_delete
354
+ if to_delete # rubocop:disable Style/SafeNavigation
341
355
  to_delete.each { |k| env.delete(k) }
356
+ end
357
+
358
+ if to_add
342
359
  env.merge! to_add
343
360
  end
344
361
  end
data/lib/puma/runner.rb CHANGED
File without changes
data/lib/puma/server.rb CHANGED
@@ -39,6 +39,7 @@ module Puma
39
39
  attr_reader :events
40
40
  attr_reader :min_threads, :max_threads # for #stats
41
41
  attr_reader :requests_count # @version 5.0.0
42
+ attr_reader :log_writer # to help with backports
42
43
 
43
44
  # @todo the following may be deprecated in the future
44
45
  attr_reader :auto_trim_time, :early_hints, :first_data_timeout,
@@ -73,6 +74,7 @@ module Puma
73
74
  def initialize(app, events=Events.stdio, options={})
74
75
  @app = app
75
76
  @events = events
77
+ @log_writer = events
76
78
 
77
79
  @check, @notify = nil
78
80
  @status = :stop
data/lib/puma/single.rb CHANGED
File without changes
@@ -50,6 +50,7 @@ module Puma
50
50
  v = v.strip
51
51
  @options[k] =
52
52
  case v
53
+ when '' then nil
53
54
  when /\A\d+\z/ then v.to_i
54
55
  when /\A\d+\.\d+\z/ then v.to_f
55
56
  else v.gsub(/\A"|"\z/, '')
data/lib/puma/systemd.rb CHANGED
File without changes
File without changes
data/lib/puma/util.rb CHANGED
@@ -17,18 +17,27 @@ module Puma
17
17
  Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
18
18
  end
19
19
 
20
- # Unescapes a URI escaped string with +encoding+. +encoding+ will be the
21
- # target encoding of the string returned, and it defaults to UTF-8
20
+ # Escapes and unescapes a URI escaped string with
21
+ # +encoding+. +encoding+ will be the target encoding of the string
22
+ # returned, and it defaults to UTF-8
22
23
  if defined?(::Encoding)
24
+ def escape(s, encoding = Encoding::UTF_8)
25
+ URI.encode_www_form_component(s, encoding)
26
+ end
27
+
23
28
  def unescape(s, encoding = Encoding::UTF_8)
24
29
  URI.decode_www_form_component(s, encoding)
25
30
  end
26
31
  else
32
+ def escape(s, encoding = nil)
33
+ URI.encode_www_form_component(s, encoding)
34
+ end
35
+
27
36
  def unescape(s, encoding = nil)
28
37
  URI.decode_www_form_component(s, encoding)
29
38
  end
30
39
  end
31
- module_function :unescape
40
+ module_function :unescape, :escape
32
41
 
33
42
  # @version 5.0.0
34
43
  def nakayoshi_gc(events)
data/lib/puma.rb CHANGED
@@ -10,9 +10,11 @@ require 'stringio'
10
10
 
11
11
  require 'thread'
12
12
 
13
+ # extension files should not be loaded with `require_relative`
13
14
  require 'puma/puma_http11'
14
- require 'puma/detect'
15
- require 'puma/json_serialization'
15
+ require_relative 'puma/detect'
16
+ require_relative 'puma/json_serialization'
17
+ require_relative 'rack/version_restriction'
16
18
 
17
19
  module Puma
18
20
  autoload :Const, 'puma/const'
@@ -23,7 +25,7 @@ module Puma
23
25
  # not in minissl.rb
24
26
  HAS_SSL = const_defined?(:MiniSSL, false) && MiniSSL.const_defined?(:Engine, false)
25
27
 
26
- HAS_UNIX_SOCKET = Object.const_defined? :UNIXSocket
28
+ HAS_UNIX_SOCKET = Object.const_defined?(:UNIXSocket) && !IS_WINDOWS
27
29
 
28
30
  if HAS_SSL
29
31
  require 'puma/minissl'
File without changes
@@ -0,0 +1,15 @@
1
+ begin
2
+ begin
3
+ # rack/version exists in Rack 2.2.0 and later, compatible with Ruby 2.3 and later
4
+ # we prefer to not load Rack
5
+ require 'rack/version'
6
+ rescue LoadError
7
+ require 'rack'
8
+ end
9
+
10
+ # Rack.release is needed for Rack v1, Rack::RELEASE was added in v2
11
+ if Gem::Version.new(Rack.release) >= Gem::Version.new("3.0.0")
12
+ raise StandardError.new "Puma 5 is not compatible with Rack 3, please upgrade to Puma 6 or higher."
13
+ end
14
+ rescue LoadError
15
+ end
data/tools/Dockerfile CHANGED
File without changes
data/tools/trickletest.rb CHANGED
File without changes
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.6.4
4
+ version: 5.6.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 1980-01-01 00:00:00.000000000 Z
11
+ date: 2024-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nio4r
@@ -115,6 +115,7 @@ files:
115
115
  - lib/puma/thread_pool.rb
116
116
  - lib/puma/util.rb
117
117
  - lib/rack/handler/puma.rb
118
+ - lib/rack/version_restriction.rb
118
119
  - tools/Dockerfile
119
120
  - tools/trickletest.rb
120
121
  homepage: https://puma.io
@@ -140,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
141
  - !ruby/object:Gem::Version
141
142
  version: '0'
142
143
  requirements: []
143
- rubygems_version: 3.2.26
144
+ rubygems_version: 3.5.16
144
145
  signing_key:
145
146
  specification_version: 4
146
147
  summary: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server for