puma 7.1.0 → 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 +71 -0
- data/README.md +17 -9
- data/docs/deployment.md +58 -23
- data/docs/jungle/README.md +1 -1
- data/docs/kubernetes.md +3 -10
- data/docs/plugins.md +2 -2
- data/docs/signals.md +10 -10
- data/docs/stats.md +1 -1
- 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/cluster/worker.rb +10 -9
- data/lib/puma/cluster.rb +2 -3
- data/lib/puma/configuration.rb +16 -9
- data/lib/puma/const.rb +2 -2
- data/lib/puma/dsl.rb +16 -6
- data/lib/puma/launcher.rb +4 -3
- 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 +3 -3
- data/lib/puma/single.rb +2 -2
- data/tools/Dockerfile +13 -5
- metadata +3 -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/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
|
|
data/lib/puma/cluster.rb
CHANGED
|
@@ -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
|
|
data/lib/puma/configuration.rb
CHANGED
|
@@ -197,7 +197,7 @@ module Puma
|
|
|
197
197
|
@clamped = false
|
|
198
198
|
end
|
|
199
199
|
|
|
200
|
-
attr_reader :plugins, :events, :hooks
|
|
200
|
+
attr_reader :plugins, :events, :hooks, :_options
|
|
201
201
|
|
|
202
202
|
def options
|
|
203
203
|
raise NotClampedError, "ensure clamp is called before accessing options" unless @clamped
|
|
@@ -238,18 +238,14 @@ module Puma
|
|
|
238
238
|
min = env['PUMA_MIN_THREADS'] || env['MIN_THREADS']
|
|
239
239
|
max = env['PUMA_MAX_THREADS'] || env['MAX_THREADS']
|
|
240
240
|
persistent_timeout = env['PUMA_PERSISTENT_TIMEOUT']
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
::Concurrent.available_processor_count
|
|
244
|
-
else
|
|
245
|
-
env['WEB_CONCURRENCY']
|
|
246
|
-
end
|
|
241
|
+
workers_env = env['WEB_CONCURRENCY']
|
|
242
|
+
workers = workers_env && workers_env.strip != "" ? parse_workers(workers_env.strip) : nil
|
|
247
243
|
|
|
248
244
|
{
|
|
249
245
|
min_threads: min && min != "" && Integer(min),
|
|
250
246
|
max_threads: max && max != "" && Integer(max),
|
|
251
247
|
persistent_timeout: persistent_timeout && persistent_timeout != "" && Integer(persistent_timeout),
|
|
252
|
-
workers: workers
|
|
248
|
+
workers: workers,
|
|
253
249
|
environment: env['APP_ENV'] || env['RACK_ENV'] || env['RAILS_ENV'],
|
|
254
250
|
}
|
|
255
251
|
end
|
|
@@ -380,12 +376,23 @@ module Puma
|
|
|
380
376
|
require 'concurrent/utility/processor_counter'
|
|
381
377
|
rescue LoadError
|
|
382
378
|
warn <<~MESSAGE
|
|
383
|
-
WEB_CONCURRENCY=auto requires the "concurrent-ruby" gem to be installed.
|
|
379
|
+
WEB_CONCURRENCY=auto or workers(:auto) requires the "concurrent-ruby" gem to be installed.
|
|
384
380
|
Please add "concurrent-ruby" to your Gemfile.
|
|
385
381
|
MESSAGE
|
|
386
382
|
raise
|
|
387
383
|
end
|
|
388
384
|
|
|
385
|
+
def parse_workers(value)
|
|
386
|
+
if value == :auto || value == 'auto'
|
|
387
|
+
require_processor_counter
|
|
388
|
+
Integer(::Concurrent.available_processor_count)
|
|
389
|
+
else
|
|
390
|
+
Integer(value)
|
|
391
|
+
end
|
|
392
|
+
rescue ArgumentError, TypeError
|
|
393
|
+
raise ArgumentError, "workers must be an Integer or :auto"
|
|
394
|
+
end
|
|
395
|
+
|
|
389
396
|
# Load and use the normal Rack builder if we can, otherwise
|
|
390
397
|
# fallback to our minimal version.
|
|
391
398
|
def rack_builder
|
data/lib/puma/const.rb
CHANGED
|
@@ -100,8 +100,8 @@ module Puma
|
|
|
100
100
|
# too taxing on performance.
|
|
101
101
|
module Const
|
|
102
102
|
|
|
103
|
-
PUMA_VERSION = VERSION = "7.
|
|
104
|
-
CODE_NAME = "
|
|
103
|
+
PUMA_VERSION = VERSION = "7.2.0"
|
|
104
|
+
CODE_NAME = "On The Corner"
|
|
105
105
|
|
|
106
106
|
PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
|
|
107
107
|
|
data/lib/puma/dsl.rb
CHANGED
|
@@ -216,6 +216,8 @@ module Puma
|
|
|
216
216
|
# activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
|
|
217
217
|
# @example
|
|
218
218
|
# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }
|
|
219
|
+
# @example
|
|
220
|
+
# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true, data_only: true}
|
|
219
221
|
#
|
|
220
222
|
def activate_control_app(url="auto", opts={})
|
|
221
223
|
if url == "auto"
|
|
@@ -240,6 +242,7 @@ module Puma
|
|
|
240
242
|
|
|
241
243
|
@options[:control_auth_token] = auth_token
|
|
242
244
|
@options[:control_url_umask] = opts[:umask] if opts[:umask]
|
|
245
|
+
@options[:control_data_only] = opts[:data_only] if opts[:data_only]
|
|
243
246
|
end
|
|
244
247
|
|
|
245
248
|
# Load additional configuration from a file.
|
|
@@ -666,21 +669,27 @@ module Puma
|
|
|
666
669
|
@options[:state_permission] = permission
|
|
667
670
|
end
|
|
668
671
|
|
|
669
|
-
# How many worker processes to run.
|
|
670
|
-
#
|
|
672
|
+
# How many worker processes to run. Typically this is set to the number of
|
|
673
|
+
# available cores.
|
|
671
674
|
#
|
|
672
675
|
# The default is the value of the environment variable +WEB_CONCURRENCY+ if
|
|
673
|
-
# set, otherwise 0.
|
|
676
|
+
# set, otherwise 0. Passing +:auto+ will set the value to
|
|
677
|
+
# +Concurrent.available_processor_count+ (requires the concurrent-ruby gem).
|
|
678
|
+
# On some platforms (e.g. under CPU quotas) this may be fractional, and Puma
|
|
679
|
+
# will round down. If it rounds down to 0, Puma will run in single mode and
|
|
680
|
+
# cluster-only hooks like +before_worker_boot+ will not execute.
|
|
681
|
+
# If you rely on cluster-only hooks, set an explicit worker count.
|
|
674
682
|
#
|
|
675
|
-
#
|
|
683
|
+
# A value of 0 or nil means run in single mode.
|
|
676
684
|
#
|
|
677
685
|
# @example
|
|
678
686
|
# workers 2
|
|
687
|
+
# workers :auto
|
|
679
688
|
#
|
|
680
689
|
# @see Puma::Cluster
|
|
681
690
|
#
|
|
682
691
|
def workers(count)
|
|
683
|
-
@options[:workers] = count.
|
|
692
|
+
@options[:workers] = count.nil? ? 0 : @config.send(:parse_workers, count)
|
|
684
693
|
end
|
|
685
694
|
|
|
686
695
|
# Disable warning message when running in cluster mode with a single worker.
|
|
@@ -995,6 +1004,7 @@ module Puma
|
|
|
995
1004
|
# The default is +true+ if your app uses more than 1 worker.
|
|
996
1005
|
#
|
|
997
1006
|
# @note Cluster mode only.
|
|
1007
|
+
# @note When using `fork_worker`, this only applies to worker 0.
|
|
998
1008
|
#
|
|
999
1009
|
# @example
|
|
1000
1010
|
# preload_app!
|
|
@@ -1378,7 +1388,7 @@ module Puma
|
|
|
1378
1388
|
#
|
|
1379
1389
|
# The default is +:auto+.
|
|
1380
1390
|
#
|
|
1381
|
-
# @see https://github.com/socketry/nio4r/blob/
|
|
1391
|
+
# @see https://github.com/socketry/nio4r/blob/main/lib/nio/selector.rb
|
|
1382
1392
|
#
|
|
1383
1393
|
def io_selector_backend(backend)
|
|
1384
1394
|
@options[:io_selector_backend] = backend.to_sym
|