puma 3.12.1 → 5.3.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.

Potentially problematic release.


This version of puma might be problematic. Click here for more details.

Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1414 -448
  3. data/LICENSE +23 -20
  4. data/README.md +131 -60
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +24 -19
  7. data/docs/compile_options.md +19 -0
  8. data/docs/deployment.md +38 -13
  9. data/docs/fork_worker.md +33 -0
  10. data/docs/jungle/README.md +9 -0
  11. data/{tools → docs}/jungle/rc.d/README.md +1 -1
  12. data/{tools → docs}/jungle/rc.d/puma +2 -2
  13. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  14. data/docs/kubernetes.md +66 -0
  15. data/docs/nginx.md +1 -1
  16. data/docs/plugins.md +20 -10
  17. data/docs/rails_dev_mode.md +29 -0
  18. data/docs/restart.md +47 -22
  19. data/docs/signals.md +7 -6
  20. data/docs/stats.md +142 -0
  21. data/docs/systemd.md +48 -70
  22. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  23. data/ext/puma_http11/ext_help.h +1 -1
  24. data/ext/puma_http11/extconf.rb +27 -0
  25. data/ext/puma_http11/http11_parser.c +84 -109
  26. data/ext/puma_http11/http11_parser.h +1 -1
  27. data/ext/puma_http11/http11_parser.java.rl +22 -38
  28. data/ext/puma_http11/http11_parser.rl +4 -2
  29. data/ext/puma_http11/http11_parser_common.rl +3 -3
  30. data/ext/puma_http11/mini_ssl.c +254 -91
  31. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  32. data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
  33. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +89 -106
  34. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +92 -22
  35. data/ext/puma_http11/puma_http11.c +34 -50
  36. data/lib/puma.rb +54 -0
  37. data/lib/puma/app/status.rb +68 -49
  38. data/lib/puma/binder.rb +191 -139
  39. data/lib/puma/cli.rb +15 -15
  40. data/lib/puma/client.rb +257 -228
  41. data/lib/puma/cluster.rb +221 -212
  42. data/lib/puma/cluster/worker.rb +183 -0
  43. data/lib/puma/cluster/worker_handle.rb +90 -0
  44. data/lib/puma/commonlogger.rb +2 -2
  45. data/lib/puma/configuration.rb +58 -51
  46. data/lib/puma/const.rb +39 -19
  47. data/lib/puma/control_cli.rb +109 -67
  48. data/lib/puma/detect.rb +24 -3
  49. data/lib/puma/dsl.rb +519 -121
  50. data/lib/puma/error_logger.rb +104 -0
  51. data/lib/puma/events.rb +55 -31
  52. data/lib/puma/io_buffer.rb +7 -5
  53. data/lib/puma/jruby_restart.rb +0 -58
  54. data/lib/puma/json.rb +96 -0
  55. data/lib/puma/launcher.rb +178 -68
  56. data/lib/puma/minissl.rb +147 -48
  57. data/lib/puma/minissl/context_builder.rb +79 -0
  58. data/lib/puma/null_io.rb +13 -1
  59. data/lib/puma/plugin.rb +6 -12
  60. data/lib/puma/plugin/tmp_restart.rb +2 -0
  61. data/lib/puma/queue_close.rb +26 -0
  62. data/lib/puma/rack/builder.rb +2 -4
  63. data/lib/puma/rack/urlmap.rb +2 -0
  64. data/lib/puma/rack_default.rb +2 -0
  65. data/lib/puma/reactor.rb +85 -316
  66. data/lib/puma/request.rb +467 -0
  67. data/lib/puma/runner.rb +31 -52
  68. data/lib/puma/server.rb +282 -680
  69. data/lib/puma/single.rb +11 -67
  70. data/lib/puma/state_file.rb +8 -3
  71. data/lib/puma/systemd.rb +46 -0
  72. data/lib/puma/thread_pool.rb +129 -81
  73. data/lib/puma/util.rb +13 -6
  74. data/lib/rack/handler/puma.rb +5 -6
  75. data/tools/Dockerfile +16 -0
  76. data/tools/trickletest.rb +0 -1
  77. metadata +42 -26
  78. data/ext/puma_http11/io_buffer.c +0 -155
  79. data/lib/puma/accept_nonblock.rb +0 -23
  80. data/lib/puma/compat.rb +0 -14
  81. data/lib/puma/convenient.rb +0 -25
  82. data/lib/puma/daemon_ext.rb +0 -33
  83. data/lib/puma/delegation.rb +0 -13
  84. data/lib/puma/java_io_buffer.rb +0 -47
  85. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
  86. data/lib/puma/tcp_logger.rb +0 -41
  87. data/tools/jungle/README.md +0 -19
  88. data/tools/jungle/init.d/README.md +0 -61
  89. data/tools/jungle/init.d/puma +0 -421
  90. data/tools/jungle/init.d/run-puma +0 -18
  91. data/tools/jungle/upstart/README.md +0 -61
  92. data/tools/jungle/upstart/puma-manager.conf +0 -31
  93. data/tools/jungle/upstart/puma.conf +0 -69
@@ -22,7 +22,9 @@ import javax.net.ssl.SSLException;
22
22
  import javax.net.ssl.SSLPeerUnverifiedException;
23
23
  import javax.net.ssl.SSLSession;
24
24
  import java.io.FileInputStream;
25
+ import java.io.InputStream;
25
26
  import java.io.IOException;
27
+ import java.nio.Buffer;
26
28
  import java.nio.ByteBuffer;
27
29
  import java.security.KeyManagementException;
28
30
  import java.security.KeyStore;
@@ -31,6 +33,8 @@ import java.security.NoSuchAlgorithmException;
31
33
  import java.security.UnrecoverableKeyException;
32
34
  import java.security.cert.CertificateEncodingException;
33
35
  import java.security.cert.CertificateException;
36
+ import java.util.concurrent.ConcurrentHashMap;
37
+ import java.util.Map;
34
38
 
35
39
  import static javax.net.ssl.SSLEngineResult.Status;
36
40
  import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
@@ -65,7 +69,7 @@ public class MiniSSL extends RubyObject {
65
69
 
66
70
  public void clear() { buffer.clear(); }
67
71
  public void compact() { buffer.compact(); }
68
- public void flip() { buffer.flip(); }
72
+ public void flip() { ((Buffer) buffer).flip(); }
69
73
  public boolean hasRemaining() { return buffer.hasRemaining(); }
70
74
  public int position() { return buffer.position(); }
71
75
 
@@ -89,7 +93,7 @@ public class MiniSSL extends RubyObject {
89
93
  public void resize(int newCapacity) {
90
94
  if (newCapacity > buffer.capacity()) {
91
95
  ByteBuffer dstTmp = ByteBuffer.allocate(newCapacity);
92
- buffer.flip();
96
+ flip();
93
97
  dstTmp.put(buffer);
94
98
  buffer = dstTmp;
95
99
  } else {
@@ -101,7 +105,7 @@ public class MiniSSL extends RubyObject {
101
105
  * Drains the buffer to a ByteList, or returns null for an empty buffer
102
106
  */
103
107
  public ByteList asByteList() {
104
- buffer.flip();
108
+ flip();
105
109
  if (!buffer.hasRemaining()) {
106
110
  buffer.clear();
107
111
  return null;
@@ -119,6 +123,8 @@ public class MiniSSL extends RubyObject {
119
123
  }
120
124
 
121
125
  private SSLEngine engine;
126
+ private boolean closed;
127
+ private boolean handshake;
122
128
  private MiniSSLBuffer inboundNetData;
123
129
  private MiniSSLBuffer outboundAppData;
124
130
  private MiniSSLBuffer outboundNetData;
@@ -127,10 +133,39 @@ public class MiniSSL extends RubyObject {
127
133
  super(runtime, klass);
128
134
  }
129
135
 
136
+ private static Map<String, KeyManagerFactory> keyManagerFactoryMap = new ConcurrentHashMap<String, KeyManagerFactory>();
137
+ private static Map<String, TrustManagerFactory> trustManagerFactoryMap = new ConcurrentHashMap<String, TrustManagerFactory>();
138
+
130
139
  @JRubyMethod(meta = true)
131
- public static IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext) {
132
- RubyClass klass = (RubyClass) recv;
140
+ public static synchronized IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext)
141
+ throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
142
+ // Create the KeyManagerFactory and TrustManagerFactory for this server
143
+ String keystoreFile = miniSSLContext.callMethod(context, "keystore").convertToString().asJavaString();
144
+ char[] password = miniSSLContext.callMethod(context, "keystore_pass").convertToString().asJavaString().toCharArray();
145
+
146
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
147
+ InputStream is = new FileInputStream(keystoreFile);
148
+ try {
149
+ ks.load(is, password);
150
+ } finally {
151
+ is.close();
152
+ }
153
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
154
+ kmf.init(ks, password);
155
+ keyManagerFactoryMap.put(keystoreFile, kmf);
133
156
 
157
+ KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
158
+ is = new FileInputStream(keystoreFile);
159
+ try {
160
+ ts.load(is, password);
161
+ } finally {
162
+ is.close();
163
+ }
164
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
165
+ tmf.init(ts);
166
+ trustManagerFactoryMap.put(keystoreFile, tmf);
167
+
168
+ RubyClass klass = (RubyClass) recv;
134
169
  return klass.newInstance(context,
135
170
  new IRubyObject[] { miniSSLContext },
136
171
  Block.NULL_BLOCK);
@@ -138,31 +173,39 @@ public class MiniSSL extends RubyObject {
138
173
 
139
174
  @JRubyMethod
140
175
  public IRubyObject initialize(ThreadContext threadContext, IRubyObject miniSSLContext)
141
- throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
176
+ throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
142
177
  KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
143
178
  KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
144
179
 
145
- char[] password = miniSSLContext.callMethod(threadContext, "keystore_pass").convertToString().asJavaString().toCharArray();
146
180
  String keystoreFile = miniSSLContext.callMethod(threadContext, "keystore").convertToString().asJavaString();
147
- ks.load(new FileInputStream(keystoreFile), password);
148
- ts.load(new FileInputStream(keystoreFile), password);
149
-
150
- KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
151
- kmf.init(ks, password);
152
-
153
- TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
154
- tmf.init(ts);
181
+ KeyManagerFactory kmf = keyManagerFactoryMap.get(keystoreFile);
182
+ TrustManagerFactory tmf = trustManagerFactoryMap.get(keystoreFile);
183
+ if(kmf == null || tmf == null) {
184
+ throw new KeyStoreException("Could not find KeyManagerFactory/TrustManagerFactory for keystore: " + keystoreFile);
185
+ }
155
186
 
156
187
  SSLContext sslCtx = SSLContext.getInstance("TLS");
157
188
 
158
189
  sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
190
+ closed = false;
191
+ handshake = false;
159
192
  engine = sslCtx.createSSLEngine();
160
193
 
161
- String[] protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
194
+ String[] protocols;
195
+ if(miniSSLContext.callMethod(threadContext, "no_tlsv1").isTrue()) {
196
+ protocols = new String[] { "TLSv1.1", "TLSv1.2" };
197
+ } else {
198
+ protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
199
+ }
200
+
201
+ if(miniSSLContext.callMethod(threadContext, "no_tlsv1_1").isTrue()) {
202
+ protocols = new String[] { "TLSv1.2" };
203
+ }
204
+
162
205
  engine.setEnabledProtocols(protocols);
163
206
  engine.setUseClientMode(false);
164
207
 
165
- long verify_mode = miniSSLContext.callMethod(threadContext, "verify_mode").convertToInteger().getLongValue();
208
+ long verify_mode = miniSSLContext.callMethod(threadContext, "verify_mode").convertToInteger("to_i").getLongValue();
166
209
  if ((verify_mode & 0x1) != 0) { // 'peer'
167
210
  engine.setWantClientAuth(true);
168
211
  }
@@ -229,14 +272,21 @@ public class MiniSSL extends RubyObject {
229
272
  // need to wait for more data to come in before we retry
230
273
  retryOp = false;
231
274
  break;
275
+ case CLOSED:
276
+ closed = true;
277
+ retryOp = false;
278
+ break;
232
279
  default:
233
- // other cases are OK and CLOSED. We're done here.
280
+ // other case is OK. We're done here.
234
281
  retryOp = false;
235
282
  }
283
+ if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) {
284
+ handshake = true;
285
+ }
236
286
  }
237
287
 
238
288
  // after each op, run any delegated tasks if needed
239
- if(engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
289
+ if(res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
240
290
  Runnable runnable;
241
291
  while ((runnable = engine.getDelegatedTask()) != null) {
242
292
  runnable.run();
@@ -260,13 +310,14 @@ public class MiniSSL extends RubyObject {
260
310
 
261
311
  HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
262
312
  boolean done = false;
313
+ SSLEngineResult res = null;
263
314
  while (!done) {
264
315
  switch (handshakeStatus) {
265
316
  case NEED_WRAP:
266
- doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
317
+ res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
267
318
  break;
268
319
  case NEED_UNWRAP:
269
- SSLEngineResult res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
320
+ res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
270
321
  if (res.getStatus() == Status.BUFFER_UNDERFLOW) {
271
322
  // need more data before we can shake more hands
272
323
  done = true;
@@ -275,7 +326,9 @@ public class MiniSSL extends RubyObject {
275
326
  default:
276
327
  done = true;
277
328
  }
278
- handshakeStatus = engine.getHandshakeStatus();
329
+ if (!done) {
330
+ handshakeStatus = res.getHandshakeStatus();
331
+ }
279
332
  }
280
333
 
281
334
  if (inboundNetData.hasRemaining()) {
@@ -349,4 +402,21 @@ public class MiniSSL extends RubyObject {
349
402
  return getRuntime().getNil();
350
403
  }
351
404
  }
405
+
406
+ @JRubyMethod(name = "init?")
407
+ public IRubyObject isInit(ThreadContext context) {
408
+ return handshake ? getRuntime().getFalse() : getRuntime().getTrue();
409
+ }
410
+
411
+ @JRubyMethod
412
+ public IRubyObject shutdown() {
413
+ if (closed || engine.isInboundDone() && engine.isOutboundDone()) {
414
+ if (engine.isOutboundDone()) {
415
+ engine.closeOutbound();
416
+ }
417
+ return getRuntime().getTrue();
418
+ } else {
419
+ return getRuntime().getFalse();
420
+ }
421
+ }
352
422
  }
@@ -10,6 +10,7 @@
10
10
  #include "ext_help.h"
11
11
  #include <assert.h>
12
12
  #include <string.h>
13
+ #include <ctype.h>
13
14
  #include "http11_parser.h"
14
15
 
15
16
  #ifndef MANAGED_STRINGS
@@ -39,7 +40,9 @@ static VALUE global_http_version;
39
40
  static VALUE global_request_path;
40
41
 
41
42
  /** Defines common length and error messages for input length validation. */
42
- #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 (was %d)"
43
+ #define QUOTE(s) #s
44
+ #define EXPLAIN_MAX_LENGTH_VALUE(s) QUOTE(s)
45
+ #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 " EXPLAIN_MAX_LENGTH_VALUE(length) " allowed length (was %d)"
43
46
 
44
47
  /** Validates the max length of given input and throws an HttpParserError exception if over. */
45
48
  #define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR, len); }
@@ -49,12 +52,16 @@ static VALUE global_request_path;
49
52
 
50
53
 
51
54
  /* Defines the maximum allowed lengths for various input elements.*/
55
+ #ifndef PUMA_QUERY_STRING_MAX_LENGTH
56
+ #define PUMA_QUERY_STRING_MAX_LENGTH (1024 * 10)
57
+ #endif
58
+
52
59
  DEF_MAX_LENGTH(FIELD_NAME, 256);
53
60
  DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
54
61
  DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
55
62
  DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
56
- DEF_MAX_LENGTH(REQUEST_PATH, 2048);
57
- DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
63
+ DEF_MAX_LENGTH(REQUEST_PATH, 8192);
64
+ DEF_MAX_LENGTH(QUERY_STRING, PUMA_QUERY_STRING_MAX_LENGTH);
58
65
  DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
59
66
 
60
67
  struct common_field {
@@ -111,21 +118,6 @@ static struct common_field common_http_fields[] = {
111
118
  # undef f
112
119
  };
113
120
 
114
- /*
115
- * qsort(3) and bsearch(3) improve average performance slightly, but may
116
- * not be worth it for lack of portability to certain platforms...
117
- */
118
- #if defined(HAVE_QSORT_BSEARCH)
119
- /* sort by length, then by name if there's a tie */
120
- static int common_field_cmp(const void *a, const void *b)
121
- {
122
- struct common_field *cfa = (struct common_field *)a;
123
- struct common_field *cfb = (struct common_field *)b;
124
- signed long diff = cfa->len - cfb->len;
125
- return diff ? diff : memcmp(cfa->name, cfb->name, cfa->len);
126
- }
127
- #endif /* HAVE_QSORT_BSEARCH */
128
-
129
121
  static void init_common_fields(void)
130
122
  {
131
123
  unsigned i;
@@ -142,28 +134,10 @@ static void init_common_fields(void)
142
134
  }
143
135
  rb_global_variable(&cf->value);
144
136
  }
145
-
146
- #if defined(HAVE_QSORT_BSEARCH)
147
- qsort(common_http_fields,
148
- ARRAY_SIZE(common_http_fields),
149
- sizeof(struct common_field),
150
- common_field_cmp);
151
- #endif /* HAVE_QSORT_BSEARCH */
152
137
  }
153
138
 
154
139
  static VALUE find_common_field_value(const char *field, size_t flen)
155
140
  {
156
- #if defined(HAVE_QSORT_BSEARCH)
157
- struct common_field key;
158
- struct common_field *found;
159
- key.name = field;
160
- key.len = (signed long)flen;
161
- found = (struct common_field *)bsearch(&key, common_http_fields,
162
- ARRAY_SIZE(common_http_fields),
163
- sizeof(struct common_field),
164
- common_field_cmp);
165
- return found ? found->value : Qnil;
166
- #else /* !HAVE_QSORT_BSEARCH */
167
141
  unsigned i;
168
142
  struct common_field *cf = common_http_fields;
169
143
  for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) {
@@ -171,7 +145,6 @@ static VALUE find_common_field_value(const char *field, size_t flen)
171
145
  return cf->value;
172
146
  }
173
147
  return Qnil;
174
- #endif /* !HAVE_QSORT_BSEARCH */
175
148
  }
176
149
 
177
150
  void http_field(puma_parser* hp, const char *field, size_t flen,
@@ -200,6 +173,8 @@ void http_field(puma_parser* hp, const char *field, size_t flen,
200
173
  f = rb_str_new(hp->buf, new_size);
201
174
  }
202
175
 
176
+ while (vlen > 0 && isspace(value[vlen - 1])) vlen--;
177
+
203
178
  /* check for duplicate header */
204
179
  v = rb_hash_aref(hp->request, f);
205
180
 
@@ -284,11 +259,18 @@ void HttpParser_free(void *data) {
284
259
  }
285
260
  }
286
261
 
287
- void HttpParser_mark(puma_parser* hp) {
262
+ void HttpParser_mark(void *ptr) {
263
+ puma_parser *hp = ptr;
288
264
  if(hp->request) rb_gc_mark(hp->request);
289
265
  if(hp->body) rb_gc_mark(hp->body);
290
266
  }
291
267
 
268
+ const rb_data_type_t HttpParser_data_type = {
269
+ "HttpParser",
270
+ { HttpParser_mark, HttpParser_free, 0 },
271
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
272
+ };
273
+
292
274
  VALUE HttpParser_alloc(VALUE klass)
293
275
  {
294
276
  puma_parser *hp = ALLOC_N(puma_parser, 1);
@@ -305,7 +287,7 @@ VALUE HttpParser_alloc(VALUE klass)
305
287
 
306
288
  puma_parser_init(hp);
307
289
 
308
- return Data_Wrap_Struct(klass, HttpParser_mark, HttpParser_free, hp);
290
+ return TypedData_Wrap_Struct(klass, &HttpParser_data_type, hp);
309
291
  }
310
292
 
311
293
  /**
@@ -317,7 +299,7 @@ VALUE HttpParser_alloc(VALUE klass)
317
299
  VALUE HttpParser_init(VALUE self)
318
300
  {
319
301
  puma_parser *http = NULL;
320
- DATA_GET(self, puma_parser, http);
302
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
321
303
  puma_parser_init(http);
322
304
 
323
305
  return self;
@@ -334,7 +316,7 @@ VALUE HttpParser_init(VALUE self)
334
316
  VALUE HttpParser_reset(VALUE self)
335
317
  {
336
318
  puma_parser *http = NULL;
337
- DATA_GET(self, puma_parser, http);
319
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
338
320
  puma_parser_init(http);
339
321
 
340
322
  return Qnil;
@@ -351,7 +333,7 @@ VALUE HttpParser_reset(VALUE self)
351
333
  VALUE HttpParser_finish(VALUE self)
352
334
  {
353
335
  puma_parser *http = NULL;
354
- DATA_GET(self, puma_parser, http);
336
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
355
337
  puma_parser_finish(http);
356
338
 
357
339
  return puma_parser_is_finished(http) ? Qtrue : Qfalse;
@@ -382,7 +364,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
382
364
  char *dptr = NULL;
383
365
  long dlen = 0;
384
366
 
385
- DATA_GET(self, puma_parser, http);
367
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
386
368
 
387
369
  from = FIX2INT(start);
388
370
  dptr = rb_extract_chars(data, &dlen);
@@ -398,7 +380,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
398
380
  VALIDATE_MAX_LENGTH(puma_parser_nread(http), HEADER);
399
381
 
400
382
  if(puma_parser_has_error(http)) {
401
- rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails.");
383
+ rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails. Are you trying to open an SSL connection to a non-SSL Puma?");
402
384
  } else {
403
385
  return INT2FIX(puma_parser_nread(http));
404
386
  }
@@ -416,7 +398,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
416
398
  VALUE HttpParser_has_error(VALUE self)
417
399
  {
418
400
  puma_parser *http = NULL;
419
- DATA_GET(self, puma_parser, http);
401
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
420
402
 
421
403
  return puma_parser_has_error(http) ? Qtrue : Qfalse;
422
404
  }
@@ -431,7 +413,7 @@ VALUE HttpParser_has_error(VALUE self)
431
413
  VALUE HttpParser_is_finished(VALUE self)
432
414
  {
433
415
  puma_parser *http = NULL;
434
- DATA_GET(self, puma_parser, http);
416
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
435
417
 
436
418
  return puma_parser_is_finished(http) ? Qtrue : Qfalse;
437
419
  }
@@ -447,7 +429,7 @@ VALUE HttpParser_is_finished(VALUE self)
447
429
  VALUE HttpParser_nread(VALUE self)
448
430
  {
449
431
  puma_parser *http = NULL;
450
- DATA_GET(self, puma_parser, http);
432
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
451
433
 
452
434
  return INT2FIX(http->nread);
453
435
  }
@@ -460,13 +442,14 @@ VALUE HttpParser_nread(VALUE self)
460
442
  */
461
443
  VALUE HttpParser_body(VALUE self) {
462
444
  puma_parser *http = NULL;
463
- DATA_GET(self, puma_parser, http);
445
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
464
446
 
465
447
  return http->body;
466
448
  }
467
449
 
468
- void Init_io_buffer(VALUE puma);
450
+ #ifdef HAVE_OPENSSL_BIO_H
469
451
  void Init_mini_ssl(VALUE mod);
452
+ #endif
470
453
 
471
454
  void Init_puma_http11()
472
455
  {
@@ -495,6 +478,7 @@ void Init_puma_http11()
495
478
  rb_define_method(cHttpParser, "body", HttpParser_body, 0);
496
479
  init_common_fields();
497
480
 
498
- Init_io_buffer(mPuma);
481
+ #ifdef HAVE_OPENSSL_BIO_H
499
482
  Init_mini_ssl(mPuma);
483
+ #endif
500
484
  }
data/lib/puma.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Standard libraries
2
4
  require 'socket'
3
5
  require 'tempfile'
@@ -8,16 +10,68 @@ require 'stringio'
8
10
 
9
11
  require 'thread'
10
12
 
13
+ require 'puma/puma_http11'
14
+ require 'puma/detect'
15
+ require 'puma/json'
16
+
11
17
  module Puma
12
18
  autoload :Const, 'puma/const'
13
19
  autoload :Server, 'puma/server'
14
20
  autoload :Launcher, 'puma/launcher'
15
21
 
22
+ # at present, MiniSSL::Engine is only defined in extension code (puma_http11),
23
+ # not in minissl.rb
24
+ HAS_SSL = const_defined?(:MiniSSL, false) && MiniSSL.const_defined?(:Engine, false)
25
+
26
+ HAS_UNIX_SOCKET = Object.const_defined? :UNIXSocket
27
+
28
+ if HAS_SSL
29
+ require 'puma/minissl'
30
+ else
31
+ module MiniSSL
32
+ # this class is defined so that it exists when Puma is compiled
33
+ # without ssl support, as Server and Reactor use it in rescue statements.
34
+ class SSLError < StandardError ; end
35
+ end
36
+ end
37
+
38
+ def self.ssl?
39
+ HAS_SSL
40
+ end
41
+
42
+ def self.abstract_unix_socket?
43
+ @abstract_unix ||=
44
+ if HAS_UNIX_SOCKET
45
+ begin
46
+ ::UNIXServer.new("\0puma.temp.unix").close
47
+ true
48
+ rescue ArgumentError # darwin
49
+ false
50
+ end
51
+ else
52
+ false
53
+ end
54
+ end
55
+
56
+ # @!attribute [rw] stats_object=
16
57
  def self.stats_object=(val)
17
58
  @get_stats = val
18
59
  end
19
60
 
61
+ # @!attribute [rw] stats_object
20
62
  def self.stats
63
+ Puma::JSON.generate @get_stats.stats
64
+ end
65
+
66
+ # @!attribute [r] stats_hash
67
+ # @version 5.0.0
68
+ def self.stats_hash
21
69
  @get_stats.stats
22
70
  end
71
+
72
+ # Thread name is new in Ruby 2.3
73
+ def self.set_thread_name(name)
74
+ return unless Thread.current.respond_to?(:name=)
75
+ Thread.current.name = "puma #{name}"
76
+ end
23
77
  end