puma 3.7.1 → 4.1.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.

Files changed (74) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +229 -1
  3. data/README.md +179 -212
  4. data/docs/architecture.md +37 -0
  5. data/{DEPLOYMENT.md → docs/deployment.md} +24 -4
  6. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  7. data/docs/images/puma-connection-flow.png +0 -0
  8. data/docs/images/puma-general-arch.png +0 -0
  9. data/docs/plugins.md +28 -0
  10. data/docs/restart.md +41 -0
  11. data/docs/signals.md +56 -3
  12. data/docs/systemd.md +130 -37
  13. data/ext/puma_http11/PumaHttp11Service.java +2 -0
  14. data/ext/puma_http11/extconf.rb +8 -0
  15. data/ext/puma_http11/http11_parser.c +84 -84
  16. data/ext/puma_http11/http11_parser.rl +9 -9
  17. data/ext/puma_http11/mini_ssl.c +105 -9
  18. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +13 -16
  19. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +72 -0
  20. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +30 -6
  21. data/lib/puma.rb +10 -0
  22. data/lib/puma/accept_nonblock.rb +2 -0
  23. data/lib/puma/app/status.rb +13 -0
  24. data/lib/puma/binder.rb +33 -18
  25. data/lib/puma/cli.rb +48 -33
  26. data/lib/puma/client.rb +94 -22
  27. data/lib/puma/cluster.rb +69 -21
  28. data/lib/puma/commonlogger.rb +2 -0
  29. data/lib/puma/configuration.rb +134 -136
  30. data/lib/puma/const.rb +16 -2
  31. data/lib/puma/control_cli.rb +31 -18
  32. data/lib/puma/convenient.rb +5 -3
  33. data/lib/puma/daemon_ext.rb +2 -0
  34. data/lib/puma/delegation.rb +2 -0
  35. data/lib/puma/detect.rb +2 -0
  36. data/lib/puma/dsl.rb +349 -113
  37. data/lib/puma/events.rb +8 -4
  38. data/lib/puma/io_buffer.rb +3 -6
  39. data/lib/puma/jruby_restart.rb +2 -1
  40. data/lib/puma/launcher.rb +60 -36
  41. data/lib/puma/minissl.rb +85 -28
  42. data/lib/puma/null_io.rb +2 -0
  43. data/lib/puma/plugin.rb +2 -0
  44. data/lib/puma/plugin/tmp_restart.rb +3 -2
  45. data/lib/puma/rack/builder.rb +4 -1
  46. data/lib/puma/rack/urlmap.rb +2 -0
  47. data/lib/puma/rack_default.rb +2 -0
  48. data/lib/puma/reactor.rb +218 -30
  49. data/lib/puma/runner.rb +18 -4
  50. data/lib/puma/server.rb +149 -56
  51. data/lib/puma/single.rb +16 -5
  52. data/lib/puma/state_file.rb +2 -0
  53. data/lib/puma/tcp_logger.rb +2 -0
  54. data/lib/puma/thread_pool.rb +59 -6
  55. data/lib/puma/util.rb +2 -6
  56. data/lib/rack/handler/puma.rb +58 -19
  57. data/tools/jungle/README.md +12 -2
  58. data/tools/jungle/init.d/README.md +2 -0
  59. data/tools/jungle/init.d/puma +8 -8
  60. data/tools/jungle/init.d/run-puma +1 -1
  61. data/tools/jungle/rc.d/README.md +74 -0
  62. data/tools/jungle/rc.d/puma +61 -0
  63. data/tools/jungle/rc.d/puma.conf +10 -0
  64. data/tools/trickletest.rb +1 -1
  65. metadata +25 -85
  66. data/.github/issue_template.md +0 -20
  67. data/Gemfile +0 -12
  68. data/Manifest.txt +0 -77
  69. data/Rakefile +0 -158
  70. data/gemfiles/2.1-Gemfile +0 -12
  71. data/lib/puma/compat.rb +0 -14
  72. data/lib/puma/java_io_buffer.rb +0 -45
  73. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
  74. data/puma.gemspec +0 -52
@@ -29,7 +29,7 @@ static void snake_upcase_char(char *c)
29
29
  /** Machine **/
30
30
 
31
31
  %%{
32
-
32
+
33
33
  machine puma_parser;
34
34
 
35
35
  action mark { MARK(mark, fpc); }
@@ -37,7 +37,7 @@ static void snake_upcase_char(char *c)
37
37
 
38
38
  action start_field { MARK(field_start, fpc); }
39
39
  action snake_upcase_field { snake_upcase_char((char *)fpc); }
40
- action write_field {
40
+ action write_field {
41
41
  parser->field_len = LEN(field_start, fpc);
42
42
  }
43
43
 
@@ -45,10 +45,10 @@ static void snake_upcase_char(char *c)
45
45
  action write_value {
46
46
  parser->http_field(parser, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
47
47
  }
48
- action request_method {
48
+ action request_method {
49
49
  parser->request_method(parser, PTR_TO(mark), LEN(mark, fpc));
50
50
  }
51
- action request_uri {
51
+ action request_uri {
52
52
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, fpc));
53
53
  }
54
54
  action fragment {
@@ -56,11 +56,11 @@ static void snake_upcase_char(char *c)
56
56
  }
57
57
 
58
58
  action start_query { MARK(query_start, fpc); }
59
- action query_string {
59
+ action query_string {
60
60
  parser->query_string(parser, PTR_TO(query_start), LEN(query_start, fpc));
61
61
  }
62
62
 
63
- action http_version {
63
+ action http_version {
64
64
  parser->http_version(parser, PTR_TO(mark), LEN(mark, fpc));
65
65
  }
66
66
 
@@ -68,8 +68,8 @@ static void snake_upcase_char(char *c)
68
68
  parser->request_path(parser, PTR_TO(mark), LEN(mark,fpc));
69
69
  }
70
70
 
71
- action done {
72
- parser->body_start = fpc - buffer + 1;
71
+ action done {
72
+ parser->body_start = fpc - buffer + 1;
73
73
  parser->header_done(parser, fpc + 1, pe - fpc - 1);
74
74
  fbreak;
75
75
  }
@@ -109,7 +109,7 @@ size_t puma_parser_execute(puma_parser *parser, const char *buffer, size_t len,
109
109
  pe = buffer+len;
110
110
 
111
111
  /* assert(*pe == '\0' && "pointer does not end on NUL"); */
112
- assert(pe - p == len - off && "pointers aren't same distance");
112
+ assert((size_t) (pe - p) == len - off && "pointers aren't same distance");
113
113
 
114
114
  %% write exec;
115
115
 
@@ -88,7 +88,7 @@ DH *get_dh1024() {
88
88
  DH *dh;
89
89
  dh = DH_new();
90
90
 
91
- #if OPENSSL_VERSION_NUMBER < 0x10100005L
91
+ #if OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER)
92
92
  dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
93
93
  dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
94
94
 
@@ -142,6 +142,7 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
142
142
  VALUE obj;
143
143
  SSL_CTX* ctx;
144
144
  SSL* ssl;
145
+ int min, ssl_options;
145
146
 
146
147
  ms_conn* conn = engine_alloc(self, &obj);
147
148
 
@@ -161,7 +162,20 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
161
162
  ID sym_verify_mode = rb_intern("verify_mode");
162
163
  VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
163
164
 
165
+ ID sym_ssl_cipher_filter = rb_intern("ssl_cipher_filter");
166
+ VALUE ssl_cipher_filter = rb_funcall(mini_ssl_ctx, sym_ssl_cipher_filter, 0);
167
+
168
+ ID sym_no_tlsv1 = rb_intern("no_tlsv1");
169
+ VALUE no_tlsv1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1, 0);
170
+
171
+ ID sym_no_tlsv1_1 = rb_intern("no_tlsv1_1");
172
+ VALUE no_tlsv1_1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1_1, 0);
173
+
174
+ #ifdef HAVE_TLS_SERVER_METHOD
175
+ ctx = SSL_CTX_new(TLS_server_method());
176
+ #else
164
177
  ctx = SSL_CTX_new(SSLv23_server_method());
178
+ #endif
165
179
  conn->ctx = ctx;
166
180
 
167
181
  SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
@@ -172,20 +186,61 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
172
186
  SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
173
187
  }
174
188
 
175
- SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION);
189
+ ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
190
+
191
+ #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
192
+ if (RTEST(no_tlsv1_1)) {
193
+ min = TLS1_2_VERSION;
194
+ }
195
+ else if (RTEST(no_tlsv1)) {
196
+ min = TLS1_1_VERSION;
197
+ }
198
+ else {
199
+ min = TLS1_VERSION;
200
+ }
201
+
202
+ SSL_CTX_set_min_proto_version(ctx, min);
203
+
204
+ SSL_CTX_set_options(ctx, ssl_options);
205
+
206
+ #else
207
+ /* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */
208
+ ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE;
209
+
210
+ if (RTEST(no_tlsv1)) {
211
+ ssl_options |= SSL_OP_NO_TLSv1;
212
+ }
213
+ if(RTEST(no_tlsv1_1)) {
214
+ ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
215
+ }
216
+ SSL_CTX_set_options(ctx, ssl_options);
217
+ #endif
218
+
176
219
  SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
177
220
 
178
- SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
221
+ if (!NIL_P(ssl_cipher_filter)) {
222
+ StringValue(ssl_cipher_filter);
223
+ SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(ssl_cipher_filter));
224
+ }
225
+ else {
226
+ SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
227
+ }
179
228
 
180
229
  DH *dh = get_dh1024();
181
230
  SSL_CTX_set_tmp_dh(ctx, dh);
182
231
 
183
- #ifndef OPENSSL_NO_ECDH
184
- EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
232
+ #if OPENSSL_VERSION_NUMBER < 0x10002000L
233
+ // Remove this case if OpenSSL 1.0.1 (now EOL) support is no
234
+ // longer needed.
235
+ EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
185
236
  if (ecdh) {
186
237
  SSL_CTX_set_tmp_ecdh(ctx, ecdh);
187
238
  EC_KEY_free(ecdh);
188
239
  }
240
+ #elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
241
+ // Prior to OpenSSL 1.1.0, servers must manually enable server-side ECDH
242
+ // negotiation.
243
+ SSL_CTX_set_ecdh_auto(ctx, 1);
189
244
  #endif
190
245
 
191
246
  ssl = SSL_new(ctx);
@@ -207,8 +262,11 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
207
262
  VALUE engine_init_client(VALUE klass) {
208
263
  VALUE obj;
209
264
  ms_conn* conn = engine_alloc(klass, &obj);
210
-
265
+ #ifdef HAVE_DTLS_METHOD
266
+ conn->ctx = SSL_CTX_new(DTLS_method());
267
+ #else
211
268
  conn->ctx = SSL_CTX_new(DTLSv1_method());
269
+ #endif
212
270
  conn->ssl = SSL_new(conn->ctx);
213
271
  SSL_set_app_data(conn->ssl, NULL);
214
272
  SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
@@ -244,7 +302,7 @@ void raise_error(SSL* ssl, int result) {
244
302
  const char* err_str;
245
303
  int err = errno;
246
304
  int ssl_err = SSL_get_error(ssl, result);
247
- int verify_err = SSL_get_verify_result(ssl);
305
+ int verify_err = (int) SSL_get_verify_result(ssl);
248
306
 
249
307
  if(SSL_ERROR_SYSCALL == ssl_err) {
250
308
  snprintf(msg, sizeof(msg), "System error: %s - %d", strerror(err), err);
@@ -257,7 +315,7 @@ void raise_error(SSL* ssl, int result) {
257
315
  err_str, verify_err);
258
316
 
259
317
  } else {
260
- err = ERR_get_error();
318
+ err = (int) ERR_get_error();
261
319
  ERR_error_string_n(err, buf, sizeof(buf));
262
320
  snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err);
263
321
 
@@ -411,6 +469,11 @@ VALUE noop(VALUE self) {
411
469
  void Init_mini_ssl(VALUE puma) {
412
470
  VALUE mod, eng;
413
471
 
472
+ /* Fake operation for documentation (RDoc, YARD) */
473
+ #if 0 == 1
474
+ puma = rb_define_module("Puma");
475
+ #endif
476
+
414
477
  SSL_library_init();
415
478
  OpenSSL_add_ssl_algorithms();
416
479
  SSL_load_error_strings();
@@ -419,6 +482,39 @@ void Init_mini_ssl(VALUE puma) {
419
482
  mod = rb_define_module_under(puma, "MiniSSL");
420
483
  eng = rb_define_class_under(mod, "Engine", rb_cObject);
421
484
 
485
+ // OpenSSL Build / Runtime/Load versions
486
+
487
+ /* Version of OpenSSL that Puma was compiled with */
488
+ rb_define_const(mod, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
489
+
490
+ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
491
+ /* Version of OpenSSL that Puma loaded with */
492
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
493
+ #else
494
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
495
+ #endif
496
+
497
+ #if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
498
+ /* True if SSL3 is not available */
499
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qtrue);
500
+ #else
501
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qfalse);
502
+ #endif
503
+
504
+ #if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
505
+ /* True if TLS1 is not available */
506
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qtrue);
507
+ #else
508
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qfalse);
509
+ #endif
510
+
511
+ #if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
512
+ /* True if TLS1_1 is not available */
513
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qtrue);
514
+ #else
515
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qfalse);
516
+ #endif
517
+
422
518
  rb_define_singleton_method(mod, "check", noop, 0);
423
519
 
424
520
  eError = rb_define_class_under(mod, "SSLError", rb_eStandardError);
@@ -447,7 +543,7 @@ VALUE raise_error(VALUE self) {
447
543
  }
448
544
 
449
545
  void Init_mini_ssl(VALUE puma) {
450
- VALUE mod, eng;
546
+ VALUE mod;
451
547
 
452
548
  mod = rb_define_module_under(puma, "MiniSSL");
453
549
  rb_define_class_under(mod, "SSLError", rb_eStandardError);
@@ -182,9 +182,6 @@ static final int puma_parser_start = 1;
182
182
  static final int puma_parser_first_final = 47;
183
183
  static final int puma_parser_error = 0;
184
184
 
185
- static final int puma_parser_en_main = 1;
186
-
187
-
188
185
  // line 69 "ext/puma_http11/http11_parser.java.rl"
189
186
 
190
187
  public static interface ElementCB {
@@ -220,7 +217,7 @@ static final int puma_parser_en_main = 1;
220
217
  public void init() {
221
218
  cs = 0;
222
219
 
223
-
220
+
224
221
  // line 225 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
225
222
  {
226
223
  cs = puma_parser_start;
@@ -252,7 +249,7 @@ static final int puma_parser_en_main = 1;
252
249
  byte[] data = buffer.bytes();
253
250
  parser.buffer = buffer;
254
251
 
255
-
252
+
256
253
  // line 257 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
257
254
  {
258
255
  int _klen;
@@ -347,7 +344,7 @@ case 1:
347
344
  break;
348
345
  case 3:
349
346
  // line 17 "ext/puma_http11/http11_parser.java.rl"
350
- {
347
+ {
351
348
  parser.field_len = p-parser.field_start;
352
349
  }
353
350
  break;
@@ -357,7 +354,7 @@ case 1:
357
354
  break;
358
355
  case 5:
359
356
  // line 22 "ext/puma_http11/http11_parser.java.rl"
360
- {
357
+ {
361
358
  if(parser.http_field != null) {
362
359
  parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, p-parser.mark);
363
360
  }
@@ -365,21 +362,21 @@ case 1:
365
362
  break;
366
363
  case 6:
367
364
  // line 27 "ext/puma_http11/http11_parser.java.rl"
368
- {
369
- if(parser.request_method != null)
365
+ {
366
+ if(parser.request_method != null)
370
367
  parser.request_method.call(parser.data, parser.mark, p-parser.mark);
371
368
  }
372
369
  break;
373
370
  case 7:
374
371
  // line 31 "ext/puma_http11/http11_parser.java.rl"
375
- {
372
+ {
376
373
  if(parser.request_uri != null)
377
374
  parser.request_uri.call(parser.data, parser.mark, p-parser.mark);
378
375
  }
379
376
  break;
380
377
  case 8:
381
378
  // line 35 "ext/puma_http11/http11_parser.java.rl"
382
- {
379
+ {
383
380
  if(parser.fragment != null)
384
381
  parser.fragment.call(parser.data, parser.mark, p-parser.mark);
385
382
  }
@@ -390,14 +387,14 @@ case 1:
390
387
  break;
391
388
  case 10:
392
389
  // line 41 "ext/puma_http11/http11_parser.java.rl"
393
- {
390
+ {
394
391
  if(parser.query_string != null)
395
392
  parser.query_string.call(parser.data, parser.query_start, p-parser.query_start);
396
393
  }
397
394
  break;
398
395
  case 11:
399
396
  // line 46 "ext/puma_http11/http11_parser.java.rl"
400
- {
397
+ {
401
398
  if(parser.http_version != null)
402
399
  parser.http_version.call(parser.data, parser.mark, p-parser.mark);
403
400
  }
@@ -411,8 +408,8 @@ case 1:
411
408
  break;
412
409
  case 13:
413
410
  // line 56 "ext/puma_http11/http11_parser.java.rl"
414
- {
415
- parser.body_start = p + 1;
411
+ {
412
+ parser.body_start = p + 1;
416
413
  if(parser.header_done != null)
417
414
  parser.header_done.call(parser.data, p + 1, pe - p - 1);
418
415
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
@@ -442,7 +439,7 @@ case 5:
442
439
 
443
440
  parser.cs = cs;
444
441
  parser.nread += (p - off);
445
-
442
+
446
443
  assert p <= pe : "buffer overflow after parsing execute";
447
444
  assert parser.nread <= len : "nread longer than length";
448
445
  assert parser.body_start <= len : "body starts after buffer end";
@@ -0,0 +1,72 @@
1
+ package org.jruby.puma;
2
+
3
+ import org.jruby.*;
4
+ import org.jruby.anno.JRubyMethod;
5
+ import org.jruby.runtime.ObjectAllocator;
6
+ import org.jruby.runtime.ThreadContext;
7
+ import org.jruby.runtime.builtin.IRubyObject;
8
+ import org.jruby.util.ByteList;
9
+
10
+ /**
11
+ * @author kares
12
+ */
13
+ public class IOBuffer extends RubyObject {
14
+
15
+ private static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
16
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
17
+ return new IOBuffer(runtime, klass);
18
+ }
19
+ };
20
+
21
+ public static void createIOBuffer(Ruby runtime) {
22
+ RubyModule mPuma = runtime.defineModule("Puma");
23
+ RubyClass cIOBuffer = mPuma.defineClassUnder("IOBuffer", runtime.getObject(), ALLOCATOR);
24
+ cIOBuffer.defineAnnotatedMethods(IOBuffer.class);
25
+ }
26
+
27
+ private static final int DEFAULT_SIZE = 4096;
28
+
29
+ final ByteList buffer = new ByteList(DEFAULT_SIZE);
30
+
31
+ IOBuffer(Ruby runtime, RubyClass klass) {
32
+ super(runtime, klass);
33
+ }
34
+
35
+ @JRubyMethod
36
+ public RubyInteger used(ThreadContext context) {
37
+ return context.runtime.newFixnum(buffer.getRealSize());
38
+ }
39
+
40
+ @JRubyMethod
41
+ public RubyInteger capacity(ThreadContext context) {
42
+ return context.runtime.newFixnum(buffer.unsafeBytes().length);
43
+ }
44
+
45
+ @JRubyMethod
46
+ public IRubyObject reset() {
47
+ buffer.setRealSize(0);
48
+ return this;
49
+ }
50
+
51
+ @JRubyMethod(name = { "to_s", "to_str" })
52
+ public RubyString to_s(ThreadContext context) {
53
+ return RubyString.newStringShared(context.runtime, buffer.unsafeBytes(), 0, buffer.getRealSize());
54
+ }
55
+
56
+ @JRubyMethod(name = "<<")
57
+ public IRubyObject add(IRubyObject str) {
58
+ addImpl(str.convertToString());
59
+ return this;
60
+ }
61
+
62
+ @JRubyMethod(rest = true)
63
+ public IRubyObject append(IRubyObject[] strs) {
64
+ for (IRubyObject str : strs) addImpl(str.convertToString());
65
+ return this;
66
+ }
67
+
68
+ private void addImpl(RubyString str) {
69
+ buffer.append(str.getByteList());
70
+ }
71
+
72
+ }
@@ -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.javasupport.JavaEmbedUtils;
9
10
  import org.jruby.runtime.Block;
10
11
  import org.jruby.runtime.ObjectAllocator;
11
12
  import org.jruby.runtime.ThreadContext;
@@ -18,15 +19,18 @@ import javax.net.ssl.SSLContext;
18
19
  import javax.net.ssl.SSLEngine;
19
20
  import javax.net.ssl.SSLEngineResult;
20
21
  import javax.net.ssl.SSLException;
22
+ import javax.net.ssl.SSLPeerUnverifiedException;
21
23
  import javax.net.ssl.SSLSession;
22
24
  import java.io.FileInputStream;
23
25
  import java.io.IOException;
26
+ import java.nio.Buffer;
24
27
  import java.nio.ByteBuffer;
25
28
  import java.security.KeyManagementException;
26
29
  import java.security.KeyStore;
27
30
  import java.security.KeyStoreException;
28
31
  import java.security.NoSuchAlgorithmException;
29
32
  import java.security.UnrecoverableKeyException;
33
+ import java.security.cert.CertificateEncodingException;
30
34
  import java.security.cert.CertificateException;
31
35
 
32
36
  import static javax.net.ssl.SSLEngineResult.Status;
@@ -62,7 +66,7 @@ public class MiniSSL extends RubyObject {
62
66
 
63
67
  public void clear() { buffer.clear(); }
64
68
  public void compact() { buffer.compact(); }
65
- public void flip() { buffer.flip(); }
69
+ public void flip() { ((Buffer) buffer).flip(); }
66
70
  public boolean hasRemaining() { return buffer.hasRemaining(); }
67
71
  public int position() { return buffer.position(); }
68
72
 
@@ -86,7 +90,7 @@ public class MiniSSL extends RubyObject {
86
90
  public void resize(int newCapacity) {
87
91
  if (newCapacity > buffer.capacity()) {
88
92
  ByteBuffer dstTmp = ByteBuffer.allocate(newCapacity);
89
- buffer.flip();
93
+ flip();
90
94
  dstTmp.put(buffer);
91
95
  buffer = dstTmp;
92
96
  } else {
@@ -98,7 +102,7 @@ public class MiniSSL extends RubyObject {
98
102
  * Drains the buffer to a ByteList, or returns null for an empty buffer
99
103
  */
100
104
  public ByteList asByteList() {
101
- buffer.flip();
105
+ flip();
102
106
  if (!buffer.hasRemaining()) {
103
107
  buffer.clear();
104
108
  return null;
@@ -155,7 +159,17 @@ public class MiniSSL extends RubyObject {
155
159
  sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
156
160
  engine = sslCtx.createSSLEngine();
157
161
 
158
- String[] protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
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
+ }
168
+
169
+ if(miniSSLContext.callMethod(threadContext, "no_tlsv1_1").isTrue()) {
170
+ protocols = new String[] { "TLSv1.2" };
171
+ }
172
+
159
173
  engine.setEnabledProtocols(protocols);
160
174
  engine.setUseClientMode(false);
161
175
 
@@ -167,6 +181,12 @@ public class MiniSSL extends RubyObject {
167
181
  engine.setNeedClientAuth(true);
168
182
  }
169
183
 
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
+ }
189
+
170
190
  SSLSession session = engine.getSession();
171
191
  inboundNetData = new MiniSSLBuffer(session.getPacketBufferSize());
172
192
  outboundAppData = new MiniSSLBuffer(session.getApplicationBufferSize());
@@ -333,7 +353,11 @@ public class MiniSSL extends RubyObject {
333
353
  }
334
354
 
335
355
  @JRubyMethod
336
- public IRubyObject peercert() {
337
- return getRuntime().getNil();
356
+ public IRubyObject peercert() throws CertificateEncodingException {
357
+ try {
358
+ return JavaEmbedUtils.javaToRuby(getRuntime(), engine.getSession().getPeerCertificates()[0].getEncoded());
359
+ } catch (SSLPeerUnverifiedException ex) {
360
+ return getRuntime().getNil();
361
+ }
338
362
  }
339
363
  }