puma 4.3.12 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +1591 -521
- data/LICENSE +23 -20
- data/README.md +130 -42
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +63 -26
- data/docs/compile_options.md +55 -0
- data/docs/deployment.md +60 -69
- data/docs/fork_worker.md +31 -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 +15 -15
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +46 -23
- data/docs/signals.md +13 -11
- data/docs/stats.md +142 -0
- data/docs/systemd.md +85 -128
- 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 +2 -4
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +49 -12
- data/ext/puma_http11/http11_parser.c +46 -48
- data/ext/puma_http11/http11_parser.h +2 -2
- data/ext/puma_http11/http11_parser.java.rl +3 -3
- data/ext/puma_http11/http11_parser.rl +3 -3
- data/ext/puma_http11/http11_parser_common.rl +2 -2
- data/ext/puma_http11/mini_ssl.c +250 -93
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +6 -6
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +4 -6
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +241 -96
- data/ext/puma_http11/puma_http11.c +46 -57
- data/lib/puma/app/status.rb +52 -38
- data/lib/puma/binder.rb +232 -119
- data/lib/puma/cli.rb +33 -33
- data/lib/puma/client.rb +125 -87
- data/lib/puma/cluster/worker.rb +175 -0
- data/lib/puma/cluster/worker_handle.rb +97 -0
- data/lib/puma/cluster.rb +224 -229
- data/lib/puma/commonlogger.rb +2 -2
- data/lib/puma/configuration.rb +112 -87
- data/lib/puma/const.rb +25 -22
- data/lib/puma/control_cli.rb +99 -79
- data/lib/puma/detect.rb +31 -2
- data/lib/puma/dsl.rb +423 -110
- data/lib/puma/error_logger.rb +112 -0
- data/lib/puma/events.rb +16 -115
- data/lib/puma/io_buffer.rb +34 -2
- data/lib/puma/jruby_restart.rb +2 -59
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +170 -148
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +35 -19
- data/lib/puma/minissl.rb +213 -55
- data/lib/puma/null_io.rb +18 -1
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +3 -12
- data/lib/puma/rack/builder.rb +5 -9
- data/lib/puma/rack_default.rb +1 -1
- data/lib/puma/reactor.rb +85 -369
- data/lib/puma/request.rb +607 -0
- data/lib/puma/runner.rb +83 -77
- data/lib/puma/server.rb +305 -789
- data/lib/puma/single.rb +18 -74
- data/lib/puma/state_file.rb +45 -8
- data/lib/puma/systemd.rb +47 -0
- data/lib/puma/thread_pool.rb +137 -66
- data/lib/puma/util.rb +21 -4
- data/lib/puma.rb +54 -5
- data/lib/rack/handler/puma.rb +11 -12
- data/tools/{docker/Dockerfile → Dockerfile} +1 -1
- metadata +31 -23
- 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
@@ -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,7 +24,9 @@ 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;
|
29
|
+
import java.io.InputStream;
|
25
30
|
import java.io.IOException;
|
26
31
|
import java.nio.Buffer;
|
27
32
|
import java.nio.ByteBuffer;
|
@@ -30,13 +35,18 @@ import java.security.KeyStore;
|
|
30
35
|
import java.security.KeyStoreException;
|
31
36
|
import java.security.NoSuchAlgorithmException;
|
32
37
|
import java.security.UnrecoverableKeyException;
|
38
|
+
import java.security.cert.Certificate;
|
33
39
|
import java.security.cert.CertificateEncodingException;
|
34
40
|
import java.security.cert.CertificateException;
|
41
|
+
import java.security.cert.X509Certificate;
|
42
|
+
import java.util.concurrent.ConcurrentHashMap;
|
43
|
+
import java.util.Map;
|
44
|
+
import java.util.function.Supplier;
|
35
45
|
|
36
46
|
import static javax.net.ssl.SSLEngineResult.Status;
|
37
47
|
import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
38
48
|
|
39
|
-
public class MiniSSL extends RubyObject {
|
49
|
+
public class MiniSSL extends RubyObject { // MiniSSL::Engine
|
40
50
|
private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
41
51
|
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
42
52
|
return new MiniSSL(runtime, klass);
|
@@ -47,11 +57,10 @@ public class MiniSSL extends RubyObject {
|
|
47
57
|
RubyModule mPuma = runtime.defineModule("Puma");
|
48
58
|
RubyModule ssl = mPuma.defineModuleUnder("MiniSSL");
|
49
59
|
|
50
|
-
|
51
|
-
|
52
|
-
runtime.getClass("IOError").getAllocator());
|
60
|
+
// Puma::MiniSSL::SSLError
|
61
|
+
ssl.defineClassUnder("SSLError", runtime.getStandardError(), runtime.getStandardError().getAllocator());
|
53
62
|
|
54
|
-
RubyClass eng = ssl.defineClassUnder("Engine",runtime.getObject(),ALLOCATOR);
|
63
|
+
RubyClass eng = ssl.defineClassUnder("Engine", runtime.getObject(), ALLOCATOR);
|
55
64
|
eng.defineAnnotatedMethods(MiniSSL.class);
|
56
65
|
}
|
57
66
|
|
@@ -77,11 +86,11 @@ public class MiniSSL extends RubyObject {
|
|
77
86
|
/**
|
78
87
|
* Writes bytes to the buffer after ensuring there's room
|
79
88
|
*/
|
80
|
-
|
81
|
-
if (buffer.remaining() <
|
82
|
-
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);
|
83
92
|
}
|
84
|
-
buffer.put(bytes);
|
93
|
+
buffer.put(bytes, offset, length);
|
85
94
|
}
|
86
95
|
|
87
96
|
/**
|
@@ -112,7 +121,7 @@ public class MiniSSL extends RubyObject {
|
|
112
121
|
|
113
122
|
buffer.get(bss);
|
114
123
|
buffer.clear();
|
115
|
-
return new ByteList(bss);
|
124
|
+
return new ByteList(bss, false);
|
116
125
|
}
|
117
126
|
|
118
127
|
@Override
|
@@ -120,6 +129,8 @@ public class MiniSSL extends RubyObject {
|
|
120
129
|
}
|
121
130
|
|
122
131
|
private SSLEngine engine;
|
132
|
+
private boolean closed;
|
133
|
+
private boolean handshake;
|
123
134
|
private MiniSSLBuffer inboundNetData;
|
124
135
|
private MiniSSLBuffer outboundAppData;
|
125
136
|
private MiniSSLBuffer outboundNetData;
|
@@ -128,52 +139,119 @@ public class MiniSSL extends RubyObject {
|
|
128
139
|
super(runtime, klass);
|
129
140
|
}
|
130
141
|
|
131
|
-
|
132
|
-
|
133
|
-
|
142
|
+
private static Map<String, KeyManagerFactory> keyManagerFactoryMap = new ConcurrentHashMap<String, KeyManagerFactory>();
|
143
|
+
private static Map<String, TrustManagerFactory> trustManagerFactoryMap = new ConcurrentHashMap<String, TrustManagerFactory>();
|
144
|
+
|
145
|
+
@JRubyMethod(meta = true) // Engine.server
|
146
|
+
public static synchronized IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext)
|
147
|
+
throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
|
148
|
+
// Create the KeyManagerFactory and TrustManagerFactory for this server
|
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
|
+
}
|
134
175
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
176
|
+
KeyStore ks = KeyStore.getInstance(keystoreType);
|
177
|
+
InputStream is = new FileInputStream(keystoreFile);
|
178
|
+
try {
|
179
|
+
ks.load(is, keystorePass);
|
180
|
+
} finally {
|
181
|
+
is.close();
|
182
|
+
}
|
183
|
+
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
184
|
+
kmf.init(ks, keystorePass);
|
185
|
+
keyManagerFactoryMap.put(keystoreFile, kmf);
|
186
|
+
|
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);
|
198
|
+
}
|
139
199
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
144
|
-
KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
|
200
|
+
RubyClass klass = (RubyClass) recv;
|
201
|
+
return klass.newInstance(context, miniSSLContext, Block.NULL_BLOCK);
|
202
|
+
}
|
145
203
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
+
}
|
150
208
|
|
151
|
-
|
152
|
-
|
209
|
+
private static boolean isDefaultSymbol(ThreadContext context, IRubyObject truststore) {
|
210
|
+
return context.runtime.newSymbol("default").equals(truststore);
|
211
|
+
}
|
153
212
|
|
154
|
-
|
155
|
-
|
213
|
+
@JRubyMethod
|
214
|
+
public IRubyObject initialize(ThreadContext context, IRubyObject miniSSLContext)
|
215
|
+
throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
|
216
|
+
|
217
|
+
String keystoreFile = miniSSLContext.callMethod(context, "keystore").convertToString().asJavaString();
|
218
|
+
KeyManagerFactory kmf = keyManagerFactoryMap.get(keystoreFile);
|
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);
|
224
|
+
}
|
156
225
|
|
157
226
|
SSLContext sslCtx = SSLContext.getInstance("TLS");
|
158
227
|
|
159
|
-
sslCtx.init(kmf.getKeyManagers(),
|
228
|
+
sslCtx.init(kmf.getKeyManagers(), getTrustManagers(tmf), null);
|
229
|
+
closed = false;
|
230
|
+
handshake = false;
|
160
231
|
engine = sslCtx.createSSLEngine();
|
161
232
|
|
162
|
-
String[]
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
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
|
+
}
|
168
241
|
|
169
|
-
|
170
|
-
|
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());
|
171
249
|
}
|
250
|
+
engine.setEnabledProtocols(enabledProtocols);
|
172
251
|
|
173
|
-
engine.setEnabledProtocols(protocols);
|
174
252
|
engine.setUseClientMode(false);
|
175
253
|
|
176
|
-
long verify_mode = miniSSLContext.callMethod(
|
254
|
+
long verify_mode = miniSSLContext.callMethod(context, "verify_mode").convertToInteger("to_i").getLongValue();
|
177
255
|
if ((verify_mode & 0x1) != 0) { // 'peer'
|
178
256
|
engine.setWantClientAuth(true);
|
179
257
|
}
|
@@ -181,10 +259,11 @@ public class MiniSSL extends RubyObject {
|
|
181
259
|
engine.setNeedClientAuth(true);
|
182
260
|
}
|
183
261
|
|
184
|
-
IRubyObject
|
185
|
-
if (
|
186
|
-
String[]
|
187
|
-
|
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());
|
188
267
|
}
|
189
268
|
|
190
269
|
SSLSession session = engine.getSession();
|
@@ -196,16 +275,53 @@ public class MiniSSL extends RubyObject {
|
|
196
275
|
return this;
|
197
276
|
}
|
198
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
|
+
|
199
320
|
@JRubyMethod
|
200
321
|
public IRubyObject inject(IRubyObject arg) {
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
return this;
|
205
|
-
} catch (Exception e) {
|
206
|
-
e.printStackTrace();
|
207
|
-
throw new RuntimeException(e);
|
208
|
-
}
|
322
|
+
ByteList bytes = arg.convertToString().getByteList();
|
323
|
+
inboundNetData.put(bytes.unsafeBytes(), bytes.getBegin(), bytes.getRealSize());
|
324
|
+
return this;
|
209
325
|
}
|
210
326
|
|
211
327
|
private enum SSLOperation {
|
@@ -225,7 +341,7 @@ public class MiniSSL extends RubyObject {
|
|
225
341
|
res = engine.unwrap(src.getRawBuffer(), dst.getRawBuffer());
|
226
342
|
break;
|
227
343
|
default:
|
228
|
-
throw new
|
344
|
+
throw new AssertionError("Unknown SSLOperation: " + sslOp);
|
229
345
|
}
|
230
346
|
|
231
347
|
switch (res.getStatus()) {
|
@@ -240,17 +356,16 @@ public class MiniSSL extends RubyObject {
|
|
240
356
|
// need to wait for more data to come in before we retry
|
241
357
|
retryOp = false;
|
242
358
|
break;
|
359
|
+
case CLOSED:
|
360
|
+
closed = true;
|
361
|
+
retryOp = false;
|
362
|
+
break;
|
243
363
|
default:
|
244
|
-
// other
|
364
|
+
// other case is OK. We're done here.
|
245
365
|
retryOp = false;
|
246
366
|
}
|
247
|
-
|
248
|
-
|
249
|
-
// after each op, run any delegated tasks if needed
|
250
|
-
if(engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
251
|
-
Runnable runnable;
|
252
|
-
while ((runnable = engine.getDelegatedTask()) != null) {
|
253
|
-
runnable.run();
|
367
|
+
if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) {
|
368
|
+
handshake = true;
|
254
369
|
}
|
255
370
|
}
|
256
371
|
|
@@ -258,7 +373,7 @@ public class MiniSSL extends RubyObject {
|
|
258
373
|
}
|
259
374
|
|
260
375
|
@JRubyMethod
|
261
|
-
public IRubyObject read()
|
376
|
+
public IRubyObject read() {
|
262
377
|
try {
|
263
378
|
inboundNetData.flip();
|
264
379
|
|
@@ -272,21 +387,30 @@ public class MiniSSL extends RubyObject {
|
|
272
387
|
HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
|
273
388
|
boolean done = false;
|
274
389
|
while (!done) {
|
390
|
+
SSLEngineResult res;
|
275
391
|
switch (handshakeStatus) {
|
276
392
|
case NEED_WRAP:
|
277
|
-
doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
|
393
|
+
res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
|
394
|
+
handshakeStatus = res.getHandshakeStatus();
|
278
395
|
break;
|
279
396
|
case NEED_UNWRAP:
|
280
|
-
|
397
|
+
res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
|
281
398
|
if (res.getStatus() == Status.BUFFER_UNDERFLOW) {
|
282
399
|
// need more data before we can shake more hands
|
283
400
|
done = true;
|
284
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();
|
285
410
|
break;
|
286
411
|
default:
|
287
412
|
done = true;
|
288
413
|
}
|
289
|
-
handshakeStatus = engine.getHandshakeStatus();
|
290
414
|
}
|
291
415
|
|
292
416
|
if (inboundNetData.hasRemaining()) {
|
@@ -300,64 +424,85 @@ public class MiniSSL extends RubyObject {
|
|
300
424
|
return getRuntime().getNil();
|
301
425
|
}
|
302
426
|
|
303
|
-
RubyString
|
304
|
-
|
305
|
-
|
306
|
-
} catch (Exception e) {
|
307
|
-
throw getRuntime().newEOFError(e.getMessage());
|
427
|
+
return RubyString.newString(getRuntime(), appDataByteList);
|
428
|
+
} catch (SSLException e) {
|
429
|
+
throw newSSLError(getRuntime(), e);
|
308
430
|
}
|
309
431
|
}
|
310
432
|
|
311
433
|
@JRubyMethod
|
312
434
|
public IRubyObject write(IRubyObject arg) {
|
313
|
-
|
314
|
-
|
315
|
-
outboundAppData = new MiniSSLBuffer(bls);
|
435
|
+
byte[] bls = arg.convertToString().getBytes();
|
436
|
+
outboundAppData = new MiniSSLBuffer(bls);
|
316
437
|
|
317
|
-
|
318
|
-
} catch (Exception e) {
|
319
|
-
e.printStackTrace();
|
320
|
-
throw new RuntimeException(e);
|
321
|
-
}
|
438
|
+
return getRuntime().newFixnum(bls.length);
|
322
439
|
}
|
323
440
|
|
324
441
|
@JRubyMethod
|
325
|
-
public IRubyObject extract()
|
442
|
+
public IRubyObject extract(ThreadContext context) {
|
326
443
|
try {
|
327
444
|
ByteList dataByteList = outboundNetData.asByteList();
|
328
445
|
if (dataByteList != null) {
|
329
|
-
RubyString
|
330
|
-
str.setValue(dataByteList);
|
331
|
-
return str;
|
446
|
+
return RubyString.newString(context.runtime, dataByteList);
|
332
447
|
}
|
333
448
|
|
334
449
|
if (!outboundAppData.hasRemaining()) {
|
335
|
-
return
|
450
|
+
return context.nil;
|
336
451
|
}
|
337
452
|
|
338
453
|
outboundNetData.clear();
|
339
454
|
doOp(SSLOperation.WRAP, outboundAppData, outboundNetData);
|
340
455
|
dataByteList = outboundNetData.asByteList();
|
341
456
|
if (dataByteList == null) {
|
342
|
-
return
|
457
|
+
return context.nil;
|
343
458
|
}
|
344
459
|
|
345
|
-
RubyString
|
346
|
-
|
347
|
-
|
348
|
-
return str;
|
349
|
-
} catch (Exception e) {
|
350
|
-
e.printStackTrace();
|
351
|
-
throw new RuntimeException(e);
|
460
|
+
return RubyString.newString(context.runtime, dataByteList);
|
461
|
+
} catch (SSLException e) {
|
462
|
+
throw newSSLError(getRuntime(), e);
|
352
463
|
}
|
353
464
|
}
|
354
465
|
|
355
466
|
@JRubyMethod
|
356
|
-
public IRubyObject peercert() throws CertificateEncodingException {
|
467
|
+
public IRubyObject peercert(ThreadContext context) throws CertificateEncodingException {
|
468
|
+
Certificate peerCert;
|
357
469
|
try {
|
358
|
-
|
359
|
-
} catch (SSLPeerUnverifiedException
|
360
|
-
|
470
|
+
peerCert = engine.getSession().getPeerCertificates()[0];
|
471
|
+
} catch (SSLPeerUnverifiedException e) {
|
472
|
+
peerCert = lastCheckedCert0; // null if trust check did not happen
|
473
|
+
}
|
474
|
+
return peerCert == null ? context.nil : JavaEmbedUtils.javaToRuby(context.runtime, peerCert.getEncoded());
|
475
|
+
}
|
476
|
+
|
477
|
+
@JRubyMethod(name = "init?")
|
478
|
+
public IRubyObject isInit(ThreadContext context) {
|
479
|
+
return handshake ? getRuntime().getFalse() : getRuntime().getTrue();
|
480
|
+
}
|
481
|
+
|
482
|
+
@JRubyMethod
|
483
|
+
public IRubyObject shutdown() {
|
484
|
+
if (closed || engine.isInboundDone() && engine.isOutboundDone()) {
|
485
|
+
if (engine.isOutboundDone()) {
|
486
|
+
engine.closeOutbound();
|
487
|
+
}
|
488
|
+
return getRuntime().getTrue();
|
489
|
+
} else {
|
490
|
+
return getRuntime().getFalse();
|
361
491
|
}
|
362
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
|
+
|
363
508
|
}
|