puma 5.6.4 → 6.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +372 -6
- data/LICENSE +0 -0
- data/README.md +79 -29
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +0 -0
- data/docs/compile_options.md +34 -0
- data/docs/deployment.md +0 -0
- data/docs/fork_worker.md +1 -3
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/jungle/README.md +0 -0
- data/docs/jungle/rc.d/README.md +0 -0
- data/docs/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +12 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +0 -0
- data/docs/rails_dev_mode.md +0 -0
- data/docs/restart.md +1 -0
- data/docs/signals.md +0 -0
- data/docs/stats.md +0 -0
- data/docs/systemd.md +3 -6
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +22 -10
- data/ext/puma_http11/http11_parser.c +1 -1
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +2 -2
- data/ext/puma_http11/http11_parser.rl +2 -2
- data/ext/puma_http11/http11_parser_common.rl +2 -2
- data/ext/puma_http11/mini_ssl.c +153 -27
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +167 -65
- data/ext/puma_http11/puma_http11.c +17 -9
- data/lib/puma/app/status.rb +7 -4
- data/lib/puma/binder.rb +51 -54
- data/lib/puma/cli.rb +16 -18
- data/lib/puma/client.rb +100 -26
- data/lib/puma/cluster/worker.rb +18 -11
- data/lib/puma/cluster/worker_handle.rb +4 -1
- data/lib/puma/cluster.rb +102 -40
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +77 -59
- data/lib/puma/const.rb +129 -92
- data/lib/puma/control_cli.rb +33 -23
- data/lib/puma/detect.rb +7 -4
- data/lib/puma/dsl.rb +251 -53
- data/lib/puma/error_logger.rb +18 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +39 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/json_serialization.rb +0 -0
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +113 -175
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +26 -12
- data/lib/puma/minissl.rb +113 -15
- data/lib/puma/null_io.rb +21 -2
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +0 -0
- data/lib/puma/rack/builder.rb +6 -6
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +365 -166
- data/lib/puma/runner.rb +56 -20
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +137 -87
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +4 -6
- data/lib/puma/thread_pool.rb +57 -19
- data/lib/puma/util.rb +12 -14
- data/lib/puma.rb +12 -11
- data/lib/rack/handler/puma.rb +113 -86
- data/tools/Dockerfile +2 -2
- data/tools/trickletest.rb +0 -0
- metadata +11 -6
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
@@ -1,6 +1,7 @@
|
|
1
1
|
package org.jruby.puma;
|
2
2
|
|
3
3
|
import org.jruby.Ruby;
|
4
|
+
import org.jruby.RubyArray;
|
4
5
|
import org.jruby.RubyClass;
|
5
6
|
import org.jruby.RubyModule;
|
6
7
|
import org.jruby.RubyObject;
|
@@ -15,6 +16,7 @@ import org.jruby.runtime.builtin.IRubyObject;
|
|
15
16
|
import org.jruby.util.ByteList;
|
16
17
|
|
17
18
|
import javax.net.ssl.KeyManagerFactory;
|
19
|
+
import javax.net.ssl.TrustManager;
|
18
20
|
import javax.net.ssl.TrustManagerFactory;
|
19
21
|
import javax.net.ssl.SSLContext;
|
20
22
|
import javax.net.ssl.SSLEngine;
|
@@ -22,6 +24,7 @@ import javax.net.ssl.SSLEngineResult;
|
|
22
24
|
import javax.net.ssl.SSLException;
|
23
25
|
import javax.net.ssl.SSLPeerUnverifiedException;
|
24
26
|
import javax.net.ssl.SSLSession;
|
27
|
+
import javax.net.ssl.X509TrustManager;
|
25
28
|
import java.io.FileInputStream;
|
26
29
|
import java.io.InputStream;
|
27
30
|
import java.io.IOException;
|
@@ -32,15 +35,19 @@ import java.security.KeyStore;
|
|
32
35
|
import java.security.KeyStoreException;
|
33
36
|
import java.security.NoSuchAlgorithmException;
|
34
37
|
import java.security.UnrecoverableKeyException;
|
38
|
+
import java.security.cert.Certificate;
|
35
39
|
import java.security.cert.CertificateEncodingException;
|
36
40
|
import java.security.cert.CertificateException;
|
41
|
+
import java.security.cert.X509Certificate;
|
37
42
|
import java.util.concurrent.ConcurrentHashMap;
|
38
43
|
import java.util.Map;
|
44
|
+
import java.util.function.Supplier;
|
39
45
|
|
40
46
|
import static javax.net.ssl.SSLEngineResult.Status;
|
41
47
|
import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
42
48
|
|
43
|
-
public class MiniSSL extends RubyObject {
|
49
|
+
public class MiniSSL extends RubyObject { // MiniSSL::Engine
|
50
|
+
private static final long serialVersionUID = -6903439483039141234L;
|
44
51
|
private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
45
52
|
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
46
53
|
return new MiniSSL(runtime, klass);
|
@@ -51,11 +58,10 @@ public class MiniSSL extends RubyObject {
|
|
51
58
|
RubyModule mPuma = runtime.defineModule("Puma");
|
52
59
|
RubyModule ssl = mPuma.defineModuleUnder("MiniSSL");
|
53
60
|
|
54
|
-
|
55
|
-
|
56
|
-
runtime.getClass("IOError").getAllocator());
|
61
|
+
// Puma::MiniSSL::SSLError
|
62
|
+
ssl.defineClassUnder("SSLError", runtime.getStandardError(), runtime.getStandardError().getAllocator());
|
57
63
|
|
58
|
-
RubyClass eng = ssl.defineClassUnder("Engine",runtime.getObject(),ALLOCATOR);
|
64
|
+
RubyClass eng = ssl.defineClassUnder("Engine", runtime.getObject(), ALLOCATOR);
|
59
65
|
eng.defineAnnotatedMethods(MiniSSL.class);
|
60
66
|
}
|
61
67
|
|
@@ -137,74 +143,116 @@ public class MiniSSL extends RubyObject {
|
|
137
143
|
private static Map<String, KeyManagerFactory> keyManagerFactoryMap = new ConcurrentHashMap<String, KeyManagerFactory>();
|
138
144
|
private static Map<String, TrustManagerFactory> trustManagerFactoryMap = new ConcurrentHashMap<String, TrustManagerFactory>();
|
139
145
|
|
140
|
-
@JRubyMethod(meta = true)
|
146
|
+
@JRubyMethod(meta = true) // Engine.server
|
141
147
|
public static synchronized IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext)
|
142
148
|
throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
|
143
149
|
// Create the KeyManagerFactory and TrustManagerFactory for this server
|
144
|
-
String keystoreFile = miniSSLContext.callMethod(context, "keystore")
|
145
|
-
char[]
|
150
|
+
String keystoreFile = asStringValue(miniSSLContext.callMethod(context, "keystore"), null);
|
151
|
+
char[] keystorePass = asStringValue(miniSSLContext.callMethod(context, "keystore_pass"), null).toCharArray();
|
152
|
+
String keystoreType = asStringValue(miniSSLContext.callMethod(context, "keystore_type"), KeyStore::getDefaultType);
|
153
|
+
|
154
|
+
String truststoreFile;
|
155
|
+
char[] truststorePass;
|
156
|
+
String truststoreType;
|
157
|
+
IRubyObject truststore = miniSSLContext.callMethod(context, "truststore");
|
158
|
+
if (truststore.isNil()) {
|
159
|
+
truststoreFile = keystoreFile;
|
160
|
+
truststorePass = keystorePass;
|
161
|
+
truststoreType = keystoreType;
|
162
|
+
} else if (!isDefaultSymbol(context, truststore)) {
|
163
|
+
truststoreFile = truststore.convertToString().asJavaString();
|
164
|
+
IRubyObject pass = miniSSLContext.callMethod(context, "truststore_pass");
|
165
|
+
if (pass.isNil()) {
|
166
|
+
truststorePass = null;
|
167
|
+
} else {
|
168
|
+
truststorePass = asStringValue(pass, null).toCharArray();
|
169
|
+
}
|
170
|
+
truststoreType = asStringValue(miniSSLContext.callMethod(context, "truststore_type"), KeyStore::getDefaultType);
|
171
|
+
} else { // self.truststore = :default
|
172
|
+
truststoreFile = null;
|
173
|
+
truststorePass = null;
|
174
|
+
truststoreType = null;
|
175
|
+
}
|
146
176
|
|
147
|
-
KeyStore ks = KeyStore.getInstance(
|
177
|
+
KeyStore ks = KeyStore.getInstance(keystoreType);
|
148
178
|
InputStream is = new FileInputStream(keystoreFile);
|
149
179
|
try {
|
150
|
-
ks.load(is,
|
180
|
+
ks.load(is, keystorePass);
|
151
181
|
} finally {
|
152
182
|
is.close();
|
153
183
|
}
|
154
184
|
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
155
|
-
kmf.init(ks,
|
185
|
+
kmf.init(ks, keystorePass);
|
156
186
|
keyManagerFactoryMap.put(keystoreFile, kmf);
|
157
187
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
188
|
+
if (truststoreFile != null) {
|
189
|
+
KeyStore ts = KeyStore.getInstance(truststoreType);
|
190
|
+
is = new FileInputStream(truststoreFile);
|
191
|
+
try {
|
192
|
+
ts.load(is, truststorePass);
|
193
|
+
} finally {
|
194
|
+
is.close();
|
195
|
+
}
|
196
|
+
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
197
|
+
tmf.init(ts);
|
198
|
+
trustManagerFactoryMap.put(truststoreFile, tmf);
|
164
199
|
}
|
165
|
-
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
166
|
-
tmf.init(ts);
|
167
|
-
trustManagerFactoryMap.put(keystoreFile, tmf);
|
168
200
|
|
169
201
|
RubyClass klass = (RubyClass) recv;
|
170
|
-
return klass.newInstance(context,
|
171
|
-
|
172
|
-
|
202
|
+
return klass.newInstance(context, miniSSLContext, Block.NULL_BLOCK);
|
203
|
+
}
|
204
|
+
|
205
|
+
private static String asStringValue(IRubyObject value, Supplier<String> defaultValue) {
|
206
|
+
if (defaultValue != null && value.isNil()) return defaultValue.get();
|
207
|
+
return value.convertToString().asJavaString();
|
208
|
+
}
|
209
|
+
|
210
|
+
private static boolean isDefaultSymbol(ThreadContext context, IRubyObject truststore) {
|
211
|
+
return context.runtime.newSymbol("default").equals(truststore);
|
173
212
|
}
|
174
213
|
|
175
214
|
@JRubyMethod
|
176
|
-
public IRubyObject initialize(ThreadContext
|
215
|
+
public IRubyObject initialize(ThreadContext context, IRubyObject miniSSLContext)
|
177
216
|
throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
|
178
217
|
|
179
|
-
String keystoreFile = miniSSLContext.callMethod(
|
218
|
+
String keystoreFile = miniSSLContext.callMethod(context, "keystore").convertToString().asJavaString();
|
180
219
|
KeyManagerFactory kmf = keyManagerFactoryMap.get(keystoreFile);
|
181
|
-
|
182
|
-
|
183
|
-
|
220
|
+
IRubyObject truststore = miniSSLContext.callMethod(context, "truststore");
|
221
|
+
String truststoreFile = isDefaultSymbol(context, truststore) ? "" : asStringValue(truststore, () -> keystoreFile);
|
222
|
+
TrustManagerFactory tmf = trustManagerFactoryMap.get(truststoreFile); // null if self.truststore = :default
|
223
|
+
if (kmf == null) {
|
224
|
+
throw new KeyStoreException("Could not find KeyManagerFactory for keystore: " + keystoreFile + " truststore: " + truststoreFile);
|
184
225
|
}
|
185
226
|
|
186
227
|
SSLContext sslCtx = SSLContext.getInstance("TLS");
|
187
228
|
|
188
|
-
sslCtx.init(kmf.getKeyManagers(),
|
229
|
+
sslCtx.init(kmf.getKeyManagers(), getTrustManagers(tmf), null);
|
189
230
|
closed = false;
|
190
231
|
handshake = false;
|
191
232
|
engine = sslCtx.createSSLEngine();
|
192
233
|
|
193
|
-
String[]
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
234
|
+
String[] enabledProtocols;
|
235
|
+
IRubyObject protocols = miniSSLContext.callMethod(context, "protocols");
|
236
|
+
if (protocols.isNil()) {
|
237
|
+
if (miniSSLContext.callMethod(context, "no_tlsv1").isTrue()) {
|
238
|
+
enabledProtocols = new String[] { "TLSv1.1", "TLSv1.2", "TLSv1.3" };
|
239
|
+
} else {
|
240
|
+
enabledProtocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" };
|
241
|
+
}
|
199
242
|
|
200
|
-
|
201
|
-
|
243
|
+
if (miniSSLContext.callMethod(context, "no_tlsv1_1").isTrue()) {
|
244
|
+
enabledProtocols = new String[] { "TLSv1.2", "TLSv1.3" };
|
245
|
+
}
|
246
|
+
} else if (protocols instanceof RubyArray) {
|
247
|
+
enabledProtocols = (String[]) ((RubyArray) protocols).toArray(new String[0]);
|
248
|
+
} else {
|
249
|
+
throw context.runtime.newTypeError(protocols, context.runtime.getArray());
|
202
250
|
}
|
251
|
+
engine.setEnabledProtocols(enabledProtocols);
|
203
252
|
|
204
|
-
engine.setEnabledProtocols(protocols);
|
205
253
|
engine.setUseClientMode(false);
|
206
254
|
|
207
|
-
long verify_mode = miniSSLContext.callMethod(
|
255
|
+
long verify_mode = miniSSLContext.callMethod(context, "verify_mode").convertToInteger("to_i").getLongValue();
|
208
256
|
if ((verify_mode & 0x1) != 0) { // 'peer'
|
209
257
|
engine.setWantClientAuth(true);
|
210
258
|
}
|
@@ -212,10 +260,11 @@ public class MiniSSL extends RubyObject {
|
|
212
260
|
engine.setNeedClientAuth(true);
|
213
261
|
}
|
214
262
|
|
215
|
-
IRubyObject
|
216
|
-
if (
|
217
|
-
String[]
|
218
|
-
|
263
|
+
IRubyObject cipher_suites = miniSSLContext.callMethod(context, "cipher_suites");
|
264
|
+
if (cipher_suites instanceof RubyArray) {
|
265
|
+
engine.setEnabledCipherSuites((String[]) ((RubyArray) cipher_suites).toArray(new String[0]));
|
266
|
+
} else if (!cipher_suites.isNil()) {
|
267
|
+
throw context.runtime.newTypeError(cipher_suites, context.runtime.getArray());
|
219
268
|
}
|
220
269
|
|
221
270
|
SSLSession session = engine.getSession();
|
@@ -227,6 +276,48 @@ public class MiniSSL extends RubyObject {
|
|
227
276
|
return this;
|
228
277
|
}
|
229
278
|
|
279
|
+
private TrustManager[] getTrustManagers(TrustManagerFactory factory) {
|
280
|
+
if (factory == null) return null; // use JDK trust defaults
|
281
|
+
final TrustManager[] tms = factory.getTrustManagers();
|
282
|
+
if (tms != null) {
|
283
|
+
for (int i=0; i<tms.length; i++) {
|
284
|
+
final TrustManager tm = tms[i];
|
285
|
+
if (tm instanceof X509TrustManager) {
|
286
|
+
tms[i] = new TrustManagerWrapper((X509TrustManager) tm);
|
287
|
+
}
|
288
|
+
}
|
289
|
+
}
|
290
|
+
return tms;
|
291
|
+
}
|
292
|
+
|
293
|
+
private volatile transient X509Certificate lastCheckedCert0;
|
294
|
+
|
295
|
+
private class TrustManagerWrapper implements X509TrustManager {
|
296
|
+
|
297
|
+
private final X509TrustManager delegate;
|
298
|
+
|
299
|
+
TrustManagerWrapper(X509TrustManager delegate) {
|
300
|
+
this.delegate = delegate;
|
301
|
+
}
|
302
|
+
|
303
|
+
@Override
|
304
|
+
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
305
|
+
lastCheckedCert0 = chain.length > 0 ? chain[0] : null;
|
306
|
+
delegate.checkClientTrusted(chain, authType);
|
307
|
+
}
|
308
|
+
|
309
|
+
@Override
|
310
|
+
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
311
|
+
delegate.checkServerTrusted(chain, authType);
|
312
|
+
}
|
313
|
+
|
314
|
+
@Override
|
315
|
+
public X509Certificate[] getAcceptedIssuers() {
|
316
|
+
return delegate.getAcceptedIssuers();
|
317
|
+
}
|
318
|
+
|
319
|
+
}
|
320
|
+
|
230
321
|
@JRubyMethod
|
231
322
|
public IRubyObject inject(IRubyObject arg) {
|
232
323
|
ByteList bytes = arg.convertToString().getByteList();
|
@@ -251,7 +342,7 @@ public class MiniSSL extends RubyObject {
|
|
251
342
|
res = engine.unwrap(src.getRawBuffer(), dst.getRawBuffer());
|
252
343
|
break;
|
253
344
|
default:
|
254
|
-
throw new
|
345
|
+
throw new AssertionError("Unknown SSLOperation: " + sslOp);
|
255
346
|
}
|
256
347
|
|
257
348
|
switch (res.getStatus()) {
|
@@ -279,14 +370,6 @@ public class MiniSSL extends RubyObject {
|
|
279
370
|
}
|
280
371
|
}
|
281
372
|
|
282
|
-
// after each op, run any delegated tasks if needed
|
283
|
-
if(res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
284
|
-
Runnable runnable;
|
285
|
-
while ((runnable = engine.getDelegatedTask()) != null) {
|
286
|
-
runnable.run();
|
287
|
-
}
|
288
|
-
}
|
289
|
-
|
290
373
|
return res;
|
291
374
|
}
|
292
375
|
|
@@ -304,11 +387,12 @@ public class MiniSSL extends RubyObject {
|
|
304
387
|
|
305
388
|
HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
|
306
389
|
boolean done = false;
|
307
|
-
SSLEngineResult res = null;
|
308
390
|
while (!done) {
|
391
|
+
SSLEngineResult res;
|
309
392
|
switch (handshakeStatus) {
|
310
393
|
case NEED_WRAP:
|
311
394
|
res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
|
395
|
+
handshakeStatus = res.getHandshakeStatus();
|
312
396
|
break;
|
313
397
|
case NEED_UNWRAP:
|
314
398
|
res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
|
@@ -316,13 +400,18 @@ public class MiniSSL extends RubyObject {
|
|
316
400
|
// need more data before we can shake more hands
|
317
401
|
done = true;
|
318
402
|
}
|
403
|
+
handshakeStatus = res.getHandshakeStatus();
|
404
|
+
break;
|
405
|
+
case NEED_TASK:
|
406
|
+
Runnable runnable;
|
407
|
+
while ((runnable = engine.getDelegatedTask()) != null) {
|
408
|
+
runnable.run();
|
409
|
+
}
|
410
|
+
handshakeStatus = engine.getHandshakeStatus();
|
319
411
|
break;
|
320
412
|
default:
|
321
413
|
done = true;
|
322
414
|
}
|
323
|
-
if (!done) {
|
324
|
-
handshakeStatus = res.getHandshakeStatus();
|
325
|
-
}
|
326
415
|
}
|
327
416
|
|
328
417
|
if (inboundNetData.hasRemaining()) {
|
@@ -338,9 +427,7 @@ public class MiniSSL extends RubyObject {
|
|
338
427
|
|
339
428
|
return RubyString.newString(getRuntime(), appDataByteList);
|
340
429
|
} catch (SSLException e) {
|
341
|
-
|
342
|
-
re.initCause(e);
|
343
|
-
throw re;
|
430
|
+
throw newSSLError(getRuntime(), e);
|
344
431
|
}
|
345
432
|
}
|
346
433
|
|
@@ -373,19 +460,19 @@ public class MiniSSL extends RubyObject {
|
|
373
460
|
|
374
461
|
return RubyString.newString(context.runtime, dataByteList);
|
375
462
|
} catch (SSLException e) {
|
376
|
-
|
377
|
-
ex.initCause(e);
|
378
|
-
throw ex;
|
463
|
+
throw newSSLError(getRuntime(), e);
|
379
464
|
}
|
380
465
|
}
|
381
466
|
|
382
467
|
@JRubyMethod
|
383
|
-
public IRubyObject peercert() throws CertificateEncodingException {
|
468
|
+
public IRubyObject peercert(ThreadContext context) throws CertificateEncodingException {
|
469
|
+
Certificate peerCert;
|
384
470
|
try {
|
385
|
-
|
471
|
+
peerCert = engine.getSession().getPeerCertificates()[0];
|
386
472
|
} catch (SSLPeerUnverifiedException e) {
|
387
|
-
|
473
|
+
peerCert = lastCheckedCert0; // null if trust check did not happen
|
388
474
|
}
|
475
|
+
return peerCert == null ? context.nil : JavaEmbedUtils.javaToRuby(context.runtime, peerCert.getEncoded());
|
389
476
|
}
|
390
477
|
|
391
478
|
@JRubyMethod(name = "init?")
|
@@ -404,4 +491,19 @@ public class MiniSSL extends RubyObject {
|
|
404
491
|
return getRuntime().getFalse();
|
405
492
|
}
|
406
493
|
}
|
494
|
+
|
495
|
+
private static RubyClass getSSLError(Ruby runtime) {
|
496
|
+
return (RubyClass) ((RubyModule) runtime.getModule("Puma").getConstantAt("MiniSSL")).getConstantAt("SSLError");
|
497
|
+
}
|
498
|
+
|
499
|
+
private static RaiseException newSSLError(Ruby runtime, SSLException cause) {
|
500
|
+
return newError(runtime, getSSLError(runtime), cause.toString(), cause);
|
501
|
+
}
|
502
|
+
|
503
|
+
private static RaiseException newError(Ruby runtime, RubyClass errorClass, String message, Throwable cause) {
|
504
|
+
RaiseException ex = RaiseException.from(runtime, errorClass, message);
|
505
|
+
ex.initCause(cause);
|
506
|
+
return ex;
|
507
|
+
}
|
508
|
+
|
407
509
|
}
|
@@ -36,13 +36,13 @@ static VALUE global_request_method;
|
|
36
36
|
static VALUE global_request_uri;
|
37
37
|
static VALUE global_fragment;
|
38
38
|
static VALUE global_query_string;
|
39
|
-
static VALUE
|
39
|
+
static VALUE global_server_protocol;
|
40
40
|
static VALUE global_request_path;
|
41
41
|
|
42
42
|
/** Defines common length and error messages for input length validation. */
|
43
43
|
#define QUOTE(s) #s
|
44
|
-
#define
|
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 "
|
44
|
+
#define EXPAND_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 " EXPAND_MAX_LENGTH_VALUE(length) " allowed length (was %d)"
|
46
46
|
|
47
47
|
/** Validates the max length of given input and throws an HttpParserError exception if over. */
|
48
48
|
#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR, len); }
|
@@ -52,15 +52,23 @@ static VALUE global_request_path;
|
|
52
52
|
|
53
53
|
|
54
54
|
/* Defines the maximum allowed lengths for various input elements.*/
|
55
|
+
#ifndef PUMA_REQUEST_URI_MAX_LENGTH
|
56
|
+
#define PUMA_REQUEST_URI_MAX_LENGTH (1024 * 12)
|
57
|
+
#endif
|
58
|
+
|
59
|
+
#ifndef PUMA_REQUEST_PATH_MAX_LENGTH
|
60
|
+
#define PUMA_REQUEST_PATH_MAX_LENGTH (8192)
|
61
|
+
#endif
|
62
|
+
|
55
63
|
#ifndef PUMA_QUERY_STRING_MAX_LENGTH
|
56
64
|
#define PUMA_QUERY_STRING_MAX_LENGTH (1024 * 10)
|
57
65
|
#endif
|
58
66
|
|
59
67
|
DEF_MAX_LENGTH(FIELD_NAME, 256);
|
60
68
|
DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
|
61
|
-
DEF_MAX_LENGTH(REQUEST_URI,
|
69
|
+
DEF_MAX_LENGTH(REQUEST_URI, PUMA_REQUEST_URI_MAX_LENGTH);
|
62
70
|
DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
|
63
|
-
DEF_MAX_LENGTH(REQUEST_PATH,
|
71
|
+
DEF_MAX_LENGTH(REQUEST_PATH, PUMA_REQUEST_PATH_MAX_LENGTH);
|
64
72
|
DEF_MAX_LENGTH(QUERY_STRING, PUMA_QUERY_STRING_MAX_LENGTH);
|
65
73
|
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
66
74
|
|
@@ -236,10 +244,10 @@ void query_string(puma_parser* hp, const char *at, size_t length)
|
|
236
244
|
rb_hash_aset(hp->request, global_query_string, val);
|
237
245
|
}
|
238
246
|
|
239
|
-
void
|
247
|
+
void server_protocol(puma_parser* hp, const char *at, size_t length)
|
240
248
|
{
|
241
249
|
VALUE val = rb_str_new(at, length);
|
242
|
-
rb_hash_aset(hp->request,
|
250
|
+
rb_hash_aset(hp->request, global_server_protocol, val);
|
243
251
|
}
|
244
252
|
|
245
253
|
/** Finalizes the request header to have a bunch of stuff that's
|
@@ -281,7 +289,7 @@ VALUE HttpParser_alloc(VALUE klass)
|
|
281
289
|
hp->fragment = fragment;
|
282
290
|
hp->request_path = request_path;
|
283
291
|
hp->query_string = query_string;
|
284
|
-
hp->
|
292
|
+
hp->server_protocol = server_protocol;
|
285
293
|
hp->header_done = header_done;
|
286
294
|
hp->request = Qnil;
|
287
295
|
|
@@ -461,7 +469,7 @@ void Init_puma_http11(void)
|
|
461
469
|
DEF_GLOBAL(request_uri, "REQUEST_URI");
|
462
470
|
DEF_GLOBAL(fragment, "FRAGMENT");
|
463
471
|
DEF_GLOBAL(query_string, "QUERY_STRING");
|
464
|
-
DEF_GLOBAL(
|
472
|
+
DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
|
465
473
|
DEF_GLOBAL(request_path, "REQUEST_PATH");
|
466
474
|
|
467
475
|
eHttpParserError = rb_define_class_under(mPuma, "HttpParserError", rb_eIOError);
|
data/lib/puma/app/status.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
require_relative '../json_serialization'
|
3
3
|
|
4
4
|
module Puma
|
5
5
|
module App
|
@@ -39,6 +39,9 @@ module Puma
|
|
39
39
|
when 'phased-restart'
|
40
40
|
@launcher.phased_restart ? 200 : 404
|
41
41
|
|
42
|
+
when 'refork'
|
43
|
+
@launcher.refork ? 200 : 404
|
44
|
+
|
42
45
|
when 'reload-worker-directory'
|
43
46
|
@launcher.send(:reload_worker_directory) ? 200 : 404
|
44
47
|
|
@@ -77,13 +80,13 @@ module Puma
|
|
77
80
|
|
78
81
|
def authenticate(env)
|
79
82
|
return true unless @auth_token
|
80
|
-
env['QUERY_STRING'].to_s.split(
|
83
|
+
env['QUERY_STRING'].to_s.split('&;').include? "token=#{@auth_token}"
|
81
84
|
end
|
82
85
|
|
83
86
|
def rack_response(status, body, content_type='application/json')
|
84
87
|
headers = {
|
85
|
-
'
|
86
|
-
'
|
88
|
+
'content-type' => content_type,
|
89
|
+
'content-length' => body.bytesize.to_s
|
87
90
|
}
|
88
91
|
|
89
92
|
[status, headers, [body]]
|