puma 6.0.0 → 6.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +392 -13
- data/LICENSE +0 -0
- data/README.md +135 -29
- data/bin/puma-wild +0 -0
- data/docs/architecture.md +0 -0
- data/docs/compile_options.md +0 -0
- data/docs/deployment.md +0 -0
- data/docs/fork_worker.md +11 -1
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/java_options.md +54 -0
- data/docs/jungle/README.md +0 -0
- data/docs/jungle/rc.d/README.md +0 -0
- data/docs/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +12 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +4 -0
- data/docs/rails_dev_mode.md +0 -0
- data/docs/restart.md +1 -0
- data/docs/signals.md +2 -2
- data/docs/stats.md +8 -3
- data/docs/systemd.md +13 -7
- data/docs/testing_benchmarks_local_files.md +0 -0
- data/docs/testing_test_rackup_ci_files.md +0 -0
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +21 -14
- data/ext/puma_http11/http11_parser.c +0 -0
- data/ext/puma_http11/http11_parser.h +0 -0
- data/ext/puma_http11/http11_parser.java.rl +0 -0
- data/ext/puma_http11/http11_parser.rl +0 -0
- data/ext/puma_http11/http11_parser_common.rl +0 -0
- data/ext/puma_http11/mini_ssl.c +107 -10
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +30 -7
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +0 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +2 -1
- data/ext/puma_http11/puma_http11.c +4 -1
- data/lib/puma/app/status.rb +1 -1
- data/lib/puma/binder.rb +26 -15
- data/lib/puma/cli.rb +13 -5
- data/lib/puma/client.rb +113 -26
- data/lib/puma/cluster/worker.rb +14 -6
- data/lib/puma/cluster/worker_handle.rb +4 -5
- data/lib/puma/cluster.rb +93 -22
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +42 -22
- data/lib/puma/const.rb +149 -89
- data/lib/puma/control_cli.rb +16 -9
- data/lib/puma/detect.rb +5 -4
- data/lib/puma/dsl.rb +432 -40
- data/lib/puma/error_logger.rb +6 -5
- data/lib/puma/events.rb +0 -0
- data/lib/puma/io_buffer.rb +10 -0
- data/lib/puma/jruby_restart.rb +0 -16
- data/lib/puma/json_serialization.rb +0 -0
- data/lib/puma/launcher/bundle_pruner.rb +0 -0
- data/lib/puma/launcher.rb +29 -29
- data/lib/puma/log_writer.rb +23 -13
- data/lib/puma/minissl/context_builder.rb +4 -0
- data/lib/puma/minissl.rb +23 -0
- data/lib/puma/null_io.rb +42 -2
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +0 -0
- data/lib/puma/plugin.rb +0 -0
- data/lib/puma/rack/builder.rb +2 -2
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/rack_default.rb +18 -3
- data/lib/puma/reactor.rb +17 -8
- data/lib/puma/request.rb +207 -126
- data/lib/puma/runner.rb +26 -4
- data/lib/puma/sd_notify.rb +146 -0
- data/lib/puma/server.rb +121 -49
- data/lib/puma/single.rb +3 -1
- data/lib/puma/state_file.rb +2 -2
- data/lib/puma/thread_pool.rb +56 -9
- data/lib/puma/util.rb +1 -1
- data/lib/puma.rb +1 -3
- data/lib/rack/handler/puma.rb +116 -86
- data/tools/Dockerfile +2 -2
- data/tools/trickletest.rb +0 -0
- metadata +12 -13
- data/lib/puma/systemd.rb +0 -47
data/ext/puma_http11/mini_ssl.c
CHANGED
@@ -36,6 +36,12 @@ void raise_file_error(const char* caller, const char *filename) {
|
|
36
36
|
rb_raise(eError, "%s: error in file '%s': %s", caller, filename, ERR_error_string(ERR_get_error(), NULL));
|
37
37
|
}
|
38
38
|
|
39
|
+
NORETURN(void raise_param_error(const char* caller, const char *param));
|
40
|
+
|
41
|
+
void raise_param_error(const char* caller, const char *param) {
|
42
|
+
rb_raise(eError, "%s: error with parameter '%s': %s", caller, param, ERR_error_string(ERR_get_error(), NULL));
|
43
|
+
}
|
44
|
+
|
39
45
|
void engine_free(void *ptr) {
|
40
46
|
ms_conn *conn = ptr;
|
41
47
|
ms_cert_buf* cert_buf = (ms_cert_buf*)SSL_get_app_data(conn->ssl);
|
@@ -185,6 +191,18 @@ static int engine_verify_callback(int preverify_ok, X509_STORE_CTX* ctx) {
|
|
185
191
|
return preverify_ok;
|
186
192
|
}
|
187
193
|
|
194
|
+
static int password_callback(char *buf, int size, int rwflag, void *userdata) {
|
195
|
+
const char *password = (const char *) userdata;
|
196
|
+
size_t len = strlen(password);
|
197
|
+
|
198
|
+
if (len > (size_t) size) {
|
199
|
+
return 0;
|
200
|
+
}
|
201
|
+
|
202
|
+
memcpy(buf, password, len);
|
203
|
+
return (int) len;
|
204
|
+
}
|
205
|
+
|
188
206
|
static VALUE
|
189
207
|
sslctx_alloc(VALUE klass) {
|
190
208
|
SSL_CTX *ctx;
|
@@ -211,11 +229,13 @@ VALUE
|
|
211
229
|
sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
212
230
|
SSL_CTX* ctx;
|
213
231
|
int ssl_options;
|
214
|
-
VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1,
|
215
|
-
verification_flags, session_id_bytes, cert_pem, key_pem;
|
232
|
+
VALUE key, cert, ca, verify_mode, ssl_cipher_filter, ssl_ciphersuites, no_tlsv1, no_tlsv1_1,
|
233
|
+
verification_flags, session_id_bytes, cert_pem, key_pem, key_password_command, key_password;
|
216
234
|
BIO *bio;
|
217
|
-
X509 *x509;
|
235
|
+
X509 *x509 = NULL;
|
218
236
|
EVP_PKEY *pkey;
|
237
|
+
pem_password_cb *password_cb = NULL;
|
238
|
+
const char *password = NULL;
|
219
239
|
#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
|
220
240
|
int min;
|
221
241
|
#endif
|
@@ -235,6 +255,8 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
235
255
|
|
236
256
|
key = rb_funcall(mini_ssl_ctx, rb_intern_const("key"), 0);
|
237
257
|
|
258
|
+
key_password_command = rb_funcall(mini_ssl_ctx, rb_intern_const("key_password_command"), 0);
|
259
|
+
|
238
260
|
cert = rb_funcall(mini_ssl_ctx, rb_intern_const("cert"), 0);
|
239
261
|
|
240
262
|
ca = rb_funcall(mini_ssl_ctx, rb_intern_const("ca"), 0);
|
@@ -247,6 +269,8 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
247
269
|
|
248
270
|
ssl_cipher_filter = rb_funcall(mini_ssl_ctx, rb_intern_const("ssl_cipher_filter"), 0);
|
249
271
|
|
272
|
+
ssl_ciphersuites = rb_funcall(mini_ssl_ctx, rb_intern_const("ssl_ciphersuites"), 0);
|
273
|
+
|
250
274
|
no_tlsv1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1"), 0);
|
251
275
|
|
252
276
|
no_tlsv1_1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1_1"), 0);
|
@@ -261,6 +285,18 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
261
285
|
}
|
262
286
|
}
|
263
287
|
|
288
|
+
if (!NIL_P(key_password_command)) {
|
289
|
+
key_password = rb_funcall(mini_ssl_ctx, rb_intern_const("key_password"), 0);
|
290
|
+
|
291
|
+
if (!NIL_P(key_password)) {
|
292
|
+
StringValue(key_password);
|
293
|
+
password_cb = password_callback;
|
294
|
+
password = RSTRING_PTR(key_password);
|
295
|
+
SSL_CTX_set_default_passwd_cb(ctx, password_cb);
|
296
|
+
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) password);
|
297
|
+
}
|
298
|
+
}
|
299
|
+
|
264
300
|
if (!NIL_P(key)) {
|
265
301
|
StringValue(key);
|
266
302
|
|
@@ -270,22 +306,71 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
270
306
|
}
|
271
307
|
|
272
308
|
if (!NIL_P(cert_pem)) {
|
309
|
+
X509 *ca = NULL;
|
310
|
+
unsigned long err;
|
311
|
+
|
273
312
|
bio = BIO_new(BIO_s_mem());
|
274
313
|
BIO_puts(bio, RSTRING_PTR(cert_pem));
|
314
|
+
|
315
|
+
/**
|
316
|
+
* Much of this pulled as a simplified version of the `use_certificate_chain_file` method
|
317
|
+
* from openssl's `ssl_rsa.c` file.
|
318
|
+
*/
|
319
|
+
|
320
|
+
/* first read the cert as the first item in the pem file */
|
275
321
|
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
322
|
+
if (NULL == x509) {
|
323
|
+
BIO_free_all(bio);
|
324
|
+
raise_param_error("PEM_read_bio_X509", "cert_pem");
|
325
|
+
}
|
276
326
|
|
277
|
-
|
278
|
-
|
279
|
-
|
327
|
+
/* Add the cert to the context */
|
328
|
+
/* 1 is success - otherwise check the error codes */
|
329
|
+
if (1 != SSL_CTX_use_certificate(ctx, x509)) {
|
330
|
+
BIO_free_all(bio);
|
331
|
+
raise_param_error("SSL_CTX_use_certificate", "cert_pem");
|
332
|
+
}
|
333
|
+
|
334
|
+
X509_free(x509); /* no longer need our reference */
|
335
|
+
|
336
|
+
/* Now lets load up the rest of the certificate chain */
|
337
|
+
/* 1 is success 0 is error */
|
338
|
+
if (0 == SSL_CTX_clear_chain_certs(ctx)) {
|
339
|
+
BIO_free_all(bio);
|
340
|
+
raise_param_error("SSL_CTX_clear_chain_certs","cert_pem");
|
341
|
+
}
|
342
|
+
|
343
|
+
while (1) {
|
344
|
+
ca = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
345
|
+
|
346
|
+
if (NULL == ca) {
|
347
|
+
break;
|
348
|
+
}
|
349
|
+
|
350
|
+
if (0 == SSL_CTX_add0_chain_cert(ctx, ca)) {
|
351
|
+
BIO_free_all(bio);
|
352
|
+
raise_param_error("SSL_CTX_add0_chain_cert","cert_pem");
|
353
|
+
}
|
354
|
+
/* don't free ca - its now owned by the context */
|
355
|
+
}
|
356
|
+
|
357
|
+
/* ca is NULL - so its either the end of the file or an error */
|
358
|
+
err = ERR_peek_last_error();
|
359
|
+
|
360
|
+
/* If its the end of the file - then we are done, in any case free the bio */
|
361
|
+
BIO_free_all(bio);
|
362
|
+
|
363
|
+
if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
|
364
|
+
ERR_clear_error();
|
365
|
+
} else {
|
366
|
+
raise_param_error("PEM_read_bio_X509","cert_pem");
|
280
367
|
}
|
281
|
-
X509_free(x509);
|
282
|
-
BIO_free(bio);
|
283
368
|
}
|
284
369
|
|
285
370
|
if (!NIL_P(key_pem)) {
|
286
371
|
bio = BIO_new(BIO_s_mem());
|
287
372
|
BIO_puts(bio, RSTRING_PTR(key_pem));
|
288
|
-
pkey = PEM_read_bio_PrivateKey(bio, NULL,
|
373
|
+
pkey = PEM_read_bio_PrivateKey(bio, NULL, password_cb, (void *) password);
|
289
374
|
|
290
375
|
if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
|
291
376
|
BIO_free(bio);
|
@@ -361,6 +446,14 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
361
446
|
SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
|
362
447
|
}
|
363
448
|
|
449
|
+
#if HAVE_SSL_CTX_SET_CIPHERSUITES
|
450
|
+
// Only override OpenSSL default ciphersuites if config option is supplied.
|
451
|
+
if (!NIL_P(ssl_ciphersuites)) {
|
452
|
+
StringValue(ssl_ciphersuites);
|
453
|
+
SSL_CTX_set_ciphersuites(ctx, RSTRING_PTR(ssl_ciphersuites));
|
454
|
+
}
|
455
|
+
#endif
|
456
|
+
|
364
457
|
#if OPENSSL_VERSION_NUMBER < 0x10002000L
|
365
458
|
// Remove this case if OpenSSL 1.0.1 (now EOL) support is no longer needed.
|
366
459
|
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
@@ -463,7 +556,7 @@ NORETURN(void raise_error(SSL* ssl, int result));
|
|
463
556
|
|
464
557
|
void raise_error(SSL* ssl, int result) {
|
465
558
|
char buf[512];
|
466
|
-
char msg[
|
559
|
+
char msg[768];
|
467
560
|
const char* err_str;
|
468
561
|
int err = errno;
|
469
562
|
int mask = 4095;
|
@@ -721,6 +814,10 @@ void Init_mini_ssl(VALUE puma) {
|
|
721
814
|
|
722
815
|
rb_define_method(eng, "init?", engine_init, 0);
|
723
816
|
|
817
|
+
/* @!attribute [r] peercert
|
818
|
+
* Returns `nil` when `MiniSSL::Context#verify_mode` is set to `VERIFY_NONE`.
|
819
|
+
* @return [String, nil] DER encoded cert
|
820
|
+
*/
|
724
821
|
rb_define_method(eng, "peercert", engine_peercert, 0);
|
725
822
|
|
726
823
|
rb_define_method(eng, "ssl_vers_st", engine_ssl_vers_st, 0);
|
File without changes
|
@@ -26,14 +26,14 @@ public class Http11 extends RubyObject {
|
|
26
26
|
public final static String MAX_FIELD_NAME_LENGTH_ERR = "HTTP element FIELD_NAME is longer than the 256 allowed length.";
|
27
27
|
public final static int MAX_FIELD_VALUE_LENGTH = 80 * 1024;
|
28
28
|
public final static String MAX_FIELD_VALUE_LENGTH_ERR = "HTTP element FIELD_VALUE is longer than the 81920 allowed length.";
|
29
|
-
public final static int MAX_REQUEST_URI_LENGTH = 1024 * 12;
|
30
|
-
public final static String MAX_REQUEST_URI_LENGTH_ERR = "HTTP element REQUEST_URI is longer than the
|
29
|
+
public final static int MAX_REQUEST_URI_LENGTH = getConstLength("PUMA_REQUEST_URI_MAX_LENGTH", 1024 * 12);
|
30
|
+
public final static String MAX_REQUEST_URI_LENGTH_ERR = "HTTP element REQUEST_URI is longer than the " + MAX_REQUEST_URI_LENGTH + " allowed length.";
|
31
31
|
public final static int MAX_FRAGMENT_LENGTH = 1024;
|
32
32
|
public final static String MAX_FRAGMENT_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 1024 allowed length.";
|
33
|
-
public final static int MAX_REQUEST_PATH_LENGTH = 8192;
|
34
|
-
public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the
|
35
|
-
public final static int MAX_QUERY_STRING_LENGTH =
|
36
|
-
public final static String MAX_QUERY_STRING_LENGTH_ERR = "HTTP element QUERY_STRING is longer than the
|
33
|
+
public final static int MAX_REQUEST_PATH_LENGTH = getConstLength("PUMA_REQUEST_PATH_MAX_LENGTH", 8192);
|
34
|
+
public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the " + MAX_REQUEST_PATH_LENGTH + " allowed length.";
|
35
|
+
public final static int MAX_QUERY_STRING_LENGTH = getConstLength("PUMA_QUERY_STRING_MAX_LENGTH", 10 * 1024);
|
36
|
+
public final static String MAX_QUERY_STRING_LENGTH_ERR = "HTTP element QUERY_STRING is longer than the " + MAX_QUERY_STRING_LENGTH +" allowed length.";
|
37
37
|
public final static int MAX_HEADER_LENGTH = 1024 * (80 + 32);
|
38
38
|
public final static String MAX_HEADER_LENGTH_ERR = "HTTP element HEADER is longer than the 114688 allowed length.";
|
39
39
|
|
@@ -48,6 +48,27 @@ public class Http11 extends RubyObject {
|
|
48
48
|
public static final ByteList QUERY_STRING_BYTELIST = new ByteList(ByteList.plain("QUERY_STRING"));
|
49
49
|
public static final ByteList SERVER_PROTOCOL_BYTELIST = new ByteList(ByteList.plain("SERVER_PROTOCOL"));
|
50
50
|
|
51
|
+
public static String getEnvOrProperty(String name) {
|
52
|
+
String envValue = System.getenv(name);
|
53
|
+
return (envValue != null) ? envValue : System.getProperty(name);
|
54
|
+
}
|
55
|
+
|
56
|
+
public static int getConstLength(String name, Integer defaultValue) {
|
57
|
+
String stringValue = getEnvOrProperty(name);
|
58
|
+
if (stringValue == null || stringValue.isEmpty()) return defaultValue;
|
59
|
+
|
60
|
+
try {
|
61
|
+
int value = Integer.parseUnsignedInt(stringValue);
|
62
|
+
if (value <= 0) {
|
63
|
+
throw new NumberFormatException("The number is not positive.");
|
64
|
+
}
|
65
|
+
return value;
|
66
|
+
} catch (NumberFormatException e) {
|
67
|
+
System.err.println(String.format("The value %s for %s is invalid. Using default value %d instead.", stringValue, name, defaultValue));
|
68
|
+
return defaultValue;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
51
72
|
private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
52
73
|
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
53
74
|
return new Http11(runtime, klass);
|
@@ -56,7 +77,7 @@ public class Http11 extends RubyObject {
|
|
56
77
|
|
57
78
|
public static void createHttp11(Ruby runtime) {
|
58
79
|
RubyModule mPuma = runtime.defineModule("Puma");
|
59
|
-
mPuma.defineClassUnder("HttpParserError",runtime.getClass("
|
80
|
+
mPuma.defineClassUnder("HttpParserError",runtime.getClass("StandardError"),runtime.getClass("StandardError").getAllocator());
|
60
81
|
|
61
82
|
RubyClass cHttpParser = mPuma.defineClassUnder("HttpParser",runtime.getObject(),ALLOCATOR);
|
62
83
|
cHttpParser.defineAnnotatedMethods(Http11.class);
|
@@ -99,6 +120,8 @@ public class Http11 extends RubyObject {
|
|
99
120
|
int bite = b.get(i) & 0xFF;
|
100
121
|
if(bite == '-') {
|
101
122
|
b.set(i, (byte)'_');
|
123
|
+
} else if(bite == '_') {
|
124
|
+
b.set(i, (byte)',');
|
102
125
|
} else {
|
103
126
|
b.set(i, (byte)Character.toUpperCase(bite));
|
104
127
|
}
|
File without changes
|
@@ -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
|
}
|
@@ -461,6 +461,9 @@ void Init_mini_ssl(VALUE mod);
|
|
461
461
|
|
462
462
|
void Init_puma_http11(void)
|
463
463
|
{
|
464
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
465
|
+
rb_ext_ractor_safe(true);
|
466
|
+
#endif
|
464
467
|
|
465
468
|
VALUE mPuma = rb_define_module("Puma");
|
466
469
|
VALUE cHttpParser = rb_define_class_under(mPuma, "HttpParser", rb_cObject);
|
@@ -472,7 +475,7 @@ void Init_puma_http11(void)
|
|
472
475
|
DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
|
473
476
|
DEF_GLOBAL(request_path, "REQUEST_PATH");
|
474
477
|
|
475
|
-
eHttpParserError = rb_define_class_under(mPuma, "HttpParserError",
|
478
|
+
eHttpParserError = rb_define_class_under(mPuma, "HttpParserError", rb_eStandardError);
|
476
479
|
rb_global_variable(&eHttpParserError);
|
477
480
|
|
478
481
|
rb_define_alloc_func(cHttpParser, HttpParser_alloc);
|
data/lib/puma/app/status.rb
CHANGED
@@ -80,7 +80,7 @@ module Puma
|
|
80
80
|
|
81
81
|
def authenticate(env)
|
82
82
|
return true unless @auth_token
|
83
|
-
env['QUERY_STRING'].to_s.split(
|
83
|
+
env['QUERY_STRING'].to_s.split(/[&;]/).include? "token=#{@auth_token}"
|
84
84
|
end
|
85
85
|
|
86
86
|
def rack_response(status, body, content_type='application/json')
|
data/lib/puma/binder.rb
CHANGED
@@ -19,13 +19,14 @@ module Puma
|
|
19
19
|
|
20
20
|
RACK_VERSION = [1,6].freeze
|
21
21
|
|
22
|
-
def initialize(log_writer, conf = Configuration.new)
|
22
|
+
def initialize(log_writer, conf = Configuration.new, env: ENV)
|
23
23
|
@log_writer = log_writer
|
24
24
|
@conf = conf
|
25
25
|
@listeners = []
|
26
26
|
@inherited_fds = {}
|
27
27
|
@activated_sockets = {}
|
28
28
|
@unix_paths = []
|
29
|
+
@env = env
|
29
30
|
|
30
31
|
@proto_env = {
|
31
32
|
"rack.version".freeze => RACK_VERSION,
|
@@ -34,7 +35,7 @@ module Puma
|
|
34
35
|
"rack.multiprocess".freeze => conf.options[:workers] >= 1,
|
35
36
|
"rack.run_once".freeze => false,
|
36
37
|
RACK_URL_SCHEME => conf.options[:rack_url_scheme],
|
37
|
-
"SCRIPT_NAME".freeze =>
|
38
|
+
"SCRIPT_NAME".freeze => env['SCRIPT_NAME'] || "",
|
38
39
|
|
39
40
|
# I'd like to set a default CONTENT_TYPE here but some things
|
40
41
|
# depend on their not being a default set and inferring
|
@@ -48,7 +49,6 @@ module Puma
|
|
48
49
|
|
49
50
|
@envs = {}
|
50
51
|
@ios = []
|
51
|
-
localhost_authority
|
52
52
|
end
|
53
53
|
|
54
54
|
attr_reader :ios
|
@@ -88,7 +88,7 @@ module Puma
|
|
88
88
|
# @version 5.0.0
|
89
89
|
#
|
90
90
|
def create_activated_fds(env_hash)
|
91
|
-
@log_writer.debug "ENV['LISTEN_FDS'] #{
|
91
|
+
@log_writer.debug "ENV['LISTEN_FDS'] #{@env['LISTEN_FDS'].inspect} env_hash['LISTEN_PID'] #{env_hash['LISTEN_PID'].inspect}"
|
92
92
|
return [] unless env_hash['LISTEN_FDS'] && env_hash['LISTEN_PID'].to_i == $$
|
93
93
|
env_hash['LISTEN_FDS'].to_i.times do |index|
|
94
94
|
sock = TCPServer.for_fd(socket_activation_fd(index))
|
@@ -142,7 +142,14 @@ module Puma
|
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
145
|
+
def before_parse(&block)
|
146
|
+
@before_parse ||= []
|
147
|
+
@before_parse << block if block
|
148
|
+
@before_parse
|
149
|
+
end
|
150
|
+
|
145
151
|
def parse(binds, log_writer = nil, log_msg = 'Listening')
|
152
|
+
before_parse.each(&:call)
|
146
153
|
log_writer ||= @log_writer
|
147
154
|
binds.each do |str|
|
148
155
|
uri = URI.parse str
|
@@ -158,10 +165,10 @@ module Puma
|
|
158
165
|
ios_len = @ios.length
|
159
166
|
params = Util.parse_query uri.query
|
160
167
|
|
161
|
-
|
168
|
+
low_latency = params.key?('low_latency') && params['low_latency'] != 'false'
|
162
169
|
backlog = params.fetch('backlog', 1024).to_i
|
163
170
|
|
164
|
-
io = add_tcp_listener uri.host, uri.port,
|
171
|
+
io = add_tcp_listener uri.host, uri.port, low_latency, backlog
|
165
172
|
|
166
173
|
@ios[ios_len..-1].each do |i|
|
167
174
|
addr = loc_addr_str i
|
@@ -184,7 +191,7 @@ module Puma
|
|
184
191
|
io = inherit_unix_listener path, fd
|
185
192
|
log_writer.log "* Inherited #{str}"
|
186
193
|
elsif sock = @activated_sockets.delete([ :unix, path ]) ||
|
187
|
-
@activated_sockets.delete([ :unix, File.realdirpath(path) ])
|
194
|
+
!abstract && @activated_sockets.delete([ :unix, File.realdirpath(path) ])
|
188
195
|
@unix_paths << path unless abstract || File.exist?(path)
|
189
196
|
io = inherit_unix_listener path, sock
|
190
197
|
log_writer.log "* Activated #{str}"
|
@@ -251,7 +258,8 @@ module Puma
|
|
251
258
|
else
|
252
259
|
ios_len = @ios.length
|
253
260
|
backlog = params.fetch('backlog', 1024).to_i
|
254
|
-
|
261
|
+
low_latency = params['low_latency'] != 'false'
|
262
|
+
io = add_ssl_listener uri.host, uri.port, ctx, low_latency, backlog
|
255
263
|
|
256
264
|
@ios[ios_len..-1].each do |i|
|
257
265
|
addr = loc_addr_str i
|
@@ -330,7 +338,7 @@ module Puma
|
|
330
338
|
return
|
331
339
|
end
|
332
340
|
|
333
|
-
host = host[1..-2] if host
|
341
|
+
host = host[1..-2] if host&.start_with? '['
|
334
342
|
tcp_server = TCPServer.new(host, port)
|
335
343
|
|
336
344
|
if optimize_for_latency
|
@@ -364,7 +372,7 @@ module Puma
|
|
364
372
|
return
|
365
373
|
end
|
366
374
|
|
367
|
-
host = host[1..-2] if host
|
375
|
+
host = host[1..-2] if host&.start_with? '['
|
368
376
|
s = TCPServer.new(host, port)
|
369
377
|
if optimize_for_latency
|
370
378
|
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
@@ -450,11 +458,14 @@ module Puma
|
|
450
458
|
|
451
459
|
def close_listeners
|
452
460
|
@listeners.each do |l, io|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
461
|
+
begin
|
462
|
+
io.close unless io.closed?
|
463
|
+
uri = URI.parse l
|
464
|
+
next unless uri.scheme == 'unix'
|
465
|
+
unix_path = "#{uri.host}#{uri.path}"
|
466
|
+
File.unlink unix_path if @unix_paths.include?(unix_path) && File.exist?(unix_path)
|
467
|
+
rescue Errno::EBADF
|
468
|
+
end
|
458
469
|
end
|
459
470
|
end
|
460
471
|
|
data/lib/puma/cli.rb
CHANGED
@@ -24,7 +24,7 @@ module Puma
|
|
24
24
|
# Create a new CLI object using +argv+ as the command line
|
25
25
|
# arguments.
|
26
26
|
#
|
27
|
-
def initialize(argv, log_writer = LogWriter.stdio, events = Events.new)
|
27
|
+
def initialize(argv, log_writer = LogWriter.stdio, events = Events.new, env: ENV)
|
28
28
|
@debug = false
|
29
29
|
@argv = argv.dup
|
30
30
|
@log_writer = log_writer
|
@@ -39,7 +39,7 @@ module Puma
|
|
39
39
|
@control_url = nil
|
40
40
|
@control_options = {}
|
41
41
|
|
42
|
-
setup_options
|
42
|
+
setup_options env
|
43
43
|
|
44
44
|
begin
|
45
45
|
@parser.parse! @argv
|
@@ -63,7 +63,7 @@ module Puma
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
@launcher = Puma::Launcher.new(@conf, :log_writer
|
66
|
+
@launcher = Puma::Launcher.new(@conf, env: ENV, log_writer: @log_writer, events: @events, argv: argv)
|
67
67
|
end
|
68
68
|
|
69
69
|
attr_reader :launcher
|
@@ -92,8 +92,8 @@ module Puma
|
|
92
92
|
# Build the OptionParser object to handle the available options.
|
93
93
|
#
|
94
94
|
|
95
|
-
def setup_options
|
96
|
-
@conf = Configuration.new do |user_config, file_config|
|
95
|
+
def setup_options(env = ENV)
|
96
|
+
@conf = Configuration.new({}, {events: @events}, env) do |user_config, file_config|
|
97
97
|
@parser = OptionParser.new do |o|
|
98
98
|
o.on "-b", "--bind URI", "URI to bind to (tcp://, unix://, ssl://)" do |arg|
|
99
99
|
user_config.bind arg
|
@@ -144,6 +144,10 @@ module Puma
|
|
144
144
|
$LOAD_PATH.unshift(*arg.split(':'))
|
145
145
|
end
|
146
146
|
|
147
|
+
o.on "--idle-timeout SECONDS", "Number of seconds until the next request before automatic shutdown" do |arg|
|
148
|
+
user_config.idle_timeout arg
|
149
|
+
end
|
150
|
+
|
147
151
|
o.on "-p", "--port PORT", "Define the TCP port to bind to",
|
148
152
|
"Use -b for more advanced options" do |arg|
|
149
153
|
user_config.bind "tcp://#{Configuration::DEFAULTS[:tcp_host]}:#{arg}"
|
@@ -153,6 +157,10 @@ module Puma
|
|
153
157
|
user_config.pidfile arg
|
154
158
|
end
|
155
159
|
|
160
|
+
o.on "--plugin PLUGIN", "Load the given PLUGIN. Can be used multiple times to load multiple plugins." do |arg|
|
161
|
+
user_config.plugin arg
|
162
|
+
end
|
163
|
+
|
156
164
|
o.on "--preload", "Preload the app. Cluster mode only" do
|
157
165
|
user_config.preload_app!
|
158
166
|
end
|