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.
- checksums.yaml +4 -4
- data/History.md +1348 -519
- data/LICENSE +23 -20
- data/README.md +74 -31
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +24 -20
- data/docs/compile_options.md +19 -0
- data/docs/deployment.md +15 -10
- data/docs/fork_worker.md +33 -0
- data/docs/jungle/README.md +9 -0
- data/{tools → docs}/jungle/rc.d/README.md +1 -1
- data/{tools → docs}/jungle/rc.d/puma +2 -2
- data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +66 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +2 -2
- data/docs/rails_dev_mode.md +29 -0
- data/docs/restart.md +46 -23
- data/docs/signals.md +7 -6
- data/docs/stats.md +142 -0
- data/docs/systemd.md +27 -67
- data/ext/puma_http11/PumaHttp11Service.java +2 -4
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +22 -8
- data/ext/puma_http11/http11_parser.c +48 -48
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +1 -1
- data/ext/puma_http11/http11_parser.rl +4 -2
- data/ext/puma_http11/mini_ssl.c +211 -118
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +5 -7
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +77 -18
- data/ext/puma_http11/puma_http11.c +32 -50
- data/lib/puma.rb +46 -0
- data/lib/puma/app/status.rb +48 -35
- data/lib/puma/binder.rb +177 -103
- data/lib/puma/cli.rb +11 -15
- data/lib/puma/client.rb +83 -76
- data/lib/puma/cluster.rb +184 -198
- data/lib/puma/cluster/worker.rb +183 -0
- data/lib/puma/cluster/worker_handle.rb +90 -0
- data/lib/puma/commonlogger.rb +2 -2
- data/lib/puma/configuration.rb +55 -49
- data/lib/puma/const.rb +13 -5
- data/lib/puma/control_cli.rb +93 -76
- data/lib/puma/detect.rb +24 -3
- data/lib/puma/dsl.rb +266 -92
- data/lib/puma/error_logger.rb +104 -0
- data/lib/puma/events.rb +55 -34
- data/lib/puma/io_buffer.rb +9 -2
- data/lib/puma/jruby_restart.rb +0 -58
- data/lib/puma/json.rb +96 -0
- data/lib/puma/launcher.rb +113 -45
- data/lib/puma/minissl.rb +114 -33
- data/lib/puma/minissl/context_builder.rb +6 -3
- data/lib/puma/null_io.rb +13 -1
- data/lib/puma/plugin.rb +1 -10
- data/lib/puma/queue_close.rb +26 -0
- data/lib/puma/rack/builder.rb +0 -4
- data/lib/puma/reactor.rb +85 -369
- data/lib/puma/request.rb +467 -0
- data/lib/puma/runner.rb +29 -58
- data/lib/puma/server.rb +267 -698
- data/lib/puma/single.rb +9 -65
- data/lib/puma/state_file.rb +8 -3
- data/lib/puma/systemd.rb +46 -0
- data/lib/puma/thread_pool.rb +119 -53
- data/lib/puma/util.rb +12 -0
- data/lib/rack/handler/puma.rb +2 -3
- data/tools/{docker/Dockerfile → Dockerfile} +0 -0
- metadata +28 -24
- data/docs/tcp_mode.md +0 -96
- data/ext/puma_http11/io_buffer.c +0 -155
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
- data/lib/puma/accept_nonblock.rb +0 -29
- data/lib/puma/tcp_logger.rb +0 -41
- data/tools/jungle/README.md +0 -19
- data/tools/jungle/init.d/README.md +0 -61
- data/tools/jungle/init.d/puma +0 -421
- data/tools/jungle/init.d/run-puma +0 -18
- data/tools/jungle/upstart/README.md +0 -61
- data/tools/jungle/upstart/puma-manager.conf +0 -31
- 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 =
|
34
|
-
public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the
|
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
|
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
|
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
|
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
|
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
|
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
|
-
|
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,
|
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
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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
|
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(
|
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
|
-
|
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
|
-
|
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
|
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,
|
57
|
-
DEF_MAX_LENGTH(QUERY_STRING,
|
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(
|
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
|
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
|
-
|
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
|
-
|
481
|
+
#ifdef HAVE_OPENSSL_BIO_H
|
501
482
|
Init_mini_ssl(mPuma);
|
483
|
+
#endif
|
502
484
|
}
|