puma 5.6.4 → 6.1.1

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.

Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +199 -3
  3. data/README.md +22 -17
  4. data/bin/puma-wild +1 -1
  5. data/docs/compile_options.md +34 -0
  6. data/docs/fork_worker.md +1 -3
  7. data/docs/nginx.md +1 -1
  8. data/docs/systemd.md +1 -2
  9. data/docs/testing_benchmarks_local_files.md +150 -0
  10. data/docs/testing_test_rackup_ci_files.md +36 -0
  11. data/ext/puma_http11/extconf.rb +18 -10
  12. data/ext/puma_http11/http11_parser.c +1 -1
  13. data/ext/puma_http11/http11_parser.h +1 -1
  14. data/ext/puma_http11/http11_parser.java.rl +2 -2
  15. data/ext/puma_http11/http11_parser.rl +2 -2
  16. data/ext/puma_http11/http11_parser_common.rl +2 -2
  17. data/ext/puma_http11/mini_ssl.c +63 -24
  18. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  19. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
  20. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +166 -65
  21. data/ext/puma_http11/puma_http11.c +17 -9
  22. data/lib/puma/app/status.rb +6 -3
  23. data/lib/puma/binder.rb +41 -46
  24. data/lib/puma/cli.rb +11 -17
  25. data/lib/puma/client.rb +54 -16
  26. data/lib/puma/cluster/worker.rb +18 -11
  27. data/lib/puma/cluster/worker_handle.rb +4 -1
  28. data/lib/puma/cluster.rb +33 -30
  29. data/lib/puma/configuration.rb +75 -58
  30. data/lib/puma/const.rb +76 -88
  31. data/lib/puma/control_cli.rb +21 -18
  32. data/lib/puma/detect.rb +4 -0
  33. data/lib/puma/dsl.rb +111 -49
  34. data/lib/puma/error_logger.rb +17 -9
  35. data/lib/puma/events.rb +6 -126
  36. data/lib/puma/io_buffer.rb +39 -4
  37. data/lib/puma/jruby_restart.rb +2 -1
  38. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  39. data/lib/puma/launcher.rb +111 -175
  40. data/lib/puma/log_writer.rb +141 -0
  41. data/lib/puma/minissl/context_builder.rb +23 -12
  42. data/lib/puma/minissl.rb +91 -15
  43. data/lib/puma/null_io.rb +5 -0
  44. data/lib/puma/plugin/systemd.rb +90 -0
  45. data/lib/puma/plugin/tmp_restart.rb +1 -1
  46. data/lib/puma/rack/builder.rb +4 -4
  47. data/lib/puma/rack_default.rb +19 -4
  48. data/lib/puma/reactor.rb +4 -4
  49. data/lib/puma/request.rb +344 -161
  50. data/lib/puma/runner.rb +52 -20
  51. data/lib/puma/sd_notify.rb +149 -0
  52. data/lib/puma/server.rb +57 -69
  53. data/lib/puma/single.rb +13 -11
  54. data/lib/puma/state_file.rb +2 -4
  55. data/lib/puma/thread_pool.rb +16 -16
  56. data/lib/puma/util.rb +12 -14
  57. data/lib/puma.rb +12 -11
  58. data/lib/rack/handler/puma.rb +115 -94
  59. metadata +10 -5
  60. data/lib/puma/queue_close.rb +0 -26
  61. data/lib/puma/systemd.rb +0 -46
@@ -2,18 +2,22 @@ require 'mkmf'
2
2
 
3
3
  dir_config("puma_http11")
4
4
 
5
- if $mingw && RUBY_VERSION >= '2.4'
5
+ if $mingw
6
6
  append_cflags '-fstack-protector-strong -D_FORTIFY_SOURCE=2'
7
7
  append_ldflags '-fstack-protector-strong -l:libssp.a'
8
8
  have_library 'ssp'
9
9
  end
10
10
 
11
- unless ENV["DISABLE_SSL"]
12
- dir_config("openssl")
11
+ unless ENV["PUMA_DISABLE_SSL"]
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 && found_pkg_config
15
17
  puts 'using OpenSSL pkgconfig (openssl.pc)'
16
18
  true
19
+ elsif have_library('libcrypto', 'BIO_read') && have_library('libssl', 'SSL_CTX_new')
20
+ true
17
21
  elsif %w'crypto libeay32'.find {|crypto| have_library(crypto, 'BIO_read')} &&
18
22
  %w'ssl ssleay32'.find {|ssl| have_library(ssl, 'SSL_CTX_new')}
19
23
  true
@@ -26,16 +30,20 @@ unless ENV["DISABLE_SSL"]
26
30
  have_header "openssl/bio.h"
27
31
 
28
32
  # below is yes for 1.0.2 & later
29
- have_func "DTLS_method" , "openssl/ssl.h"
33
+ have_func "DTLS_method" , "openssl/ssl.h"
34
+ have_func "SSL_CTX_set_session_cache_mode(NULL, 0)", "openssl/ssl.h"
30
35
 
31
36
  # below are yes for 1.1.0 & later
32
- have_func "TLS_server_method" , "openssl/ssl.h"
33
- have_func "SSL_CTX_set_min_proto_version(NULL, 0)", "openssl/ssl.h"
37
+ have_func "TLS_server_method" , "openssl/ssl.h"
38
+ have_func "SSL_CTX_set_min_proto_version(NULL, 0)" , "openssl/ssl.h"
34
39
 
35
- have_func "X509_STORE_up_ref"
40
+ have_func "X509_STORE_up_ref"
36
41
  have_func "SSL_CTX_set_ecdh_auto(NULL, 0)" , "openssl/ssl.h"
37
42
 
38
- # below are yes for 3.0.0 & later, use for OpenSSL 3 detection
43
+ # below exists in 1.1.0 and later, but isn't documented until 3.0.0
44
+ have_func "SSL_CTX_set_dh_auto(NULL, 0)" , "openssl/ssl.h"
45
+
46
+ # below is yes for 3.0.0 & later
39
47
  have_func "SSL_get1_peer_certificate" , "openssl/ssl.h"
40
48
 
41
49
  # Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
@@ -48,7 +56,7 @@ unless ENV["DISABLE_SSL"]
48
56
  end
49
57
  end
50
58
 
51
- if ENV["MAKE_WARNINGS_INTO_ERRORS"]
59
+ if ENV["PUMA_MAKE_WARNINGS_INTO_ERRORS"]
52
60
  # Make all warnings into errors
53
61
  # Except `implicit-fallthrough` since most failures comes from ragel state machine generated code
54
62
  if respond_to?(:append_cflags, true) # Ruby 2.5 and later
@@ -297,7 +297,7 @@ case 13:
297
297
  tr18:
298
298
  #line 65 "ext/puma_http11/http11_parser.rl"
299
299
  {
300
- parser->http_version(parser, PTR_TO(mark), LEN(mark, p));
300
+ parser->server_protocol(parser, PTR_TO(mark), LEN(mark, p));
301
301
  }
302
302
  goto st14;
303
303
  tr26:
@@ -46,7 +46,7 @@ typedef struct puma_parser {
46
46
  element_cb fragment;
47
47
  element_cb request_path;
48
48
  element_cb query_string;
49
- element_cb http_version;
49
+ element_cb server_protocol;
50
50
  element_cb header_done;
51
51
 
52
52
  char buf[BUFFER_LEN];
@@ -39,8 +39,8 @@ public class Http11Parser {
39
39
  Http11.query_string(runtime, parser.data, parser.buffer, parser.query_start, fpc-parser.query_start);
40
40
  }
41
41
 
42
- action http_version {
43
- Http11.http_version(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
42
+ action server_protocol {
43
+ Http11.server_protocol(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
44
44
  }
45
45
 
46
46
  action request_path {
@@ -62,8 +62,8 @@ static void snake_upcase_char(char *c)
62
62
  parser->query_string(parser, PTR_TO(query_start), LEN(query_start, fpc));
63
63
  }
64
64
 
65
- action http_version {
66
- parser->http_version(parser, PTR_TO(mark), LEN(mark, fpc));
65
+ action server_protocol {
66
+ parser->server_protocol(parser, PTR_TO(mark), LEN(mark, fpc));
67
67
  }
68
68
 
69
69
  action request_path {
@@ -38,8 +38,8 @@
38
38
  Method = ( upper | digit | safe ){1,20} >mark %request_method;
39
39
 
40
40
  http_number = ( digit+ "." digit+ ) ;
41
- HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
42
- Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ;
41
+ Server_Protocol = ( "HTTP/" http_number ) >mark %server_protocol ;
42
+ Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " Server_Protocol CRLF ) ;
43
43
 
44
44
  field_name = ( token -- ":" )+ >start_field $snake_upcase_field %write_field;
45
45
 
@@ -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
 
@@ -204,25 +210,28 @@ sslctx_alloc(VALUE klass) {
204
210
  VALUE
205
211
  sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
206
212
  SSL_CTX* ctx;
207
-
208
- #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
209
- int min;
210
- #endif
211
213
  int ssl_options;
212
214
  VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1,
213
215
  verification_flags, session_id_bytes, cert_pem, key_pem;
214
- #ifndef HAVE_SSL_GET1_PEER_CERTIFICATE
215
- DH *dh;
216
- #endif
217
216
  BIO *bio;
218
217
  X509 *x509;
219
218
  EVP_PKEY *pkey;
220
-
219
+ #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
220
+ int min;
221
+ #endif
222
+ #ifndef HAVE_SSL_CTX_SET_DH_AUTO
223
+ DH *dh;
224
+ #endif
221
225
  #if OPENSSL_VERSION_NUMBER < 0x10002000L
222
226
  EC_KEY *ecdh;
223
227
  #endif
228
+ #ifdef HAVE_SSL_CTX_SET_SESSION_CACHE_MODE
229
+ VALUE reuse, reuse_cache_size, reuse_timeout;
224
230
 
225
- TypedData_Get_Struct(self, SSL_CTX, &sslctx_type, ctx);
231
+ reuse = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse"), 0);
232
+ reuse_cache_size = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse_cache_size"), 0);
233
+ reuse_timeout = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse_timeout"), 0);
234
+ #endif
226
235
 
227
236
  key = rb_funcall(mini_ssl_ctx, rb_intern_const("key"), 0);
228
237
 
@@ -242,14 +251,22 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
242
251
 
243
252
  no_tlsv1_1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1_1"), 0);
244
253
 
254
+ TypedData_Get_Struct(self, SSL_CTX, &sslctx_type, ctx);
255
+
245
256
  if (!NIL_P(cert)) {
246
257
  StringValue(cert);
247
- SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
258
+
259
+ if (SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert)) != 1) {
260
+ raise_file_error("SSL_CTX_use_certificate_chain_file", RSTRING_PTR(cert));
261
+ }
248
262
  }
249
263
 
250
264
  if (!NIL_P(key)) {
251
265
  StringValue(key);
252
- SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM);
266
+
267
+ if (SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM) != 1) {
268
+ raise_file_error("SSL_CTX_use_PrivateKey_file", RSTRING_PTR(key));
269
+ }
253
270
  }
254
271
 
255
272
  if (!NIL_P(cert_pem)) {
@@ -257,7 +274,12 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
257
274
  BIO_puts(bio, RSTRING_PTR(cert_pem));
258
275
  x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
259
276
 
260
- SSL_CTX_use_certificate(ctx, x509);
277
+ if (SSL_CTX_use_certificate(ctx, x509) != 1) {
278
+ BIO_free(bio);
279
+ raise_file_error("SSL_CTX_use_certificate", RSTRING_PTR(cert_pem));
280
+ }
281
+ X509_free(x509);
282
+ BIO_free(bio);
261
283
  }
262
284
 
263
285
  if (!NIL_P(key_pem)) {
@@ -265,7 +287,12 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
265
287
  BIO_puts(bio, RSTRING_PTR(key_pem));
266
288
  pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
267
289
 
268
- SSL_CTX_use_PrivateKey(ctx, pkey);
290
+ if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
291
+ BIO_free(bio);
292
+ raise_file_error("SSL_CTX_use_PrivateKey", RSTRING_PTR(key_pem));
293
+ }
294
+ EVP_PKEY_free(pkey);
295
+ BIO_free(bio);
269
296
  }
270
297
 
271
298
  verification_flags = rb_funcall(mini_ssl_ctx, rb_intern_const("verification_flags"), 0);
@@ -278,7 +305,9 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
278
305
 
279
306
  if (!NIL_P(ca)) {
280
307
  StringValue(ca);
281
- SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
308
+ if (SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL) != 1) {
309
+ raise_file_error("SSL_CTX_load_verify_locations", RSTRING_PTR(ca));
310
+ }
282
311
  }
283
312
 
284
313
  ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
@@ -296,8 +325,6 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
296
325
 
297
326
  SSL_CTX_set_min_proto_version(ctx, min);
298
327
 
299
- SSL_CTX_set_options(ctx, ssl_options);
300
-
301
328
  #else
302
329
  /* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */
303
330
  ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE;
@@ -308,10 +335,23 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
308
335
  if(RTEST(no_tlsv1_1)) {
309
336
  ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
310
337
  }
311
- SSL_CTX_set_options(ctx, ssl_options);
312
338
  #endif
313
339
 
314
- SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
340
+ #ifdef HAVE_SSL_CTX_SET_SESSION_CACHE_MODE
341
+ if (!NIL_P(reuse)) {
342
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
343
+ if (!NIL_P(reuse_cache_size)) {
344
+ SSL_CTX_sess_set_cache_size(ctx, NUM2INT(reuse_cache_size));
345
+ }
346
+ if (!NIL_P(reuse_timeout)) {
347
+ SSL_CTX_set_timeout(ctx, NUM2INT(reuse_timeout));
348
+ }
349
+ } else {
350
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
351
+ }
352
+ #endif
353
+
354
+ SSL_CTX_set_options(ctx, ssl_options);
315
355
 
316
356
  if (!NIL_P(ssl_cipher_filter)) {
317
357
  StringValue(ssl_cipher_filter);
@@ -322,8 +362,7 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
322
362
  }
323
363
 
324
364
  #if OPENSSL_VERSION_NUMBER < 0x10002000L
325
- // Remove this case if OpenSSL 1.0.1 (now EOL) support is no
326
- // longer needed.
365
+ // Remove this case if OpenSSL 1.0.1 (now EOL) support is no longer needed.
327
366
  ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
328
367
  if (ecdh) {
329
368
  SSL_CTX_set_tmp_ecdh(ctx, ecdh);
@@ -355,7 +394,7 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
355
394
 
356
395
  // printf("\ninitialize end security_level %d\n", SSL_CTX_get_security_level(ctx));
357
396
 
358
- #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
397
+ #ifdef HAVE_SSL_CTX_SET_DH_AUTO
359
398
  // https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_dh_auto.html
360
399
  SSL_CTX_set_dh_auto(ctx, 1);
361
400
  #else
@@ -46,7 +46,7 @@ public class Http11 extends RubyObject {
46
46
  public static final ByteList FRAGMENT_BYTELIST = new ByteList(ByteList.plain("FRAGMENT"));
47
47
  public static final ByteList REQUEST_PATH_BYTELIST = new ByteList(ByteList.plain("REQUEST_PATH"));
48
48
  public static final ByteList QUERY_STRING_BYTELIST = new ByteList(ByteList.plain("QUERY_STRING"));
49
- public static final ByteList HTTP_VERSION_BYTELIST = new ByteList(ByteList.plain("HTTP_VERSION"));
49
+ public static final ByteList SERVER_PROTOCOL_BYTELIST = new ByteList(ByteList.plain("SERVER_PROTOCOL"));
50
50
 
51
51
  private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
52
52
  public IRubyObject allocate(Ruby runtime, RubyClass klass) {
@@ -153,9 +153,9 @@ public class Http11 extends RubyObject {
153
153
  req.fastASet(RubyString.newStringShared(runtime, QUERY_STRING_BYTELIST),val);
154
154
  }
155
155
 
156
- public static void http_version(Ruby runtime, RubyHash req, ByteList buffer, int at, int length) {
156
+ public static void server_protocol(Ruby runtime, RubyHash req, ByteList buffer, int at, int length) {
157
157
  RubyString val = RubyString.newString(runtime,new ByteList(buffer,at,length));
158
- req.fastASet(RubyString.newStringShared(runtime, HTTP_VERSION_BYTELIST),val);
158
+ req.fastASet(RubyString.newStringShared(runtime, SERVER_PROTOCOL_BYTELIST),val);
159
159
  }
160
160
 
161
161
  public void header_done(Ruby runtime, RubyHash req, ByteList buffer, int at, int length) {
@@ -383,7 +383,7 @@ case 1:
383
383
  case 11:
384
384
  // line 42 "ext/puma_http11/http11_parser.java.rl"
385
385
  {
386
- Http11.http_version(runtime, parser.data, parser.buffer, parser.mark, p-parser.mark);
386
+ Http11.server_protocol(runtime, parser.data, parser.buffer, parser.mark, p-parser.mark);
387
387
  }
388
388
  break;
389
389
  case 12: