puma 4.3.3 → 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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1348 -519
  3. data/LICENSE +23 -20
  4. data/README.md +74 -31
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +24 -20
  7. data/docs/compile_options.md +19 -0
  8. data/docs/deployment.md +15 -10
  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 +2 -2
  17. data/docs/rails_dev_mode.md +29 -0
  18. data/docs/restart.md +46 -23
  19. data/docs/signals.md +7 -6
  20. data/docs/stats.md +142 -0
  21. data/docs/systemd.md +27 -67
  22. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  23. data/ext/puma_http11/ext_help.h +1 -1
  24. data/ext/puma_http11/extconf.rb +22 -8
  25. data/ext/puma_http11/http11_parser.c +48 -48
  26. data/ext/puma_http11/http11_parser.h +1 -1
  27. data/ext/puma_http11/http11_parser.java.rl +1 -1
  28. data/ext/puma_http11/http11_parser.rl +4 -2
  29. data/ext/puma_http11/mini_ssl.c +211 -118
  30. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  31. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  32. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +5 -7
  33. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +77 -18
  34. data/ext/puma_http11/puma_http11.c +32 -50
  35. data/lib/puma.rb +46 -0
  36. data/lib/puma/app/status.rb +48 -35
  37. data/lib/puma/binder.rb +177 -103
  38. data/lib/puma/cli.rb +11 -15
  39. data/lib/puma/client.rb +83 -76
  40. data/lib/puma/cluster.rb +184 -198
  41. data/lib/puma/cluster/worker.rb +183 -0
  42. data/lib/puma/cluster/worker_handle.rb +90 -0
  43. data/lib/puma/commonlogger.rb +2 -2
  44. data/lib/puma/configuration.rb +55 -49
  45. data/lib/puma/const.rb +13 -5
  46. data/lib/puma/control_cli.rb +93 -76
  47. data/lib/puma/detect.rb +24 -3
  48. data/lib/puma/dsl.rb +266 -92
  49. data/lib/puma/error_logger.rb +104 -0
  50. data/lib/puma/events.rb +55 -34
  51. data/lib/puma/io_buffer.rb +9 -2
  52. data/lib/puma/jruby_restart.rb +0 -58
  53. data/lib/puma/json.rb +96 -0
  54. data/lib/puma/launcher.rb +113 -45
  55. data/lib/puma/minissl.rb +114 -33
  56. data/lib/puma/minissl/context_builder.rb +6 -3
  57. data/lib/puma/null_io.rb +13 -1
  58. data/lib/puma/plugin.rb +1 -10
  59. data/lib/puma/queue_close.rb +26 -0
  60. data/lib/puma/rack/builder.rb +0 -4
  61. data/lib/puma/reactor.rb +85 -369
  62. data/lib/puma/request.rb +467 -0
  63. data/lib/puma/runner.rb +29 -58
  64. data/lib/puma/server.rb +267 -698
  65. data/lib/puma/single.rb +9 -65
  66. data/lib/puma/state_file.rb +8 -3
  67. data/lib/puma/systemd.rb +46 -0
  68. data/lib/puma/thread_pool.rb +119 -53
  69. data/lib/puma/util.rb +12 -0
  70. data/lib/rack/handler/puma.rb +2 -3
  71. data/tools/{docker/Dockerfile → Dockerfile} +0 -0
  72. metadata +28 -24
  73. data/docs/tcp_mode.md +0 -96
  74. data/ext/puma_http11/io_buffer.c +0 -155
  75. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  76. data/lib/puma/accept_nonblock.rb +0 -29
  77. data/lib/puma/tcp_logger.rb +0 -41
  78. data/tools/jungle/README.md +0 -19
  79. data/tools/jungle/init.d/README.md +0 -61
  80. data/tools/jungle/init.d/puma +0 -421
  81. data/tools/jungle/init.d/run-puma +0 -18
  82. data/tools/jungle/upstart/README.md +0 -61
  83. data/tools/jungle/upstart/puma-manager.conf +0 -31
  84. data/tools/jungle/upstart/puma.conf +0 -69
@@ -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
  }
@@ -182,8 +182,6 @@ static final int puma_parser_start = 1;
182
182
  static final int puma_parser_first_final = 46;
183
183
  static final int puma_parser_error = 0;
184
184
 
185
- static final int puma_parser_en_main = 1;
186
-
187
185
 
188
186
  // line 62 "ext/puma_http11/http11_parser.java.rl"
189
187
 
@@ -212,12 +210,12 @@ static final int puma_parser_en_main = 1;
212
210
  cs = 0;
213
211
 
214
212
 
215
- // line 218 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
213
+ // line 214 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
216
214
  {
217
215
  cs = puma_parser_start;
218
216
  }
219
217
 
220
- // line 90 "ext/puma_http11/http11_parser.java.rl"
218
+ // line 88 "ext/puma_http11/http11_parser.java.rl"
221
219
 
222
220
  body_start = 0;
223
221
  content_len = 0;
@@ -244,7 +242,7 @@ static final int puma_parser_en_main = 1;
244
242
  parser.buffer = buffer;
245
243
 
246
244
 
247
- // line 250 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
245
+ // line 246 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
248
246
  {
249
247
  int _klen;
250
248
  int _trans = 0;
@@ -400,7 +398,7 @@ case 1:
400
398
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
401
399
  }
402
400
  break;
403
- // line 406 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
401
+ // line 402 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
404
402
  }
405
403
  }
406
404
  }
@@ -420,7 +418,7 @@ case 5:
420
418
  break; }
421
419
  }
422
420
 
423
- // line 116 "ext/puma_http11/http11_parser.java.rl"
421
+ // line 114 "ext/puma_http11/http11_parser.java.rl"
424
422
 
425
423
  parser.cs = cs;
426
424
  parser.nread += (p - off);
@@ -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
@@ -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,
@@ -286,11 +259,18 @@ void HttpParser_free(void *data) {
286
259
  }
287
260
  }
288
261
 
289
- void HttpParser_mark(puma_parser* hp) {
262
+ void HttpParser_mark(void *ptr) {
263
+ puma_parser *hp = ptr;
290
264
  if(hp->request) rb_gc_mark(hp->request);
291
265
  if(hp->body) rb_gc_mark(hp->body);
292
266
  }
293
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
+
294
274
  VALUE HttpParser_alloc(VALUE klass)
295
275
  {
296
276
  puma_parser *hp = ALLOC_N(puma_parser, 1);
@@ -307,7 +287,7 @@ VALUE HttpParser_alloc(VALUE klass)
307
287
 
308
288
  puma_parser_init(hp);
309
289
 
310
- return Data_Wrap_Struct(klass, HttpParser_mark, HttpParser_free, hp);
290
+ return TypedData_Wrap_Struct(klass, &HttpParser_data_type, hp);
311
291
  }
312
292
 
313
293
  /**
@@ -319,7 +299,7 @@ VALUE HttpParser_alloc(VALUE klass)
319
299
  VALUE HttpParser_init(VALUE self)
320
300
  {
321
301
  puma_parser *http = NULL;
322
- DATA_GET(self, puma_parser, http);
302
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
323
303
  puma_parser_init(http);
324
304
 
325
305
  return self;
@@ -336,7 +316,7 @@ VALUE HttpParser_init(VALUE self)
336
316
  VALUE HttpParser_reset(VALUE self)
337
317
  {
338
318
  puma_parser *http = NULL;
339
- DATA_GET(self, puma_parser, http);
319
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
340
320
  puma_parser_init(http);
341
321
 
342
322
  return Qnil;
@@ -353,7 +333,7 @@ VALUE HttpParser_reset(VALUE self)
353
333
  VALUE HttpParser_finish(VALUE self)
354
334
  {
355
335
  puma_parser *http = NULL;
356
- DATA_GET(self, puma_parser, http);
336
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
357
337
  puma_parser_finish(http);
358
338
 
359
339
  return puma_parser_is_finished(http) ? Qtrue : Qfalse;
@@ -384,7 +364,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
384
364
  char *dptr = NULL;
385
365
  long dlen = 0;
386
366
 
387
- DATA_GET(self, puma_parser, http);
367
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
388
368
 
389
369
  from = FIX2INT(start);
390
370
  dptr = rb_extract_chars(data, &dlen);
@@ -400,7 +380,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
400
380
  VALIDATE_MAX_LENGTH(puma_parser_nread(http), HEADER);
401
381
 
402
382
  if(puma_parser_has_error(http)) {
403
- 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?");
404
384
  } else {
405
385
  return INT2FIX(puma_parser_nread(http));
406
386
  }
@@ -418,7 +398,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
418
398
  VALUE HttpParser_has_error(VALUE self)
419
399
  {
420
400
  puma_parser *http = NULL;
421
- DATA_GET(self, puma_parser, http);
401
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
422
402
 
423
403
  return puma_parser_has_error(http) ? Qtrue : Qfalse;
424
404
  }
@@ -433,7 +413,7 @@ VALUE HttpParser_has_error(VALUE self)
433
413
  VALUE HttpParser_is_finished(VALUE self)
434
414
  {
435
415
  puma_parser *http = NULL;
436
- DATA_GET(self, puma_parser, http);
416
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
437
417
 
438
418
  return puma_parser_is_finished(http) ? Qtrue : Qfalse;
439
419
  }
@@ -449,7 +429,7 @@ VALUE HttpParser_is_finished(VALUE self)
449
429
  VALUE HttpParser_nread(VALUE self)
450
430
  {
451
431
  puma_parser *http = NULL;
452
- DATA_GET(self, puma_parser, http);
432
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
453
433
 
454
434
  return INT2FIX(http->nread);
455
435
  }
@@ -462,13 +442,14 @@ VALUE HttpParser_nread(VALUE self)
462
442
  */
463
443
  VALUE HttpParser_body(VALUE self) {
464
444
  puma_parser *http = NULL;
465
- DATA_GET(self, puma_parser, http);
445
+ DATA_GET(self, puma_parser, &HttpParser_data_type, http);
466
446
 
467
447
  return http->body;
468
448
  }
469
449
 
470
- void Init_io_buffer(VALUE puma);
450
+ #ifdef HAVE_OPENSSL_BIO_H
471
451
  void Init_mini_ssl(VALUE mod);
452
+ #endif
472
453
 
473
454
  void Init_puma_http11()
474
455
  {
@@ -497,6 +478,7 @@ void Init_puma_http11()
497
478
  rb_define_method(cHttpParser, "body", HttpParser_body, 0);
498
479
  init_common_fields();
499
480
 
500
- Init_io_buffer(mPuma);
481
+ #ifdef HAVE_OPENSSL_BIO_H
501
482
  Init_mini_ssl(mPuma);
483
+ #endif
502
484
  }