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.
Files changed (136) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +3334 -0
  3. data/LICENSE +23 -20
  4. data/README.md +387 -100
  5. data/bin/puma-wild +25 -0
  6. data/bin/pumactl +1 -1
  7. data/docs/5.0-Upgrade.md +98 -0
  8. data/docs/6.0-Upgrade.md +56 -0
  9. data/docs/7.0-Upgrade.md +52 -0
  10. data/docs/8.0-Upgrade.md +100 -0
  11. data/docs/architecture.md +74 -0
  12. data/docs/compile_options.md +55 -0
  13. data/docs/deployment.md +137 -0
  14. data/docs/fork_worker.md +41 -0
  15. data/docs/grpc.md +62 -0
  16. data/docs/images/favicon.svg +1 -0
  17. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  18. data/docs/images/puma-connection-flow.png +0 -0
  19. data/docs/images/puma-general-arch.png +0 -0
  20. data/docs/images/running-puma.svg +1 -0
  21. data/docs/images/standard-logo.svg +1 -0
  22. data/docs/java_options.md +54 -0
  23. data/docs/jungle/README.md +9 -0
  24. data/docs/jungle/rc.d/README.md +74 -0
  25. data/docs/jungle/rc.d/puma +61 -0
  26. data/docs/jungle/rc.d/puma.conf +10 -0
  27. data/docs/kubernetes.md +73 -0
  28. data/docs/nginx.md +5 -5
  29. data/docs/plugins.md +42 -0
  30. data/docs/rails_dev_mode.md +28 -0
  31. data/docs/restart.md +65 -0
  32. data/docs/signals.md +98 -0
  33. data/docs/stats.md +148 -0
  34. data/docs/systemd.md +253 -0
  35. data/docs/testing_benchmarks_local_files.md +150 -0
  36. data/docs/testing_test_rackup_ci_files.md +36 -0
  37. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  38. data/ext/puma_http11/extconf.rb +59 -2
  39. data/ext/puma_http11/http11_parser.c +319 -487
  40. data/ext/puma_http11/http11_parser.h +15 -13
  41. data/ext/puma_http11/http11_parser.java.rl +64 -94
  42. data/ext/puma_http11/http11_parser.rl +27 -24
  43. data/ext/puma_http11/http11_parser_common.rl +8 -8
  44. data/ext/puma_http11/mini_ssl.c +696 -38
  45. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  46. data/ext/puma_http11/org/jruby/puma/EnvKey.java +241 -0
  47. data/ext/puma_http11/org/jruby/puma/Http11.java +241 -145
  48. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +174 -221
  49. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +413 -193
  50. data/ext/puma_http11/puma_http11.c +183 -175
  51. data/lib/puma/app/status.rb +77 -29
  52. data/lib/puma/binder.rb +349 -119
  53. data/lib/puma/cli.rb +163 -801
  54. data/lib/puma/client.rb +627 -144
  55. data/lib/puma/client_env.rb +171 -0
  56. data/lib/puma/cluster/worker.rb +183 -0
  57. data/lib/puma/cluster/worker_handle.rb +127 -0
  58. data/lib/puma/cluster.rb +634 -0
  59. data/lib/puma/cluster_accept_loop_delay.rb +91 -0
  60. data/lib/puma/commonlogger.rb +115 -0
  61. data/lib/puma/configuration.rb +420 -198
  62. data/lib/puma/const.rb +266 -115
  63. data/lib/puma/control_cli.rb +219 -120
  64. data/lib/puma/detect.rb +56 -2
  65. data/lib/puma/dsl.rb +1562 -0
  66. data/lib/puma/error_logger.rb +115 -0
  67. data/lib/puma/events.rb +44 -60
  68. data/lib/puma/io_buffer.rb +48 -5
  69. data/lib/puma/jruby_restart.rb +2 -51
  70. data/lib/puma/json_serialization.rb +96 -0
  71. data/lib/puma/launcher/bundle_pruner.rb +102 -0
  72. data/lib/puma/launcher.rb +501 -0
  73. data/lib/puma/log_writer.rb +153 -0
  74. data/lib/puma/minissl/context_builder.rb +96 -0
  75. data/lib/puma/minissl.rb +355 -37
  76. data/lib/puma/null_io.rb +79 -12
  77. data/lib/puma/plugin/systemd.rb +90 -0
  78. data/lib/puma/plugin/tmp_restart.rb +36 -0
  79. data/lib/puma/plugin.rb +111 -0
  80. data/lib/puma/rack/builder.rb +297 -0
  81. data/lib/puma/rack/urlmap.rb +93 -0
  82. data/lib/puma/rack_default.rb +21 -4
  83. data/lib/puma/reactor.rb +102 -133
  84. data/lib/puma/response.rb +532 -0
  85. data/lib/puma/runner.rb +211 -0
  86. data/lib/puma/sd_notify.rb +146 -0
  87. data/lib/puma/server.rb +582 -445
  88. data/lib/puma/server_plugin_control.rb +32 -0
  89. data/lib/puma/single.rb +72 -0
  90. data/lib/puma/state_file.rb +69 -0
  91. data/lib/puma/thread_pool.rb +389 -57
  92. data/lib/puma/util.rb +125 -0
  93. data/lib/puma.rb +80 -6
  94. data/lib/rack/handler/puma.rb +125 -47
  95. data/tools/Dockerfile +26 -0
  96. data/tools/trickletest.rb +44 -0
  97. metadata +88 -148
  98. data/COPYING +0 -55
  99. data/Gemfile +0 -10
  100. data/History.txt +0 -302
  101. data/Manifest.txt +0 -60
  102. data/Rakefile +0 -165
  103. data/TODO +0 -5
  104. data/docs/config.md +0 -0
  105. data/ext/puma_http11/ext_help.h +0 -15
  106. data/ext/puma_http11/io_buffer.c +0 -154
  107. data/lib/puma/accept_nonblock.rb +0 -23
  108. data/lib/puma/capistrano.rb +0 -34
  109. data/lib/puma/compat.rb +0 -11
  110. data/lib/puma/daemon_ext.rb +0 -20
  111. data/lib/puma/delegation.rb +0 -11
  112. data/lib/puma/java_io_buffer.rb +0 -45
  113. data/lib/puma/rack_patch.rb +0 -25
  114. data/puma.gemspec +0 -45
  115. data/test/test_app_status.rb +0 -88
  116. data/test/test_cli.rb +0 -171
  117. data/test/test_config.rb +0 -16
  118. data/test/test_http10.rb +0 -27
  119. data/test/test_http11.rb +0 -126
  120. data/test/test_integration.rb +0 -154
  121. data/test/test_iobuffer.rb +0 -38
  122. data/test/test_minissl.rb +0 -25
  123. data/test/test_null_io.rb +0 -31
  124. data/test/test_persistent.rb +0 -238
  125. data/test/test_puma_server.rb +0 -224
  126. data/test/test_rack_handler.rb +0 -10
  127. data/test/test_rack_server.rb +0 -141
  128. data/test/test_thread_pool.rb +0 -146
  129. data/test/test_unix_socket.rb +0 -39
  130. data/test/test_ws.rb +0 -89
  131. data/tools/jungle/init.d/README.md +0 -54
  132. data/tools/jungle/init.d/puma +0 -332
  133. data/tools/jungle/init.d/run-puma +0 -3
  134. data/tools/jungle/upstart/README.md +0 -61
  135. data/tools/jungle/upstart/puma-manager.conf +0 -31
  136. 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 "ext_help.h"
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
- #ifndef MANAGED_STRINGS
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 global_http_version;
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 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 " # length " allowed length."
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, "%s", MAX_##N##_LENGTH_ERR); }
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
- #define DEF_GLOBAL(N, val) global_##N = rb_str_new2(val); rb_global_variable(&global_##N)
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, 1024 * 12);
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, 1024);
56
- DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
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
- const size_t len;
61
- const char *name;
67
+ const size_t len;
68
+ const char *name;
62
69
  int raw;
63
- VALUE value;
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
- f("ACCEPT"),
75
- f("ACCEPT_CHARSET"),
76
- f("ACCEPT_ENCODING"),
77
- f("ACCEPT_LANGUAGE"),
78
- f("ALLOW"),
79
- f("AUTHORIZATION"),
80
- f("CACHE_CONTROL"),
81
- f("CONNECTION"),
82
- f("CONTENT_ENCODING"),
83
- fr("CONTENT_LENGTH"),
84
- fr("CONTENT_TYPE"),
85
- f("COOKIE"),
86
- f("DATE"),
87
- f("EXPECT"),
88
- f("FROM"),
89
- f("HOST"),
90
- f("IF_MATCH"),
91
- f("IF_MODIFIED_SINCE"),
92
- f("IF_NONE_MATCH"),
93
- f("IF_RANGE"),
94
- f("IF_UNMODIFIED_SINCE"),
95
- f("KEEP_ALIVE"), /* Firefox sends this */
96
- f("MAX_FORWARDS"),
97
- f("PRAGMA"),
98
- f("PROXY_AUTHORIZATION"),
99
- f("RANGE"),
100
- f("REFERER"),
101
- f("TE"),
102
- f("TRAILER"),
103
- f("TRANSFER_ENCODING"),
104
- f("UPGRADE"),
105
- f("USER_AGENT"),
106
- f("VIA"),
107
- f("X_FORWARDED_FOR"), /* common for proxies */
108
- f("X_REAL_IP"), /* common for proxies */
109
- f("WARNING")
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 = rb_str_new(cf->name, cf->len);
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 = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
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
- void http_field(http_parser* hp, const char *field, size_t flen,
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 = rb_str_new(hp->buf, new_size);
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
- rb_hash_aset(hp->request, f, v);
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(http_parser* hp, const char *at, size_t length)
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(http_parser* hp, const char *at, size_t length)
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(http_parser* hp, const char *at, size_t length)
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(http_parser* hp, const char *at, size_t length)
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(http_parser* hp, const char *at, size_t length)
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 http_version(http_parser* hp, const char *at, size_t length)
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, global_http_version, val);
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(http_parser* hp, const char *at, size_t length)
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 HttpParser_free(void *data) {
271
- TRACE();
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
- if(data) {
274
- xfree(data);
275
- }
267
+ static size_t HttpParser_size(const void *ptr) {
268
+ return sizeof(puma_parser);
276
269
  }
277
270
 
278
- void HttpParser_mark(http_parser* hp) {
279
- if(hp->request) rb_gc_mark(hp->request);
280
- if(hp->body) rb_gc_mark(hp->body);
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
- VALUE HttpParser_alloc(VALUE klass)
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
- http_parser *hp = ALLOC_N(http_parser, 1);
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->http_version = http_version;
297
+ hp->server_protocol = server_protocol;
294
298
  hp->header_done = header_done;
295
299
  hp->request = Qnil;
296
300
 
297
- http_parser_init(hp);
301
+ puma_parser_init(hp);
298
302
 
299
- return Data_Wrap_Struct(klass, HttpParser_mark, HttpParser_free, hp);
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
- http_parser *http = NULL;
311
- DATA_GET(self, http_parser, http);
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
- http_parser *http = NULL;
328
- DATA_GET(self, http_parser, http);
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
- http_parser *http = NULL;
345
- DATA_GET(self, http_parser, http);
346
- http_parser_finish(http);
356
+ puma_parser *http = HttpParser_unwrap(self);
357
+ puma_parser_finish(http);
347
358
 
348
- return http_parser_is_finished(http) ? Qtrue : Qfalse;
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
- http_parser *http = NULL;
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
- dptr = rb_extract_chars(data, &dlen);
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
- http_parser_execute(http, dptr, dlen, from);
394
+ puma_parser_execute(http, dptr, dlen, from);
387
395
 
388
- rb_free_chars(dptr);
389
- VALIDATE_MAX_LENGTH(http_parser_nread(http), HEADER);
396
+ VALIDATE_MAX_LENGTH(puma_parser_nread(http), HEADER);
390
397
 
391
- if(http_parser_has_error(http)) {
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(http_parser_nread(http));
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
- http_parser *http = NULL;
410
- DATA_GET(self, http_parser, http);
416
+ puma_parser *http = HttpParser_unwrap(self);
411
417
 
412
- return http_parser_has_error(http) ? Qtrue : Qfalse;
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
- http_parser *http = NULL;
425
- DATA_GET(self, http_parser, http);
430
+ puma_parser *http = HttpParser_unwrap(self);
426
431
 
427
- return http_parser_is_finished(http) ? Qtrue : Qfalse;
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
- http_parser *http = NULL;
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
- http_parser *http = NULL;
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
- void Init_io_buffer(VALUE puma);
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(request_method, "REQUEST_METHOD");
469
- DEF_GLOBAL(request_uri, "REQUEST_URI");
470
- DEF_GLOBAL(fragment, "FRAGMENT");
471
- DEF_GLOBAL(query_string, "QUERY_STRING");
472
- DEF_GLOBAL(http_version, "HTTP_VERSION");
473
- DEF_GLOBAL(request_path, "REQUEST_PATH");
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
- Init_io_buffer(mPuma);
496
+ #ifdef HAVE_OPENSSL_BIO_H
490
497
  Init_mini_ssl(mPuma);
498
+ #endif
491
499
  }