puma 4.3.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +94 -3
  3. data/LICENSE +23 -20
  4. data/README.md +26 -13
  5. data/docs/architecture.md +3 -3
  6. data/docs/deployment.md +9 -3
  7. data/docs/fork_worker.md +31 -0
  8. data/docs/jungle/README.md +13 -0
  9. data/{tools → docs}/jungle/rc.d/README.md +0 -0
  10. data/{tools → docs}/jungle/rc.d/puma +0 -0
  11. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  12. data/{tools → docs}/jungle/upstart/README.md +0 -0
  13. data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
  14. data/{tools → docs}/jungle/upstart/puma.conf +0 -0
  15. data/docs/signals.md +7 -6
  16. data/docs/systemd.md +1 -63
  17. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  18. data/ext/puma_http11/extconf.rb +4 -3
  19. data/ext/puma_http11/http11_parser.c +3 -1
  20. data/ext/puma_http11/http11_parser.rl +3 -1
  21. data/ext/puma_http11/mini_ssl.c +15 -2
  22. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  23. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  24. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +77 -18
  25. data/ext/puma_http11/puma_http11.c +7 -38
  26. data/lib/puma.rb +17 -0
  27. data/lib/puma/app/status.rb +18 -3
  28. data/lib/puma/binder.rb +88 -68
  29. data/lib/puma/cli.rb +7 -15
  30. data/lib/puma/client.rb +67 -14
  31. data/lib/puma/cluster.rb +191 -74
  32. data/lib/puma/commonlogger.rb +2 -2
  33. data/lib/puma/configuration.rb +31 -42
  34. data/lib/puma/const.rb +4 -3
  35. data/lib/puma/control_cli.rb +29 -17
  36. data/lib/puma/detect.rb +17 -0
  37. data/lib/puma/dsl.rb +144 -70
  38. data/lib/puma/error_logger.rb +97 -0
  39. data/lib/puma/events.rb +35 -31
  40. data/lib/puma/io_buffer.rb +9 -2
  41. data/lib/puma/jruby_restart.rb +0 -58
  42. data/lib/puma/launcher.rb +49 -31
  43. data/lib/puma/minissl.rb +60 -18
  44. data/lib/puma/minissl/context_builder.rb +0 -3
  45. data/lib/puma/null_io.rb +1 -1
  46. data/lib/puma/plugin.rb +1 -10
  47. data/lib/puma/rack/builder.rb +0 -4
  48. data/lib/puma/reactor.rb +9 -4
  49. data/lib/puma/runner.rb +8 -36
  50. data/lib/puma/server.rb +149 -186
  51. data/lib/puma/single.rb +7 -64
  52. data/lib/puma/state_file.rb +6 -3
  53. data/lib/puma/thread_pool.rb +94 -49
  54. data/lib/rack/handler/puma.rb +1 -3
  55. data/tools/{docker/Dockerfile → Dockerfile} +0 -0
  56. metadata +21 -23
  57. data/docs/tcp_mode.md +0 -96
  58. data/ext/puma_http11/io_buffer.c +0 -155
  59. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  60. data/lib/puma/tcp_logger.rb +0 -41
  61. data/tools/jungle/README.md +0 -19
  62. data/tools/jungle/init.d/README.md +0 -61
  63. data/tools/jungle/init.d/puma +0 -421
  64. data/tools/jungle/init.d/run-puma +0 -18
@@ -1,18 +1,16 @@
1
1
  package puma;
2
2
 
3
3
  import java.io.IOException;
4
-
4
+
5
5
  import org.jruby.Ruby;
6
6
  import org.jruby.runtime.load.BasicLibraryService;
7
7
 
8
8
  import org.jruby.puma.Http11;
9
- import org.jruby.puma.IOBuffer;
10
9
  import org.jruby.puma.MiniSSL;
11
10
 
12
- public class PumaHttp11Service implements BasicLibraryService {
11
+ public class PumaHttp11Service implements BasicLibraryService {
13
12
  public boolean basicLoad(final Ruby runtime) throws IOException {
14
13
  Http11.createHttp11(runtime);
15
- IOBuffer.createIOBuffer(runtime);
16
14
  MiniSSL.createMiniSSL(runtime);
17
15
  return true;
18
16
  }
@@ -1,9 +1,10 @@
1
1
  require 'mkmf'
2
2
 
3
3
  dir_config("puma_http11")
4
- if RUBY_PLATFORM[/mingw32/]
5
- append_cflags '-D_FORTIFY_SOURCE=2'
6
- append_ldflags '-fstack-protector'
4
+
5
+ if $mingw && RUBY_VERSION >= '2.4'
6
+ append_cflags '-fstack-protector-strong -D_FORTIFY_SOURCE=2'
7
+ append_ldflags '-fstack-protector-strong -l:libssp.a'
7
8
  have_library 'ssp'
8
9
  end
9
10
 
@@ -14,12 +14,14 @@
14
14
 
15
15
  /*
16
16
  * capitalizes all lower-case ASCII characters,
17
- * converts dashes to underscores.
17
+ * converts dashes to underscores, and underscores to commas.
18
18
  */
19
19
  static void snake_upcase_char(char *c)
20
20
  {
21
21
  if (*c >= 'a' && *c <= 'z')
22
22
  *c &= ~0x20;
23
+ else if (*c == '_')
24
+ *c = ',';
23
25
  else if (*c == '-')
24
26
  *c = '_';
25
27
  }
@@ -12,12 +12,14 @@
12
12
 
13
13
  /*
14
14
  * capitalizes all lower-case ASCII characters,
15
- * converts dashes to underscores.
15
+ * converts dashes to underscores, and underscores to commas.
16
16
  */
17
17
  static void snake_upcase_char(char *c)
18
18
  {
19
19
  if (*c >= 'a' && *c <= 'z')
20
20
  *c &= ~0x20;
21
+ else if (*c == '_')
22
+ *c = ',';
21
23
  else if (*c == '-')
22
24
  *c = '_';
23
25
  }
@@ -301,6 +301,7 @@ void raise_error(SSL* ssl, int result) {
301
301
  char msg[512];
302
302
  const char* err_str;
303
303
  int err = errno;
304
+ int mask = 4095;
304
305
  int ssl_err = SSL_get_error(ssl, result);
305
306
  int verify_err = (int) SSL_get_verify_result(ssl);
306
307
 
@@ -317,8 +318,8 @@ void raise_error(SSL* ssl, int result) {
317
318
  } else {
318
319
  err = (int) ERR_get_error();
319
320
  ERR_error_string_n(err, buf, sizeof(buf));
320
- snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err);
321
-
321
+ int errexp = err & mask;
322
+ snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, errexp);
322
323
  }
323
324
  } else {
324
325
  snprintf(msg, sizeof(msg), "Unknown OpenSSL error: %d", ssl_err);
@@ -462,6 +463,16 @@ VALUE engine_peercert(VALUE self) {
462
463
  return rb_cert_buf;
463
464
  }
464
465
 
466
+ /* @see Puma::MiniSSL::Socket#ssl_version_state
467
+ * @version 5.0.0
468
+ */
469
+ static VALUE
470
+ engine_ssl_vers_st(VALUE self) {
471
+ ms_conn* conn;
472
+ Data_Get_Struct(self, ms_conn, conn);
473
+ return rb_ary_new3(2, rb_str_new2(SSL_get_version(conn->ssl)), rb_str_new2(SSL_state_string(conn->ssl)));
474
+ }
475
+
465
476
  VALUE noop(VALUE self) {
466
477
  return Qnil;
467
478
  }
@@ -533,6 +544,8 @@ void Init_mini_ssl(VALUE puma) {
533
544
  rb_define_method(eng, "init?", engine_init, 0);
534
545
 
535
546
  rb_define_method(eng, "peercert", engine_peercert, 0);
547
+
548
+ rb_define_method(eng, "ssl_vers_st", engine_ssl_vers_st, 0);
536
549
  }
537
550
 
538
551
  #else
@@ -0,0 +1,15 @@
1
+ package puma;
2
+
3
+ import java.io.IOException;
4
+
5
+ import org.jruby.Ruby;
6
+ import org.jruby.runtime.load.BasicLibraryService;
7
+
8
+ import org.jruby.puma.Http11;
9
+
10
+ public class PumaHttp11Service implements BasicLibraryService {
11
+ public boolean basicLoad(final Ruby runtime) throws IOException {
12
+ Http11.createHttp11(runtime);
13
+ return true;
14
+ }
15
+ }
@@ -30,8 +30,8 @@ public class Http11 extends RubyObject {
30
30
  public final static String MAX_REQUEST_URI_LENGTH_ERR = "HTTP element REQUEST_URI is longer than the 12288 allowed length.";
31
31
  public final static int MAX_FRAGMENT_LENGTH = 1024;
32
32
  public final static String MAX_FRAGMENT_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 1024 allowed length.";
33
- public final static int MAX_REQUEST_PATH_LENGTH = 2048;
34
- public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 2048 allowed length.";
33
+ public final static int MAX_REQUEST_PATH_LENGTH = 8192;
34
+ public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 8192 allowed length.";
35
35
  public final static int MAX_QUERY_STRING_LENGTH = 1024 * 10;
36
36
  public final static String MAX_QUERY_STRING_LENGTH_ERR = "HTTP element QUERY_STRING is longer than the 10240 allowed length.";
37
37
  public final static int MAX_HEADER_LENGTH = 1024 * (80 + 32);
@@ -197,7 +197,7 @@ public class Http11 extends RubyObject {
197
197
  validateMaxLength(runtime, parser.nread,MAX_HEADER_LENGTH, MAX_HEADER_LENGTH_ERR);
198
198
 
199
199
  if(hp.has_error()) {
200
- throw newHTTPParserError(runtime, "Invalid HTTP format, parsing fails.");
200
+ throw newHTTPParserError(runtime, "Invalid HTTP format, parsing fails. Are you trying to open an SSL connection to a non-SSL Puma?");
201
201
  } else {
202
202
  return runtime.newFixnum(parser.nread);
203
203
  }
@@ -22,6 +22,7 @@ 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;
26
27
  import java.nio.Buffer;
27
28
  import java.nio.ByteBuffer;
@@ -32,6 +33,8 @@ import java.security.NoSuchAlgorithmException;
32
33
  import java.security.UnrecoverableKeyException;
33
34
  import java.security.cert.CertificateEncodingException;
34
35
  import java.security.cert.CertificateException;
36
+ import java.util.concurrent.ConcurrentHashMap;
37
+ import java.util.Map;
35
38
 
36
39
  import static javax.net.ssl.SSLEngineResult.Status;
37
40
  import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
@@ -120,6 +123,8 @@ public class MiniSSL extends RubyObject {
120
123
  }
121
124
 
122
125
  private SSLEngine engine;
126
+ private boolean closed;
127
+ private boolean handshake;
123
128
  private MiniSSLBuffer inboundNetData;
124
129
  private MiniSSLBuffer outboundAppData;
125
130
  private MiniSSLBuffer outboundNetData;
@@ -128,10 +133,39 @@ public class MiniSSL extends RubyObject {
128
133
  super(runtime, klass);
129
134
  }
130
135
 
136
+ private static Map<String, KeyManagerFactory> keyManagerFactoryMap = new ConcurrentHashMap<String, KeyManagerFactory>();
137
+ private static Map<String, TrustManagerFactory> trustManagerFactoryMap = new ConcurrentHashMap<String, TrustManagerFactory>();
138
+
131
139
  @JRubyMethod(meta = true)
132
- public static IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext) {
133
- 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();
134
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);
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;
135
169
  return klass.newInstance(context,
136
170
  new IRubyObject[] { miniSSLContext },
137
171
  Block.NULL_BLOCK);
@@ -139,24 +173,22 @@ public class MiniSSL extends RubyObject {
139
173
 
140
174
  @JRubyMethod
141
175
  public IRubyObject initialize(ThreadContext threadContext, IRubyObject miniSSLContext)
142
- throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
176
+ throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
143
177
  KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
144
178
  KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
145
179
 
146
- char[] password = miniSSLContext.callMethod(threadContext, "keystore_pass").convertToString().asJavaString().toCharArray();
147
180
  String keystoreFile = miniSSLContext.callMethod(threadContext, "keystore").convertToString().asJavaString();
148
- ks.load(new FileInputStream(keystoreFile), password);
149
- ts.load(new FileInputStream(keystoreFile), password);
150
-
151
- KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
152
- kmf.init(ks, password);
153
-
154
- TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
155
- 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
+ }
156
186
 
157
187
  SSLContext sslCtx = SSLContext.getInstance("TLS");
158
188
 
159
189
  sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
190
+ closed = false;
191
+ handshake = false;
160
192
  engine = sslCtx.createSSLEngine();
161
193
 
162
194
  String[] protocols;
@@ -173,7 +205,7 @@ public class MiniSSL extends RubyObject {
173
205
  engine.setEnabledProtocols(protocols);
174
206
  engine.setUseClientMode(false);
175
207
 
176
- long verify_mode = miniSSLContext.callMethod(threadContext, "verify_mode").convertToInteger().getLongValue();
208
+ long verify_mode = miniSSLContext.callMethod(threadContext, "verify_mode").convertToInteger("to_i").getLongValue();
177
209
  if ((verify_mode & 0x1) != 0) { // 'peer'
178
210
  engine.setWantClientAuth(true);
179
211
  }
@@ -240,14 +272,21 @@ public class MiniSSL extends RubyObject {
240
272
  // need to wait for more data to come in before we retry
241
273
  retryOp = false;
242
274
  break;
275
+ case CLOSED:
276
+ closed = true;
277
+ retryOp = false;
278
+ break;
243
279
  default:
244
- // other cases are OK and CLOSED. We're done here.
280
+ // other case is OK. We're done here.
245
281
  retryOp = false;
246
282
  }
283
+ if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) {
284
+ handshake = true;
285
+ }
247
286
  }
248
287
 
249
288
  // after each op, run any delegated tasks if needed
250
- if(engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
289
+ if(res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
251
290
  Runnable runnable;
252
291
  while ((runnable = engine.getDelegatedTask()) != null) {
253
292
  runnable.run();
@@ -271,13 +310,14 @@ public class MiniSSL extends RubyObject {
271
310
 
272
311
  HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
273
312
  boolean done = false;
313
+ SSLEngineResult res = null;
274
314
  while (!done) {
275
315
  switch (handshakeStatus) {
276
316
  case NEED_WRAP:
277
- doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
317
+ res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
278
318
  break;
279
319
  case NEED_UNWRAP:
280
- SSLEngineResult res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
320
+ res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
281
321
  if (res.getStatus() == Status.BUFFER_UNDERFLOW) {
282
322
  // need more data before we can shake more hands
283
323
  done = true;
@@ -286,7 +326,9 @@ public class MiniSSL extends RubyObject {
286
326
  default:
287
327
  done = true;
288
328
  }
289
- handshakeStatus = engine.getHandshakeStatus();
329
+ if (!done) {
330
+ handshakeStatus = res.getHandshakeStatus();
331
+ }
290
332
  }
291
333
 
292
334
  if (inboundNetData.hasRemaining()) {
@@ -360,4 +402,21 @@ public class MiniSSL extends RubyObject {
360
402
  return getRuntime().getNil();
361
403
  }
362
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
+ }
363
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
@@ -53,7 +54,7 @@ DEF_MAX_LENGTH(FIELD_NAME, 256);
53
54
  DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
54
55
  DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
55
56
  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(REQUEST_PATH, 8192);
57
58
  DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
58
59
  DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
59
60
 
@@ -111,21 +112,6 @@ static struct common_field common_http_fields[] = {
111
112
  # undef f
112
113
  };
113
114
 
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
115
  static void init_common_fields(void)
130
116
  {
131
117
  unsigned i;
@@ -142,28 +128,10 @@ static void init_common_fields(void)
142
128
  }
143
129
  rb_global_variable(&cf->value);
144
130
  }
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
131
  }
153
132
 
154
133
  static VALUE find_common_field_value(const char *field, size_t flen)
155
134
  {
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
135
  unsigned i;
168
136
  struct common_field *cf = common_http_fields;
169
137
  for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) {
@@ -171,7 +139,6 @@ static VALUE find_common_field_value(const char *field, size_t flen)
171
139
  return cf->value;
172
140
  }
173
141
  return Qnil;
174
- #endif /* !HAVE_QSORT_BSEARCH */
175
142
  }
176
143
 
177
144
  void http_field(puma_parser* hp, const char *field, size_t flen,
@@ -400,7 +367,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
400
367
  VALIDATE_MAX_LENGTH(puma_parser_nread(http), HEADER);
401
368
 
402
369
  if(puma_parser_has_error(http)) {
403
- rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails.");
370
+ rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails. Are you trying to open an SSL connection to a non-SSL Puma?");
404
371
  } else {
405
372
  return INT2FIX(puma_parser_nread(http));
406
373
  }
@@ -467,8 +434,9 @@ VALUE HttpParser_body(VALUE self) {
467
434
  return http->body;
468
435
  }
469
436
 
470
- void Init_io_buffer(VALUE puma);
437
+ #ifdef HAVE_OPENSSL_BIO_H
471
438
  void Init_mini_ssl(VALUE mod);
439
+ #endif
472
440
 
473
441
  void Init_puma_http11()
474
442
  {
@@ -497,6 +465,7 @@ void Init_puma_http11()
497
465
  rb_define_method(cHttpParser, "body", HttpParser_body, 0);
498
466
  init_common_fields();
499
467
 
500
- Init_io_buffer(mPuma);
468
+ #ifdef HAVE_OPENSSL_BIO_H
501
469
  Init_mini_ssl(mPuma);
470
+ #endif
502
471
  }
@@ -10,6 +10,9 @@ require 'stringio'
10
10
 
11
11
  require 'thread'
12
12
 
13
+ require_relative 'puma/puma_http11'
14
+ require_relative 'puma/detect'
15
+
13
16
  module Puma
14
17
  autoload :Const, 'puma/const'
15
18
  autoload :Server, 'puma/server'
@@ -20,6 +23,12 @@ module Puma
20
23
  end
21
24
 
22
25
  def self.stats
26
+ require 'json'
27
+ @get_stats.stats.to_json
28
+ end
29
+
30
+ # @version 5.0.0
31
+ def self.stats_hash
23
32
  @get_stats.stats
24
33
  end
25
34
 
@@ -28,4 +37,12 @@ module Puma
28
37
  return unless Thread.current.respond_to?(:name=)
29
38
  Thread.current.name = "puma #{name}"
30
39
  end
40
+
41
+ unless HAS_SSL
42
+ module MiniSSL
43
+ # this class is defined so that it exists when Puma is compiled
44
+ # without ssl support, as Server and Reactor use it in rescue statements.
45
+ class SSLError < StandardError ; end
46
+ end
47
+ end
31
48
  end