puma 4.3.8 → 5.6.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1543 -521
  3. data/LICENSE +23 -20
  4. data/README.md +120 -36
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +63 -26
  7. data/docs/compile_options.md +21 -0
  8. data/docs/deployment.md +60 -69
  9. data/docs/fork_worker.md +33 -0
  10. data/docs/jungle/README.md +9 -0
  11. data/{tools → docs}/jungle/rc.d/README.md +1 -1
  12. data/{tools → docs}/jungle/rc.d/puma +2 -2
  13. data/docs/kubernetes.md +66 -0
  14. data/docs/nginx.md +1 -1
  15. data/docs/plugins.md +15 -15
  16. data/docs/rails_dev_mode.md +28 -0
  17. data/docs/restart.md +46 -23
  18. data/docs/signals.md +13 -11
  19. data/docs/stats.md +142 -0
  20. data/docs/systemd.md +85 -128
  21. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  22. data/ext/puma_http11/ext_help.h +1 -1
  23. data/ext/puma_http11/extconf.rb +51 -9
  24. data/ext/puma_http11/http11_parser.c +68 -57
  25. data/ext/puma_http11/http11_parser.h +1 -1
  26. data/ext/puma_http11/http11_parser.java.rl +1 -1
  27. data/ext/puma_http11/http11_parser.rl +1 -1
  28. data/ext/puma_http11/http11_parser_common.rl +1 -1
  29. data/ext/puma_http11/mini_ssl.c +295 -124
  30. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  31. data/ext/puma_http11/org/jruby/puma/Http11.java +5 -3
  32. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +51 -51
  33. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +109 -67
  34. data/ext/puma_http11/puma_http11.c +32 -51
  35. data/lib/puma/app/status.rb +50 -36
  36. data/lib/puma/binder.rb +225 -106
  37. data/lib/puma/cli.rb +24 -18
  38. data/lib/puma/client.rb +197 -92
  39. data/lib/puma/cluster/worker.rb +173 -0
  40. data/lib/puma/cluster/worker_handle.rb +94 -0
  41. data/lib/puma/cluster.rb +212 -220
  42. data/lib/puma/commonlogger.rb +2 -2
  43. data/lib/puma/configuration.rb +58 -49
  44. data/lib/puma/const.rb +26 -9
  45. data/lib/puma/control_cli.rb +99 -76
  46. data/lib/puma/detect.rb +29 -2
  47. data/lib/puma/dsl.rb +368 -96
  48. data/lib/puma/error_logger.rb +104 -0
  49. data/lib/puma/events.rb +55 -34
  50. data/lib/puma/io_buffer.rb +9 -2
  51. data/lib/puma/jruby_restart.rb +0 -58
  52. data/lib/puma/json_serialization.rb +96 -0
  53. data/lib/puma/launcher.rb +128 -46
  54. data/lib/puma/minissl/context_builder.rb +14 -9
  55. data/lib/puma/minissl.rb +137 -50
  56. data/lib/puma/null_io.rb +18 -1
  57. data/lib/puma/plugin.rb +3 -12
  58. data/lib/puma/queue_close.rb +26 -0
  59. data/lib/puma/rack/builder.rb +1 -5
  60. data/lib/puma/reactor.rb +85 -369
  61. data/lib/puma/request.rb +489 -0
  62. data/lib/puma/runner.rb +46 -61
  63. data/lib/puma/server.rb +292 -751
  64. data/lib/puma/single.rb +9 -65
  65. data/lib/puma/state_file.rb +48 -8
  66. data/lib/puma/systemd.rb +46 -0
  67. data/lib/puma/thread_pool.rb +125 -57
  68. data/lib/puma/util.rb +32 -4
  69. data/lib/puma.rb +48 -0
  70. data/lib/rack/handler/puma.rb +2 -3
  71. data/lib/rack/version_restriction.rb +15 -0
  72. data/tools/{docker/Dockerfile → Dockerfile} +1 -1
  73. metadata +29 -24
  74. data/docs/tcp_mode.md +0 -96
  75. data/ext/puma_http11/io_buffer.c +0 -155
  76. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  77. data/lib/puma/accept_nonblock.rb +0 -29
  78. data/lib/puma/tcp_logger.rb +0 -41
  79. data/tools/jungle/README.md +0 -19
  80. data/tools/jungle/init.d/README.md +0 -61
  81. data/tools/jungle/init.d/puma +0 -421
  82. data/tools/jungle/init.d/run-puma +0 -18
  83. data/tools/jungle/upstart/README.md +0 -61
  84. data/tools/jungle/upstart/puma-manager.conf +0 -31
  85. data/tools/jungle/upstart/puma.conf +0 -69
  86. /data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
@@ -34,9 +34,9 @@ private static short[] init__puma_parser_key_offsets_0()
34
34
  {
35
35
  return new short [] {
36
36
  0, 0, 8, 17, 27, 29, 30, 31, 32, 33, 34, 36,
37
- 39, 41, 44, 45, 61, 62, 78, 80, 81, 89, 97, 107,
38
- 115, 124, 132, 140, 149, 158, 167, 176, 185, 194, 203, 212,
39
- 221, 230, 239, 248, 257, 266, 275, 284, 293, 302, 303
37
+ 39, 41, 44, 45, 61, 62, 78, 85, 91, 99, 107, 117,
38
+ 125, 134, 142, 150, 159, 168, 177, 186, 195, 204, 213, 222,
39
+ 231, 240, 249, 258, 267, 276, 285, 294, 303, 312, 313
40
40
  };
41
41
  }
42
42
 
@@ -52,26 +52,27 @@ private static char[] init__puma_parser_trans_keys_0()
52
52
  46, 48, 57, 48, 57, 13, 48, 57, 10, 13, 33, 124,
53
53
  126, 35, 39, 42, 43, 45, 46, 48, 57, 65, 90, 94,
54
54
  122, 10, 33, 58, 124, 126, 35, 39, 42, 43, 45, 46,
55
- 48, 57, 65, 90, 94, 122, 13, 32, 13, 32, 60, 62,
56
- 127, 0, 31, 34, 35, 32, 60, 62, 127, 0, 31, 34,
57
- 35, 43, 58, 45, 46, 48, 57, 65, 90, 97, 122, 32,
58
- 34, 35, 60, 62, 127, 0, 31, 32, 34, 35, 60, 62,
59
- 63, 127, 0, 31, 32, 34, 35, 60, 62, 127, 0, 31,
60
- 32, 34, 35, 60, 62, 127, 0, 31, 32, 36, 95, 45,
61
- 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57,
62
- 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32,
63
- 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45,
64
- 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57,
65
- 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32,
66
- 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45,
67
- 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57,
68
- 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32,
69
- 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45,
70
- 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57,
71
- 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32,
72
- 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45,
73
- 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57,
74
- 65, 90, 32, 0
55
+ 48, 57, 65, 90, 94, 122, 13, 32, 127, 0, 8, 10,
56
+ 31, 13, 127, 0, 8, 10, 31, 32, 60, 62, 127, 0,
57
+ 31, 34, 35, 32, 60, 62, 127, 0, 31, 34, 35, 43,
58
+ 58, 45, 46, 48, 57, 65, 90, 97, 122, 32, 34, 35,
59
+ 60, 62, 127, 0, 31, 32, 34, 35, 60, 62, 63, 127,
60
+ 0, 31, 32, 34, 35, 60, 62, 127, 0, 31, 32, 34,
61
+ 35, 60, 62, 127, 0, 31, 32, 36, 95, 45, 46, 48,
62
+ 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90,
63
+ 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95,
64
+ 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48,
65
+ 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90,
66
+ 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95,
67
+ 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48,
68
+ 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90,
69
+ 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95,
70
+ 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48,
71
+ 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90,
72
+ 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95,
73
+ 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48,
74
+ 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90,
75
+ 32, 0
75
76
  };
76
77
  }
77
78
 
@@ -82,7 +83,7 @@ private static byte[] init__puma_parser_single_lengths_0()
82
83
  {
83
84
  return new byte [] {
84
85
  0, 2, 3, 4, 2, 1, 1, 1, 1, 1, 0, 1,
85
- 0, 1, 1, 4, 1, 4, 2, 1, 4, 4, 2, 6,
86
+ 0, 1, 1, 4, 1, 4, 3, 2, 4, 4, 2, 6,
86
87
  7, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3,
87
88
  3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0
88
89
  };
@@ -95,7 +96,7 @@ private static byte[] init__puma_parser_range_lengths_0()
95
96
  {
96
97
  return new byte [] {
97
98
  0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 1, 1,
98
- 1, 1, 0, 6, 0, 6, 0, 0, 2, 2, 4, 1,
99
+ 1, 1, 0, 6, 0, 6, 2, 2, 2, 2, 4, 1,
99
100
  1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
100
101
  3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0
101
102
  };
@@ -108,9 +109,9 @@ private static short[] init__puma_parser_index_offsets_0()
108
109
  {
109
110
  return new short [] {
110
111
  0, 0, 6, 13, 21, 24, 26, 28, 30, 32, 34, 36,
111
- 39, 41, 44, 46, 57, 59, 70, 73, 75, 82, 89, 96,
112
- 104, 113, 121, 129, 136, 143, 150, 157, 164, 171, 178, 185,
113
- 192, 199, 206, 213, 220, 227, 234, 241, 248, 255, 257
112
+ 39, 41, 44, 46, 57, 59, 70, 76, 81, 88, 95, 102,
113
+ 110, 119, 127, 135, 142, 149, 156, 163, 170, 177, 184, 191,
114
+ 198, 205, 212, 219, 226, 233, 240, 247, 254, 261, 263
114
115
  };
115
116
  }
116
117
 
@@ -126,22 +127,23 @@ private static byte[] init__puma_parser_indicies_0()
126
127
  16, 15, 1, 17, 1, 18, 17, 1, 19, 1, 20, 21,
127
128
  21, 21, 21, 21, 21, 21, 21, 21, 1, 22, 1, 23,
128
129
  24, 23, 23, 23, 23, 23, 23, 23, 23, 1, 26, 27,
129
- 25, 29, 28, 30, 1, 1, 1, 1, 1, 31, 32, 1,
130
- 1, 1, 1, 1, 33, 34, 35, 34, 34, 34, 34, 1,
131
- 8, 1, 9, 1, 1, 1, 1, 35, 36, 1, 38, 1,
132
- 1, 39, 1, 1, 37, 40, 1, 42, 1, 1, 1, 1,
133
- 41, 43, 1, 45, 1, 1, 1, 1, 44, 2, 46, 46,
134
- 46, 46, 46, 1, 2, 47, 47, 47, 47, 47, 1, 2,
135
- 48, 48, 48, 48, 48, 1, 2, 49, 49, 49, 49, 49,
136
- 1, 2, 50, 50, 50, 50, 50, 1, 2, 51, 51, 51,
137
- 51, 51, 1, 2, 52, 52, 52, 52, 52, 1, 2, 53,
138
- 53, 53, 53, 53, 1, 2, 54, 54, 54, 54, 54, 1,
139
- 2, 55, 55, 55, 55, 55, 1, 2, 56, 56, 56, 56,
140
- 56, 1, 2, 57, 57, 57, 57, 57, 1, 2, 58, 58,
141
- 58, 58, 58, 1, 2, 59, 59, 59, 59, 59, 1, 2,
142
- 60, 60, 60, 60, 60, 1, 2, 61, 61, 61, 61, 61,
143
- 1, 2, 62, 62, 62, 62, 62, 1, 2, 63, 63, 63,
144
- 63, 63, 1, 2, 1, 1, 0
130
+ 1, 1, 1, 25, 29, 1, 1, 1, 28, 30, 1, 1,
131
+ 1, 1, 1, 31, 32, 1, 1, 1, 1, 1, 33, 34,
132
+ 35, 34, 34, 34, 34, 1, 8, 1, 9, 1, 1, 1,
133
+ 1, 35, 36, 1, 38, 1, 1, 39, 1, 1, 37, 40,
134
+ 1, 42, 1, 1, 1, 1, 41, 43, 1, 45, 1, 1,
135
+ 1, 1, 44, 2, 46, 46, 46, 46, 46, 1, 2, 47,
136
+ 47, 47, 47, 47, 1, 2, 48, 48, 48, 48, 48, 1,
137
+ 2, 49, 49, 49, 49, 49, 1, 2, 50, 50, 50, 50,
138
+ 50, 1, 2, 51, 51, 51, 51, 51, 1, 2, 52, 52,
139
+ 52, 52, 52, 1, 2, 53, 53, 53, 53, 53, 1, 2,
140
+ 54, 54, 54, 54, 54, 1, 2, 55, 55, 55, 55, 55,
141
+ 1, 2, 56, 56, 56, 56, 56, 1, 2, 57, 57, 57,
142
+ 57, 57, 1, 2, 58, 58, 58, 58, 58, 1, 2, 59,
143
+ 59, 59, 59, 59, 1, 2, 60, 60, 60, 60, 60, 1,
144
+ 2, 61, 61, 61, 61, 61, 1, 2, 62, 62, 62, 62,
145
+ 62, 1, 2, 63, 63, 63, 63, 63, 1, 2, 1, 1,
146
+ 0
145
147
  };
146
148
  }
147
149
 
@@ -182,8 +184,6 @@ static final int puma_parser_start = 1;
182
184
  static final int puma_parser_first_final = 46;
183
185
  static final int puma_parser_error = 0;
184
186
 
185
- static final int puma_parser_en_main = 1;
186
-
187
187
 
188
188
  // line 62 "ext/puma_http11/http11_parser.java.rl"
189
189
 
@@ -212,12 +212,12 @@ static final int puma_parser_en_main = 1;
212
212
  cs = 0;
213
213
 
214
214
 
215
- // line 218 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
215
+ // line 216 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
216
216
  {
217
217
  cs = puma_parser_start;
218
218
  }
219
219
 
220
- // line 90 "ext/puma_http11/http11_parser.java.rl"
220
+ // line 88 "ext/puma_http11/http11_parser.java.rl"
221
221
 
222
222
  body_start = 0;
223
223
  content_len = 0;
@@ -244,7 +244,7 @@ static final int puma_parser_en_main = 1;
244
244
  parser.buffer = buffer;
245
245
 
246
246
 
247
- // line 250 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
247
+ // line 248 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
248
248
  {
249
249
  int _klen;
250
250
  int _trans = 0;
@@ -400,7 +400,7 @@ case 1:
400
400
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
401
401
  }
402
402
  break;
403
- // line 406 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
403
+ // line 404 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
404
404
  }
405
405
  }
406
406
  }
@@ -420,7 +420,7 @@ case 5:
420
420
  break; }
421
421
  }
422
422
 
423
- // line 116 "ext/puma_http11/http11_parser.java.rl"
423
+ // line 114 "ext/puma_http11/http11_parser.java.rl"
424
424
 
425
425
  parser.cs = cs;
426
426
  parser.nread += (p - off);
@@ -6,6 +6,7 @@ import org.jruby.RubyModule;
6
6
  import org.jruby.RubyObject;
7
7
  import org.jruby.RubyString;
8
8
  import org.jruby.anno.JRubyMethod;
9
+ import org.jruby.exceptions.RaiseException;
9
10
  import org.jruby.javasupport.JavaEmbedUtils;
10
11
  import org.jruby.runtime.Block;
11
12
  import org.jruby.runtime.ObjectAllocator;
@@ -22,6 +23,7 @@ import javax.net.ssl.SSLException;
22
23
  import javax.net.ssl.SSLPeerUnverifiedException;
23
24
  import javax.net.ssl.SSLSession;
24
25
  import java.io.FileInputStream;
26
+ import java.io.InputStream;
25
27
  import java.io.IOException;
26
28
  import java.nio.Buffer;
27
29
  import java.nio.ByteBuffer;
@@ -32,6 +34,8 @@ import java.security.NoSuchAlgorithmException;
32
34
  import java.security.UnrecoverableKeyException;
33
35
  import java.security.cert.CertificateEncodingException;
34
36
  import java.security.cert.CertificateException;
37
+ import java.util.concurrent.ConcurrentHashMap;
38
+ import java.util.Map;
35
39
 
36
40
  import static javax.net.ssl.SSLEngineResult.Status;
37
41
  import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
@@ -77,11 +81,11 @@ public class MiniSSL extends RubyObject {
77
81
  /**
78
82
  * Writes bytes to the buffer after ensuring there's room
79
83
  */
80
- public void put(byte[] bytes) {
81
- if (buffer.remaining() < bytes.length) {
82
- resize(buffer.limit() + bytes.length);
84
+ private void put(byte[] bytes, final int offset, final int length) {
85
+ if (buffer.remaining() < length) {
86
+ resize(buffer.limit() + length);
83
87
  }
84
- buffer.put(bytes);
88
+ buffer.put(bytes, offset, length);
85
89
  }
86
90
 
87
91
  /**
@@ -112,7 +116,7 @@ public class MiniSSL extends RubyObject {
112
116
 
113
117
  buffer.get(bss);
114
118
  buffer.clear();
115
- return new ByteList(bss);
119
+ return new ByteList(bss, false);
116
120
  }
117
121
 
118
122
  @Override
@@ -120,6 +124,8 @@ public class MiniSSL extends RubyObject {
120
124
  }
121
125
 
122
126
  private SSLEngine engine;
127
+ private boolean closed;
128
+ private boolean handshake;
123
129
  private MiniSSLBuffer inboundNetData;
124
130
  private MiniSSLBuffer outboundAppData;
125
131
  private MiniSSLBuffer outboundNetData;
@@ -128,10 +134,39 @@ public class MiniSSL extends RubyObject {
128
134
  super(runtime, klass);
129
135
  }
130
136
 
137
+ private static Map<String, KeyManagerFactory> keyManagerFactoryMap = new ConcurrentHashMap<String, KeyManagerFactory>();
138
+ private static Map<String, TrustManagerFactory> trustManagerFactoryMap = new ConcurrentHashMap<String, TrustManagerFactory>();
139
+
131
140
  @JRubyMethod(meta = true)
132
- public static IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext) {
133
- RubyClass klass = (RubyClass) recv;
141
+ public static synchronized IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext)
142
+ throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
143
+ // Create the KeyManagerFactory and TrustManagerFactory for this server
144
+ String keystoreFile = miniSSLContext.callMethod(context, "keystore").convertToString().asJavaString();
145
+ char[] password = miniSSLContext.callMethod(context, "keystore_pass").convertToString().asJavaString().toCharArray();
146
+
147
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
148
+ InputStream is = new FileInputStream(keystoreFile);
149
+ try {
150
+ ks.load(is, password);
151
+ } finally {
152
+ is.close();
153
+ }
154
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
155
+ kmf.init(ks, password);
156
+ keyManagerFactoryMap.put(keystoreFile, kmf);
134
157
 
158
+ KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
159
+ is = new FileInputStream(keystoreFile);
160
+ try {
161
+ ts.load(is, password);
162
+ } finally {
163
+ is.close();
164
+ }
165
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
166
+ tmf.init(ts);
167
+ trustManagerFactoryMap.put(keystoreFile, tmf);
168
+
169
+ RubyClass klass = (RubyClass) recv;
135
170
  return klass.newInstance(context,
136
171
  new IRubyObject[] { miniSSLContext },
137
172
  Block.NULL_BLOCK);
@@ -139,24 +174,20 @@ public class MiniSSL extends RubyObject {
139
174
 
140
175
  @JRubyMethod
141
176
  public IRubyObject initialize(ThreadContext threadContext, IRubyObject miniSSLContext)
142
- throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
143
- KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
144
- KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
177
+ throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
145
178
 
146
- char[] password = miniSSLContext.callMethod(threadContext, "keystore_pass").convertToString().asJavaString().toCharArray();
147
179
  String keystoreFile = miniSSLContext.callMethod(threadContext, "keystore").convertToString().asJavaString();
148
- ks.load(new FileInputStream(keystoreFile), password);
149
- ts.load(new FileInputStream(keystoreFile), password);
150
-
151
- KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
152
- kmf.init(ks, password);
153
-
154
- TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
155
- tmf.init(ts);
180
+ KeyManagerFactory kmf = keyManagerFactoryMap.get(keystoreFile);
181
+ TrustManagerFactory tmf = trustManagerFactoryMap.get(keystoreFile);
182
+ if(kmf == null || tmf == null) {
183
+ throw new KeyStoreException("Could not find KeyManagerFactory/TrustManagerFactory for keystore: " + keystoreFile);
184
+ }
156
185
 
157
186
  SSLContext sslCtx = SSLContext.getInstance("TLS");
158
187
 
159
188
  sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
189
+ closed = false;
190
+ handshake = false;
160
191
  engine = sslCtx.createSSLEngine();
161
192
 
162
193
  String[] protocols;
@@ -173,7 +204,7 @@ public class MiniSSL extends RubyObject {
173
204
  engine.setEnabledProtocols(protocols);
174
205
  engine.setUseClientMode(false);
175
206
 
176
- long verify_mode = miniSSLContext.callMethod(threadContext, "verify_mode").convertToInteger().getLongValue();
207
+ long verify_mode = miniSSLContext.callMethod(threadContext, "verify_mode").convertToInteger("to_i").getLongValue();
177
208
  if ((verify_mode & 0x1) != 0) { // 'peer'
178
209
  engine.setWantClientAuth(true);
179
210
  }
@@ -198,14 +229,9 @@ public class MiniSSL extends RubyObject {
198
229
 
199
230
  @JRubyMethod
200
231
  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);
208
- }
232
+ ByteList bytes = arg.convertToString().getByteList();
233
+ inboundNetData.put(bytes.unsafeBytes(), bytes.getBegin(), bytes.getRealSize());
234
+ return this;
209
235
  }
210
236
 
211
237
  private enum SSLOperation {
@@ -240,17 +266,16 @@ public class MiniSSL extends RubyObject {
240
266
  // need to wait for more data to come in before we retry
241
267
  retryOp = false;
242
268
  break;
269
+ case CLOSED:
270
+ closed = true;
271
+ retryOp = false;
272
+ break;
243
273
  default:
244
- // other cases are OK and CLOSED. We're done here.
274
+ // other case is OK. We're done here.
245
275
  retryOp = false;
246
276
  }
247
- }
248
-
249
- // after each op, run any delegated tasks if needed
250
- if(engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
251
- Runnable runnable;
252
- while ((runnable = engine.getDelegatedTask()) != null) {
253
- runnable.run();
277
+ if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) {
278
+ handshake = true;
254
279
  }
255
280
  }
256
281
 
@@ -258,7 +283,7 @@ public class MiniSSL extends RubyObject {
258
283
  }
259
284
 
260
285
  @JRubyMethod
261
- public IRubyObject read() throws Exception {
286
+ public IRubyObject read() {
262
287
  try {
263
288
  inboundNetData.flip();
264
289
 
@@ -272,21 +297,30 @@ public class MiniSSL extends RubyObject {
272
297
  HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
273
298
  boolean done = false;
274
299
  while (!done) {
300
+ SSLEngineResult res;
275
301
  switch (handshakeStatus) {
276
302
  case NEED_WRAP:
277
- doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
303
+ res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
304
+ handshakeStatus = res.getHandshakeStatus();
278
305
  break;
279
306
  case NEED_UNWRAP:
280
- SSLEngineResult res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
307
+ res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
281
308
  if (res.getStatus() == Status.BUFFER_UNDERFLOW) {
282
309
  // need more data before we can shake more hands
283
310
  done = true;
284
311
  }
312
+ handshakeStatus = res.getHandshakeStatus();
313
+ break;
314
+ case NEED_TASK:
315
+ Runnable runnable;
316
+ while ((runnable = engine.getDelegatedTask()) != null) {
317
+ runnable.run();
318
+ }
319
+ handshakeStatus = engine.getHandshakeStatus();
285
320
  break;
286
321
  default:
287
322
  done = true;
288
323
  }
289
- handshakeStatus = engine.getHandshakeStatus();
290
324
  }
291
325
 
292
326
  if (inboundNetData.hasRemaining()) {
@@ -300,55 +334,46 @@ public class MiniSSL extends RubyObject {
300
334
  return getRuntime().getNil();
301
335
  }
302
336
 
303
- RubyString str = getRuntime().newString("");
304
- str.setValue(appDataByteList);
305
- return str;
306
- } catch (Exception e) {
307
- throw getRuntime().newEOFError(e.getMessage());
337
+ return RubyString.newString(getRuntime(), appDataByteList);
338
+ } catch (SSLException e) {
339
+ RaiseException re = getRuntime().newEOFError(e.getMessage());
340
+ re.initCause(e);
341
+ throw re;
308
342
  }
309
343
  }
310
344
 
311
345
  @JRubyMethod
312
346
  public IRubyObject write(IRubyObject arg) {
313
- try {
314
- byte[] bls = arg.convertToString().getBytes();
315
- outboundAppData = new MiniSSLBuffer(bls);
347
+ byte[] bls = arg.convertToString().getBytes();
348
+ outboundAppData = new MiniSSLBuffer(bls);
316
349
 
317
- return getRuntime().newFixnum(bls.length);
318
- } catch (Exception e) {
319
- e.printStackTrace();
320
- throw new RuntimeException(e);
321
- }
350
+ return getRuntime().newFixnum(bls.length);
322
351
  }
323
352
 
324
353
  @JRubyMethod
325
- public IRubyObject extract() throws SSLException {
354
+ public IRubyObject extract(ThreadContext context) {
326
355
  try {
327
356
  ByteList dataByteList = outboundNetData.asByteList();
328
357
  if (dataByteList != null) {
329
- RubyString str = getRuntime().newString("");
330
- str.setValue(dataByteList);
331
- return str;
358
+ return RubyString.newString(context.runtime, dataByteList);
332
359
  }
333
360
 
334
361
  if (!outboundAppData.hasRemaining()) {
335
- return getRuntime().getNil();
362
+ return context.nil;
336
363
  }
337
364
 
338
365
  outboundNetData.clear();
339
366
  doOp(SSLOperation.WRAP, outboundAppData, outboundNetData);
340
367
  dataByteList = outboundNetData.asByteList();
341
368
  if (dataByteList == null) {
342
- return getRuntime().getNil();
369
+ return context.nil;
343
370
  }
344
371
 
345
- RubyString str = getRuntime().newString("");
346
- str.setValue(dataByteList);
347
-
348
- return str;
349
- } catch (Exception e) {
350
- e.printStackTrace();
351
- throw new RuntimeException(e);
372
+ return RubyString.newString(context.runtime, dataByteList);
373
+ } catch (SSLException e) {
374
+ RaiseException ex = context.runtime.newRuntimeError(e.toString());
375
+ ex.initCause(e);
376
+ throw ex;
352
377
  }
353
378
  }
354
379
 
@@ -356,8 +381,25 @@ public class MiniSSL extends RubyObject {
356
381
  public IRubyObject peercert() throws CertificateEncodingException {
357
382
  try {
358
383
  return JavaEmbedUtils.javaToRuby(getRuntime(), engine.getSession().getPeerCertificates()[0].getEncoded());
359
- } catch (SSLPeerUnverifiedException ex) {
384
+ } catch (SSLPeerUnverifiedException e) {
360
385
  return getRuntime().getNil();
361
386
  }
362
387
  }
388
+
389
+ @JRubyMethod(name = "init?")
390
+ public IRubyObject isInit(ThreadContext context) {
391
+ return handshake ? getRuntime().getFalse() : getRuntime().getTrue();
392
+ }
393
+
394
+ @JRubyMethod
395
+ public IRubyObject shutdown() {
396
+ if (closed || engine.isInboundDone() && engine.isOutboundDone()) {
397
+ if (engine.isOutboundDone()) {
398
+ engine.closeOutbound();
399
+ }
400
+ return getRuntime().getTrue();
401
+ } else {
402
+ return getRuntime().getFalse();
403
+ }
404
+ }
363
405
  }