puma 2.7.0 → 3.1.1

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