puma 2.2.0 → 8.0.2
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 +7 -0
- data/History.md +3334 -0
- data/LICENSE +23 -20
- data/README.md +387 -100
- data/bin/puma-wild +25 -0
- data/bin/pumactl +1 -1
- data/docs/5.0-Upgrade.md +98 -0
- data/docs/6.0-Upgrade.md +56 -0
- data/docs/7.0-Upgrade.md +52 -0
- data/docs/8.0-Upgrade.md +100 -0
- data/docs/architecture.md +74 -0
- data/docs/compile_options.md +55 -0
- data/docs/deployment.md +137 -0
- data/docs/fork_worker.md +41 -0
- data/docs/grpc.md +62 -0
- data/docs/images/favicon.svg +1 -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/images/running-puma.svg +1 -0
- data/docs/images/standard-logo.svg +1 -0
- data/docs/java_options.md +54 -0
- data/docs/jungle/README.md +9 -0
- data/docs/jungle/rc.d/README.md +74 -0
- data/docs/jungle/rc.d/puma +61 -0
- data/docs/jungle/rc.d/puma.conf +10 -0
- data/docs/kubernetes.md +73 -0
- data/docs/nginx.md +5 -5
- data/docs/plugins.md +42 -0
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +65 -0
- data/docs/signals.md +98 -0
- data/docs/stats.md +148 -0
- data/docs/systemd.md +253 -0
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/PumaHttp11Service.java +2 -2
- data/ext/puma_http11/extconf.rb +59 -2
- data/ext/puma_http11/http11_parser.c +319 -487
- data/ext/puma_http11/http11_parser.h +15 -13
- data/ext/puma_http11/http11_parser.java.rl +64 -94
- data/ext/puma_http11/http11_parser.rl +27 -24
- data/ext/puma_http11/http11_parser_common.rl +8 -8
- data/ext/puma_http11/mini_ssl.c +696 -38
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/EnvKey.java +241 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +241 -145
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +174 -221
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +413 -193
- data/ext/puma_http11/puma_http11.c +183 -175
- data/lib/puma/app/status.rb +77 -29
- data/lib/puma/binder.rb +349 -119
- data/lib/puma/cli.rb +163 -801
- data/lib/puma/client.rb +627 -144
- data/lib/puma/client_env.rb +171 -0
- data/lib/puma/cluster/worker.rb +183 -0
- data/lib/puma/cluster/worker_handle.rb +127 -0
- data/lib/puma/cluster.rb +634 -0
- data/lib/puma/cluster_accept_loop_delay.rb +91 -0
- data/lib/puma/commonlogger.rb +115 -0
- data/lib/puma/configuration.rb +420 -198
- data/lib/puma/const.rb +266 -115
- data/lib/puma/control_cli.rb +219 -120
- data/lib/puma/detect.rb +56 -2
- data/lib/puma/dsl.rb +1562 -0
- data/lib/puma/error_logger.rb +115 -0
- data/lib/puma/events.rb +44 -60
- data/lib/puma/io_buffer.rb +48 -5
- data/lib/puma/jruby_restart.rb +2 -51
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher/bundle_pruner.rb +102 -0
- data/lib/puma/launcher.rb +501 -0
- data/lib/puma/log_writer.rb +153 -0
- data/lib/puma/minissl/context_builder.rb +96 -0
- data/lib/puma/minissl.rb +355 -37
- data/lib/puma/null_io.rb +79 -12
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +36 -0
- data/lib/puma/plugin.rb +111 -0
- data/lib/puma/rack/builder.rb +297 -0
- data/lib/puma/rack/urlmap.rb +93 -0
- data/lib/puma/rack_default.rb +21 -4
- data/lib/puma/reactor.rb +102 -133
- data/lib/puma/response.rb +532 -0
- data/lib/puma/runner.rb +211 -0
- data/lib/puma/sd_notify.rb +146 -0
- data/lib/puma/server.rb +582 -445
- data/lib/puma/server_plugin_control.rb +32 -0
- data/lib/puma/single.rb +72 -0
- data/lib/puma/state_file.rb +69 -0
- data/lib/puma/thread_pool.rb +389 -57
- data/lib/puma/util.rb +125 -0
- data/lib/puma.rb +80 -6
- data/lib/rack/handler/puma.rb +125 -47
- data/tools/Dockerfile +26 -0
- data/tools/trickletest.rb +44 -0
- metadata +88 -148
- data/COPYING +0 -55
- data/Gemfile +0 -10
- data/History.txt +0 -302
- data/Manifest.txt +0 -60
- data/Rakefile +0 -165
- data/TODO +0 -5
- data/docs/config.md +0 -0
- data/ext/puma_http11/ext_help.h +0 -15
- data/ext/puma_http11/io_buffer.c +0 -154
- data/lib/puma/accept_nonblock.rb +0 -23
- data/lib/puma/capistrano.rb +0 -34
- data/lib/puma/compat.rb +0 -11
- data/lib/puma/daemon_ext.rb +0 -20
- data/lib/puma/delegation.rb +0 -11
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack_patch.rb +0 -25
- data/puma.gemspec +0 -45
- data/test/test_app_status.rb +0 -88
- data/test/test_cli.rb +0 -171
- data/test/test_config.rb +0 -16
- data/test/test_http10.rb +0 -27
- data/test/test_http11.rb +0 -126
- data/test/test_integration.rb +0 -154
- data/test/test_iobuffer.rb +0 -38
- data/test/test_minissl.rb +0 -25
- data/test/test_null_io.rb +0 -31
- data/test/test_persistent.rb +0 -238
- data/test/test_puma_server.rb +0 -224
- data/test/test_rack_handler.rb +0 -10
- data/test/test_rack_server.rb +0 -141
- data/test/test_thread_pool.rb +0 -146
- data/test/test_unix_socket.rb +0 -39
- data/test/test_ws.rb +0 -89
- data/tools/jungle/init.d/README.md +0 -54
- data/tools/jungle/init.d/puma +0 -332
- data/tools/jungle/init.d/run-puma +0 -3
- data/tools/jungle/upstart/README.md +0 -61
- data/tools/jungle/upstart/puma-manager.conf +0 -31
- data/tools/jungle/upstart/puma.conf +0 -52
|
@@ -1,29 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Copyright (c) 2005 Zed A. Shaw
|
|
3
3
|
* You can redistribute it and/or modify it under the same terms as Ruby.
|
|
4
|
+
* License 3-clause BSD
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
#define RSTRING_NOT_MODIFIED 1
|
|
7
8
|
|
|
8
9
|
#include "ruby.h"
|
|
9
|
-
#include "
|
|
10
|
+
#include "ruby/encoding.h"
|
|
10
11
|
#include <assert.h>
|
|
11
12
|
#include <string.h>
|
|
13
|
+
#include <ctype.h>
|
|
12
14
|
#include "http11_parser.h"
|
|
13
15
|
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
#ifndef RSTRING_PTR
|
|
17
|
-
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
|
18
|
-
#endif
|
|
19
|
-
#ifndef RSTRING_LEN
|
|
20
|
-
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
|
21
|
-
#endif
|
|
22
|
-
|
|
23
|
-
#define rb_extract_chars(e, sz) (*sz = RSTRING_LEN(e), RSTRING_PTR(e))
|
|
24
|
-
#define rb_free_chars(e) /* nothing */
|
|
25
|
-
|
|
26
|
-
#endif
|
|
16
|
+
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
27
17
|
|
|
28
18
|
static VALUE eHttpParserError;
|
|
29
19
|
|
|
@@ -34,33 +24,50 @@ static VALUE global_request_method;
|
|
|
34
24
|
static VALUE global_request_uri;
|
|
35
25
|
static VALUE global_fragment;
|
|
36
26
|
static VALUE global_query_string;
|
|
37
|
-
static VALUE
|
|
27
|
+
static VALUE global_server_protocol;
|
|
38
28
|
static VALUE global_request_path;
|
|
39
29
|
|
|
40
30
|
/** Defines common length and error messages for input length validation. */
|
|
41
|
-
#define
|
|
31
|
+
#define QUOTE(s) #s
|
|
32
|
+
#define EXPAND_MAX_LENGTH_VALUE(s) QUOTE(s)
|
|
33
|
+
#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 " EXPAND_MAX_LENGTH_VALUE(length) " allowed length (was %d)"
|
|
42
34
|
|
|
43
35
|
/** Validates the max length of given input and throws an HttpParserError exception if over. */
|
|
44
|
-
#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError,
|
|
36
|
+
#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR, len); }
|
|
45
37
|
|
|
46
38
|
/** Defines global strings in the init method. */
|
|
47
|
-
|
|
48
|
-
|
|
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
|
+
}
|
|
49
44
|
|
|
50
45
|
/* Defines the maximum allowed lengths for various input elements.*/
|
|
46
|
+
#ifndef PUMA_REQUEST_URI_MAX_LENGTH
|
|
47
|
+
#define PUMA_REQUEST_URI_MAX_LENGTH (1024 * 12)
|
|
48
|
+
#endif
|
|
49
|
+
|
|
50
|
+
#ifndef PUMA_REQUEST_PATH_MAX_LENGTH
|
|
51
|
+
#define PUMA_REQUEST_PATH_MAX_LENGTH (8192)
|
|
52
|
+
#endif
|
|
53
|
+
|
|
54
|
+
#ifndef PUMA_QUERY_STRING_MAX_LENGTH
|
|
55
|
+
#define PUMA_QUERY_STRING_MAX_LENGTH (1024 * 10)
|
|
56
|
+
#endif
|
|
57
|
+
|
|
51
58
|
DEF_MAX_LENGTH(FIELD_NAME, 256);
|
|
52
59
|
DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
|
|
53
|
-
DEF_MAX_LENGTH(REQUEST_URI,
|
|
60
|
+
DEF_MAX_LENGTH(REQUEST_URI, PUMA_REQUEST_URI_MAX_LENGTH);
|
|
54
61
|
DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
|
|
55
|
-
DEF_MAX_LENGTH(REQUEST_PATH,
|
|
56
|
-
DEF_MAX_LENGTH(QUERY_STRING,
|
|
62
|
+
DEF_MAX_LENGTH(REQUEST_PATH, PUMA_REQUEST_PATH_MAX_LENGTH);
|
|
63
|
+
DEF_MAX_LENGTH(QUERY_STRING, PUMA_QUERY_STRING_MAX_LENGTH);
|
|
57
64
|
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
|
58
65
|
|
|
59
66
|
struct common_field {
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
const size_t len;
|
|
68
|
+
const char *name;
|
|
62
69
|
int raw;
|
|
63
|
-
|
|
70
|
+
VALUE value;
|
|
64
71
|
};
|
|
65
72
|
|
|
66
73
|
/*
|
|
@@ -71,60 +78,45 @@ struct common_field {
|
|
|
71
78
|
static struct common_field common_http_fields[] = {
|
|
72
79
|
# define f(N) { (sizeof(N) - 1), N, 0, Qnil }
|
|
73
80
|
# define fr(N) { (sizeof(N) - 1), N, 1, Qnil }
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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")
|
|
110
117
|
# undef f
|
|
111
118
|
};
|
|
112
119
|
|
|
113
|
-
/*
|
|
114
|
-
* qsort(3) and bsearch(3) improve average performance slightly, but may
|
|
115
|
-
* not be worth it for lack of portability to certain platforms...
|
|
116
|
-
*/
|
|
117
|
-
#if defined(HAVE_QSORT_BSEARCH)
|
|
118
|
-
/* sort by length, then by name if there's a tie */
|
|
119
|
-
static int common_field_cmp(const void *a, const void *b)
|
|
120
|
-
{
|
|
121
|
-
struct common_field *cfa = (struct common_field *)a;
|
|
122
|
-
struct common_field *cfb = (struct common_field *)b;
|
|
123
|
-
signed long diff = cfa->len - cfb->len;
|
|
124
|
-
return diff ? diff : memcmp(cfa->name, cfb->name, cfa->len);
|
|
125
|
-
}
|
|
126
|
-
#endif /* HAVE_QSORT_BSEARCH */
|
|
127
|
-
|
|
128
120
|
static void init_common_fields(void)
|
|
129
121
|
{
|
|
130
122
|
unsigned i;
|
|
@@ -133,36 +125,18 @@ static void init_common_fields(void)
|
|
|
133
125
|
memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
|
|
134
126
|
|
|
135
127
|
for(i = 0; i < ARRAY_SIZE(common_http_fields); cf++, i++) {
|
|
128
|
+
rb_global_variable(&cf->value);
|
|
136
129
|
if(cf->raw) {
|
|
137
|
-
cf->value =
|
|
130
|
+
cf->value = rb_enc_interned_str(cf->name, cf->len, rb_utf8_encoding());
|
|
138
131
|
} else {
|
|
139
132
|
memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1);
|
|
140
|
-
cf->value =
|
|
133
|
+
cf->value = rb_enc_interned_str(tmp, HTTP_PREFIX_LEN + cf->len, rb_utf8_encoding());
|
|
141
134
|
}
|
|
142
|
-
rb_global_variable(&cf->value);
|
|
143
135
|
}
|
|
144
|
-
|
|
145
|
-
#if defined(HAVE_QSORT_BSEARCH)
|
|
146
|
-
qsort(common_http_fields,
|
|
147
|
-
ARRAY_SIZE(common_http_fields),
|
|
148
|
-
sizeof(struct common_field),
|
|
149
|
-
common_field_cmp);
|
|
150
|
-
#endif /* HAVE_QSORT_BSEARCH */
|
|
151
136
|
}
|
|
152
137
|
|
|
153
138
|
static VALUE find_common_field_value(const char *field, size_t flen)
|
|
154
139
|
{
|
|
155
|
-
#if defined(HAVE_QSORT_BSEARCH)
|
|
156
|
-
struct common_field key;
|
|
157
|
-
struct common_field *found;
|
|
158
|
-
key.name = field;
|
|
159
|
-
key.len = (signed long)flen;
|
|
160
|
-
found = (struct common_field *)bsearch(&key, common_http_fields,
|
|
161
|
-
ARRAY_SIZE(common_http_fields),
|
|
162
|
-
sizeof(struct common_field),
|
|
163
|
-
common_field_cmp);
|
|
164
|
-
return found ? found->value : Qnil;
|
|
165
|
-
#else /* !HAVE_QSORT_BSEARCH */
|
|
166
140
|
unsigned i;
|
|
167
141
|
struct common_field *cf = common_http_fields;
|
|
168
142
|
for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) {
|
|
@@ -170,20 +144,21 @@ static VALUE find_common_field_value(const char *field, size_t flen)
|
|
|
170
144
|
return cf->value;
|
|
171
145
|
}
|
|
172
146
|
return Qnil;
|
|
173
|
-
#endif /* !HAVE_QSORT_BSEARCH */
|
|
174
147
|
}
|
|
175
148
|
|
|
176
|
-
|
|
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,
|
|
177
154
|
const char *value, size_t vlen)
|
|
178
155
|
{
|
|
179
|
-
VALUE v = Qnil;
|
|
180
156
|
VALUE f = Qnil;
|
|
157
|
+
VALUE v;
|
|
181
158
|
|
|
182
159
|
VALIDATE_MAX_LENGTH(flen, FIELD_NAME);
|
|
183
160
|
VALIDATE_MAX_LENGTH(vlen, FIELD_VALUE);
|
|
184
161
|
|
|
185
|
-
v = rb_str_new(value, vlen);
|
|
186
|
-
|
|
187
162
|
f = find_common_field_value(field, flen);
|
|
188
163
|
|
|
189
164
|
if (f == Qnil) {
|
|
@@ -198,13 +173,29 @@ void http_field(http_parser* hp, const char *field, size_t flen,
|
|
|
198
173
|
memcpy(hp->buf, HTTP_PREFIX, HTTP_PREFIX_LEN);
|
|
199
174
|
memcpy(hp->buf + HTTP_PREFIX_LEN, field, flen);
|
|
200
175
|
|
|
201
|
-
f =
|
|
176
|
+
f = rb_enc_interned_str(hp->buf, new_size, rb_utf8_encoding());
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
while (vlen > 0 && is_ows(value[vlen - 1])) vlen--;
|
|
180
|
+
while (vlen > 0 && is_ows(value[0])) {
|
|
181
|
+
vlen--;
|
|
182
|
+
value++;
|
|
202
183
|
}
|
|
203
184
|
|
|
204
|
-
|
|
185
|
+
/* check for duplicate header */
|
|
186
|
+
v = rb_hash_aref(hp->request, f);
|
|
187
|
+
|
|
188
|
+
if (v == Qnil) {
|
|
189
|
+
v = rb_str_new(value, vlen);
|
|
190
|
+
rb_hash_aset(hp->request, f, v);
|
|
191
|
+
} else {
|
|
192
|
+
/* if duplicate header, normalize to comma-separated values */
|
|
193
|
+
rb_str_cat2(v, ", ");
|
|
194
|
+
rb_str_cat(v, value, vlen);
|
|
195
|
+
}
|
|
205
196
|
}
|
|
206
197
|
|
|
207
|
-
void request_method(
|
|
198
|
+
static void request_method(puma_parser* hp, const char *at, size_t length)
|
|
208
199
|
{
|
|
209
200
|
VALUE val = Qnil;
|
|
210
201
|
|
|
@@ -212,7 +203,7 @@ void request_method(http_parser* hp, const char *at, size_t length)
|
|
|
212
203
|
rb_hash_aset(hp->request, global_request_method, val);
|
|
213
204
|
}
|
|
214
205
|
|
|
215
|
-
void request_uri(
|
|
206
|
+
static void request_uri(puma_parser* hp, const char *at, size_t length)
|
|
216
207
|
{
|
|
217
208
|
VALUE val = Qnil;
|
|
218
209
|
|
|
@@ -222,7 +213,7 @@ void request_uri(http_parser* hp, const char *at, size_t length)
|
|
|
222
213
|
rb_hash_aset(hp->request, global_request_uri, val);
|
|
223
214
|
}
|
|
224
215
|
|
|
225
|
-
void fragment(
|
|
216
|
+
static void fragment(puma_parser* hp, const char *at, size_t length)
|
|
226
217
|
{
|
|
227
218
|
VALUE val = Qnil;
|
|
228
219
|
|
|
@@ -232,7 +223,7 @@ void fragment(http_parser* hp, const char *at, size_t length)
|
|
|
232
223
|
rb_hash_aset(hp->request, global_fragment, val);
|
|
233
224
|
}
|
|
234
225
|
|
|
235
|
-
void request_path(
|
|
226
|
+
static void request_path(puma_parser* hp, const char *at, size_t length)
|
|
236
227
|
{
|
|
237
228
|
VALUE val = Qnil;
|
|
238
229
|
|
|
@@ -242,7 +233,7 @@ void request_path(http_parser* hp, const char *at, size_t length)
|
|
|
242
233
|
rb_hash_aset(hp->request, global_request_path, val);
|
|
243
234
|
}
|
|
244
235
|
|
|
245
|
-
void query_string(
|
|
236
|
+
static void query_string(puma_parser* hp, const char *at, size_t length)
|
|
246
237
|
{
|
|
247
238
|
VALUE val = Qnil;
|
|
248
239
|
|
|
@@ -252,51 +243,74 @@ void query_string(http_parser* hp, const char *at, size_t length)
|
|
|
252
243
|
rb_hash_aset(hp->request, global_query_string, val);
|
|
253
244
|
}
|
|
254
245
|
|
|
255
|
-
void
|
|
246
|
+
static void server_protocol(puma_parser* hp, const char *at, size_t length)
|
|
256
247
|
{
|
|
257
248
|
VALUE val = rb_str_new(at, length);
|
|
258
|
-
rb_hash_aset(hp->request,
|
|
249
|
+
rb_hash_aset(hp->request, global_server_protocol, val);
|
|
259
250
|
}
|
|
260
251
|
|
|
261
252
|
/** Finalizes the request header to have a bunch of stuff that's
|
|
262
253
|
needed. */
|
|
263
254
|
|
|
264
|
-
void header_done(
|
|
255
|
+
static void header_done(puma_parser* hp, const char *at, size_t length)
|
|
265
256
|
{
|
|
266
257
|
hp->body = rb_str_new(at, length);
|
|
267
258
|
}
|
|
268
259
|
|
|
269
260
|
|
|
270
|
-
void
|
|
271
|
-
|
|
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
|
+
}
|
|
272
266
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
267
|
+
static size_t HttpParser_size(const void *ptr) {
|
|
268
|
+
return sizeof(puma_parser);
|
|
276
269
|
}
|
|
277
270
|
|
|
278
|
-
void
|
|
279
|
-
|
|
280
|
-
|
|
271
|
+
static void HttpParser_compact(void *ptr) {
|
|
272
|
+
puma_parser *hp = ptr;
|
|
273
|
+
hp->request = rb_gc_location(hp->request);
|
|
274
|
+
hp->body = rb_gc_location(hp->body);
|
|
281
275
|
}
|
|
282
276
|
|
|
283
|
-
|
|
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,
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
static VALUE HttpParser_alloc(VALUE klass)
|
|
284
289
|
{
|
|
285
|
-
|
|
286
|
-
TRACE();
|
|
290
|
+
puma_parser *hp = ALLOC_N(puma_parser, 1);
|
|
287
291
|
hp->http_field = http_field;
|
|
288
292
|
hp->request_method = request_method;
|
|
289
293
|
hp->request_uri = request_uri;
|
|
290
294
|
hp->fragment = fragment;
|
|
291
295
|
hp->request_path = request_path;
|
|
292
296
|
hp->query_string = query_string;
|
|
293
|
-
hp->
|
|
297
|
+
hp->server_protocol = server_protocol;
|
|
294
298
|
hp->header_done = header_done;
|
|
295
299
|
hp->request = Qnil;
|
|
296
300
|
|
|
297
|
-
|
|
301
|
+
puma_parser_init(hp);
|
|
298
302
|
|
|
299
|
-
return
|
|
303
|
+
return TypedData_Wrap_Struct(klass, &HttpParser_data_type, hp);
|
|
304
|
+
}
|
|
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;
|
|
300
314
|
}
|
|
301
315
|
|
|
302
316
|
/**
|
|
@@ -305,11 +319,10 @@ VALUE HttpParser_alloc(VALUE klass)
|
|
|
305
319
|
*
|
|
306
320
|
* Creates a new parser.
|
|
307
321
|
*/
|
|
308
|
-
VALUE HttpParser_init(VALUE self)
|
|
322
|
+
static VALUE HttpParser_init(VALUE self)
|
|
309
323
|
{
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
http_parser_init(http);
|
|
324
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
325
|
+
puma_parser_init(http);
|
|
313
326
|
|
|
314
327
|
return self;
|
|
315
328
|
}
|
|
@@ -322,11 +335,10 @@ VALUE HttpParser_init(VALUE self)
|
|
|
322
335
|
* Resets the parser to it's initial state so that you can reuse it
|
|
323
336
|
* rather than making new ones.
|
|
324
337
|
*/
|
|
325
|
-
VALUE HttpParser_reset(VALUE self)
|
|
338
|
+
static VALUE HttpParser_reset(VALUE self)
|
|
326
339
|
{
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
http_parser_init(http);
|
|
340
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
341
|
+
puma_parser_init(http);
|
|
330
342
|
|
|
331
343
|
return Qnil;
|
|
332
344
|
}
|
|
@@ -339,13 +351,12 @@ VALUE HttpParser_reset(VALUE self)
|
|
|
339
351
|
* Finishes a parser early which could put in a "good" or bad state.
|
|
340
352
|
* You should call reset after finish it or bad things will happen.
|
|
341
353
|
*/
|
|
342
|
-
VALUE HttpParser_finish(VALUE self)
|
|
354
|
+
static VALUE HttpParser_finish(VALUE self)
|
|
343
355
|
{
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
http_parser_finish(http);
|
|
356
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
357
|
+
puma_parser_finish(http);
|
|
347
358
|
|
|
348
|
-
return
|
|
359
|
+
return puma_parser_is_finished(http) ? Qtrue : Qfalse;
|
|
349
360
|
}
|
|
350
361
|
|
|
351
362
|
|
|
@@ -366,32 +377,28 @@ VALUE HttpParser_finish(VALUE self)
|
|
|
366
377
|
* the parsing from that position. It needs all of the original data as well
|
|
367
378
|
* so you have to append to the data buffer as you read.
|
|
368
379
|
*/
|
|
369
|
-
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)
|
|
370
381
|
{
|
|
371
|
-
|
|
382
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
372
383
|
int from = 0;
|
|
373
384
|
char *dptr = NULL;
|
|
374
385
|
long dlen = 0;
|
|
375
386
|
|
|
376
|
-
DATA_GET(self, http_parser, http);
|
|
377
|
-
|
|
378
387
|
from = FIX2INT(start);
|
|
379
|
-
|
|
388
|
+
RSTRING_GETMEM(data, dptr, dlen);
|
|
380
389
|
|
|
381
390
|
if(from >= dlen) {
|
|
382
|
-
rb_free_chars(dptr);
|
|
383
391
|
rb_raise(eHttpParserError, "%s", "Requested start is after data buffer end.");
|
|
384
392
|
} else {
|
|
385
393
|
http->request = req_hash;
|
|
386
|
-
|
|
394
|
+
puma_parser_execute(http, dptr, dlen, from);
|
|
387
395
|
|
|
388
|
-
|
|
389
|
-
VALIDATE_MAX_LENGTH(http_parser_nread(http), HEADER);
|
|
396
|
+
VALIDATE_MAX_LENGTH(puma_parser_nread(http), HEADER);
|
|
390
397
|
|
|
391
|
-
if(
|
|
392
|
-
rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails.");
|
|
398
|
+
if(puma_parser_has_error(http)) {
|
|
399
|
+
rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails. Are you trying to open an SSL connection to a non-SSL Puma?");
|
|
393
400
|
} else {
|
|
394
|
-
return INT2FIX(
|
|
401
|
+
return INT2FIX(puma_parser_nread(http));
|
|
395
402
|
}
|
|
396
403
|
}
|
|
397
404
|
}
|
|
@@ -404,12 +411,11 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
|
|
|
404
411
|
*
|
|
405
412
|
* Tells you whether the parser is in an error state.
|
|
406
413
|
*/
|
|
407
|
-
VALUE HttpParser_has_error(VALUE self)
|
|
414
|
+
static VALUE HttpParser_has_error(VALUE self)
|
|
408
415
|
{
|
|
409
|
-
|
|
410
|
-
DATA_GET(self, http_parser, http);
|
|
416
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
411
417
|
|
|
412
|
-
return
|
|
418
|
+
return puma_parser_has_error(http) ? Qtrue : Qfalse;
|
|
413
419
|
}
|
|
414
420
|
|
|
415
421
|
|
|
@@ -419,12 +425,11 @@ VALUE HttpParser_has_error(VALUE self)
|
|
|
419
425
|
*
|
|
420
426
|
* Tells you whether the parser is finished or not and in a good state.
|
|
421
427
|
*/
|
|
422
|
-
VALUE HttpParser_is_finished(VALUE self)
|
|
428
|
+
static VALUE HttpParser_is_finished(VALUE self)
|
|
423
429
|
{
|
|
424
|
-
|
|
425
|
-
DATA_GET(self, http_parser, http);
|
|
430
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
426
431
|
|
|
427
|
-
return
|
|
432
|
+
return puma_parser_is_finished(http) ? Qtrue : Qfalse;
|
|
428
433
|
}
|
|
429
434
|
|
|
430
435
|
|
|
@@ -435,10 +440,9 @@ VALUE HttpParser_is_finished(VALUE self)
|
|
|
435
440
|
* Returns the amount of data processed so far during this processing cycle. It is
|
|
436
441
|
* set to 0 on initialize or reset calls and is incremented each time execute is called.
|
|
437
442
|
*/
|
|
438
|
-
VALUE HttpParser_nread(VALUE self)
|
|
443
|
+
static VALUE HttpParser_nread(VALUE self)
|
|
439
444
|
{
|
|
440
|
-
|
|
441
|
-
DATA_GET(self, http_parser, http);
|
|
445
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
442
446
|
|
|
443
447
|
return INT2FIX(http->nread);
|
|
444
448
|
}
|
|
@@ -449,31 +453,34 @@ VALUE HttpParser_nread(VALUE self)
|
|
|
449
453
|
*
|
|
450
454
|
* If the request included a body, returns it.
|
|
451
455
|
*/
|
|
452
|
-
VALUE HttpParser_body(VALUE self) {
|
|
453
|
-
|
|
454
|
-
DATA_GET(self, http_parser, http);
|
|
456
|
+
static VALUE HttpParser_body(VALUE self) {
|
|
457
|
+
puma_parser *http = HttpParser_unwrap(self);
|
|
455
458
|
|
|
456
459
|
return http->body;
|
|
457
460
|
}
|
|
458
461
|
|
|
459
|
-
|
|
462
|
+
#ifdef HAVE_OPENSSL_BIO_H
|
|
460
463
|
void Init_mini_ssl(VALUE mod);
|
|
464
|
+
#endif
|
|
461
465
|
|
|
462
|
-
void Init_puma_http11()
|
|
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);
|
|
@@ -486,6 +493,7 @@ void Init_puma_http11()
|
|
|
486
493
|
rb_define_method(cHttpParser, "body", HttpParser_body, 0);
|
|
487
494
|
init_common_fields();
|
|
488
495
|
|
|
489
|
-
|
|
496
|
+
#ifdef HAVE_OPENSSL_BIO_H
|
|
490
497
|
Init_mini_ssl(mPuma);
|
|
498
|
+
#endif
|
|
491
499
|
}
|