puma 3.12.6 → 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 +1806 -451
- data/LICENSE +23 -20
- data/README.md +217 -65
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +59 -21
- data/docs/compile_options.md +55 -0
- data/docs/deployment.md +69 -58
- data/docs/fork_worker.md +31 -0
- 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 +9 -0
- data/{tools → docs}/jungle/rc.d/README.md +1 -1
- data/{tools → docs}/jungle/rc.d/puma +2 -2
- data/docs/kubernetes.md +66 -0
- data/docs/nginx.md +2 -2
- data/docs/plugins.md +22 -12
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +47 -22
- data/docs/signals.md +13 -11
- data/docs/stats.md +142 -0
- data/docs/systemd.md +94 -120
- 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 -2
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +61 -3
- data/ext/puma_http11/http11_parser.c +103 -117
- data/ext/puma_http11/http11_parser.h +2 -2
- data/ext/puma_http11/http11_parser.java.rl +22 -38
- data/ext/puma_http11/http11_parser.rl +3 -3
- data/ext/puma_http11/http11_parser_common.rl +6 -6
- data/ext/puma_http11/mini_ssl.c +389 -99
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +84 -99
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +248 -92
- data/ext/puma_http11/puma_http11.c +49 -57
- data/lib/puma/app/status.rb +71 -49
- data/lib/puma/binder.rb +244 -150
- data/lib/puma/cli.rb +38 -34
- data/lib/puma/client.rb +388 -244
- data/lib/puma/cluster/worker.rb +180 -0
- data/lib/puma/cluster/worker_handle.rb +97 -0
- data/lib/puma/cluster.rb +261 -243
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +116 -88
- data/lib/puma/const.rb +154 -104
- data/lib/puma/control_cli.rb +115 -70
- data/lib/puma/detect.rb +33 -2
- data/lib/puma/dsl.rb +764 -134
- data/lib/puma/error_logger.rb +113 -0
- data/lib/puma/events.rb +16 -112
- data/lib/puma/io_buffer.rb +42 -5
- 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 +184 -133
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +93 -0
- data/lib/puma/minissl.rb +263 -70
- data/lib/puma/null_io.rb +18 -1
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +3 -1
- data/lib/puma/plugin.rb +7 -13
- data/lib/puma/rack/builder.rb +9 -11
- data/lib/puma/rack/urlmap.rb +2 -0
- data/lib/puma/rack_default.rb +21 -4
- data/lib/puma/reactor.rb +93 -315
- data/lib/puma/request.rb +671 -0
- data/lib/puma/runner.rb +94 -69
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +327 -772
- data/lib/puma/single.rb +20 -74
- data/lib/puma/state_file.rb +45 -8
- data/lib/puma/thread_pool.rb +146 -92
- data/lib/puma/util.rb +22 -10
- data/lib/puma.rb +60 -5
- data/lib/rack/handler/puma.rb +116 -90
- data/tools/Dockerfile +16 -0
- data/tools/trickletest.rb +0 -1
- metadata +54 -32
- data/ext/puma_http11/io_buffer.c +0 -155
- data/lib/puma/accept_nonblock.rb +0 -23
- data/lib/puma/compat.rb +0 -14
- data/lib/puma/convenient.rb +0 -25
- data/lib/puma/daemon_ext.rb +0 -33
- data/lib/puma/delegation.rb +0 -13
- data/lib/puma/java_io_buffer.rb +0 -47
- data/lib/puma/rack/backports/uri/common_193.rb +0 -33
- 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
- /data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
@@ -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,21 +24,29 @@ 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;
|
31
|
+
import java.nio.Buffer;
|
26
32
|
import java.nio.ByteBuffer;
|
27
33
|
import java.security.KeyManagementException;
|
28
34
|
import java.security.KeyStore;
|
29
35
|
import java.security.KeyStoreException;
|
30
36
|
import java.security.NoSuchAlgorithmException;
|
31
37
|
import java.security.UnrecoverableKeyException;
|
38
|
+
import java.security.cert.Certificate;
|
32
39
|
import java.security.cert.CertificateEncodingException;
|
33
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;
|
34
45
|
|
35
46
|
import static javax.net.ssl.SSLEngineResult.Status;
|
36
47
|
import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
37
48
|
|
38
|
-
public class MiniSSL extends RubyObject {
|
49
|
+
public class MiniSSL extends RubyObject { // MiniSSL::Engine
|
39
50
|
private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
40
51
|
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
41
52
|
return new MiniSSL(runtime, klass);
|
@@ -46,11 +57,10 @@ public class MiniSSL extends RubyObject {
|
|
46
57
|
RubyModule mPuma = runtime.defineModule("Puma");
|
47
58
|
RubyModule ssl = mPuma.defineModuleUnder("MiniSSL");
|
48
59
|
|
49
|
-
|
50
|
-
|
51
|
-
runtime.getClass("IOError").getAllocator());
|
60
|
+
// Puma::MiniSSL::SSLError
|
61
|
+
ssl.defineClassUnder("SSLError", runtime.getStandardError(), runtime.getStandardError().getAllocator());
|
52
62
|
|
53
|
-
RubyClass eng = ssl.defineClassUnder("Engine",runtime.getObject(),ALLOCATOR);
|
63
|
+
RubyClass eng = ssl.defineClassUnder("Engine", runtime.getObject(), ALLOCATOR);
|
54
64
|
eng.defineAnnotatedMethods(MiniSSL.class);
|
55
65
|
}
|
56
66
|
|
@@ -65,7 +75,7 @@ public class MiniSSL extends RubyObject {
|
|
65
75
|
|
66
76
|
public void clear() { buffer.clear(); }
|
67
77
|
public void compact() { buffer.compact(); }
|
68
|
-
public void flip() { buffer.flip(); }
|
78
|
+
public void flip() { ((Buffer) buffer).flip(); }
|
69
79
|
public boolean hasRemaining() { return buffer.hasRemaining(); }
|
70
80
|
public int position() { return buffer.position(); }
|
71
81
|
|
@@ -76,11 +86,11 @@ public class MiniSSL extends RubyObject {
|
|
76
86
|
/**
|
77
87
|
* Writes bytes to the buffer after ensuring there's room
|
78
88
|
*/
|
79
|
-
|
80
|
-
if (buffer.remaining() <
|
81
|
-
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);
|
82
92
|
}
|
83
|
-
buffer.put(bytes);
|
93
|
+
buffer.put(bytes, offset, length);
|
84
94
|
}
|
85
95
|
|
86
96
|
/**
|
@@ -89,7 +99,7 @@ public class MiniSSL extends RubyObject {
|
|
89
99
|
public void resize(int newCapacity) {
|
90
100
|
if (newCapacity > buffer.capacity()) {
|
91
101
|
ByteBuffer dstTmp = ByteBuffer.allocate(newCapacity);
|
92
|
-
|
102
|
+
flip();
|
93
103
|
dstTmp.put(buffer);
|
94
104
|
buffer = dstTmp;
|
95
105
|
} else {
|
@@ -101,7 +111,7 @@ public class MiniSSL extends RubyObject {
|
|
101
111
|
* Drains the buffer to a ByteList, or returns null for an empty buffer
|
102
112
|
*/
|
103
113
|
public ByteList asByteList() {
|
104
|
-
|
114
|
+
flip();
|
105
115
|
if (!buffer.hasRemaining()) {
|
106
116
|
buffer.clear();
|
107
117
|
return null;
|
@@ -111,7 +121,7 @@ public class MiniSSL extends RubyObject {
|
|
111
121
|
|
112
122
|
buffer.get(bss);
|
113
123
|
buffer.clear();
|
114
|
-
return new ByteList(bss);
|
124
|
+
return new ByteList(bss, false);
|
115
125
|
}
|
116
126
|
|
117
127
|
@Override
|
@@ -119,6 +129,8 @@ public class MiniSSL extends RubyObject {
|
|
119
129
|
}
|
120
130
|
|
121
131
|
private SSLEngine engine;
|
132
|
+
private boolean closed;
|
133
|
+
private boolean handshake;
|
122
134
|
private MiniSSLBuffer inboundNetData;
|
123
135
|
private MiniSSLBuffer outboundAppData;
|
124
136
|
private MiniSSLBuffer outboundNetData;
|
@@ -127,42 +139,119 @@ public class MiniSSL extends RubyObject {
|
|
127
139
|
super(runtime, klass);
|
128
140
|
}
|
129
141
|
|
130
|
-
|
131
|
-
|
132
|
-
|
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
|
+
}
|
133
175
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
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
|
+
}
|
138
199
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
143
|
-
KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
|
200
|
+
RubyClass klass = (RubyClass) recv;
|
201
|
+
return klass.newInstance(context, miniSSLContext, Block.NULL_BLOCK);
|
202
|
+
}
|
144
203
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
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
|
+
}
|
149
208
|
|
150
|
-
|
151
|
-
|
209
|
+
private static boolean isDefaultSymbol(ThreadContext context, IRubyObject truststore) {
|
210
|
+
return context.runtime.newSymbol("default").equals(truststore);
|
211
|
+
}
|
152
212
|
|
153
|
-
|
154
|
-
|
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
|
+
}
|
155
225
|
|
156
226
|
SSLContext sslCtx = SSLContext.getInstance("TLS");
|
157
227
|
|
158
|
-
sslCtx.init(kmf.getKeyManagers(),
|
228
|
+
sslCtx.init(kmf.getKeyManagers(), getTrustManagers(tmf), null);
|
229
|
+
closed = false;
|
230
|
+
handshake = false;
|
159
231
|
engine = sslCtx.createSSLEngine();
|
160
232
|
|
161
|
-
String[]
|
162
|
-
|
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
|
+
}
|
241
|
+
|
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());
|
249
|
+
}
|
250
|
+
engine.setEnabledProtocols(enabledProtocols);
|
251
|
+
|
163
252
|
engine.setUseClientMode(false);
|
164
253
|
|
165
|
-
long verify_mode = miniSSLContext.callMethod(
|
254
|
+
long verify_mode = miniSSLContext.callMethod(context, "verify_mode").convertToInteger("to_i").getLongValue();
|
166
255
|
if ((verify_mode & 0x1) != 0) { // 'peer'
|
167
256
|
engine.setWantClientAuth(true);
|
168
257
|
}
|
@@ -170,10 +259,11 @@ public class MiniSSL extends RubyObject {
|
|
170
259
|
engine.setNeedClientAuth(true);
|
171
260
|
}
|
172
261
|
|
173
|
-
IRubyObject
|
174
|
-
if (
|
175
|
-
String[]
|
176
|
-
|
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());
|
177
267
|
}
|
178
268
|
|
179
269
|
SSLSession session = engine.getSession();
|
@@ -185,16 +275,53 @@ public class MiniSSL extends RubyObject {
|
|
185
275
|
return this;
|
186
276
|
}
|
187
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
|
+
|
188
320
|
@JRubyMethod
|
189
321
|
public IRubyObject inject(IRubyObject arg) {
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
return this;
|
194
|
-
} catch (Exception e) {
|
195
|
-
e.printStackTrace();
|
196
|
-
throw new RuntimeException(e);
|
197
|
-
}
|
322
|
+
ByteList bytes = arg.convertToString().getByteList();
|
323
|
+
inboundNetData.put(bytes.unsafeBytes(), bytes.getBegin(), bytes.getRealSize());
|
324
|
+
return this;
|
198
325
|
}
|
199
326
|
|
200
327
|
private enum SSLOperation {
|
@@ -214,7 +341,7 @@ public class MiniSSL extends RubyObject {
|
|
214
341
|
res = engine.unwrap(src.getRawBuffer(), dst.getRawBuffer());
|
215
342
|
break;
|
216
343
|
default:
|
217
|
-
throw new
|
344
|
+
throw new AssertionError("Unknown SSLOperation: " + sslOp);
|
218
345
|
}
|
219
346
|
|
220
347
|
switch (res.getStatus()) {
|
@@ -229,17 +356,16 @@ public class MiniSSL extends RubyObject {
|
|
229
356
|
// need to wait for more data to come in before we retry
|
230
357
|
retryOp = false;
|
231
358
|
break;
|
359
|
+
case CLOSED:
|
360
|
+
closed = true;
|
361
|
+
retryOp = false;
|
362
|
+
break;
|
232
363
|
default:
|
233
|
-
// other
|
364
|
+
// other case is OK. We're done here.
|
234
365
|
retryOp = false;
|
235
366
|
}
|
236
|
-
|
237
|
-
|
238
|
-
// after each op, run any delegated tasks if needed
|
239
|
-
if(engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
240
|
-
Runnable runnable;
|
241
|
-
while ((runnable = engine.getDelegatedTask()) != null) {
|
242
|
-
runnable.run();
|
367
|
+
if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) {
|
368
|
+
handshake = true;
|
243
369
|
}
|
244
370
|
}
|
245
371
|
|
@@ -247,7 +373,7 @@ public class MiniSSL extends RubyObject {
|
|
247
373
|
}
|
248
374
|
|
249
375
|
@JRubyMethod
|
250
|
-
public IRubyObject read()
|
376
|
+
public IRubyObject read() {
|
251
377
|
try {
|
252
378
|
inboundNetData.flip();
|
253
379
|
|
@@ -261,21 +387,30 @@ public class MiniSSL extends RubyObject {
|
|
261
387
|
HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
|
262
388
|
boolean done = false;
|
263
389
|
while (!done) {
|
390
|
+
SSLEngineResult res;
|
264
391
|
switch (handshakeStatus) {
|
265
392
|
case NEED_WRAP:
|
266
|
-
doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
|
393
|
+
res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
|
394
|
+
handshakeStatus = res.getHandshakeStatus();
|
267
395
|
break;
|
268
396
|
case NEED_UNWRAP:
|
269
|
-
|
397
|
+
res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
|
270
398
|
if (res.getStatus() == Status.BUFFER_UNDERFLOW) {
|
271
399
|
// need more data before we can shake more hands
|
272
400
|
done = true;
|
273
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();
|
274
410
|
break;
|
275
411
|
default:
|
276
412
|
done = true;
|
277
413
|
}
|
278
|
-
handshakeStatus = engine.getHandshakeStatus();
|
279
414
|
}
|
280
415
|
|
281
416
|
if (inboundNetData.hasRemaining()) {
|
@@ -289,64 +424,85 @@ public class MiniSSL extends RubyObject {
|
|
289
424
|
return getRuntime().getNil();
|
290
425
|
}
|
291
426
|
|
292
|
-
RubyString
|
293
|
-
|
294
|
-
|
295
|
-
} catch (Exception e) {
|
296
|
-
throw getRuntime().newEOFError(e.getMessage());
|
427
|
+
return RubyString.newString(getRuntime(), appDataByteList);
|
428
|
+
} catch (SSLException e) {
|
429
|
+
throw newSSLError(getRuntime(), e);
|
297
430
|
}
|
298
431
|
}
|
299
432
|
|
300
433
|
@JRubyMethod
|
301
434
|
public IRubyObject write(IRubyObject arg) {
|
302
|
-
|
303
|
-
|
304
|
-
outboundAppData = new MiniSSLBuffer(bls);
|
435
|
+
byte[] bls = arg.convertToString().getBytes();
|
436
|
+
outboundAppData = new MiniSSLBuffer(bls);
|
305
437
|
|
306
|
-
|
307
|
-
} catch (Exception e) {
|
308
|
-
e.printStackTrace();
|
309
|
-
throw new RuntimeException(e);
|
310
|
-
}
|
438
|
+
return getRuntime().newFixnum(bls.length);
|
311
439
|
}
|
312
440
|
|
313
441
|
@JRubyMethod
|
314
|
-
public IRubyObject extract()
|
442
|
+
public IRubyObject extract(ThreadContext context) {
|
315
443
|
try {
|
316
444
|
ByteList dataByteList = outboundNetData.asByteList();
|
317
445
|
if (dataByteList != null) {
|
318
|
-
RubyString
|
319
|
-
str.setValue(dataByteList);
|
320
|
-
return str;
|
446
|
+
return RubyString.newString(context.runtime, dataByteList);
|
321
447
|
}
|
322
448
|
|
323
449
|
if (!outboundAppData.hasRemaining()) {
|
324
|
-
return
|
450
|
+
return context.nil;
|
325
451
|
}
|
326
452
|
|
327
453
|
outboundNetData.clear();
|
328
454
|
doOp(SSLOperation.WRAP, outboundAppData, outboundNetData);
|
329
455
|
dataByteList = outboundNetData.asByteList();
|
330
456
|
if (dataByteList == null) {
|
331
|
-
return
|
457
|
+
return context.nil;
|
332
458
|
}
|
333
459
|
|
334
|
-
RubyString
|
335
|
-
|
336
|
-
|
337
|
-
return str;
|
338
|
-
} catch (Exception e) {
|
339
|
-
e.printStackTrace();
|
340
|
-
throw new RuntimeException(e);
|
460
|
+
return RubyString.newString(context.runtime, dataByteList);
|
461
|
+
} catch (SSLException e) {
|
462
|
+
throw newSSLError(getRuntime(), e);
|
341
463
|
}
|
342
464
|
}
|
343
465
|
|
344
466
|
@JRubyMethod
|
345
|
-
public IRubyObject peercert() throws CertificateEncodingException {
|
467
|
+
public IRubyObject peercert(ThreadContext context) throws CertificateEncodingException {
|
468
|
+
Certificate peerCert;
|
346
469
|
try {
|
347
|
-
|
348
|
-
} catch (SSLPeerUnverifiedException
|
349
|
-
|
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();
|
350
491
|
}
|
351
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
|
+
|
352
508
|
}
|