puma 6.4.1 → 7.2.1
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 +407 -8
- data/README.md +109 -49
- data/docs/deployment.md +58 -23
- data/docs/fork_worker.md +11 -1
- data/docs/java_options.md +54 -0
- data/docs/jungle/README.md +1 -1
- data/docs/kubernetes.md +11 -16
- data/docs/plugins.md +6 -2
- data/docs/restart.md +2 -2
- data/docs/signals.md +21 -21
- data/docs/stats.md +11 -5
- data/docs/systemd.md +14 -5
- data/ext/puma_http11/extconf.rb +20 -32
- data/ext/puma_http11/mini_ssl.c +29 -9
- data/ext/puma_http11/org/jruby/puma/Http11.java +40 -9
- data/ext/puma_http11/puma_http11.c +125 -118
- data/lib/puma/app/status.rb +11 -3
- data/lib/puma/binder.rb +21 -11
- data/lib/puma/cli.rb +10 -8
- data/lib/puma/client.rb +183 -83
- data/lib/puma/cluster/worker.rb +24 -21
- data/lib/puma/cluster/worker_handle.rb +38 -8
- data/lib/puma/cluster.rb +73 -47
- data/lib/puma/cluster_accept_loop_delay.rb +91 -0
- data/lib/puma/commonlogger.rb +3 -3
- data/lib/puma/configuration.rb +131 -60
- data/lib/puma/const.rb +31 -12
- data/lib/puma/control_cli.rb +10 -6
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +411 -121
- data/lib/puma/error_logger.rb +7 -5
- data/lib/puma/events.rb +25 -10
- data/lib/puma/io_buffer.rb +8 -4
- data/lib/puma/jruby_restart.rb +0 -16
- data/lib/puma/launcher/bundle_pruner.rb +1 -1
- data/lib/puma/launcher.rb +73 -55
- data/lib/puma/log_writer.rb +9 -9
- data/lib/puma/minissl/context_builder.rb +1 -0
- data/lib/puma/minissl.rb +1 -1
- data/lib/puma/null_io.rb +26 -0
- data/lib/puma/plugin/systemd.rb +3 -3
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/reactor.rb +19 -13
- data/lib/puma/request.rb +71 -39
- data/lib/puma/runner.rb +15 -17
- data/lib/puma/sd_notify.rb +1 -4
- data/lib/puma/server.rb +134 -73
- data/lib/puma/single.rb +7 -4
- data/lib/puma/state_file.rb +3 -2
- data/lib/puma/thread_pool.rb +57 -80
- data/lib/puma/util.rb +0 -7
- data/lib/puma.rb +10 -0
- data/lib/rack/handler/puma.rb +10 -7
- data/tools/Dockerfile +15 -5
- metadata +14 -15
- data/ext/puma_http11/ext_help.h +0 -15
|
@@ -7,25 +7,13 @@
|
|
|
7
7
|
#define RSTRING_NOT_MODIFIED 1
|
|
8
8
|
|
|
9
9
|
#include "ruby.h"
|
|
10
|
-
#include "
|
|
10
|
+
#include "ruby/encoding.h"
|
|
11
11
|
#include <assert.h>
|
|
12
12
|
#include <string.h>
|
|
13
13
|
#include <ctype.h>
|
|
14
14
|
#include "http11_parser.h"
|
|
15
15
|
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
#ifndef RSTRING_PTR
|
|
19
|
-
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
|
20
|
-
#endif
|
|
21
|
-
#ifndef RSTRING_LEN
|
|
22
|
-
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
|
23
|
-
#endif
|
|
24
|
-
|
|
25
|
-
#define rb_extract_chars(e, sz) (*sz = RSTRING_LEN(e), RSTRING_PTR(e))
|
|
26
|
-
#define rb_free_chars(e) /* nothing */
|
|
27
|
-
|
|
28
|
-
#endif
|
|
16
|
+
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
29
17
|
|
|
30
18
|
static VALUE eHttpParserError;
|
|
31
19
|
|
|
@@ -48,8 +36,11 @@ static VALUE global_request_path;
|
|
|
48
36
|
#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR, len); }
|
|
49
37
|
|
|
50
38
|
/** Defines global strings in the init method. */
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
static inline void DEF_GLOBAL(VALUE *var, const char *cstr)
|
|
40
|
+
{
|
|
41
|
+
rb_global_variable(var);
|
|
42
|
+
*var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
|
|
43
|
+
}
|
|
53
44
|
|
|
54
45
|
/* Defines the maximum allowed lengths for various input elements.*/
|
|
55
46
|
#ifndef PUMA_REQUEST_URI_MAX_LENGTH
|
|
@@ -73,10 +64,10 @@ DEF_MAX_LENGTH(QUERY_STRING, PUMA_QUERY_STRING_MAX_LENGTH);
|
|
|
73
64
|
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
|
74
65
|
|
|
75
66
|
struct common_field {
|
|
76
|
-
|
|
77
|
-
|
|
67
|
+
const size_t len;
|
|
68
|
+
const char *name;
|
|
78
69
|
int raw;
|
|
79
|
-
|
|
70
|
+
VALUE value;
|
|
80
71
|
};
|
|
81
72
|
|
|
82
73
|
/*
|
|
@@ -87,42 +78,42 @@ struct common_field {
|
|
|
87
78
|
static struct common_field common_http_fields[] = {
|
|
88
79
|
# define f(N) { (sizeof(N) - 1), N, 0, Qnil }
|
|
89
80
|
# define fr(N) { (sizeof(N) - 1), N, 1, Qnil }
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
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")
|
|
126
117
|
# undef f
|
|
127
118
|
};
|
|
128
119
|
|
|
@@ -134,13 +125,13 @@ static void init_common_fields(void)
|
|
|
134
125
|
memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
|
|
135
126
|
|
|
136
127
|
for(i = 0; i < ARRAY_SIZE(common_http_fields); cf++, i++) {
|
|
128
|
+
rb_global_variable(&cf->value);
|
|
137
129
|
if(cf->raw) {
|
|
138
|
-
cf->value =
|
|
130
|
+
cf->value = rb_enc_interned_str(cf->name, cf->len, rb_utf8_encoding());
|
|
139
131
|
} else {
|
|
140
132
|
memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1);
|
|
141
|
-
cf->value =
|
|
133
|
+
cf->value = rb_enc_interned_str(tmp, HTTP_PREFIX_LEN + cf->len, rb_utf8_encoding());
|
|
142
134
|
}
|
|
143
|
-
rb_global_variable(&cf->value);
|
|
144
135
|
}
|
|
145
136
|
}
|
|
146
137
|
|
|
@@ -155,7 +146,11 @@ static VALUE find_common_field_value(const char *field, size_t flen)
|
|
|
155
146
|
return Qnil;
|
|
156
147
|
}
|
|
157
148
|
|
|
158
|
-
|
|
149
|
+
static int is_ows(const char c) {
|
|
150
|
+
return c == ' ' || c == '\t';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static void http_field(puma_parser* hp, const char *field, size_t flen,
|
|
159
154
|
const char *value, size_t vlen)
|
|
160
155
|
{
|
|
161
156
|
VALUE f = Qnil;
|
|
@@ -178,10 +173,14 @@ void http_field(puma_parser* hp, const char *field, size_t flen,
|
|
|
178
173
|
memcpy(hp->buf, HTTP_PREFIX, HTTP_PREFIX_LEN);
|
|
179
174
|
memcpy(hp->buf + HTTP_PREFIX_LEN, field, flen);
|
|
180
175
|
|
|
181
|
-
f =
|
|
176
|
+
f = rb_enc_interned_str(hp->buf, new_size, rb_utf8_encoding());
|
|
182
177
|
}
|
|
183
178
|
|
|
184
|
-
while (vlen > 0 &&
|
|
179
|
+
while (vlen > 0 && is_ows(value[vlen - 1])) vlen--;
|
|
180
|
+
while (vlen > 0 && is_ows(value[0])) {
|
|
181
|
+
vlen--;
|
|
182
|
+
value++;
|
|
183
|
+
}
|
|
185
184
|
|
|
186
185
|
/* check for duplicate header */
|
|
187
186
|
v = rb_hash_aref(hp->request, f);
|
|
@@ -196,7 +195,7 @@ void http_field(puma_parser* hp, const char *field, size_t flen,
|
|
|
196
195
|
}
|
|
197
196
|
}
|
|
198
197
|
|
|
199
|
-
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)
|
|
200
199
|
{
|
|
201
200
|
VALUE val = Qnil;
|
|
202
201
|
|
|
@@ -204,7 +203,7 @@ void request_method(puma_parser* hp, const char *at, size_t length)
|
|
|
204
203
|
rb_hash_aset(hp->request, global_request_method, val);
|
|
205
204
|
}
|
|
206
205
|
|
|
207
|
-
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)
|
|
208
207
|
{
|
|
209
208
|
VALUE val = Qnil;
|
|
210
209
|
|
|
@@ -214,7 +213,7 @@ void request_uri(puma_parser* hp, const char *at, size_t length)
|
|
|
214
213
|
rb_hash_aset(hp->request, global_request_uri, val);
|
|
215
214
|
}
|
|
216
215
|
|
|
217
|
-
void fragment(puma_parser* hp, const char *at, size_t length)
|
|
216
|
+
static void fragment(puma_parser* hp, const char *at, size_t length)
|
|
218
217
|
{
|
|
219
218
|
VALUE val = Qnil;
|
|
220
219
|
|
|
@@ -224,7 +223,7 @@ void fragment(puma_parser* hp, const char *at, size_t length)
|
|
|
224
223
|
rb_hash_aset(hp->request, global_fragment, val);
|
|
225
224
|
}
|
|
226
225
|
|
|
227
|
-
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)
|
|
228
227
|
{
|
|
229
228
|
VALUE val = Qnil;
|
|
230
229
|
|
|
@@ -234,7 +233,7 @@ void request_path(puma_parser* hp, const char *at, size_t length)
|
|
|
234
233
|
rb_hash_aset(hp->request, global_request_path, val);
|
|
235
234
|
}
|
|
236
235
|
|
|
237
|
-
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)
|
|
238
237
|
{
|
|
239
238
|
VALUE val = Qnil;
|
|
240
239
|
|
|
@@ -244,7 +243,7 @@ void query_string(puma_parser* hp, const char *at, size_t length)
|
|
|
244
243
|
rb_hash_aset(hp->request, global_query_string, val);
|
|
245
244
|
}
|
|
246
245
|
|
|
247
|
-
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)
|
|
248
247
|
{
|
|
249
248
|
VALUE val = rb_str_new(at, length);
|
|
250
249
|
rb_hash_aset(hp->request, global_server_protocol, val);
|
|
@@ -253,36 +252,42 @@ void server_protocol(puma_parser* hp, const char *at, size_t length)
|
|
|
253
252
|
/** Finalizes the request header to have a bunch of stuff that's
|
|
254
253
|
needed. */
|
|
255
254
|
|
|
256
|
-
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)
|
|
257
256
|
{
|
|
258
257
|
hp->body = rb_str_new(at, length);
|
|
259
258
|
}
|
|
260
259
|
|
|
261
260
|
|
|
262
|
-
void
|
|
263
|
-
|
|
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
|
+
}
|
|
264
266
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
267
|
+
static size_t HttpParser_size(const void *ptr) {
|
|
268
|
+
return sizeof(puma_parser);
|
|
268
269
|
}
|
|
269
270
|
|
|
270
|
-
void
|
|
271
|
+
static void HttpParser_compact(void *ptr) {
|
|
271
272
|
puma_parser *hp = ptr;
|
|
272
|
-
|
|
273
|
-
|
|
273
|
+
hp->request = rb_gc_location(hp->request);
|
|
274
|
+
hp->body = rb_gc_location(hp->body);
|
|
274
275
|
}
|
|
275
276
|
|
|
276
|
-
const rb_data_type_t HttpParser_data_type = {
|
|
277
|
-
"HttpParser",
|
|
278
|
-
|
|
279
|
-
|
|
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,
|
|
280
286
|
};
|
|
281
287
|
|
|
282
|
-
VALUE HttpParser_alloc(VALUE klass)
|
|
288
|
+
static VALUE HttpParser_alloc(VALUE klass)
|
|
283
289
|
{
|
|
284
290
|
puma_parser *hp = ALLOC_N(puma_parser, 1);
|
|
285
|
-
TRACE();
|
|
286
291
|
hp->http_field = http_field;
|
|
287
292
|
hp->request_method = request_method;
|
|
288
293
|
hp->request_uri = request_uri;
|
|
@@ -298,16 +303,25 @@ VALUE HttpParser_alloc(VALUE klass)
|
|
|
298
303
|
return TypedData_Wrap_Struct(klass, &HttpParser_data_type, hp);
|
|
299
304
|
}
|
|
300
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
|
+
|
|
301
316
|
/**
|
|
302
317
|
* call-seq:
|
|
303
318
|
* parser.new -> parser
|
|
304
319
|
*
|
|
305
320
|
* Creates a new parser.
|
|
306
321
|
*/
|
|
307
|
-
VALUE HttpParser_init(VALUE self)
|
|
322
|
+
static VALUE HttpParser_init(VALUE self)
|
|
308
323
|
{
|
|
309
|
-
puma_parser *http =
|
|
310
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
324
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
311
325
|
puma_parser_init(http);
|
|
312
326
|
|
|
313
327
|
return self;
|
|
@@ -321,10 +335,9 @@ VALUE HttpParser_init(VALUE self)
|
|
|
321
335
|
* Resets the parser to it's initial state so that you can reuse it
|
|
322
336
|
* rather than making new ones.
|
|
323
337
|
*/
|
|
324
|
-
VALUE HttpParser_reset(VALUE self)
|
|
338
|
+
static VALUE HttpParser_reset(VALUE self)
|
|
325
339
|
{
|
|
326
|
-
puma_parser *http =
|
|
327
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
340
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
328
341
|
puma_parser_init(http);
|
|
329
342
|
|
|
330
343
|
return Qnil;
|
|
@@ -338,10 +351,9 @@ VALUE HttpParser_reset(VALUE self)
|
|
|
338
351
|
* Finishes a parser early which could put in a "good" or bad state.
|
|
339
352
|
* You should call reset after finish it or bad things will happen.
|
|
340
353
|
*/
|
|
341
|
-
VALUE HttpParser_finish(VALUE self)
|
|
354
|
+
static VALUE HttpParser_finish(VALUE self)
|
|
342
355
|
{
|
|
343
|
-
puma_parser *http =
|
|
344
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
356
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
345
357
|
puma_parser_finish(http);
|
|
346
358
|
|
|
347
359
|
return puma_parser_is_finished(http) ? Qtrue : Qfalse;
|
|
@@ -365,26 +377,22 @@ VALUE HttpParser_finish(VALUE self)
|
|
|
365
377
|
* the parsing from that position. It needs all of the original data as well
|
|
366
378
|
* so you have to append to the data buffer as you read.
|
|
367
379
|
*/
|
|
368
|
-
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)
|
|
369
381
|
{
|
|
370
|
-
puma_parser *http =
|
|
382
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
371
383
|
int from = 0;
|
|
372
384
|
char *dptr = NULL;
|
|
373
385
|
long dlen = 0;
|
|
374
386
|
|
|
375
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
376
|
-
|
|
377
387
|
from = FIX2INT(start);
|
|
378
|
-
|
|
388
|
+
RSTRING_GETMEM(data, dptr, dlen);
|
|
379
389
|
|
|
380
390
|
if(from >= dlen) {
|
|
381
|
-
rb_free_chars(dptr);
|
|
382
391
|
rb_raise(eHttpParserError, "%s", "Requested start is after data buffer end.");
|
|
383
392
|
} else {
|
|
384
393
|
http->request = req_hash;
|
|
385
394
|
puma_parser_execute(http, dptr, dlen, from);
|
|
386
395
|
|
|
387
|
-
rb_free_chars(dptr);
|
|
388
396
|
VALIDATE_MAX_LENGTH(puma_parser_nread(http), HEADER);
|
|
389
397
|
|
|
390
398
|
if(puma_parser_has_error(http)) {
|
|
@@ -403,10 +411,9 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
|
|
|
403
411
|
*
|
|
404
412
|
* Tells you whether the parser is in an error state.
|
|
405
413
|
*/
|
|
406
|
-
VALUE HttpParser_has_error(VALUE self)
|
|
414
|
+
static VALUE HttpParser_has_error(VALUE self)
|
|
407
415
|
{
|
|
408
|
-
puma_parser *http =
|
|
409
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
416
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
410
417
|
|
|
411
418
|
return puma_parser_has_error(http) ? Qtrue : Qfalse;
|
|
412
419
|
}
|
|
@@ -418,10 +425,9 @@ VALUE HttpParser_has_error(VALUE self)
|
|
|
418
425
|
*
|
|
419
426
|
* Tells you whether the parser is finished or not and in a good state.
|
|
420
427
|
*/
|
|
421
|
-
VALUE HttpParser_is_finished(VALUE self)
|
|
428
|
+
static VALUE HttpParser_is_finished(VALUE self)
|
|
422
429
|
{
|
|
423
|
-
puma_parser *http =
|
|
424
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
430
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
425
431
|
|
|
426
432
|
return puma_parser_is_finished(http) ? Qtrue : Qfalse;
|
|
427
433
|
}
|
|
@@ -434,10 +440,9 @@ VALUE HttpParser_is_finished(VALUE self)
|
|
|
434
440
|
* Returns the amount of data processed so far during this processing cycle. It is
|
|
435
441
|
* set to 0 on initialize or reset calls and is incremented each time execute is called.
|
|
436
442
|
*/
|
|
437
|
-
VALUE HttpParser_nread(VALUE self)
|
|
443
|
+
static VALUE HttpParser_nread(VALUE self)
|
|
438
444
|
{
|
|
439
|
-
puma_parser *http =
|
|
440
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
445
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
441
446
|
|
|
442
447
|
return INT2FIX(http->nread);
|
|
443
448
|
}
|
|
@@ -448,9 +453,8 @@ VALUE HttpParser_nread(VALUE self)
|
|
|
448
453
|
*
|
|
449
454
|
* If the request included a body, returns it.
|
|
450
455
|
*/
|
|
451
|
-
VALUE HttpParser_body(VALUE self) {
|
|
452
|
-
puma_parser *http =
|
|
453
|
-
DATA_GET(self, puma_parser, &HttpParser_data_type, http);
|
|
456
|
+
static VALUE HttpParser_body(VALUE self) {
|
|
457
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
454
458
|
|
|
455
459
|
return http->body;
|
|
456
460
|
}
|
|
@@ -459,21 +463,24 @@ VALUE HttpParser_body(VALUE self) {
|
|
|
459
463
|
void Init_mini_ssl(VALUE mod);
|
|
460
464
|
#endif
|
|
461
465
|
|
|
462
|
-
void Init_puma_http11(void)
|
|
466
|
+
RUBY_FUNC_EXPORTED void Init_puma_http11(void)
|
|
463
467
|
{
|
|
468
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
|
469
|
+
rb_ext_ractor_safe(true);
|
|
470
|
+
#endif
|
|
464
471
|
|
|
465
472
|
VALUE mPuma = rb_define_module("Puma");
|
|
466
473
|
VALUE cHttpParser = rb_define_class_under(mPuma, "HttpParser", rb_cObject);
|
|
467
474
|
|
|
468
|
-
DEF_GLOBAL(
|
|
469
|
-
DEF_GLOBAL(
|
|
470
|
-
DEF_GLOBAL(
|
|
471
|
-
DEF_GLOBAL(
|
|
472
|
-
DEF_GLOBAL(
|
|
473
|
-
DEF_GLOBAL(
|
|
475
|
+
DEF_GLOBAL(&global_request_method, "REQUEST_METHOD");
|
|
476
|
+
DEF_GLOBAL(&global_request_uri, "REQUEST_URI");
|
|
477
|
+
DEF_GLOBAL(&global_fragment, "FRAGMENT");
|
|
478
|
+
DEF_GLOBAL(&global_query_string, "QUERY_STRING");
|
|
479
|
+
DEF_GLOBAL(&global_server_protocol, "SERVER_PROTOCOL");
|
|
480
|
+
DEF_GLOBAL(&global_request_path, "REQUEST_PATH");
|
|
474
481
|
|
|
475
|
-
eHttpParserError = rb_define_class_under(mPuma, "HttpParserError", rb_eIOError);
|
|
476
482
|
rb_global_variable(&eHttpParserError);
|
|
483
|
+
eHttpParserError = rb_define_class_under(mPuma, "HttpParserError", rb_eStandardError);
|
|
477
484
|
|
|
478
485
|
rb_define_alloc_func(cHttpParser, HttpParser_alloc);
|
|
479
486
|
rb_define_method(cHttpParser, "initialize", HttpParser_init, 0);
|
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
|
|
|
@@ -80,7 +88,7 @@ module Puma
|
|
|
80
88
|
|
|
81
89
|
def authenticate(env)
|
|
82
90
|
return true unless @auth_token
|
|
83
|
-
env['QUERY_STRING'].to_s.split(
|
|
91
|
+
env['QUERY_STRING'].to_s.split(/[&;]/).include? "token=#{@auth_token}"
|
|
84
92
|
end
|
|
85
93
|
|
|
86
94
|
def rack_response(status, body, content_type='application/json')
|
data/lib/puma/binder.rb
CHANGED
|
@@ -5,7 +5,6 @@ require 'socket'
|
|
|
5
5
|
|
|
6
6
|
require_relative 'const'
|
|
7
7
|
require_relative 'util'
|
|
8
|
-
require_relative 'configuration'
|
|
9
8
|
|
|
10
9
|
module Puma
|
|
11
10
|
|
|
@@ -19,22 +18,23 @@ module Puma
|
|
|
19
18
|
|
|
20
19
|
RACK_VERSION = [1,6].freeze
|
|
21
20
|
|
|
22
|
-
def initialize(log_writer,
|
|
21
|
+
def initialize(log_writer, options, env: ENV)
|
|
23
22
|
@log_writer = log_writer
|
|
24
|
-
@
|
|
23
|
+
@options = options
|
|
25
24
|
@listeners = []
|
|
26
25
|
@inherited_fds = {}
|
|
27
26
|
@activated_sockets = {}
|
|
28
27
|
@unix_paths = []
|
|
28
|
+
@env = env
|
|
29
29
|
|
|
30
30
|
@proto_env = {
|
|
31
31
|
"rack.version".freeze => RACK_VERSION,
|
|
32
32
|
"rack.errors".freeze => log_writer.stderr,
|
|
33
|
-
"rack.multithread".freeze =>
|
|
34
|
-
"rack.multiprocess".freeze =>
|
|
33
|
+
"rack.multithread".freeze => options[:max_threads] > 1,
|
|
34
|
+
"rack.multiprocess".freeze => options[:workers] >= 1,
|
|
35
35
|
"rack.run_once".freeze => false,
|
|
36
|
-
RACK_URL_SCHEME =>
|
|
37
|
-
"SCRIPT_NAME".freeze =>
|
|
36
|
+
RACK_URL_SCHEME => options[:rack_url_scheme],
|
|
37
|
+
"SCRIPT_NAME".freeze => env['SCRIPT_NAME'] || "",
|
|
38
38
|
|
|
39
39
|
# I'd like to set a default CONTENT_TYPE here but some things
|
|
40
40
|
# depend on their not being a default set and inferring
|
|
@@ -43,7 +43,10 @@ module Puma
|
|
|
43
43
|
|
|
44
44
|
"QUERY_STRING".freeze => "",
|
|
45
45
|
SERVER_SOFTWARE => PUMA_SERVER_STRING,
|
|
46
|
-
GATEWAY_INTERFACE => CGI_VER
|
|
46
|
+
GATEWAY_INTERFACE => CGI_VER,
|
|
47
|
+
|
|
48
|
+
RACK_AFTER_REPLY => nil,
|
|
49
|
+
RACK_RESPONSE_FINISHED => nil,
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
@envs = {}
|
|
@@ -87,7 +90,7 @@ module Puma
|
|
|
87
90
|
# @version 5.0.0
|
|
88
91
|
#
|
|
89
92
|
def create_activated_fds(env_hash)
|
|
90
|
-
@log_writer.debug "ENV['LISTEN_FDS'] #{
|
|
93
|
+
@log_writer.debug "ENV['LISTEN_FDS'] #{@env['LISTEN_FDS'].inspect} env_hash['LISTEN_PID'] #{env_hash['LISTEN_PID'].inspect}"
|
|
91
94
|
return [] unless env_hash['LISTEN_FDS'] && env_hash['LISTEN_PID'].to_i == $$
|
|
92
95
|
env_hash['LISTEN_FDS'].to_i.times do |index|
|
|
93
96
|
sock = TCPServer.for_fd(socket_activation_fd(index))
|
|
@@ -141,7 +144,14 @@ module Puma
|
|
|
141
144
|
end
|
|
142
145
|
end
|
|
143
146
|
|
|
147
|
+
def before_parse(&block)
|
|
148
|
+
@before_parse ||= []
|
|
149
|
+
@before_parse << block if block
|
|
150
|
+
@before_parse
|
|
151
|
+
end
|
|
152
|
+
|
|
144
153
|
def parse(binds, log_writer = nil, log_msg = 'Listening')
|
|
154
|
+
before_parse.each(&:call)
|
|
145
155
|
log_writer ||= @log_writer
|
|
146
156
|
binds.each do |str|
|
|
147
157
|
uri = URI.parse str
|
|
@@ -183,7 +193,7 @@ module Puma
|
|
|
183
193
|
io = inherit_unix_listener path, fd
|
|
184
194
|
log_writer.log "* Inherited #{str}"
|
|
185
195
|
elsif sock = @activated_sockets.delete([ :unix, path ]) ||
|
|
186
|
-
@activated_sockets.delete([ :unix, File.realdirpath(path) ])
|
|
196
|
+
!abstract && @activated_sockets.delete([ :unix, File.realdirpath(path) ])
|
|
187
197
|
@unix_paths << path unless abstract || File.exist?(path)
|
|
188
198
|
io = inherit_unix_listener path, sock
|
|
189
199
|
log_writer.log "* Activated #{str}"
|
|
@@ -235,7 +245,7 @@ module Puma
|
|
|
235
245
|
cert_key.each do |v|
|
|
236
246
|
if params[v]&.start_with?('store:')
|
|
237
247
|
index = Integer(params.delete(v).split('store:').last)
|
|
238
|
-
params["#{v}_pem"] = @
|
|
248
|
+
params["#{v}_pem"] = @options[:store][index]
|
|
239
249
|
end
|
|
240
250
|
end
|
|
241
251
|
MiniSSL::ContextBuilder.new(params, @log_writer).context
|
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,10 +39,8 @@ module Puma
|
|
|
39
39
|
@control_url = nil
|
|
40
40
|
@control_options = {}
|
|
41
41
|
|
|
42
|
-
setup_options
|
|
43
|
-
|
|
44
42
|
begin
|
|
45
|
-
|
|
43
|
+
setup_options env
|
|
46
44
|
|
|
47
45
|
if file = @argv.shift
|
|
48
46
|
@conf.configure do |user_config, file_config|
|
|
@@ -63,7 +61,7 @@ module Puma
|
|
|
63
61
|
end
|
|
64
62
|
end
|
|
65
63
|
|
|
66
|
-
@launcher = Puma::Launcher.new(@conf, :log_writer
|
|
64
|
+
@launcher = Puma::Launcher.new(@conf, env: ENV, log_writer: @log_writer, events: @events, argv: argv)
|
|
67
65
|
end
|
|
68
66
|
|
|
69
67
|
attr_reader :launcher
|
|
@@ -92,8 +90,8 @@ module Puma
|
|
|
92
90
|
# Build the OptionParser object to handle the available options.
|
|
93
91
|
#
|
|
94
92
|
|
|
95
|
-
def setup_options
|
|
96
|
-
@conf = Configuration.new({}, {events: @events}) do |user_config, file_config|
|
|
93
|
+
def setup_options(env = ENV)
|
|
94
|
+
@conf = Configuration.new({}, { events: @events }, env) do |user_config, file_config|
|
|
97
95
|
@parser = OptionParser.new do |o|
|
|
98
96
|
o.on "-b", "--bind URI", "URI to bind to (tcp://, unix://, ssl://)" do |arg|
|
|
99
97
|
user_config.bind arg
|
|
@@ -157,6 +155,10 @@ module Puma
|
|
|
157
155
|
user_config.pidfile arg
|
|
158
156
|
end
|
|
159
157
|
|
|
158
|
+
o.on "--plugin PLUGIN", "Load the given PLUGIN. Can be used multiple times to load multiple plugins." do |arg|
|
|
159
|
+
user_config.plugin arg
|
|
160
|
+
end
|
|
161
|
+
|
|
160
162
|
o.on "--preload", "Preload the app. Cluster mode only" do
|
|
161
163
|
user_config.preload_app!
|
|
162
164
|
end
|
|
@@ -236,7 +238,7 @@ module Puma
|
|
|
236
238
|
$stdout.puts o
|
|
237
239
|
exit 0
|
|
238
240
|
end
|
|
239
|
-
end
|
|
241
|
+
end.parse! @argv
|
|
240
242
|
end
|
|
241
243
|
end
|
|
242
244
|
end
|