puma 5.5.2 → 6.3.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.
- checksums.yaml +4 -4
- data/History.md +336 -3
- data/README.md +61 -16
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +4 -4
- data/docs/compile_options.md +34 -0
- data/docs/fork_worker.md +1 -3
- data/docs/nginx.md +1 -1
- data/docs/signals.md +1 -0
- data/docs/systemd.md +1 -2
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/extconf.rb +28 -14
- 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 +135 -23
- 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 +188 -102
- data/ext/puma_http11/puma_http11.c +18 -10
- data/lib/puma/app/status.rb +7 -4
- data/lib/puma/binder.rb +62 -51
- data/lib/puma/cli.rb +19 -20
- data/lib/puma/client.rb +108 -26
- data/lib/puma/cluster/worker.rb +23 -16
- data/lib/puma/cluster/worker_handle.rb +8 -1
- data/lib/puma/cluster.rb +62 -41
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +76 -55
- data/lib/puma/const.rb +133 -97
- data/lib/puma/control_cli.rb +21 -18
- data/lib/puma/detect.rb +12 -2
- data/lib/puma/dsl.rb +270 -55
- 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/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +114 -175
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +30 -16
- data/lib/puma/minissl.rb +126 -17
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +1 -1
- data/lib/puma/rack/builder.rb +6 -6
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +365 -161
- data/lib/puma/runner.rb +55 -22
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +91 -94
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +39 -7
- data/lib/puma/thread_pool.rb +25 -21
- data/lib/puma/util.rb +12 -14
- data/lib/puma.rb +12 -11
- data/lib/rack/handler/puma.rb +113 -86
- data/tools/Dockerfile +1 -1
- metadata +11 -6
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
@@ -1,11 +1,13 @@
|
|
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;
|
7
8
|
import org.jruby.RubyString;
|
8
9
|
import org.jruby.anno.JRubyMethod;
|
10
|
+
import org.jruby.exceptions.RaiseException;
|
9
11
|
import org.jruby.javasupport.JavaEmbedUtils;
|
10
12
|
import org.jruby.runtime.Block;
|
11
13
|
import org.jruby.runtime.ObjectAllocator;
|
@@ -14,6 +16,7 @@ import org.jruby.runtime.builtin.IRubyObject;
|
|
14
16
|
import org.jruby.util.ByteList;
|
15
17
|
|
16
18
|
import javax.net.ssl.KeyManagerFactory;
|
19
|
+
import javax.net.ssl.TrustManager;
|
17
20
|
import javax.net.ssl.TrustManagerFactory;
|
18
21
|
import javax.net.ssl.SSLContext;
|
19
22
|
import javax.net.ssl.SSLEngine;
|
@@ -21,6 +24,7 @@ import javax.net.ssl.SSLEngineResult;
|
|
21
24
|
import javax.net.ssl.SSLException;
|
22
25
|
import javax.net.ssl.SSLPeerUnverifiedException;
|
23
26
|
import javax.net.ssl.SSLSession;
|
27
|
+
import javax.net.ssl.X509TrustManager;
|
24
28
|
import java.io.FileInputStream;
|
25
29
|
import java.io.InputStream;
|
26
30
|
import java.io.IOException;
|
@@ -31,15 +35,18 @@ import java.security.KeyStore;
|
|
31
35
|
import java.security.KeyStoreException;
|
32
36
|
import java.security.NoSuchAlgorithmException;
|
33
37
|
import java.security.UnrecoverableKeyException;
|
38
|
+
import java.security.cert.Certificate;
|
34
39
|
import java.security.cert.CertificateEncodingException;
|
35
40
|
import java.security.cert.CertificateException;
|
41
|
+
import java.security.cert.X509Certificate;
|
36
42
|
import java.util.concurrent.ConcurrentHashMap;
|
37
43
|
import java.util.Map;
|
44
|
+
import java.util.function.Supplier;
|
38
45
|
|
39
46
|
import static javax.net.ssl.SSLEngineResult.Status;
|
40
47
|
import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
41
48
|
|
42
|
-
public class MiniSSL extends RubyObject {
|
49
|
+
public class MiniSSL extends RubyObject { // MiniSSL::Engine
|
43
50
|
private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
44
51
|
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
45
52
|
return new MiniSSL(runtime, klass);
|
@@ -50,11 +57,10 @@ public class MiniSSL extends RubyObject {
|
|
50
57
|
RubyModule mPuma = runtime.defineModule("Puma");
|
51
58
|
RubyModule ssl = mPuma.defineModuleUnder("MiniSSL");
|
52
59
|
|
53
|
-
|
54
|
-
|
55
|
-
runtime.getClass("IOError").getAllocator());
|
60
|
+
// Puma::MiniSSL::SSLError
|
61
|
+
ssl.defineClassUnder("SSLError", runtime.getStandardError(), runtime.getStandardError().getAllocator());
|
56
62
|
|
57
|
-
RubyClass eng = ssl.defineClassUnder("Engine",runtime.getObject(),ALLOCATOR);
|
63
|
+
RubyClass eng = ssl.defineClassUnder("Engine", runtime.getObject(), ALLOCATOR);
|
58
64
|
eng.defineAnnotatedMethods(MiniSSL.class);
|
59
65
|
}
|
60
66
|
|
@@ -80,11 +86,11 @@ public class MiniSSL extends RubyObject {
|
|
80
86
|
/**
|
81
87
|
* Writes bytes to the buffer after ensuring there's room
|
82
88
|
*/
|
83
|
-
|
84
|
-
if (buffer.remaining() <
|
85
|
-
resize(buffer.limit() +
|
89
|
+
private void put(byte[] bytes, final int offset, final int length) {
|
90
|
+
if (buffer.remaining() < length) {
|
91
|
+
resize(buffer.limit() + length);
|
86
92
|
}
|
87
|
-
buffer.put(bytes);
|
93
|
+
buffer.put(bytes, offset, length);
|
88
94
|
}
|
89
95
|
|
90
96
|
/**
|
@@ -115,7 +121,7 @@ public class MiniSSL extends RubyObject {
|
|
115
121
|
|
116
122
|
buffer.get(bss);
|
117
123
|
buffer.clear();
|
118
|
-
return new ByteList(bss);
|
124
|
+
return new ByteList(bss, false);
|
119
125
|
}
|
120
126
|
|
121
127
|
@Override
|
@@ -136,76 +142,116 @@ public class MiniSSL extends RubyObject {
|
|
136
142
|
private static Map<String, KeyManagerFactory> keyManagerFactoryMap = new ConcurrentHashMap<String, KeyManagerFactory>();
|
137
143
|
private static Map<String, TrustManagerFactory> trustManagerFactoryMap = new ConcurrentHashMap<String, TrustManagerFactory>();
|
138
144
|
|
139
|
-
@JRubyMethod(meta = true)
|
145
|
+
@JRubyMethod(meta = true) // Engine.server
|
140
146
|
public static synchronized IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext)
|
141
147
|
throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
|
142
148
|
// Create the KeyManagerFactory and TrustManagerFactory for this server
|
143
|
-
String keystoreFile = miniSSLContext.callMethod(context, "keystore")
|
144
|
-
char[]
|
149
|
+
String keystoreFile = asStringValue(miniSSLContext.callMethod(context, "keystore"), null);
|
150
|
+
char[] keystorePass = asStringValue(miniSSLContext.callMethod(context, "keystore_pass"), null).toCharArray();
|
151
|
+
String keystoreType = asStringValue(miniSSLContext.callMethod(context, "keystore_type"), KeyStore::getDefaultType);
|
152
|
+
|
153
|
+
String truststoreFile;
|
154
|
+
char[] truststorePass;
|
155
|
+
String truststoreType;
|
156
|
+
IRubyObject truststore = miniSSLContext.callMethod(context, "truststore");
|
157
|
+
if (truststore.isNil()) {
|
158
|
+
truststoreFile = keystoreFile;
|
159
|
+
truststorePass = keystorePass;
|
160
|
+
truststoreType = keystoreType;
|
161
|
+
} else if (!isDefaultSymbol(context, truststore)) {
|
162
|
+
truststoreFile = truststore.convertToString().asJavaString();
|
163
|
+
IRubyObject pass = miniSSLContext.callMethod(context, "truststore_pass");
|
164
|
+
if (pass.isNil()) {
|
165
|
+
truststorePass = null;
|
166
|
+
} else {
|
167
|
+
truststorePass = asStringValue(pass, null).toCharArray();
|
168
|
+
}
|
169
|
+
truststoreType = asStringValue(miniSSLContext.callMethod(context, "truststore_type"), KeyStore::getDefaultType);
|
170
|
+
} else { // self.truststore = :default
|
171
|
+
truststoreFile = null;
|
172
|
+
truststorePass = null;
|
173
|
+
truststoreType = null;
|
174
|
+
}
|
145
175
|
|
146
|
-
KeyStore ks = KeyStore.getInstance(
|
176
|
+
KeyStore ks = KeyStore.getInstance(keystoreType);
|
147
177
|
InputStream is = new FileInputStream(keystoreFile);
|
148
178
|
try {
|
149
|
-
ks.load(is,
|
179
|
+
ks.load(is, keystorePass);
|
150
180
|
} finally {
|
151
181
|
is.close();
|
152
182
|
}
|
153
183
|
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
154
|
-
kmf.init(ks,
|
184
|
+
kmf.init(ks, keystorePass);
|
155
185
|
keyManagerFactoryMap.put(keystoreFile, kmf);
|
156
186
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
187
|
+
if (truststoreFile != null) {
|
188
|
+
KeyStore ts = KeyStore.getInstance(truststoreType);
|
189
|
+
is = new FileInputStream(truststoreFile);
|
190
|
+
try {
|
191
|
+
ts.load(is, truststorePass);
|
192
|
+
} finally {
|
193
|
+
is.close();
|
194
|
+
}
|
195
|
+
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
196
|
+
tmf.init(ts);
|
197
|
+
trustManagerFactoryMap.put(truststoreFile, tmf);
|
163
198
|
}
|
164
|
-
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
165
|
-
tmf.init(ts);
|
166
|
-
trustManagerFactoryMap.put(keystoreFile, tmf);
|
167
199
|
|
168
200
|
RubyClass klass = (RubyClass) recv;
|
169
|
-
return klass.newInstance(context,
|
170
|
-
|
171
|
-
|
201
|
+
return klass.newInstance(context, miniSSLContext, Block.NULL_BLOCK);
|
202
|
+
}
|
203
|
+
|
204
|
+
private static String asStringValue(IRubyObject value, Supplier<String> defaultValue) {
|
205
|
+
if (defaultValue != null && value.isNil()) return defaultValue.get();
|
206
|
+
return value.convertToString().asJavaString();
|
207
|
+
}
|
208
|
+
|
209
|
+
private static boolean isDefaultSymbol(ThreadContext context, IRubyObject truststore) {
|
210
|
+
return context.runtime.newSymbol("default").equals(truststore);
|
172
211
|
}
|
173
212
|
|
174
213
|
@JRubyMethod
|
175
|
-
public IRubyObject initialize(ThreadContext
|
214
|
+
public IRubyObject initialize(ThreadContext context, IRubyObject miniSSLContext)
|
176
215
|
throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
|
177
|
-
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
178
|
-
KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
|
179
216
|
|
180
|
-
String keystoreFile = miniSSLContext.callMethod(
|
217
|
+
String keystoreFile = miniSSLContext.callMethod(context, "keystore").convertToString().asJavaString();
|
181
218
|
KeyManagerFactory kmf = keyManagerFactoryMap.get(keystoreFile);
|
182
|
-
|
183
|
-
|
184
|
-
|
219
|
+
IRubyObject truststore = miniSSLContext.callMethod(context, "truststore");
|
220
|
+
String truststoreFile = isDefaultSymbol(context, truststore) ? "" : asStringValue(truststore, () -> keystoreFile);
|
221
|
+
TrustManagerFactory tmf = trustManagerFactoryMap.get(truststoreFile); // null if self.truststore = :default
|
222
|
+
if (kmf == null) {
|
223
|
+
throw new KeyStoreException("Could not find KeyManagerFactory for keystore: " + keystoreFile + " truststore: " + truststoreFile);
|
185
224
|
}
|
186
225
|
|
187
226
|
SSLContext sslCtx = SSLContext.getInstance("TLS");
|
188
227
|
|
189
|
-
sslCtx.init(kmf.getKeyManagers(),
|
228
|
+
sslCtx.init(kmf.getKeyManagers(), getTrustManagers(tmf), null);
|
190
229
|
closed = false;
|
191
230
|
handshake = false;
|
192
231
|
engine = sslCtx.createSSLEngine();
|
193
232
|
|
194
|
-
String[]
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
233
|
+
String[] enabledProtocols;
|
234
|
+
IRubyObject protocols = miniSSLContext.callMethod(context, "protocols");
|
235
|
+
if (protocols.isNil()) {
|
236
|
+
if (miniSSLContext.callMethod(context, "no_tlsv1").isTrue()) {
|
237
|
+
enabledProtocols = new String[] { "TLSv1.1", "TLSv1.2", "TLSv1.3" };
|
238
|
+
} else {
|
239
|
+
enabledProtocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" };
|
240
|
+
}
|
200
241
|
|
201
|
-
|
202
|
-
|
242
|
+
if (miniSSLContext.callMethod(context, "no_tlsv1_1").isTrue()) {
|
243
|
+
enabledProtocols = new String[] { "TLSv1.2", "TLSv1.3" };
|
244
|
+
}
|
245
|
+
} else if (protocols instanceof RubyArray) {
|
246
|
+
enabledProtocols = (String[]) ((RubyArray) protocols).toArray(new String[0]);
|
247
|
+
} else {
|
248
|
+
throw context.runtime.newTypeError(protocols, context.runtime.getArray());
|
203
249
|
}
|
250
|
+
engine.setEnabledProtocols(enabledProtocols);
|
204
251
|
|
205
|
-
engine.setEnabledProtocols(protocols);
|
206
252
|
engine.setUseClientMode(false);
|
207
253
|
|
208
|
-
long verify_mode = miniSSLContext.callMethod(
|
254
|
+
long verify_mode = miniSSLContext.callMethod(context, "verify_mode").convertToInteger("to_i").getLongValue();
|
209
255
|
if ((verify_mode & 0x1) != 0) { // 'peer'
|
210
256
|
engine.setWantClientAuth(true);
|
211
257
|
}
|
@@ -213,10 +259,11 @@ public class MiniSSL extends RubyObject {
|
|
213
259
|
engine.setNeedClientAuth(true);
|
214
260
|
}
|
215
261
|
|
216
|
-
IRubyObject
|
217
|
-
if (
|
218
|
-
String[]
|
219
|
-
|
262
|
+
IRubyObject cipher_suites = miniSSLContext.callMethod(context, "cipher_suites");
|
263
|
+
if (cipher_suites instanceof RubyArray) {
|
264
|
+
engine.setEnabledCipherSuites((String[]) ((RubyArray) cipher_suites).toArray(new String[0]));
|
265
|
+
} else if (!cipher_suites.isNil()) {
|
266
|
+
throw context.runtime.newTypeError(cipher_suites, context.runtime.getArray());
|
220
267
|
}
|
221
268
|
|
222
269
|
SSLSession session = engine.getSession();
|
@@ -228,16 +275,53 @@ public class MiniSSL extends RubyObject {
|
|
228
275
|
return this;
|
229
276
|
}
|
230
277
|
|
278
|
+
private TrustManager[] getTrustManagers(TrustManagerFactory factory) {
|
279
|
+
if (factory == null) return null; // use JDK trust defaults
|
280
|
+
final TrustManager[] tms = factory.getTrustManagers();
|
281
|
+
if (tms != null) {
|
282
|
+
for (int i=0; i<tms.length; i++) {
|
283
|
+
final TrustManager tm = tms[i];
|
284
|
+
if (tm instanceof X509TrustManager) {
|
285
|
+
tms[i] = new TrustManagerWrapper((X509TrustManager) tm);
|
286
|
+
}
|
287
|
+
}
|
288
|
+
}
|
289
|
+
return tms;
|
290
|
+
}
|
291
|
+
|
292
|
+
private volatile transient X509Certificate lastCheckedCert0;
|
293
|
+
|
294
|
+
private class TrustManagerWrapper implements X509TrustManager {
|
295
|
+
|
296
|
+
private final X509TrustManager delegate;
|
297
|
+
|
298
|
+
TrustManagerWrapper(X509TrustManager delegate) {
|
299
|
+
this.delegate = delegate;
|
300
|
+
}
|
301
|
+
|
302
|
+
@Override
|
303
|
+
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
304
|
+
lastCheckedCert0 = chain.length > 0 ? chain[0] : null;
|
305
|
+
delegate.checkClientTrusted(chain, authType);
|
306
|
+
}
|
307
|
+
|
308
|
+
@Override
|
309
|
+
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
310
|
+
delegate.checkServerTrusted(chain, authType);
|
311
|
+
}
|
312
|
+
|
313
|
+
@Override
|
314
|
+
public X509Certificate[] getAcceptedIssuers() {
|
315
|
+
return delegate.getAcceptedIssuers();
|
316
|
+
}
|
317
|
+
|
318
|
+
}
|
319
|
+
|
231
320
|
@JRubyMethod
|
232
321
|
public IRubyObject inject(IRubyObject arg) {
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
return this;
|
237
|
-
} catch (Exception e) {
|
238
|
-
e.printStackTrace();
|
239
|
-
throw new RuntimeException(e);
|
240
|
-
}
|
322
|
+
ByteList bytes = arg.convertToString().getByteList();
|
323
|
+
inboundNetData.put(bytes.unsafeBytes(), bytes.getBegin(), bytes.getRealSize());
|
324
|
+
return this;
|
241
325
|
}
|
242
326
|
|
243
327
|
private enum SSLOperation {
|
@@ -257,7 +341,7 @@ public class MiniSSL extends RubyObject {
|
|
257
341
|
res = engine.unwrap(src.getRawBuffer(), dst.getRawBuffer());
|
258
342
|
break;
|
259
343
|
default:
|
260
|
-
throw new
|
344
|
+
throw new AssertionError("Unknown SSLOperation: " + sslOp);
|
261
345
|
}
|
262
346
|
|
263
347
|
switch (res.getStatus()) {
|
@@ -285,19 +369,11 @@ public class MiniSSL extends RubyObject {
|
|
285
369
|
}
|
286
370
|
}
|
287
371
|
|
288
|
-
// after each op, run any delegated tasks if needed
|
289
|
-
if(res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
290
|
-
Runnable runnable;
|
291
|
-
while ((runnable = engine.getDelegatedTask()) != null) {
|
292
|
-
runnable.run();
|
293
|
-
}
|
294
|
-
}
|
295
|
-
|
296
372
|
return res;
|
297
373
|
}
|
298
374
|
|
299
375
|
@JRubyMethod
|
300
|
-
public IRubyObject read()
|
376
|
+
public IRubyObject read() {
|
301
377
|
try {
|
302
378
|
inboundNetData.flip();
|
303
379
|
|
@@ -310,11 +386,12 @@ public class MiniSSL extends RubyObject {
|
|
310
386
|
|
311
387
|
HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
|
312
388
|
boolean done = false;
|
313
|
-
SSLEngineResult res = null;
|
314
389
|
while (!done) {
|
390
|
+
SSLEngineResult res;
|
315
391
|
switch (handshakeStatus) {
|
316
392
|
case NEED_WRAP:
|
317
393
|
res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
|
394
|
+
handshakeStatus = res.getHandshakeStatus();
|
318
395
|
break;
|
319
396
|
case NEED_UNWRAP:
|
320
397
|
res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
|
@@ -322,13 +399,18 @@ public class MiniSSL extends RubyObject {
|
|
322
399
|
// need more data before we can shake more hands
|
323
400
|
done = true;
|
324
401
|
}
|
402
|
+
handshakeStatus = res.getHandshakeStatus();
|
403
|
+
break;
|
404
|
+
case NEED_TASK:
|
405
|
+
Runnable runnable;
|
406
|
+
while ((runnable = engine.getDelegatedTask()) != null) {
|
407
|
+
runnable.run();
|
408
|
+
}
|
409
|
+
handshakeStatus = engine.getHandshakeStatus();
|
325
410
|
break;
|
326
411
|
default:
|
327
412
|
done = true;
|
328
413
|
}
|
329
|
-
if (!done) {
|
330
|
-
handshakeStatus = res.getHandshakeStatus();
|
331
|
-
}
|
332
414
|
}
|
333
415
|
|
334
416
|
if (inboundNetData.hasRemaining()) {
|
@@ -342,65 +424,54 @@ public class MiniSSL extends RubyObject {
|
|
342
424
|
return getRuntime().getNil();
|
343
425
|
}
|
344
426
|
|
345
|
-
RubyString
|
346
|
-
|
347
|
-
|
348
|
-
} catch (Exception e) {
|
349
|
-
throw getRuntime().newEOFError(e.getMessage());
|
427
|
+
return RubyString.newString(getRuntime(), appDataByteList);
|
428
|
+
} catch (SSLException e) {
|
429
|
+
throw newSSLError(getRuntime(), e);
|
350
430
|
}
|
351
431
|
}
|
352
432
|
|
353
433
|
@JRubyMethod
|
354
434
|
public IRubyObject write(IRubyObject arg) {
|
355
|
-
|
356
|
-
|
357
|
-
outboundAppData = new MiniSSLBuffer(bls);
|
435
|
+
byte[] bls = arg.convertToString().getBytes();
|
436
|
+
outboundAppData = new MiniSSLBuffer(bls);
|
358
437
|
|
359
|
-
|
360
|
-
} catch (Exception e) {
|
361
|
-
e.printStackTrace();
|
362
|
-
throw new RuntimeException(e);
|
363
|
-
}
|
438
|
+
return getRuntime().newFixnum(bls.length);
|
364
439
|
}
|
365
440
|
|
366
441
|
@JRubyMethod
|
367
|
-
public IRubyObject extract()
|
442
|
+
public IRubyObject extract(ThreadContext context) {
|
368
443
|
try {
|
369
444
|
ByteList dataByteList = outboundNetData.asByteList();
|
370
445
|
if (dataByteList != null) {
|
371
|
-
RubyString
|
372
|
-
str.setValue(dataByteList);
|
373
|
-
return str;
|
446
|
+
return RubyString.newString(context.runtime, dataByteList);
|
374
447
|
}
|
375
448
|
|
376
449
|
if (!outboundAppData.hasRemaining()) {
|
377
|
-
return
|
450
|
+
return context.nil;
|
378
451
|
}
|
379
452
|
|
380
453
|
outboundNetData.clear();
|
381
454
|
doOp(SSLOperation.WRAP, outboundAppData, outboundNetData);
|
382
455
|
dataByteList = outboundNetData.asByteList();
|
383
456
|
if (dataByteList == null) {
|
384
|
-
return
|
457
|
+
return context.nil;
|
385
458
|
}
|
386
459
|
|
387
|
-
RubyString
|
388
|
-
|
389
|
-
|
390
|
-
return str;
|
391
|
-
} catch (Exception e) {
|
392
|
-
e.printStackTrace();
|
393
|
-
throw new RuntimeException(e);
|
460
|
+
return RubyString.newString(context.runtime, dataByteList);
|
461
|
+
} catch (SSLException e) {
|
462
|
+
throw newSSLError(getRuntime(), e);
|
394
463
|
}
|
395
464
|
}
|
396
465
|
|
397
466
|
@JRubyMethod
|
398
|
-
public IRubyObject peercert() throws CertificateEncodingException {
|
467
|
+
public IRubyObject peercert(ThreadContext context) throws CertificateEncodingException {
|
468
|
+
Certificate peerCert;
|
399
469
|
try {
|
400
|
-
|
401
|
-
} catch (SSLPeerUnverifiedException
|
402
|
-
|
470
|
+
peerCert = engine.getSession().getPeerCertificates()[0];
|
471
|
+
} catch (SSLPeerUnverifiedException e) {
|
472
|
+
peerCert = lastCheckedCert0; // null if trust check did not happen
|
403
473
|
}
|
474
|
+
return peerCert == null ? context.nil : JavaEmbedUtils.javaToRuby(context.runtime, peerCert.getEncoded());
|
404
475
|
}
|
405
476
|
|
406
477
|
@JRubyMethod(name = "init?")
|
@@ -419,4 +490,19 @@ public class MiniSSL extends RubyObject {
|
|
419
490
|
return getRuntime().getFalse();
|
420
491
|
}
|
421
492
|
}
|
493
|
+
|
494
|
+
private static RubyClass getSSLError(Ruby runtime) {
|
495
|
+
return (RubyClass) ((RubyModule) runtime.getModule("Puma").getConstantAt("MiniSSL")).getConstantAt("SSLError");
|
496
|
+
}
|
497
|
+
|
498
|
+
private static RaiseException newSSLError(Ruby runtime, SSLException cause) {
|
499
|
+
return newError(runtime, getSSLError(runtime), cause.toString(), cause);
|
500
|
+
}
|
501
|
+
|
502
|
+
private static RaiseException newError(Ruby runtime, RubyClass errorClass, String message, Throwable cause) {
|
503
|
+
RaiseException ex = new RaiseException(runtime, errorClass, message, true);
|
504
|
+
ex.initCause(cause);
|
505
|
+
return ex;
|
506
|
+
}
|
507
|
+
|
422
508
|
}
|
@@ -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
|
|
@@ -451,7 +459,7 @@ VALUE HttpParser_body(VALUE self) {
|
|
451
459
|
void Init_mini_ssl(VALUE mod);
|
452
460
|
#endif
|
453
461
|
|
454
|
-
void Init_puma_http11()
|
462
|
+
void Init_puma_http11(void)
|
455
463
|
{
|
456
464
|
|
457
465
|
VALUE mPuma = rb_define_module("Puma");
|
@@ -461,7 +469,7 @@ void Init_puma_http11()
|
|
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]]
|