puma 3.11.2 → 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 +5 -5
- data/History.md +1708 -422
- data/LICENSE +23 -20
- data/README.md +190 -64
- 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/docs/jungle/rc.d/README.md +74 -0
- data/docs/jungle/rc.d/puma +61 -0
- data/docs/jungle/rc.d/puma.conf +10 -0
- data/docs/kubernetes.md +66 -0
- data/docs/nginx.md +1 -1
- 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 +100 -115
- 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 +106 -118
- 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 +6 -4
- data/ext/puma_http11/http11_parser_common.rl +6 -6
- data/ext/puma_http11/mini_ssl.c +376 -93
- 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 +250 -88
- data/ext/puma_http11/puma_http11.c +49 -57
- data/lib/puma/app/status.rb +71 -49
- data/lib/puma/binder.rb +243 -148
- data/lib/puma/cli.rb +50 -35
- data/lib/puma/client.rb +369 -232
- data/lib/puma/cluster/worker.rb +175 -0
- data/lib/puma/cluster/worker_handle.rb +97 -0
- data/lib/puma/cluster.rb +268 -235
- data/lib/puma/commonlogger.rb +4 -2
- data/lib/puma/configuration.rb +116 -88
- data/lib/puma/const.rb +49 -30
- data/lib/puma/control_cli.rb +124 -77
- data/lib/puma/detect.rb +33 -2
- data/lib/puma/dsl.rb +685 -138
- data/lib/puma/error_logger.rb +112 -0
- data/lib/puma/events.rb +17 -111
- data/lib/puma/io_buffer.rb +34 -5
- data/lib/puma/jruby_restart.rb +4 -59
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +197 -130
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +92 -0
- data/lib/puma/minissl.rb +256 -70
- data/lib/puma/null_io.rb +20 -1
- data/lib/puma/plugin/tmp_restart.rb +3 -1
- data/lib/puma/plugin.rb +9 -13
- data/lib/puma/rack/builder.rb +8 -9
- data/lib/puma/rack/urlmap.rb +2 -0
- data/lib/puma/rack_default.rb +3 -1
- data/lib/puma/reactor.rb +90 -187
- data/lib/puma/request.rb +607 -0
- data/lib/puma/runner.rb +94 -71
- data/lib/puma/server.rb +336 -703
- data/lib/puma/single.rb +27 -72
- data/lib/puma/state_file.rb +46 -7
- data/lib/puma/systemd.rb +47 -0
- data/lib/puma/thread_pool.rb +185 -91
- data/lib/puma/util.rb +23 -10
- data/lib/puma.rb +68 -3
- data/lib/rack/handler/puma.rb +17 -14
- data/tools/Dockerfile +16 -0
- data/tools/trickletest.rb +0 -1
- metadata +53 -30
- 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 -23
- data/lib/puma/daemon_ext.rb +0 -31
- data/lib/puma/delegation.rb +0 -11
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack/backports/uri/common_193.rb +0 -33
- data/lib/puma/tcp_logger.rb +0 -39
- data/tools/jungle/README.md +0 -13
- data/tools/jungle/init.d/README.md +0 -59
- 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,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,6 +259,13 @@ public class MiniSSL extends RubyObject {
|
|
170
259
|
engine.setNeedClientAuth(true);
|
171
260
|
}
|
172
261
|
|
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());
|
267
|
+
}
|
268
|
+
|
173
269
|
SSLSession session = engine.getSession();
|
174
270
|
inboundNetData = new MiniSSLBuffer(session.getPacketBufferSize());
|
175
271
|
outboundAppData = new MiniSSLBuffer(session.getApplicationBufferSize());
|
@@ -179,16 +275,53 @@ public class MiniSSL extends RubyObject {
|
|
179
275
|
return this;
|
180
276
|
}
|
181
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
|
+
|
182
320
|
@JRubyMethod
|
183
321
|
public IRubyObject inject(IRubyObject arg) {
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
return this;
|
188
|
-
} catch (Exception e) {
|
189
|
-
e.printStackTrace();
|
190
|
-
throw new RuntimeException(e);
|
191
|
-
}
|
322
|
+
ByteList bytes = arg.convertToString().getByteList();
|
323
|
+
inboundNetData.put(bytes.unsafeBytes(), bytes.getBegin(), bytes.getRealSize());
|
324
|
+
return this;
|
192
325
|
}
|
193
326
|
|
194
327
|
private enum SSLOperation {
|
@@ -208,7 +341,7 @@ public class MiniSSL extends RubyObject {
|
|
208
341
|
res = engine.unwrap(src.getRawBuffer(), dst.getRawBuffer());
|
209
342
|
break;
|
210
343
|
default:
|
211
|
-
throw new
|
344
|
+
throw new AssertionError("Unknown SSLOperation: " + sslOp);
|
212
345
|
}
|
213
346
|
|
214
347
|
switch (res.getStatus()) {
|
@@ -223,17 +356,16 @@ public class MiniSSL extends RubyObject {
|
|
223
356
|
// need to wait for more data to come in before we retry
|
224
357
|
retryOp = false;
|
225
358
|
break;
|
359
|
+
case CLOSED:
|
360
|
+
closed = true;
|
361
|
+
retryOp = false;
|
362
|
+
break;
|
226
363
|
default:
|
227
|
-
// other
|
364
|
+
// other case is OK. We're done here.
|
228
365
|
retryOp = false;
|
229
366
|
}
|
230
|
-
|
231
|
-
|
232
|
-
// after each op, run any delegated tasks if needed
|
233
|
-
if(engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
234
|
-
Runnable runnable;
|
235
|
-
while ((runnable = engine.getDelegatedTask()) != null) {
|
236
|
-
runnable.run();
|
367
|
+
if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) {
|
368
|
+
handshake = true;
|
237
369
|
}
|
238
370
|
}
|
239
371
|
|
@@ -241,7 +373,7 @@ public class MiniSSL extends RubyObject {
|
|
241
373
|
}
|
242
374
|
|
243
375
|
@JRubyMethod
|
244
|
-
public IRubyObject read()
|
376
|
+
public IRubyObject read() {
|
245
377
|
try {
|
246
378
|
inboundNetData.flip();
|
247
379
|
|
@@ -255,21 +387,30 @@ public class MiniSSL extends RubyObject {
|
|
255
387
|
HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
|
256
388
|
boolean done = false;
|
257
389
|
while (!done) {
|
390
|
+
SSLEngineResult res;
|
258
391
|
switch (handshakeStatus) {
|
259
392
|
case NEED_WRAP:
|
260
|
-
doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
|
393
|
+
res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
|
394
|
+
handshakeStatus = res.getHandshakeStatus();
|
261
395
|
break;
|
262
396
|
case NEED_UNWRAP:
|
263
|
-
|
397
|
+
res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
|
264
398
|
if (res.getStatus() == Status.BUFFER_UNDERFLOW) {
|
265
399
|
// need more data before we can shake more hands
|
266
400
|
done = true;
|
267
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();
|
268
410
|
break;
|
269
411
|
default:
|
270
412
|
done = true;
|
271
413
|
}
|
272
|
-
handshakeStatus = engine.getHandshakeStatus();
|
273
414
|
}
|
274
415
|
|
275
416
|
if (inboundNetData.hasRemaining()) {
|
@@ -283,64 +424,85 @@ public class MiniSSL extends RubyObject {
|
|
283
424
|
return getRuntime().getNil();
|
284
425
|
}
|
285
426
|
|
286
|
-
RubyString
|
287
|
-
|
288
|
-
|
289
|
-
} catch (Exception e) {
|
290
|
-
throw getRuntime().newEOFError(e.getMessage());
|
427
|
+
return RubyString.newString(getRuntime(), appDataByteList);
|
428
|
+
} catch (SSLException e) {
|
429
|
+
throw newSSLError(getRuntime(), e);
|
291
430
|
}
|
292
431
|
}
|
293
432
|
|
294
433
|
@JRubyMethod
|
295
434
|
public IRubyObject write(IRubyObject arg) {
|
296
|
-
|
297
|
-
|
298
|
-
outboundAppData = new MiniSSLBuffer(bls);
|
435
|
+
byte[] bls = arg.convertToString().getBytes();
|
436
|
+
outboundAppData = new MiniSSLBuffer(bls);
|
299
437
|
|
300
|
-
|
301
|
-
} catch (Exception e) {
|
302
|
-
e.printStackTrace();
|
303
|
-
throw new RuntimeException(e);
|
304
|
-
}
|
438
|
+
return getRuntime().newFixnum(bls.length);
|
305
439
|
}
|
306
440
|
|
307
441
|
@JRubyMethod
|
308
|
-
public IRubyObject extract()
|
442
|
+
public IRubyObject extract(ThreadContext context) {
|
309
443
|
try {
|
310
444
|
ByteList dataByteList = outboundNetData.asByteList();
|
311
445
|
if (dataByteList != null) {
|
312
|
-
RubyString
|
313
|
-
str.setValue(dataByteList);
|
314
|
-
return str;
|
446
|
+
return RubyString.newString(context.runtime, dataByteList);
|
315
447
|
}
|
316
448
|
|
317
449
|
if (!outboundAppData.hasRemaining()) {
|
318
|
-
return
|
450
|
+
return context.nil;
|
319
451
|
}
|
320
452
|
|
321
453
|
outboundNetData.clear();
|
322
454
|
doOp(SSLOperation.WRAP, outboundAppData, outboundNetData);
|
323
455
|
dataByteList = outboundNetData.asByteList();
|
324
456
|
if (dataByteList == null) {
|
325
|
-
return
|
457
|
+
return context.nil;
|
326
458
|
}
|
327
459
|
|
328
|
-
RubyString
|
329
|
-
|
330
|
-
|
331
|
-
return str;
|
332
|
-
} catch (Exception e) {
|
333
|
-
e.printStackTrace();
|
334
|
-
throw new RuntimeException(e);
|
460
|
+
return RubyString.newString(context.runtime, dataByteList);
|
461
|
+
} catch (SSLException e) {
|
462
|
+
throw newSSLError(getRuntime(), e);
|
335
463
|
}
|
336
464
|
}
|
337
465
|
|
338
466
|
@JRubyMethod
|
339
|
-
public IRubyObject peercert() throws CertificateEncodingException {
|
467
|
+
public IRubyObject peercert(ThreadContext context) throws CertificateEncodingException {
|
468
|
+
Certificate peerCert;
|
340
469
|
try {
|
341
|
-
|
342
|
-
} catch (SSLPeerUnverifiedException
|
343
|
-
|
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();
|
344
491
|
}
|
345
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
|
+
|
346
508
|
}
|