puma 2.0.0.b5 → 5.0.0.beta1

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.

Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +1598 -0
  3. data/LICENSE +23 -20
  4. data/README.md +222 -62
  5. data/bin/puma-wild +31 -0
  6. data/bin/pumactl +1 -1
  7. data/docs/architecture.md +37 -0
  8. data/docs/deployment.md +113 -0
  9. data/docs/fork_worker.md +31 -0
  10. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  11. data/docs/images/puma-connection-flow.png +0 -0
  12. data/docs/images/puma-general-arch.png +0 -0
  13. data/docs/jungle/README.md +13 -0
  14. data/docs/jungle/rc.d/README.md +74 -0
  15. data/docs/jungle/rc.d/puma +61 -0
  16. data/docs/jungle/rc.d/puma.conf +10 -0
  17. data/docs/jungle/upstart/README.md +61 -0
  18. data/docs/jungle/upstart/puma-manager.conf +31 -0
  19. data/docs/jungle/upstart/puma.conf +69 -0
  20. data/docs/nginx.md +5 -10
  21. data/docs/plugins.md +38 -0
  22. data/docs/restart.md +41 -0
  23. data/docs/signals.md +97 -0
  24. data/docs/systemd.md +228 -0
  25. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  26. data/ext/puma_http11/extconf.rb +23 -2
  27. data/ext/puma_http11/http11_parser.c +301 -482
  28. data/ext/puma_http11/http11_parser.h +13 -11
  29. data/ext/puma_http11/http11_parser.java.rl +26 -42
  30. data/ext/puma_http11/http11_parser.rl +22 -21
  31. data/ext/puma_http11/http11_parser_common.rl +5 -5
  32. data/ext/puma_http11/mini_ssl.c +377 -18
  33. data/ext/puma_http11/org/jruby/puma/Http11.java +108 -107
  34. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +137 -170
  35. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +265 -191
  36. data/ext/puma_http11/puma_http11.c +57 -81
  37. data/lib/puma.rb +25 -4
  38. data/lib/puma/accept_nonblock.rb +7 -1
  39. data/lib/puma/app/status.rb +61 -24
  40. data/lib/puma/binder.rb +212 -78
  41. data/lib/puma/cli.rb +149 -644
  42. data/lib/puma/client.rb +316 -65
  43. data/lib/puma/cluster.rb +659 -0
  44. data/lib/puma/commonlogger.rb +108 -0
  45. data/lib/puma/configuration.rb +279 -180
  46. data/lib/puma/const.rb +126 -39
  47. data/lib/puma/control_cli.rb +183 -96
  48. data/lib/puma/detect.rb +20 -1
  49. data/lib/puma/dsl.rb +776 -0
  50. data/lib/puma/events.rb +91 -23
  51. data/lib/puma/io_buffer.rb +9 -5
  52. data/lib/puma/jruby_restart.rb +9 -5
  53. data/lib/puma/launcher.rb +487 -0
  54. data/lib/puma/minissl.rb +239 -93
  55. data/lib/puma/minissl/context_builder.rb +76 -0
  56. data/lib/puma/null_io.rb +22 -12
  57. data/lib/puma/plugin.rb +111 -0
  58. data/lib/puma/plugin/tmp_restart.rb +36 -0
  59. data/lib/puma/rack/builder.rb +297 -0
  60. data/lib/puma/rack/urlmap.rb +93 -0
  61. data/lib/puma/rack_default.rb +9 -0
  62. data/lib/puma/reactor.rb +290 -43
  63. data/lib/puma/runner.rb +163 -0
  64. data/lib/puma/server.rb +493 -126
  65. data/lib/puma/single.rb +66 -0
  66. data/lib/puma/state_file.rb +34 -0
  67. data/lib/puma/thread_pool.rb +228 -47
  68. data/lib/puma/util.rb +115 -0
  69. data/lib/rack/handler/puma.rb +78 -31
  70. data/tools/Dockerfile +16 -0
  71. data/tools/trickletest.rb +44 -0
  72. metadata +60 -155
  73. data/COPYING +0 -55
  74. data/Gemfile +0 -8
  75. data/History.txt +0 -196
  76. data/Manifest.txt +0 -56
  77. data/Rakefile +0 -121
  78. data/TODO +0 -5
  79. data/docs/config.md +0 -0
  80. data/ext/puma_http11/io_buffer.c +0 -154
  81. data/lib/puma/capistrano.rb +0 -26
  82. data/lib/puma/compat.rb +0 -11
  83. data/lib/puma/daemon_ext.rb +0 -20
  84. data/lib/puma/delegation.rb +0 -11
  85. data/lib/puma/java_io_buffer.rb +0 -45
  86. data/lib/puma/rack_patch.rb +0 -25
  87. data/puma.gemspec +0 -45
  88. data/test/test_app_status.rb +0 -88
  89. data/test/test_cli.rb +0 -171
  90. data/test/test_config.rb +0 -16
  91. data/test/test_http10.rb +0 -27
  92. data/test/test_http11.rb +0 -126
  93. data/test/test_integration.rb +0 -150
  94. data/test/test_iobuffer.rb +0 -38
  95. data/test/test_minissl.rb +0 -22
  96. data/test/test_null_io.rb +0 -31
  97. data/test/test_persistent.rb +0 -238
  98. data/test/test_puma_server.rb +0 -128
  99. data/test/test_rack_handler.rb +0 -10
  100. data/test/test_rack_server.rb +0 -141
  101. data/test/test_thread_pool.rb +0 -146
  102. data/test/test_unix_socket.rb +0 -39
  103. data/test/test_ws.rb +0 -89
  104. data/tools/jungle/README.md +0 -54
  105. data/tools/jungle/puma +0 -332
  106. data/tools/jungle/run-puma +0 -3
@@ -2,29 +2,39 @@ package org.jruby.puma;
2
2
 
3
3
  import org.jruby.Ruby;
4
4
  import org.jruby.RubyClass;
5
- import org.jruby.RubyHash;
6
5
  import org.jruby.RubyModule;
7
- import org.jruby.RubyNumeric;
8
6
  import org.jruby.RubyObject;
9
7
  import org.jruby.RubyString;
10
-
11
8
  import org.jruby.anno.JRubyMethod;
12
-
9
+ import org.jruby.javasupport.JavaEmbedUtils;
13
10
  import org.jruby.runtime.Block;
14
11
  import org.jruby.runtime.ObjectAllocator;
15
12
  import org.jruby.runtime.ThreadContext;
16
13
  import org.jruby.runtime.builtin.IRubyObject;
17
-
18
- import org.jruby.exceptions.RaiseException;
19
-
20
14
  import org.jruby.util.ByteList;
21
15
 
22
-
23
- import javax.net.ssl.*;
24
- import javax.net.ssl.SSLEngineResult.*;
25
- import java.io.*;
26
- import java.security.*;
27
- import java.nio.*;
16
+ import javax.net.ssl.KeyManagerFactory;
17
+ import javax.net.ssl.TrustManagerFactory;
18
+ import javax.net.ssl.SSLContext;
19
+ import javax.net.ssl.SSLEngine;
20
+ import javax.net.ssl.SSLEngineResult;
21
+ import javax.net.ssl.SSLException;
22
+ import javax.net.ssl.SSLPeerUnverifiedException;
23
+ import javax.net.ssl.SSLSession;
24
+ import java.io.FileInputStream;
25
+ import java.io.IOException;
26
+ import java.nio.Buffer;
27
+ import java.nio.ByteBuffer;
28
+ import java.security.KeyManagementException;
29
+ import java.security.KeyStore;
30
+ import java.security.KeyStoreException;
31
+ import java.security.NoSuchAlgorithmException;
32
+ import java.security.UnrecoverableKeyException;
33
+ import java.security.cert.CertificateEncodingException;
34
+ import java.security.cert.CertificateException;
35
+
36
+ import static javax.net.ssl.SSLEngineResult.Status;
37
+ import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
28
38
 
29
39
  public class MiniSSL extends RubyObject {
30
40
  private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
@@ -35,7 +45,7 @@ public class MiniSSL extends RubyObject {
35
45
 
36
46
  public static void createMiniSSL(Ruby runtime) {
37
47
  RubyModule mPuma = runtime.defineModule("Puma");
38
- RubyModule ssl = mPuma.defineModuleUnder("MiniSSL");
48
+ RubyModule ssl = mPuma.defineModuleUnder("MiniSSL");
39
49
 
40
50
  mPuma.defineClassUnder("SSLError",
41
51
  runtime.getClass("IOError"),
@@ -45,55 +55,101 @@ public class MiniSSL extends RubyObject {
45
55
  eng.defineAnnotatedMethods(MiniSSL.class);
46
56
  }
47
57
 
48
- private Ruby runtime;
49
- private SSLContext sslc;
58
+ /**
59
+ * Fairly transparent wrapper around {@link java.nio.ByteBuffer} which adds the enhancements we need
60
+ */
61
+ private static class MiniSSLBuffer {
62
+ ByteBuffer buffer;
63
+
64
+ private MiniSSLBuffer(int capacity) { buffer = ByteBuffer.allocate(capacity); }
65
+ private MiniSSLBuffer(byte[] initialContents) { buffer = ByteBuffer.wrap(initialContents); }
66
+
67
+ public void clear() { buffer.clear(); }
68
+ public void compact() { buffer.compact(); }
69
+ public void flip() { ((Buffer) buffer).flip(); }
70
+ public boolean hasRemaining() { return buffer.hasRemaining(); }
71
+ public int position() { return buffer.position(); }
72
+
73
+ public ByteBuffer getRawBuffer() {
74
+ return buffer;
75
+ }
76
+
77
+ /**
78
+ * Writes bytes to the buffer after ensuring there's room
79
+ */
80
+ public void put(byte[] bytes) {
81
+ if (buffer.remaining() < bytes.length) {
82
+ resize(buffer.limit() + bytes.length);
83
+ }
84
+ buffer.put(bytes);
85
+ }
86
+
87
+ /**
88
+ * Ensures that newCapacity bytes can be written to this buffer, only re-allocating if necessary
89
+ */
90
+ public void resize(int newCapacity) {
91
+ if (newCapacity > buffer.capacity()) {
92
+ ByteBuffer dstTmp = ByteBuffer.allocate(newCapacity);
93
+ flip();
94
+ dstTmp.put(buffer);
95
+ buffer = dstTmp;
96
+ } else {
97
+ buffer.limit(newCapacity);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Drains the buffer to a ByteList, or returns null for an empty buffer
103
+ */
104
+ public ByteList asByteList() {
105
+ flip();
106
+ if (!buffer.hasRemaining()) {
107
+ buffer.clear();
108
+ return null;
109
+ }
110
+
111
+ byte[] bss = new byte[buffer.limit()];
112
+
113
+ buffer.get(bss);
114
+ buffer.clear();
115
+ return new ByteList(bss);
116
+ }
117
+
118
+ @Override
119
+ public String toString() { return buffer.toString(); }
120
+ }
50
121
 
51
- private SSLEngine engine;
122
+ private SSLEngine engine;
123
+ private MiniSSLBuffer inboundNetData;
124
+ private MiniSSLBuffer outboundAppData;
125
+ private MiniSSLBuffer outboundNetData;
52
126
 
53
- private ByteBuffer peerAppData;
54
- private ByteBuffer peerNetData;
55
- private ByteBuffer netData;
56
- private ByteBuffer dummy;
57
-
58
127
  public MiniSSL(Ruby runtime, RubyClass klass) {
59
128
  super(runtime, klass);
60
-
61
- this.runtime = runtime;
62
129
  }
63
130
 
64
131
  @JRubyMethod(meta = true)
65
- public static IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject key, IRubyObject cert) {
66
- RubyClass klass = (RubyClass) recv;
67
- IRubyObject newInstance = klass.newInstance(context,
68
- new IRubyObject[] { key, cert },
69
- Block.NULL_BLOCK);
132
+ public static IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext) {
133
+ RubyClass klass = (RubyClass) recv;
70
134
 
71
- return newInstance;
135
+ return klass.newInstance(context,
136
+ new IRubyObject[] { miniSSLContext },
137
+ Block.NULL_BLOCK);
72
138
  }
73
139
 
74
140
  @JRubyMethod
75
- public IRubyObject initialize(IRubyObject key, IRubyObject cert)
76
- throws java.security.KeyStoreException,
77
- java.io.FileNotFoundException,
78
- java.io.IOException,
79
- java.io.FileNotFoundException,
80
- java.security.NoSuchAlgorithmException,
81
- java.security.KeyManagementException,
82
- java.security.cert.CertificateException,
83
- java.security.UnrecoverableKeyException
84
- {
141
+ public IRubyObject initialize(ThreadContext threadContext, IRubyObject miniSSLContext)
142
+ throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
85
143
  KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
86
144
  KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
87
145
 
88
- char[] pass = "blahblah".toCharArray();
89
-
90
- ks.load(new FileInputStream(key.convertToString().asJavaString()),
91
- pass);
92
- ts.load(new FileInputStream(cert.convertToString().asJavaString()),
93
- pass);
146
+ char[] password = miniSSLContext.callMethod(threadContext, "keystore_pass").convertToString().asJavaString().toCharArray();
147
+ String keystoreFile = miniSSLContext.callMethod(threadContext, "keystore").convertToString().asJavaString();
148
+ ks.load(new FileInputStream(keystoreFile), password);
149
+ ts.load(new FileInputStream(keystoreFile), password);
94
150
 
95
151
  KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
96
- kmf.init(ks, pass);
152
+ kmf.init(ks, password);
97
153
 
98
154
  TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
99
155
  tmf.init(ts);
@@ -101,189 +157,207 @@ public class MiniSSL extends RubyObject {
101
157
  SSLContext sslCtx = SSLContext.getInstance("TLS");
102
158
 
103
159
  sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
160
+ engine = sslCtx.createSSLEngine();
104
161
 
105
- sslc = sslCtx;
106
-
107
- engine = sslc.createSSLEngine();
108
- engine.setUseClientMode(false);
109
- // engine.setNeedClientAuth(true);
162
+ String[] protocols;
163
+ if(miniSSLContext.callMethod(threadContext, "no_tlsv1").isTrue()) {
164
+ protocols = new String[] { "TLSv1.1", "TLSv1.2" };
165
+ } else {
166
+ protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
167
+ }
110
168
 
111
- SSLSession session = engine.getSession();
112
- peerNetData = ByteBuffer.allocate(session.getPacketBufferSize());
113
- peerAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
114
- netData = ByteBuffer.allocate(session.getPacketBufferSize());
115
- peerNetData.limit(0);
116
- peerAppData.limit(0);
117
- netData.limit(0);
118
-
119
- peerNetData.clear();
120
- peerAppData.clear();
121
- netData.clear();
122
-
123
- dummy = ByteBuffer.allocate(0);
124
-
125
- return this;
126
- }
169
+ if(miniSSLContext.callMethod(threadContext, "no_tlsv1_1").isTrue()) {
170
+ protocols = new String[] { "TLSv1.2" };
171
+ }
127
172
 
128
- @JRubyMethod
129
- public IRubyObject inject(IRubyObject arg) {
130
- byte[] bytes = arg.convertToString().getBytes();
173
+ engine.setEnabledProtocols(protocols);
174
+ engine.setUseClientMode(false);
131
175
 
132
- peerNetData.limit(peerNetData.limit() + bytes.length);
176
+ long verify_mode = miniSSLContext.callMethod(threadContext, "verify_mode").convertToInteger().getLongValue();
177
+ if ((verify_mode & 0x1) != 0) { // 'peer'
178
+ engine.setWantClientAuth(true);
179
+ }
180
+ if ((verify_mode & 0x2) != 0) { // 'force_peer'
181
+ engine.setNeedClientAuth(true);
182
+ }
133
183
 
134
- log("capacity: " + peerNetData.capacity() + " limit: " + peerNetData.limit());
184
+ IRubyObject sslCipherListObject = miniSSLContext.callMethod(threadContext, "ssl_cipher_list");
185
+ if (!sslCipherListObject.isNil()) {
186
+ String[] sslCipherList = sslCipherListObject.convertToString().asJavaString().split(",");
187
+ engine.setEnabledCipherSuites(sslCipherList);
188
+ }
135
189
 
136
- peerNetData.put(bytes);
190
+ SSLSession session = engine.getSession();
191
+ inboundNetData = new MiniSSLBuffer(session.getPacketBufferSize());
192
+ outboundAppData = new MiniSSLBuffer(session.getApplicationBufferSize());
193
+ outboundAppData.flip();
194
+ outboundNetData = new MiniSSLBuffer(session.getPacketBufferSize());
137
195
 
138
- log("netData: " + peerNetData.position() + "/" + peerAppData.limit());
139
196
  return this;
140
197
  }
141
198
 
142
199
  @JRubyMethod
143
- public IRubyObject read() throws javax.net.ssl.SSLException, Exception {
144
- peerAppData.clear();
145
- peerNetData.flip();
146
- SSLEngineResult res;
147
-
148
- log("available read: " + peerNetData.position() + "/ " + peerNetData.limit());
149
-
150
- if(!peerNetData.hasRemaining()) {
151
- return getRuntime().getNil();
152
- }
153
-
154
- do {
155
- res = engine.unwrap(peerNetData, peerAppData);
156
- } while(res.getStatus() == SSLEngineResult.Status.OK &&
157
- res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP &&
158
- res.bytesProduced() == 0);
159
-
160
- log("read: ", res);
161
-
162
- if(peerNetData.hasRemaining()) {
163
- log("STILL HAD peerNetData!");
200
+ public IRubyObject inject(IRubyObject arg) {
201
+ try {
202
+ byte[] bytes = arg.convertToString().getBytes();
203
+ inboundNetData.put(bytes);
204
+ return this;
205
+ } catch (Exception e) {
206
+ e.printStackTrace();
207
+ throw new RuntimeException(e);
164
208
  }
209
+ }
165
210
 
166
- peerNetData.position(0);
167
- peerNetData.limit(0);
168
-
169
- HandshakeStatus hsStatus = runDelegatedTasks(res, engine);
211
+ private enum SSLOperation {
212
+ WRAP,
213
+ UNWRAP
214
+ }
170
215
 
171
- if(res.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
172
- return getRuntime().getNil();
173
- }
216
+ private SSLEngineResult doOp(SSLOperation sslOp, MiniSSLBuffer src, MiniSSLBuffer dst) throws SSLException {
217
+ SSLEngineResult res = null;
218
+ boolean retryOp = true;
219
+ while (retryOp) {
220
+ switch (sslOp) {
221
+ case WRAP:
222
+ res = engine.wrap(src.getRawBuffer(), dst.getRawBuffer());
223
+ break;
224
+ case UNWRAP:
225
+ res = engine.unwrap(src.getRawBuffer(), dst.getRawBuffer());
226
+ break;
227
+ default:
228
+ throw new IllegalStateException("Unknown SSLOperation: " + sslOp);
229
+ }
174
230
 
175
- if(hsStatus == HandshakeStatus.NEED_WRAP) {
176
- netData.clear();
177
- log("netData: " + netData.limit());
178
- engine.wrap(dummy, netData);
179
- return getRuntime().getNil();
231
+ switch (res.getStatus()) {
232
+ case BUFFER_OVERFLOW:
233
+ // increase the buffer size to accommodate the overflowing data
234
+ int newSize = Math.max(engine.getSession().getPacketBufferSize(), engine.getSession().getApplicationBufferSize());
235
+ dst.resize(newSize + dst.position());
236
+ // retry the operation
237
+ retryOp = true;
238
+ break;
239
+ case BUFFER_UNDERFLOW:
240
+ // need to wait for more data to come in before we retry
241
+ retryOp = false;
242
+ break;
243
+ default:
244
+ // other cases are OK and CLOSED. We're done here.
245
+ retryOp = false;
246
+ }
180
247
  }
181
248
 
182
- if(hsStatus == HandshakeStatus.NEED_UNWRAP) {
183
- return getRuntime().getNil();
184
-
185
- // log("peerNet: " + peerNetData.position() + "/" + peerNetData.limit());
186
- // log("peerApp: " + peerAppData.position() + "/" + peerAppData.limit());
187
-
188
- // peerNetData.compact();
189
-
190
- // log("peerNet: " + peerNetData.position() + "/" + peerNetData.limit());
191
- // do {
192
- // res = engine.unwrap(peerNetData, peerAppData);
193
- // } while(res.getStatus() == SSLEngineResult.Status.OK &&
194
- // res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP &&
195
- // res.bytesProduced() == 0);
196
- // return getRuntime().getNil();
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();
254
+ }
197
255
  }
198
256
 
199
- // if(peerAppData.position() == 0 &&
200
- // res.getStatus() == SSLEngineResult.Status.OK &&
201
- // peerNetData.hasRemaining()) {
202
- // res = engine.unwrap(peerNetData, peerAppData);
203
- // }
204
-
205
- byte[] bss = new byte[peerAppData.limit()];
206
-
207
- peerAppData.get(bss);
208
-
209
- RubyString str = getRuntime().newString("");
210
- str.setValue(new ByteList(bss));
211
-
212
- return str;
257
+ return res;
213
258
  }
214
259
 
215
- private static HandshakeStatus runDelegatedTasks(SSLEngineResult result,
216
- SSLEngine engine) throws Exception {
260
+ @JRubyMethod
261
+ public IRubyObject read() throws Exception {
262
+ try {
263
+ inboundNetData.flip();
217
264
 
218
- HandshakeStatus hsStatus = result.getHandshakeStatus();
265
+ if(!inboundNetData.hasRemaining()) {
266
+ return getRuntime().getNil();
267
+ }
219
268
 
220
- if(hsStatus == HandshakeStatus.NEED_TASK) {
221
- Runnable runnable;
222
- while ((runnable = engine.getDelegatedTask()) != null) {
223
- log("\trunning delegated task...");
224
- runnable.run();
269
+ MiniSSLBuffer inboundAppData = new MiniSSLBuffer(engine.getSession().getApplicationBufferSize());
270
+ doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
271
+
272
+ HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
273
+ boolean done = false;
274
+ while (!done) {
275
+ switch (handshakeStatus) {
276
+ case NEED_WRAP:
277
+ doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
278
+ break;
279
+ case NEED_UNWRAP:
280
+ SSLEngineResult res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
281
+ if (res.getStatus() == Status.BUFFER_UNDERFLOW) {
282
+ // need more data before we can shake more hands
283
+ done = true;
284
+ }
285
+ break;
286
+ default:
287
+ done = true;
288
+ }
289
+ handshakeStatus = engine.getHandshakeStatus();
225
290
  }
226
- hsStatus = engine.getHandshakeStatus();
227
- if (hsStatus == HandshakeStatus.NEED_TASK) {
228
- throw new Exception(
229
- "handshake shouldn't need additional tasks");
291
+
292
+ if (inboundNetData.hasRemaining()) {
293
+ inboundNetData.compact();
294
+ } else {
295
+ inboundNetData.clear();
230
296
  }
231
- log("\tnew HandshakeStatus: " + hsStatus);
232
- }
233
297
 
234
- return hsStatus;
235
- }
236
-
237
-
238
- private static void log(String str, SSLEngineResult result) {
239
- System.out.println("The format of the SSLEngineResult is: \n" +
240
- "\t\"getStatus() / getHandshakeStatus()\" +\n" +
241
- "\t\"bytesConsumed() / bytesProduced()\"\n");
242
-
243
- HandshakeStatus hsStatus = result.getHandshakeStatus();
244
- log(str +
245
- result.getStatus() + "/" + hsStatus + ", " +
246
- result.bytesConsumed() + "/" + result.bytesProduced() +
247
- " bytes");
248
- if (hsStatus == HandshakeStatus.FINISHED) {
249
- log("\t...ready for application data");
298
+ ByteList appDataByteList = inboundAppData.asByteList();
299
+ if (appDataByteList == null) {
300
+ return getRuntime().getNil();
301
+ }
302
+
303
+ RubyString str = getRuntime().newString("");
304
+ str.setValue(appDataByteList);
305
+ return str;
306
+ } catch (Exception e) {
307
+ throw getRuntime().newEOFError(e.getMessage());
250
308
  }
251
309
  }
252
310
 
253
- private static void log(String str) {
254
- System.out.println(str);
311
+ @JRubyMethod
312
+ public IRubyObject write(IRubyObject arg) {
313
+ try {
314
+ byte[] bls = arg.convertToString().getBytes();
315
+ outboundAppData = new MiniSSLBuffer(bls);
316
+
317
+ return getRuntime().newFixnum(bls.length);
318
+ } catch (Exception e) {
319
+ e.printStackTrace();
320
+ throw new RuntimeException(e);
321
+ }
255
322
  }
256
-
257
-
258
323
 
259
324
  @JRubyMethod
260
- public IRubyObject write(IRubyObject arg) throws javax.net.ssl.SSLException {
261
- log("write from: " + netData.position());
325
+ public IRubyObject extract() throws SSLException {
326
+ try {
327
+ ByteList dataByteList = outboundNetData.asByteList();
328
+ if (dataByteList != null) {
329
+ RubyString str = getRuntime().newString("");
330
+ str.setValue(dataByteList);
331
+ return str;
332
+ }
333
+
334
+ if (!outboundAppData.hasRemaining()) {
335
+ return getRuntime().getNil();
336
+ }
262
337
 
263
- byte[] bls = arg.convertToString().getBytes();
264
- ByteBuffer src = ByteBuffer.wrap(bls);
338
+ outboundNetData.clear();
339
+ doOp(SSLOperation.WRAP, outboundAppData, outboundNetData);
340
+ dataByteList = outboundNetData.asByteList();
341
+ if (dataByteList == null) {
342
+ return getRuntime().getNil();
343
+ }
265
344
 
266
- SSLEngineResult res = engine.wrap(src, netData);
345
+ RubyString str = getRuntime().newString("");
346
+ str.setValue(dataByteList);
267
347
 
268
- return getRuntime().newFixnum(res.bytesConsumed());
348
+ return str;
349
+ } catch (Exception e) {
350
+ e.printStackTrace();
351
+ throw new RuntimeException(e);
352
+ }
269
353
  }
270
354
 
271
355
  @JRubyMethod
272
- public IRubyObject extract() {
273
- netData.flip();
274
-
275
- if(!netData.hasRemaining()) {
356
+ public IRubyObject peercert() throws CertificateEncodingException {
357
+ try {
358
+ return JavaEmbedUtils.javaToRuby(getRuntime(), engine.getSession().getPeerCertificates()[0].getEncoded());
359
+ } catch (SSLPeerUnverifiedException ex) {
276
360
  return getRuntime().getNil();
277
361
  }
278
-
279
- byte[] bss = new byte[netData.limit()];
280
-
281
- netData.get(bss);
282
- netData.clear();
283
-
284
- RubyString str = getRuntime().newString("");
285
- str.setValue(new ByteList(bss));
286
-
287
- return str;
288
362
  }
289
363
  }