puma 7.0.4 → 7.2.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 +94 -0
- data/README.md +24 -11
- data/docs/deployment.md +58 -23
- data/docs/jungle/README.md +1 -1
- data/docs/kubernetes.md +5 -12
- data/docs/plugins.md +2 -2
- data/docs/signals.md +10 -10
- data/docs/stats.md +2 -2
- data/docs/systemd.md +3 -3
- data/ext/puma_http11/puma_http11.c +101 -109
- data/lib/puma/app/status.rb +10 -2
- data/lib/puma/client.rb +21 -25
- data/lib/puma/cluster/worker.rb +10 -9
- data/lib/puma/cluster/worker_handle.rb +2 -2
- data/lib/puma/cluster.rb +11 -10
- data/lib/puma/cluster_accept_loop_delay.rb +17 -18
- data/lib/puma/configuration.rb +17 -9
- data/lib/puma/const.rb +2 -2
- data/lib/puma/dsl.rb +41 -10
- data/lib/puma/launcher.rb +32 -26
- data/lib/puma/reactor.rb +3 -12
- data/lib/puma/request.rb +10 -8
- data/lib/puma/runner.rb +1 -1
- data/lib/puma/server.rb +35 -31
- data/lib/puma/single.rb +2 -2
- data/lib/puma/state_file.rb +3 -2
- data/lib/puma/thread_pool.rb +10 -1
- data/tools/Dockerfile +13 -5
- metadata +4 -4
- data/ext/puma_http11/ext_help.h +0 -15
|
@@ -8,25 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
#include "ruby.h"
|
|
10
10
|
#include "ruby/encoding.h"
|
|
11
|
-
#include "ext_help.h"
|
|
12
11
|
#include <assert.h>
|
|
13
12
|
#include <string.h>
|
|
14
13
|
#include <ctype.h>
|
|
15
14
|
#include "http11_parser.h"
|
|
16
15
|
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
#ifndef RSTRING_PTR
|
|
20
|
-
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
|
21
|
-
#endif
|
|
22
|
-
#ifndef RSTRING_LEN
|
|
23
|
-
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
|
24
|
-
#endif
|
|
25
|
-
|
|
26
|
-
#define rb_extract_chars(e, sz) (*sz = RSTRING_LEN(e), RSTRING_PTR(e))
|
|
27
|
-
#define rb_free_chars(e) /* nothing */
|
|
28
|
-
|
|
29
|
-
#endif
|
|
16
|
+
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
30
17
|
|
|
31
18
|
static VALUE eHttpParserError;
|
|
32
19
|
|
|
@@ -51,8 +38,8 @@ static VALUE global_request_path;
|
|
|
51
38
|
/** Defines global strings in the init method. */
|
|
52
39
|
static inline void DEF_GLOBAL(VALUE *var, const char *cstr)
|
|
53
40
|
{
|
|
54
|
-
|
|
55
|
-
|
|
41
|
+
rb_global_variable(var);
|
|
42
|
+
*var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
|
|
56
43
|
}
|
|
57
44
|
|
|
58
45
|
/* Defines the maximum allowed lengths for various input elements.*/
|
|
@@ -77,10 +64,10 @@ DEF_MAX_LENGTH(QUERY_STRING, PUMA_QUERY_STRING_MAX_LENGTH);
|
|
|
77
64
|
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
|
78
65
|
|
|
79
66
|
struct common_field {
|
|
80
|
-
|
|
81
|
-
|
|
67
|
+
const size_t len;
|
|
68
|
+
const char *name;
|
|
82
69
|
int raw;
|
|
83
|
-
|
|
70
|
+
VALUE value;
|
|
84
71
|
};
|
|
85
72
|
|
|
86
73
|
/*
|
|
@@ -91,42 +78,42 @@ struct common_field {
|
|
|
91
78
|
static struct common_field common_http_fields[] = {
|
|
92
79
|
# define f(N) { (sizeof(N) - 1), N, 0, Qnil }
|
|
93
80
|
# define fr(N) { (sizeof(N) - 1), N, 1, Qnil }
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
81
|
+
f("ACCEPT"),
|
|
82
|
+
f("ACCEPT_CHARSET"),
|
|
83
|
+
f("ACCEPT_ENCODING"),
|
|
84
|
+
f("ACCEPT_LANGUAGE"),
|
|
85
|
+
f("ALLOW"),
|
|
86
|
+
f("AUTHORIZATION"),
|
|
87
|
+
f("CACHE_CONTROL"),
|
|
88
|
+
f("CONNECTION"),
|
|
89
|
+
f("CONTENT_ENCODING"),
|
|
90
|
+
fr("CONTENT_LENGTH"),
|
|
91
|
+
fr("CONTENT_TYPE"),
|
|
92
|
+
f("COOKIE"),
|
|
93
|
+
f("DATE"),
|
|
94
|
+
f("EXPECT"),
|
|
95
|
+
f("FROM"),
|
|
96
|
+
f("HOST"),
|
|
97
|
+
f("IF_MATCH"),
|
|
98
|
+
f("IF_MODIFIED_SINCE"),
|
|
99
|
+
f("IF_NONE_MATCH"),
|
|
100
|
+
f("IF_RANGE"),
|
|
101
|
+
f("IF_UNMODIFIED_SINCE"),
|
|
102
|
+
f("KEEP_ALIVE"), /* Firefox sends this */
|
|
103
|
+
f("MAX_FORWARDS"),
|
|
104
|
+
f("PRAGMA"),
|
|
105
|
+
f("PROXY_AUTHORIZATION"),
|
|
106
|
+
f("RANGE"),
|
|
107
|
+
f("REFERER"),
|
|
108
|
+
f("TE"),
|
|
109
|
+
f("TRAILER"),
|
|
110
|
+
f("TRANSFER_ENCODING"),
|
|
111
|
+
f("UPGRADE"),
|
|
112
|
+
f("USER_AGENT"),
|
|
113
|
+
f("VIA"),
|
|
114
|
+
f("X_FORWARDED_FOR"), /* common for proxies */
|
|
115
|
+
f("X_REAL_IP"), /* common for proxies */
|
|
116
|
+
f("WARNING")
|
|
130
117
|
# undef f
|
|
131
118
|
};
|
|
132
119
|
|
|
@@ -140,10 +127,10 @@ static void init_common_fields(void)
|
|
|
140
127
|
for(i = 0; i < ARRAY_SIZE(common_http_fields); cf++, i++) {
|
|
141
128
|
rb_global_variable(&cf->value);
|
|
142
129
|
if(cf->raw) {
|
|
143
|
-
cf->value =
|
|
130
|
+
cf->value = rb_enc_interned_str(cf->name, cf->len, rb_utf8_encoding());
|
|
144
131
|
} else {
|
|
145
132
|
memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1);
|
|
146
|
-
cf->value =
|
|
133
|
+
cf->value = rb_enc_interned_str(tmp, HTTP_PREFIX_LEN + cf->len, rb_utf8_encoding());
|
|
147
134
|
}
|
|
148
135
|
}
|
|
149
136
|
}
|
|
@@ -163,7 +150,7 @@ static int is_ows(const char c) {
|
|
|
163
150
|
return c == ' ' || c == '\t';
|
|
164
151
|
}
|
|
165
152
|
|
|
166
|
-
void http_field(puma_parser* hp, const char *field, size_t flen,
|
|
153
|
+
static void http_field(puma_parser* hp, const char *field, size_t flen,
|
|
167
154
|
const char *value, size_t vlen)
|
|
168
155
|
{
|
|
169
156
|
VALUE f = Qnil;
|
|
@@ -186,7 +173,7 @@ void http_field(puma_parser* hp, const char *field, size_t flen,
|
|
|
186
173
|
memcpy(hp->buf, HTTP_PREFIX, HTTP_PREFIX_LEN);
|
|
187
174
|
memcpy(hp->buf + HTTP_PREFIX_LEN, field, flen);
|
|
188
175
|
|
|
189
|
-
f =
|
|
176
|
+
f = rb_enc_interned_str(hp->buf, new_size, rb_utf8_encoding());
|
|
190
177
|
}
|
|
191
178
|
|
|
192
179
|
while (vlen > 0 && is_ows(value[vlen - 1])) vlen--;
|
|
@@ -208,7 +195,7 @@ void http_field(puma_parser* hp, const char *field, size_t flen,
|
|
|
208
195
|
}
|
|
209
196
|
}
|
|
210
197
|
|
|
211
|
-
void request_method(puma_parser* hp, const char *at, size_t length)
|
|
198
|
+
static void request_method(puma_parser* hp, const char *at, size_t length)
|
|
212
199
|
{
|
|
213
200
|
VALUE val = Qnil;
|
|
214
201
|
|
|
@@ -216,7 +203,7 @@ void request_method(puma_parser* hp, const char *at, size_t length)
|
|
|
216
203
|
rb_hash_aset(hp->request, global_request_method, val);
|
|
217
204
|
}
|
|
218
205
|
|
|
219
|
-
void request_uri(puma_parser* hp, const char *at, size_t length)
|
|
206
|
+
static void request_uri(puma_parser* hp, const char *at, size_t length)
|
|
220
207
|
{
|
|
221
208
|
VALUE val = Qnil;
|
|
222
209
|
|
|
@@ -226,7 +213,7 @@ void request_uri(puma_parser* hp, const char *at, size_t length)
|
|
|
226
213
|
rb_hash_aset(hp->request, global_request_uri, val);
|
|
227
214
|
}
|
|
228
215
|
|
|
229
|
-
void fragment(puma_parser* hp, const char *at, size_t length)
|
|
216
|
+
static void fragment(puma_parser* hp, const char *at, size_t length)
|
|
230
217
|
{
|
|
231
218
|
VALUE val = Qnil;
|
|
232
219
|
|
|
@@ -236,7 +223,7 @@ void fragment(puma_parser* hp, const char *at, size_t length)
|
|
|
236
223
|
rb_hash_aset(hp->request, global_fragment, val);
|
|
237
224
|
}
|
|
238
225
|
|
|
239
|
-
void request_path(puma_parser* hp, const char *at, size_t length)
|
|
226
|
+
static void request_path(puma_parser* hp, const char *at, size_t length)
|
|
240
227
|
{
|
|
241
228
|
VALUE val = Qnil;
|
|
242
229
|
|
|
@@ -246,7 +233,7 @@ void request_path(puma_parser* hp, const char *at, size_t length)
|
|
|
246
233
|
rb_hash_aset(hp->request, global_request_path, val);
|
|
247
234
|
}
|
|
248
235
|
|
|
249
|
-
void query_string(puma_parser* hp, const char *at, size_t length)
|
|
236
|
+
static void query_string(puma_parser* hp, const char *at, size_t length)
|
|
250
237
|
{
|
|
251
238
|
VALUE val = Qnil;
|
|
252
239
|
|
|
@@ -256,7 +243,7 @@ void query_string(puma_parser* hp, const char *at, size_t length)
|
|
|
256
243
|
rb_hash_aset(hp->request, global_query_string, val);
|
|
257
244
|
}
|
|
258
245
|
|
|
259
|
-
void server_protocol(puma_parser* hp, const char *at, size_t length)
|
|
246
|
+
static void server_protocol(puma_parser* hp, const char *at, size_t length)
|
|
260
247
|
{
|
|
261
248
|
VALUE val = rb_str_new(at, length);
|
|
262
249
|
rb_hash_aset(hp->request, global_server_protocol, val);
|
|
@@ -265,36 +252,42 @@ void server_protocol(puma_parser* hp, const char *at, size_t length)
|
|
|
265
252
|
/** Finalizes the request header to have a bunch of stuff that's
|
|
266
253
|
needed. */
|
|
267
254
|
|
|
268
|
-
void header_done(puma_parser* hp, const char *at, size_t length)
|
|
255
|
+
static void header_done(puma_parser* hp, const char *at, size_t length)
|
|
269
256
|
{
|
|
270
257
|
hp->body = rb_str_new(at, length);
|
|
271
258
|
}
|
|
272
259
|
|
|
273
260
|
|
|
274
|
-
void
|
|
275
|
-
|
|
261
|
+
static void HttpParser_mark(void *ptr) {
|
|
262
|
+
puma_parser *hp = ptr;
|
|
263
|
+
rb_gc_mark_movable(hp->request);
|
|
264
|
+
rb_gc_mark_movable(hp->body);
|
|
265
|
+
}
|
|
276
266
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
267
|
+
static size_t HttpParser_size(const void *ptr) {
|
|
268
|
+
return sizeof(puma_parser);
|
|
280
269
|
}
|
|
281
270
|
|
|
282
|
-
void
|
|
271
|
+
static void HttpParser_compact(void *ptr) {
|
|
283
272
|
puma_parser *hp = ptr;
|
|
284
|
-
|
|
285
|
-
|
|
273
|
+
hp->request = rb_gc_location(hp->request);
|
|
274
|
+
hp->body = rb_gc_location(hp->body);
|
|
286
275
|
}
|
|
287
276
|
|
|
288
|
-
const rb_data_type_t HttpParser_data_type = {
|
|
289
|
-
"HttpParser",
|
|
290
|
-
|
|
291
|
-
|
|
277
|
+
static const rb_data_type_t HttpParser_data_type = {
|
|
278
|
+
.wrap_struct_name = "Puma::HttpParser",
|
|
279
|
+
.function = {
|
|
280
|
+
.dmark = HttpParser_mark,
|
|
281
|
+
.dfree = RUBY_TYPED_DEFAULT_FREE,
|
|
282
|
+
.dsize = HttpParser_size,
|
|
283
|
+
.dcompact = HttpParser_compact,
|
|
284
|
+
},
|
|
285
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
292
286
|
};
|
|
293
287
|
|
|
294
|
-
VALUE HttpParser_alloc(VALUE klass)
|
|
288
|
+
static VALUE HttpParser_alloc(VALUE klass)
|
|
295
289
|
{
|
|
296
290
|
puma_parser *hp = ALLOC_N(puma_parser, 1);
|
|
297
|
-
TRACE();
|
|
298
291
|
hp->http_field = http_field;
|
|
299
292
|
hp->request_method = request_method;
|
|
300
293
|
hp->request_uri = request_uri;
|
|
@@ -310,16 +303,25 @@ VALUE HttpParser_alloc(VALUE klass)
|
|
|
310
303
|
return TypedData_Wrap_Struct(klass, &HttpParser_data_type, hp);
|
|
311
304
|
}
|
|
312
305
|
|
|
306
|
+
static inline puma_parser *HttpParser_unwrap(VALUE self)
|
|
307
|
+
{
|
|
308
|
+
puma_parser *http;
|
|
309
|
+
TypedData_Get_Struct(self, puma_parser, &HttpParser_data_type, http);
|
|
310
|
+
if (http == NULL) {
|
|
311
|
+
rb_raise(rb_eArgError, "%s", "NULL http_parser found");
|
|
312
|
+
}
|
|
313
|
+
return http;
|
|
314
|
+
}
|
|
315
|
+
|
|
313
316
|
/**
|
|
314
317
|
* call-seq:
|
|
315
318
|
* parser.new -> parser
|
|
316
319
|
*
|
|
317
320
|
* Creates a new parser.
|
|
318
321
|
*/
|
|
319
|
-
VALUE HttpParser_init(VALUE self)
|
|
322
|
+
static VALUE HttpParser_init(VALUE self)
|
|
320
323
|
{
|
|
321
|
-
puma_parser *http =
|
|
322
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
324
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
323
325
|
puma_parser_init(http);
|
|
324
326
|
|
|
325
327
|
return self;
|
|
@@ -333,10 +335,9 @@ VALUE HttpParser_init(VALUE self)
|
|
|
333
335
|
* Resets the parser to it's initial state so that you can reuse it
|
|
334
336
|
* rather than making new ones.
|
|
335
337
|
*/
|
|
336
|
-
VALUE HttpParser_reset(VALUE self)
|
|
338
|
+
static VALUE HttpParser_reset(VALUE self)
|
|
337
339
|
{
|
|
338
|
-
puma_parser *http =
|
|
339
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
340
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
340
341
|
puma_parser_init(http);
|
|
341
342
|
|
|
342
343
|
return Qnil;
|
|
@@ -350,10 +351,9 @@ VALUE HttpParser_reset(VALUE self)
|
|
|
350
351
|
* Finishes a parser early which could put in a "good" or bad state.
|
|
351
352
|
* You should call reset after finish it or bad things will happen.
|
|
352
353
|
*/
|
|
353
|
-
VALUE HttpParser_finish(VALUE self)
|
|
354
|
+
static VALUE HttpParser_finish(VALUE self)
|
|
354
355
|
{
|
|
355
|
-
puma_parser *http =
|
|
356
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
356
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
357
357
|
puma_parser_finish(http);
|
|
358
358
|
|
|
359
359
|
return puma_parser_is_finished(http) ? Qtrue : Qfalse;
|
|
@@ -377,26 +377,22 @@ VALUE HttpParser_finish(VALUE self)
|
|
|
377
377
|
* the parsing from that position. It needs all of the original data as well
|
|
378
378
|
* so you have to append to the data buffer as you read.
|
|
379
379
|
*/
|
|
380
|
-
VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
|
|
380
|
+
static VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
|
|
381
381
|
{
|
|
382
|
-
puma_parser *http =
|
|
382
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
383
383
|
int from = 0;
|
|
384
384
|
char *dptr = NULL;
|
|
385
385
|
long dlen = 0;
|
|
386
386
|
|
|
387
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
388
|
-
|
|
389
387
|
from = FIX2INT(start);
|
|
390
|
-
|
|
388
|
+
RSTRING_GETMEM(data, dptr, dlen);
|
|
391
389
|
|
|
392
390
|
if(from >= dlen) {
|
|
393
|
-
rb_free_chars(dptr);
|
|
394
391
|
rb_raise(eHttpParserError, "%s", "Requested start is after data buffer end.");
|
|
395
392
|
} else {
|
|
396
393
|
http->request = req_hash;
|
|
397
394
|
puma_parser_execute(http, dptr, dlen, from);
|
|
398
395
|
|
|
399
|
-
rb_free_chars(dptr);
|
|
400
396
|
VALIDATE_MAX_LENGTH(puma_parser_nread(http), HEADER);
|
|
401
397
|
|
|
402
398
|
if(puma_parser_has_error(http)) {
|
|
@@ -415,10 +411,9 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
|
|
|
415
411
|
*
|
|
416
412
|
* Tells you whether the parser is in an error state.
|
|
417
413
|
*/
|
|
418
|
-
VALUE HttpParser_has_error(VALUE self)
|
|
414
|
+
static VALUE HttpParser_has_error(VALUE self)
|
|
419
415
|
{
|
|
420
|
-
puma_parser *http =
|
|
421
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
416
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
422
417
|
|
|
423
418
|
return puma_parser_has_error(http) ? Qtrue : Qfalse;
|
|
424
419
|
}
|
|
@@ -430,10 +425,9 @@ VALUE HttpParser_has_error(VALUE self)
|
|
|
430
425
|
*
|
|
431
426
|
* Tells you whether the parser is finished or not and in a good state.
|
|
432
427
|
*/
|
|
433
|
-
VALUE HttpParser_is_finished(VALUE self)
|
|
428
|
+
static VALUE HttpParser_is_finished(VALUE self)
|
|
434
429
|
{
|
|
435
|
-
puma_parser *http =
|
|
436
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
430
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
437
431
|
|
|
438
432
|
return puma_parser_is_finished(http) ? Qtrue : Qfalse;
|
|
439
433
|
}
|
|
@@ -446,10 +440,9 @@ VALUE HttpParser_is_finished(VALUE self)
|
|
|
446
440
|
* Returns the amount of data processed so far during this processing cycle. It is
|
|
447
441
|
* set to 0 on initialize or reset calls and is incremented each time execute is called.
|
|
448
442
|
*/
|
|
449
|
-
VALUE HttpParser_nread(VALUE self)
|
|
443
|
+
static VALUE HttpParser_nread(VALUE self)
|
|
450
444
|
{
|
|
451
|
-
puma_parser *http =
|
|
452
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
445
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
453
446
|
|
|
454
447
|
return INT2FIX(http->nread);
|
|
455
448
|
}
|
|
@@ -460,9 +453,8 @@ VALUE HttpParser_nread(VALUE self)
|
|
|
460
453
|
*
|
|
461
454
|
* If the request included a body, returns it.
|
|
462
455
|
*/
|
|
463
|
-
VALUE HttpParser_body(VALUE self) {
|
|
464
|
-
puma_parser *http =
|
|
465
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
456
|
+
static VALUE HttpParser_body(VALUE self) {
|
|
457
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
466
458
|
|
|
467
459
|
return http->body;
|
|
468
460
|
}
|
|
@@ -471,7 +463,7 @@ VALUE HttpParser_body(VALUE self) {
|
|
|
471
463
|
void Init_mini_ssl(VALUE mod);
|
|
472
464
|
#endif
|
|
473
465
|
|
|
474
|
-
void Init_puma_http11(void)
|
|
466
|
+
RUBY_FUNC_EXPORTED void Init_puma_http11(void)
|
|
475
467
|
{
|
|
476
468
|
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
|
477
469
|
rb_ext_ractor_safe(true);
|
data/lib/puma/app/status.rb
CHANGED
|
@@ -7,13 +7,16 @@ module Puma
|
|
|
7
7
|
# can respond to.
|
|
8
8
|
class Status
|
|
9
9
|
OK_STATUS = '{ "status": "ok" }'.freeze
|
|
10
|
+
READ_ONLY_COMMANDS = %w[gc-stats stats].freeze
|
|
10
11
|
|
|
11
12
|
# @param launcher [::Puma::Launcher]
|
|
12
13
|
# @param token [String, nil] the token used for authentication
|
|
14
|
+
# @param data_only [Boolean] if true, restrict to read-only data commands
|
|
13
15
|
#
|
|
14
|
-
def initialize(launcher, token
|
|
16
|
+
def initialize(launcher, token: nil, data_only: false)
|
|
15
17
|
@launcher = launcher
|
|
16
18
|
@auth_token = token
|
|
19
|
+
@enabled_commands = READ_ONLY_COMMANDS if data_only
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
# most commands call methods in `::Puma::Launcher` based on command in
|
|
@@ -25,8 +28,13 @@ module Puma
|
|
|
25
28
|
|
|
26
29
|
# resp_type is processed by following case statement, return
|
|
27
30
|
# is a number (status) or a string used as the body of a 200 response
|
|
31
|
+
command = env['PATH_INFO'][/\/([^\/]+)$/, 1]
|
|
32
|
+
if @enabled_commands && !@enabled_commands.include?(command)
|
|
33
|
+
return rack_response(404, "Command #{command.inspect} unavailable", 'text/plain')
|
|
34
|
+
end
|
|
35
|
+
|
|
28
36
|
resp_type =
|
|
29
|
-
case
|
|
37
|
+
case command
|
|
30
38
|
when 'stop'
|
|
31
39
|
@launcher.stop ; 200
|
|
32
40
|
|
data/lib/puma/client.rb
CHANGED
|
@@ -500,40 +500,36 @@ module Puma
|
|
|
500
500
|
# after this
|
|
501
501
|
remain = @body_remain
|
|
502
502
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
503
|
+
# don't bother with reading zero bytes
|
|
504
|
+
unless remain.zero?
|
|
505
|
+
begin
|
|
506
|
+
chunk = @io.read_nonblock(remain.clamp(0, CHUNK_SIZE), @read_buffer)
|
|
507
|
+
rescue IO::WaitReadable
|
|
508
|
+
return false
|
|
509
|
+
rescue SystemCallError, IOError
|
|
510
|
+
raise ConnectionError, "Connection error detected during read"
|
|
511
|
+
end
|
|
508
512
|
|
|
509
|
-
|
|
510
|
-
chunk
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
513
|
+
# No chunk means a closed socket
|
|
514
|
+
unless chunk
|
|
515
|
+
@body.close
|
|
516
|
+
@buffer = nil
|
|
517
|
+
set_ready
|
|
518
|
+
raise EOFError
|
|
519
|
+
end
|
|
516
520
|
|
|
517
|
-
|
|
518
|
-
unless chunk
|
|
519
|
-
@body.close
|
|
520
|
-
@buffer = nil
|
|
521
|
-
set_ready
|
|
522
|
-
raise EOFError
|
|
521
|
+
remain -= @body.write(chunk)
|
|
523
522
|
end
|
|
524
523
|
|
|
525
|
-
remain -= @body.write(chunk)
|
|
526
|
-
|
|
527
524
|
if remain <= 0
|
|
528
525
|
@body.rewind
|
|
529
526
|
@buffer = nil
|
|
530
527
|
set_ready
|
|
531
|
-
|
|
528
|
+
true
|
|
529
|
+
else
|
|
530
|
+
@body_remain = remain
|
|
531
|
+
false
|
|
532
532
|
end
|
|
533
|
-
|
|
534
|
-
@body_remain = remain
|
|
535
|
-
|
|
536
|
-
false
|
|
537
533
|
end
|
|
538
534
|
|
|
539
535
|
def read_chunked_body
|
data/lib/puma/cluster/worker.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Puma
|
|
|
14
14
|
class Worker < Puma::Runner # :nodoc:
|
|
15
15
|
attr_reader :index, :master
|
|
16
16
|
|
|
17
|
-
def initialize(index:, master:, launcher:, pipes:,
|
|
17
|
+
def initialize(index:, master:, launcher:, pipes:, app: nil)
|
|
18
18
|
super(launcher)
|
|
19
19
|
|
|
20
20
|
@index = index
|
|
@@ -23,7 +23,8 @@ module Puma
|
|
|
23
23
|
@worker_write = pipes[:worker_write]
|
|
24
24
|
@fork_pipe = pipes[:fork_pipe]
|
|
25
25
|
@wakeup = pipes[:wakeup]
|
|
26
|
-
@
|
|
26
|
+
@app = app
|
|
27
|
+
@server = nil
|
|
27
28
|
@hook_data = {}
|
|
28
29
|
end
|
|
29
30
|
|
|
@@ -57,7 +58,7 @@ module Puma
|
|
|
57
58
|
@config.run_hooks(:before_worker_boot, index, @log_writer, @hook_data)
|
|
58
59
|
|
|
59
60
|
begin
|
|
60
|
-
|
|
61
|
+
@server = start_server
|
|
61
62
|
rescue Exception => e
|
|
62
63
|
log "! Unable to start worker"
|
|
63
64
|
log e
|
|
@@ -85,7 +86,7 @@ module Puma
|
|
|
85
86
|
if idx == -1 # stop server
|
|
86
87
|
if restart_server.length > 0
|
|
87
88
|
restart_server.clear
|
|
88
|
-
server.begin_restart(true)
|
|
89
|
+
@server.begin_restart(true)
|
|
89
90
|
@config.run_hooks(:before_refork, nil, @log_writer, @hook_data)
|
|
90
91
|
end
|
|
91
92
|
elsif idx == -2 # refork cycle is done
|
|
@@ -103,7 +104,7 @@ module Puma
|
|
|
103
104
|
Signal.trap "SIGTERM" do
|
|
104
105
|
@worker_write << "#{PIPE_EXTERNAL_TERM}#{Process.pid}\n" rescue nil
|
|
105
106
|
restart_server.clear
|
|
106
|
-
server.stop
|
|
107
|
+
@server.stop
|
|
107
108
|
restart_server << false
|
|
108
109
|
end
|
|
109
110
|
|
|
@@ -115,7 +116,7 @@ module Puma
|
|
|
115
116
|
end
|
|
116
117
|
|
|
117
118
|
while restart_server.pop
|
|
118
|
-
server_thread = server.run
|
|
119
|
+
server_thread = @server.run
|
|
119
120
|
|
|
120
121
|
if @log_writer.debug? && index == 0
|
|
121
122
|
debug_loaded_extensions "Loaded Extensions - worker 0:"
|
|
@@ -129,13 +130,13 @@ module Puma
|
|
|
129
130
|
begin
|
|
130
131
|
payload = base_payload.dup
|
|
131
132
|
|
|
132
|
-
hsh = server.stats
|
|
133
|
+
hsh = @server.stats
|
|
133
134
|
hsh.each do |k, v|
|
|
134
135
|
payload << %Q! "#{k}":#{v || 0},!
|
|
135
136
|
end
|
|
136
137
|
# sub call properly adds 'closing' string
|
|
137
138
|
io << payload.sub(/,\z/, " }\n")
|
|
138
|
-
server.reset_max
|
|
139
|
+
@server.reset_max
|
|
139
140
|
rescue IOError
|
|
140
141
|
break
|
|
141
142
|
end
|
|
@@ -164,7 +165,7 @@ module Puma
|
|
|
164
165
|
launcher: @launcher,
|
|
165
166
|
pipes: { check_pipe: @check_pipe,
|
|
166
167
|
worker_write: @worker_write },
|
|
167
|
-
|
|
168
|
+
app: @app
|
|
168
169
|
new_worker.run
|
|
169
170
|
end
|
|
170
171
|
|
|
@@ -28,10 +28,10 @@ module Puma
|
|
|
28
28
|
@worker_max = Array.new WORKER_MAX_KEYS.length, 0
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status, :started_at
|
|
31
|
+
attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status, :started_at, :process_status
|
|
32
32
|
|
|
33
33
|
# @version 5.0.0
|
|
34
|
-
attr_writer :pid, :phase
|
|
34
|
+
attr_writer :pid, :phase, :process_status
|
|
35
35
|
|
|
36
36
|
def booted?
|
|
37
37
|
@stage == :booted
|
data/lib/puma/cluster.rb
CHANGED
|
@@ -23,7 +23,7 @@ module Puma
|
|
|
23
23
|
@next_check = Time.now
|
|
24
24
|
|
|
25
25
|
@worker_max = [] # keeps track of 'max' stat values
|
|
26
|
-
@
|
|
26
|
+
@pending_phased_restart = false
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
# Returns the list of cluster worker handles.
|
|
@@ -186,7 +186,7 @@ module Puma
|
|
|
186
186
|
# we need to phase any workers out (which will restart
|
|
187
187
|
# in the right phase).
|
|
188
188
|
#
|
|
189
|
-
w = @workers.find { |x| x.phase
|
|
189
|
+
w = @workers.find { |x| x.phase < @phase }
|
|
190
190
|
|
|
191
191
|
if w
|
|
192
192
|
if refork
|
|
@@ -221,12 +221,11 @@ module Puma
|
|
|
221
221
|
pipes[:wakeup] = @wakeup
|
|
222
222
|
end
|
|
223
223
|
|
|
224
|
-
server = start_server if preload?
|
|
225
224
|
new_worker = Worker.new index: index,
|
|
226
225
|
master: master,
|
|
227
226
|
launcher: @launcher,
|
|
228
227
|
pipes: pipes,
|
|
229
|
-
|
|
228
|
+
app: (app if preload?)
|
|
230
229
|
new_worker.run
|
|
231
230
|
end
|
|
232
231
|
|
|
@@ -238,7 +237,7 @@ module Puma
|
|
|
238
237
|
def phased_restart(refork = false)
|
|
239
238
|
return false if @options[:preload_app] && !refork
|
|
240
239
|
|
|
241
|
-
@
|
|
240
|
+
@pending_phased_restart = refork ? :refork : true
|
|
242
241
|
wakeup!
|
|
243
242
|
|
|
244
243
|
true
|
|
@@ -456,11 +455,11 @@ module Puma
|
|
|
456
455
|
break
|
|
457
456
|
end
|
|
458
457
|
|
|
459
|
-
if @
|
|
460
|
-
start_phased_restart(@
|
|
458
|
+
if @pending_phased_restart
|
|
459
|
+
start_phased_restart(@pending_phased_restart == :refork)
|
|
461
460
|
|
|
462
|
-
in_phased_restart = @
|
|
463
|
-
@
|
|
461
|
+
in_phased_restart = @pending_phased_restart
|
|
462
|
+
@pending_phased_restart = false
|
|
464
463
|
|
|
465
464
|
workers_not_booted = @options[:workers]
|
|
466
465
|
# worker 0 is not restarted on refork
|
|
@@ -583,7 +582,9 @@ module Puma
|
|
|
583
582
|
# `Process.wait2(-1)` from detecting a terminated process: https://bugs.ruby-lang.org/issues/19837.
|
|
584
583
|
# 2. When `fork_worker` is enabled, some worker may not be direct children,
|
|
585
584
|
# but grand children. Because of this they won't be reaped by `Process.wait2(-1)`.
|
|
586
|
-
if reaped_children.delete(w.pid) || Process.
|
|
585
|
+
if (status = reaped_children.delete(w.pid) || Process.wait2(w.pid, Process::WNOHANG)&.last)
|
|
586
|
+
w.process_status = status
|
|
587
|
+
@config.run_hooks(:after_worker_shutdown, w, @log_writer)
|
|
587
588
|
true
|
|
588
589
|
else
|
|
589
590
|
w.term if w.term?
|