puma 4.3.6 → 5.6.4
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 +1486 -518
- data/LICENSE +23 -20
- data/README.md +120 -36
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +63 -26
- data/docs/compile_options.md +21 -0
- data/docs/deployment.md +60 -69
- data/docs/fork_worker.md +33 -0
- 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/jungle/README.md +9 -0
- data/{tools → docs}/jungle/rc.d/README.md +1 -1
- data/{tools → docs}/jungle/rc.d/puma +2 -2
- data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +66 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +15 -15
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +46 -23
- data/docs/signals.md +13 -11
- data/docs/stats.md +142 -0
- data/docs/systemd.md +85 -128
- data/ext/puma_http11/PumaHttp11Service.java +2 -4
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +46 -9
- data/ext/puma_http11/http11_parser.c +68 -57
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +1 -1
- data/ext/puma_http11/http11_parser.rl +1 -1
- data/ext/puma_http11/http11_parser_common.rl +1 -1
- data/ext/puma_http11/mini_ssl.c +275 -122
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +51 -51
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +105 -61
- data/ext/puma_http11/puma_http11.c +32 -51
- data/lib/puma/app/status.rb +47 -36
- data/lib/puma/binder.rb +225 -106
- data/lib/puma/cli.rb +24 -18
- data/lib/puma/client.rb +174 -91
- data/lib/puma/cluster/worker.rb +173 -0
- data/lib/puma/cluster/worker_handle.rb +94 -0
- data/lib/puma/cluster.rb +212 -220
- data/lib/puma/commonlogger.rb +2 -2
- data/lib/puma/configuration.rb +58 -49
- data/lib/puma/const.rb +18 -9
- data/lib/puma/control_cli.rb +93 -76
- data/lib/puma/detect.rb +29 -2
- data/lib/puma/dsl.rb +364 -96
- data/lib/puma/error_logger.rb +104 -0
- data/lib/puma/events.rb +55 -34
- data/lib/puma/io_buffer.rb +9 -2
- data/lib/puma/jruby_restart.rb +0 -58
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher.rb +117 -46
- data/lib/puma/minissl/context_builder.rb +14 -9
- data/lib/puma/minissl.rb +128 -46
- data/lib/puma/null_io.rb +13 -1
- data/lib/puma/plugin/tmp_restart.rb +0 -0
- data/lib/puma/plugin.rb +3 -12
- data/lib/puma/queue_close.rb +26 -0
- data/lib/puma/rack/builder.rb +1 -5
- data/lib/puma/rack/urlmap.rb +0 -0
- data/lib/puma/rack_default.rb +0 -0
- data/lib/puma/reactor.rb +85 -369
- data/lib/puma/request.rb +472 -0
- data/lib/puma/runner.rb +46 -61
- data/lib/puma/server.rb +287 -743
- data/lib/puma/single.rb +9 -65
- data/lib/puma/state_file.rb +47 -8
- data/lib/puma/systemd.rb +46 -0
- data/lib/puma/thread_pool.rb +125 -57
- data/lib/puma/util.rb +20 -1
- data/lib/puma.rb +46 -0
- data/lib/rack/handler/puma.rb +2 -3
- data/tools/{docker/Dockerfile → Dockerfile} +1 -1
- data/tools/trickletest.rb +0 -0
- metadata +28 -24
- data/docs/tcp_mode.md +0 -96
- data/ext/puma_http11/io_buffer.c +0 -155
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
- data/lib/puma/accept_nonblock.rb +0 -29
- data/lib/puma/tcp_logger.rb +0 -41
- data/tools/jungle/README.md +0 -19
- data/tools/jungle/init.d/README.md +0 -61
- data/tools/jungle/init.d/puma +0 -421
- data/tools/jungle/init.d/run-puma +0 -18
- data/tools/jungle/upstart/README.md +0 -61
- data/tools/jungle/upstart/puma-manager.conf +0 -31
- data/tools/jungle/upstart/puma.conf +0 -69
@@ -40,7 +40,9 @@ static VALUE global_http_version;
|
|
40
40
|
static VALUE global_request_path;
|
41
41
|
|
42
42
|
/** Defines common length and error messages for input length validation. */
|
43
|
-
#define
|
43
|
+
#define QUOTE(s) #s
|
44
|
+
#define EXPLAIN_MAX_LENGTH_VALUE(s) QUOTE(s)
|
45
|
+
#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the " EXPLAIN_MAX_LENGTH_VALUE(length) " allowed length (was %d)"
|
44
46
|
|
45
47
|
/** Validates the max length of given input and throws an HttpParserError exception if over. */
|
46
48
|
#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR, len); }
|
@@ -50,12 +52,16 @@ static VALUE global_request_path;
|
|
50
52
|
|
51
53
|
|
52
54
|
/* Defines the maximum allowed lengths for various input elements.*/
|
55
|
+
#ifndef PUMA_QUERY_STRING_MAX_LENGTH
|
56
|
+
#define PUMA_QUERY_STRING_MAX_LENGTH (1024 * 10)
|
57
|
+
#endif
|
58
|
+
|
53
59
|
DEF_MAX_LENGTH(FIELD_NAME, 256);
|
54
60
|
DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
|
55
61
|
DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
|
56
62
|
DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
|
57
|
-
DEF_MAX_LENGTH(REQUEST_PATH,
|
58
|
-
DEF_MAX_LENGTH(QUERY_STRING,
|
63
|
+
DEF_MAX_LENGTH(REQUEST_PATH, 8192);
|
64
|
+
DEF_MAX_LENGTH(QUERY_STRING, PUMA_QUERY_STRING_MAX_LENGTH);
|
59
65
|
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
60
66
|
|
61
67
|
struct common_field {
|
@@ -112,21 +118,6 @@ static struct common_field common_http_fields[] = {
|
|
112
118
|
# undef f
|
113
119
|
};
|
114
120
|
|
115
|
-
/*
|
116
|
-
* qsort(3) and bsearch(3) improve average performance slightly, but may
|
117
|
-
* not be worth it for lack of portability to certain platforms...
|
118
|
-
*/
|
119
|
-
#if defined(HAVE_QSORT_BSEARCH)
|
120
|
-
/* sort by length, then by name if there's a tie */
|
121
|
-
static int common_field_cmp(const void *a, const void *b)
|
122
|
-
{
|
123
|
-
struct common_field *cfa = (struct common_field *)a;
|
124
|
-
struct common_field *cfb = (struct common_field *)b;
|
125
|
-
signed long diff = cfa->len - cfb->len;
|
126
|
-
return diff ? diff : memcmp(cfa->name, cfb->name, cfa->len);
|
127
|
-
}
|
128
|
-
#endif /* HAVE_QSORT_BSEARCH */
|
129
|
-
|
130
121
|
static void init_common_fields(void)
|
131
122
|
{
|
132
123
|
unsigned i;
|
@@ -143,28 +134,10 @@ static void init_common_fields(void)
|
|
143
134
|
}
|
144
135
|
rb_global_variable(&cf->value);
|
145
136
|
}
|
146
|
-
|
147
|
-
#if defined(HAVE_QSORT_BSEARCH)
|
148
|
-
qsort(common_http_fields,
|
149
|
-
ARRAY_SIZE(common_http_fields),
|
150
|
-
sizeof(struct common_field),
|
151
|
-
common_field_cmp);
|
152
|
-
#endif /* HAVE_QSORT_BSEARCH */
|
153
137
|
}
|
154
138
|
|
155
139
|
static VALUE find_common_field_value(const char *field, size_t flen)
|
156
140
|
{
|
157
|
-
#if defined(HAVE_QSORT_BSEARCH)
|
158
|
-
struct common_field key;
|
159
|
-
struct common_field *found;
|
160
|
-
key.name = field;
|
161
|
-
key.len = (signed long)flen;
|
162
|
-
found = (struct common_field *)bsearch(&key, common_http_fields,
|
163
|
-
ARRAY_SIZE(common_http_fields),
|
164
|
-
sizeof(struct common_field),
|
165
|
-
common_field_cmp);
|
166
|
-
return found ? found->value : Qnil;
|
167
|
-
#else /* !HAVE_QSORT_BSEARCH */
|
168
141
|
unsigned i;
|
169
142
|
struct common_field *cf = common_http_fields;
|
170
143
|
for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) {
|
@@ -172,7 +145,6 @@ static VALUE find_common_field_value(const char *field, size_t flen)
|
|
172
145
|
return cf->value;
|
173
146
|
}
|
174
147
|
return Qnil;
|
175
|
-
#endif /* !HAVE_QSORT_BSEARCH */
|
176
148
|
}
|
177
149
|
|
178
150
|
void http_field(puma_parser* hp, const char *field, size_t flen,
|
@@ -287,11 +259,18 @@ void HttpParser_free(void *data) {
|
|
287
259
|
}
|
288
260
|
}
|
289
261
|
|
290
|
-
void HttpParser_mark(
|
262
|
+
void HttpParser_mark(void *ptr) {
|
263
|
+
puma_parser *hp = ptr;
|
291
264
|
if(hp->request) rb_gc_mark(hp->request);
|
292
265
|
if(hp->body) rb_gc_mark(hp->body);
|
293
266
|
}
|
294
267
|
|
268
|
+
const rb_data_type_t HttpParser_data_type = {
|
269
|
+
"HttpParser",
|
270
|
+
{ HttpParser_mark, HttpParser_free, 0 },
|
271
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
|
272
|
+
};
|
273
|
+
|
295
274
|
VALUE HttpParser_alloc(VALUE klass)
|
296
275
|
{
|
297
276
|
puma_parser *hp = ALLOC_N(puma_parser, 1);
|
@@ -308,7 +287,7 @@ VALUE HttpParser_alloc(VALUE klass)
|
|
308
287
|
|
309
288
|
puma_parser_init(hp);
|
310
289
|
|
311
|
-
return
|
290
|
+
return TypedData_Wrap_Struct(klass, &HttpParser_data_type, hp);
|
312
291
|
}
|
313
292
|
|
314
293
|
/**
|
@@ -320,7 +299,7 @@ VALUE HttpParser_alloc(VALUE klass)
|
|
320
299
|
VALUE HttpParser_init(VALUE self)
|
321
300
|
{
|
322
301
|
puma_parser *http = NULL;
|
323
|
-
DATA_GET(self, puma_parser, http);
|
302
|
+
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
324
303
|
puma_parser_init(http);
|
325
304
|
|
326
305
|
return self;
|
@@ -337,7 +316,7 @@ VALUE HttpParser_init(VALUE self)
|
|
337
316
|
VALUE HttpParser_reset(VALUE self)
|
338
317
|
{
|
339
318
|
puma_parser *http = NULL;
|
340
|
-
DATA_GET(self, puma_parser, http);
|
319
|
+
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
341
320
|
puma_parser_init(http);
|
342
321
|
|
343
322
|
return Qnil;
|
@@ -354,7 +333,7 @@ VALUE HttpParser_reset(VALUE self)
|
|
354
333
|
VALUE HttpParser_finish(VALUE self)
|
355
334
|
{
|
356
335
|
puma_parser *http = NULL;
|
357
|
-
DATA_GET(self, puma_parser, http);
|
336
|
+
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
358
337
|
puma_parser_finish(http);
|
359
338
|
|
360
339
|
return puma_parser_is_finished(http) ? Qtrue : Qfalse;
|
@@ -385,7 +364,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
|
|
385
364
|
char *dptr = NULL;
|
386
365
|
long dlen = 0;
|
387
366
|
|
388
|
-
DATA_GET(self, puma_parser, http);
|
367
|
+
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
389
368
|
|
390
369
|
from = FIX2INT(start);
|
391
370
|
dptr = rb_extract_chars(data, &dlen);
|
@@ -401,7 +380,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
|
|
401
380
|
VALIDATE_MAX_LENGTH(puma_parser_nread(http), HEADER);
|
402
381
|
|
403
382
|
if(puma_parser_has_error(http)) {
|
404
|
-
rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails.");
|
383
|
+
rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails. Are you trying to open an SSL connection to a non-SSL Puma?");
|
405
384
|
} else {
|
406
385
|
return INT2FIX(puma_parser_nread(http));
|
407
386
|
}
|
@@ -419,7 +398,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
|
|
419
398
|
VALUE HttpParser_has_error(VALUE self)
|
420
399
|
{
|
421
400
|
puma_parser *http = NULL;
|
422
|
-
DATA_GET(self, puma_parser, http);
|
401
|
+
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
423
402
|
|
424
403
|
return puma_parser_has_error(http) ? Qtrue : Qfalse;
|
425
404
|
}
|
@@ -434,7 +413,7 @@ VALUE HttpParser_has_error(VALUE self)
|
|
434
413
|
VALUE HttpParser_is_finished(VALUE self)
|
435
414
|
{
|
436
415
|
puma_parser *http = NULL;
|
437
|
-
DATA_GET(self, puma_parser, http);
|
416
|
+
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
438
417
|
|
439
418
|
return puma_parser_is_finished(http) ? Qtrue : Qfalse;
|
440
419
|
}
|
@@ -450,7 +429,7 @@ VALUE HttpParser_is_finished(VALUE self)
|
|
450
429
|
VALUE HttpParser_nread(VALUE self)
|
451
430
|
{
|
452
431
|
puma_parser *http = NULL;
|
453
|
-
DATA_GET(self, puma_parser, http);
|
432
|
+
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
454
433
|
|
455
434
|
return INT2FIX(http->nread);
|
456
435
|
}
|
@@ -463,15 +442,16 @@ VALUE HttpParser_nread(VALUE self)
|
|
463
442
|
*/
|
464
443
|
VALUE HttpParser_body(VALUE self) {
|
465
444
|
puma_parser *http = NULL;
|
466
|
-
DATA_GET(self, puma_parser, http);
|
445
|
+
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
467
446
|
|
468
447
|
return http->body;
|
469
448
|
}
|
470
449
|
|
471
|
-
|
450
|
+
#ifdef HAVE_OPENSSL_BIO_H
|
472
451
|
void Init_mini_ssl(VALUE mod);
|
452
|
+
#endif
|
473
453
|
|
474
|
-
void Init_puma_http11()
|
454
|
+
void Init_puma_http11(void)
|
475
455
|
{
|
476
456
|
|
477
457
|
VALUE mPuma = rb_define_module("Puma");
|
@@ -498,6 +478,7 @@ void Init_puma_http11()
|
|
498
478
|
rb_define_method(cHttpParser, "body", HttpParser_body, 0);
|
499
479
|
init_common_fields();
|
500
480
|
|
501
|
-
|
481
|
+
#ifdef HAVE_OPENSSL_BIO_H
|
502
482
|
Init_mini_ssl(mPuma);
|
483
|
+
#endif
|
503
484
|
}
|
data/lib/puma/app/status.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require 'puma/json_serialization'
|
2
3
|
|
3
4
|
module Puma
|
4
5
|
module App
|
@@ -7,58 +8,68 @@ module Puma
|
|
7
8
|
class Status
|
8
9
|
OK_STATUS = '{ "status": "ok" }'.freeze
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
# @param launcher [::Puma::Launcher]
|
12
|
+
# @param token [String, nil] the token used for authentication
|
13
|
+
#
|
14
|
+
def initialize(launcher, token = nil)
|
15
|
+
@launcher = launcher
|
12
16
|
@auth_token = token
|
13
17
|
end
|
14
18
|
|
19
|
+
# most commands call methods in `::Puma::Launcher` based on command in
|
20
|
+
# `env['PATH_INFO']`
|
15
21
|
def call(env)
|
16
22
|
unless authenticate(env)
|
17
23
|
return rack_response(403, 'Invalid auth token', 'text/plain')
|
18
24
|
end
|
19
25
|
|
20
|
-
|
21
|
-
|
22
|
-
|
26
|
+
# resp_type is processed by following case statement, return
|
27
|
+
# is a number (status) or a string used as the body of a 200 response
|
28
|
+
resp_type =
|
29
|
+
case env['PATH_INFO'][/\/([^\/]+)$/, 1]
|
30
|
+
when 'stop'
|
31
|
+
@launcher.stop ; 200
|
23
32
|
|
24
|
-
|
25
|
-
|
26
|
-
@cli.stop
|
27
|
-
rack_response(200, OK_STATUS)
|
33
|
+
when 'halt'
|
34
|
+
@launcher.halt ; 200
|
28
35
|
|
29
|
-
|
30
|
-
|
31
|
-
rack_response(200, OK_STATUS)
|
36
|
+
when 'restart'
|
37
|
+
@launcher.restart ; 200
|
32
38
|
|
33
|
-
|
34
|
-
|
35
|
-
rack_response(200, OK_STATUS)
|
39
|
+
when 'phased-restart'
|
40
|
+
@launcher.phased_restart ? 200 : 404
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
rack_response(404, '{ "error": "phased restart not available" }')
|
40
|
-
else
|
41
|
-
rack_response(200, OK_STATUS)
|
42
|
-
end
|
42
|
+
when 'reload-worker-directory'
|
43
|
+
@launcher.send(:reload_worker_directory) ? 200 : 404
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
rack_response(404, '{ "error": "reload_worker_directory not available" }')
|
47
|
-
else
|
48
|
-
rack_response(200, OK_STATUS)
|
49
|
-
end
|
45
|
+
when 'gc'
|
46
|
+
GC.start ; 200
|
50
47
|
|
51
|
-
|
52
|
-
|
53
|
-
rack_response(200, OK_STATUS)
|
48
|
+
when 'gc-stats'
|
49
|
+
Puma::JSONSerialization.generate GC.stat
|
54
50
|
|
55
|
-
|
56
|
-
|
51
|
+
when 'stats'
|
52
|
+
Puma::JSONSerialization.generate @launcher.stats
|
53
|
+
|
54
|
+
when 'thread-backtraces'
|
55
|
+
backtraces = []
|
56
|
+
@launcher.thread_status do |name, backtrace|
|
57
|
+
backtraces << { name: name, backtrace: backtrace }
|
58
|
+
end
|
59
|
+
Puma::JSONSerialization.generate backtraces
|
60
|
+
|
61
|
+
else
|
62
|
+
return rack_response(404, "Unsupported action", 'text/plain')
|
63
|
+
end
|
57
64
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
65
|
+
case resp_type
|
66
|
+
when String
|
67
|
+
rack_response 200, resp_type
|
68
|
+
when 200
|
69
|
+
rack_response 200, OK_STATUS
|
70
|
+
when 404
|
71
|
+
str = env['PATH_INFO'][/\/(\S+)/, 1].tr '-', '_'
|
72
|
+
rack_response 404, "{ \"error\": \"#{str} not available\" }"
|
62
73
|
end
|
63
74
|
end
|
64
75
|
|