puma 3.0.0.rc1 → 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 (91) hide show
  1. checksums.yaml +5 -5
  2. data/{History.txt → History.md} +703 -70
  3. data/LICENSE +23 -20
  4. data/README.md +173 -163
  5. data/docs/architecture.md +37 -0
  6. data/{DEPLOYMENT.md → docs/deployment.md} +28 -6
  7. data/docs/fork_worker.md +31 -0
  8. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  9. data/docs/images/puma-connection-flow.png +0 -0
  10. data/docs/images/puma-general-arch.png +0 -0
  11. data/docs/jungle/README.md +13 -0
  12. data/docs/jungle/rc.d/README.md +74 -0
  13. data/docs/jungle/rc.d/puma +61 -0
  14. data/docs/jungle/rc.d/puma.conf +10 -0
  15. data/{tools → docs}/jungle/upstart/README.md +0 -0
  16. data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
  17. data/{tools → docs}/jungle/upstart/puma.conf +1 -1
  18. data/docs/nginx.md +2 -2
  19. data/docs/plugins.md +38 -0
  20. data/docs/restart.md +41 -0
  21. data/docs/signals.md +57 -3
  22. data/docs/systemd.md +228 -0
  23. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  24. data/ext/puma_http11/extconf.rb +16 -0
  25. data/ext/puma_http11/http11_parser.c +287 -468
  26. data/ext/puma_http11/http11_parser.h +1 -0
  27. data/ext/puma_http11/http11_parser.java.rl +21 -37
  28. data/ext/puma_http11/http11_parser.rl +10 -9
  29. data/ext/puma_http11/http11_parser_common.rl +4 -4
  30. data/ext/puma_http11/mini_ssl.c +159 -10
  31. data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
  32. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +99 -132
  33. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +30 -6
  34. data/ext/puma_http11/puma_http11.c +6 -38
  35. data/lib/puma.rb +25 -5
  36. data/lib/puma/accept_nonblock.rb +7 -1
  37. data/lib/puma/app/status.rb +53 -26
  38. data/lib/puma/binder.rb +150 -119
  39. data/lib/puma/cli.rb +56 -38
  40. data/lib/puma/client.rb +277 -80
  41. data/lib/puma/cluster.rb +326 -130
  42. data/lib/puma/commonlogger.rb +21 -20
  43. data/lib/puma/configuration.rb +160 -161
  44. data/lib/puma/const.rb +50 -47
  45. data/lib/puma/control_cli.rb +104 -63
  46. data/lib/puma/detect.rb +13 -1
  47. data/lib/puma/dsl.rb +463 -114
  48. data/lib/puma/events.rb +22 -13
  49. data/lib/puma/io_buffer.rb +9 -5
  50. data/lib/puma/jruby_restart.rb +2 -59
  51. data/lib/puma/launcher.rb +195 -105
  52. data/lib/puma/minissl.rb +110 -4
  53. data/lib/puma/minissl/context_builder.rb +76 -0
  54. data/lib/puma/null_io.rb +9 -14
  55. data/lib/puma/plugin.rb +32 -12
  56. data/lib/puma/plugin/tmp_restart.rb +19 -6
  57. data/lib/puma/rack/builder.rb +7 -5
  58. data/lib/puma/rack/urlmap.rb +11 -8
  59. data/lib/puma/rack_default.rb +2 -0
  60. data/lib/puma/reactor.rb +242 -32
  61. data/lib/puma/runner.rb +41 -30
  62. data/lib/puma/server.rb +265 -183
  63. data/lib/puma/single.rb +22 -63
  64. data/lib/puma/state_file.rb +9 -2
  65. data/lib/puma/thread_pool.rb +179 -68
  66. data/lib/puma/util.rb +3 -11
  67. data/lib/rack/handler/puma.rb +60 -11
  68. data/tools/Dockerfile +16 -0
  69. data/tools/trickletest.rb +1 -2
  70. metadata +35 -99
  71. data/COPYING +0 -55
  72. data/Gemfile +0 -13
  73. data/Manifest.txt +0 -79
  74. data/Rakefile +0 -158
  75. data/docs/config.md +0 -0
  76. data/ext/puma_http11/io_buffer.c +0 -155
  77. data/lib/puma/capistrano.rb +0 -94
  78. data/lib/puma/compat.rb +0 -18
  79. data/lib/puma/convenient.rb +0 -23
  80. data/lib/puma/daemon_ext.rb +0 -31
  81. data/lib/puma/delegation.rb +0 -11
  82. data/lib/puma/java_io_buffer.rb +0 -45
  83. data/lib/puma/rack/backports/uri/common_18.rb +0 -56
  84. data/lib/puma/rack/backports/uri/common_192.rb +0 -52
  85. data/lib/puma/rack/backports/uri/common_193.rb +0 -29
  86. data/lib/puma/tcp_logger.rb +0 -32
  87. data/puma.gemspec +0 -52
  88. data/tools/jungle/README.md +0 -9
  89. data/tools/jungle/init.d/README.md +0 -54
  90. data/tools/jungle/init.d/puma +0 -394
  91. data/tools/jungle/init.d/run-puma +0 -3
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Copyright (c) 2005 Zed A. Shaw
3
3
  * You can redistribute it and/or modify it under the same terms as Ruby.
4
+ * License 3-clause BSD
4
5
  */
5
6
 
6
7
  #ifndef http11_parser_h
@@ -1,5 +1,7 @@
1
1
  package org.jruby.puma;
2
2
 
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyHash;
3
5
  import org.jruby.util.ByteList;
4
6
 
5
7
  public class Http11Parser {
@@ -19,44 +21,35 @@ public class Http11Parser {
19
21
  }
20
22
 
21
23
  action start_value { parser.mark = fpc; }
22
- action write_value {
23
- if(parser.http_field != null) {
24
- parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, fpc-parser.mark);
25
- }
24
+ action write_value {
25
+ Http11.http_field(runtime, parser.data, parser.buffer, parser.field_start, parser.field_len, parser.mark, fpc-parser.mark);
26
26
  }
27
- action request_method {
28
- if(parser.request_method != null)
29
- parser.request_method.call(parser.data, parser.mark, fpc-parser.mark);
27
+ action request_method {
28
+ Http11.request_method(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
30
29
  }
31
- action request_uri {
32
- if(parser.request_uri != null)
33
- parser.request_uri.call(parser.data, parser.mark, fpc-parser.mark);
30
+ action request_uri {
31
+ Http11.request_uri(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
34
32
  }
35
- action fragment {
36
- if(parser.fragment != null)
37
- parser.fragment.call(parser.data, parser.mark, fpc-parser.mark);
33
+ action fragment {
34
+ Http11.fragment(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
38
35
  }
39
36
 
40
37
  action start_query {parser.query_start = fpc; }
41
- action query_string {
42
- if(parser.query_string != null)
43
- parser.query_string.call(parser.data, parser.query_start, fpc-parser.query_start);
38
+ action query_string {
39
+ Http11.query_string(runtime, parser.data, parser.buffer, parser.query_start, fpc-parser.query_start);
44
40
  }
45
41
 
46
- action http_version {
47
- if(parser.http_version != null)
48
- parser.http_version.call(parser.data, parser.mark, fpc-parser.mark);
42
+ action http_version {
43
+ Http11.http_version(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
49
44
  }
50
45
 
51
46
  action request_path {
52
- if(parser.request_path != null)
53
- parser.request_path.call(parser.data, parser.mark, fpc-parser.mark);
47
+ Http11.request_path(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
54
48
  }
55
49
 
56
50
  action done {
57
- parser.body_start = fpc + 1;
58
- if(parser.header_done != null)
59
- parser.header_done.call(parser.data, fpc + 1, pe - fpc - 1);
51
+ parser.body_start = fpc + 1;
52
+ http.header_done(runtime, parser.data, parser.buffer, fpc + 1, pe - fpc - 1);
60
53
  fbreak;
61
54
  }
62
55
 
@@ -68,11 +61,11 @@ public class Http11Parser {
68
61
  %% write data;
69
62
 
70
63
  public static interface ElementCB {
71
- public void call(Object data, int at, int length);
64
+ public void call(Ruby runtime, RubyHash data, ByteList buffer, int at, int length);
72
65
  }
73
66
 
74
67
  public static interface FieldCB {
75
- public void call(Object data, int field, int flen, int value, int vlen);
68
+ public void call(Ruby runtime, RubyHash data, ByteList buffer, int field, int flen, int value, int vlen);
76
69
  }
77
70
 
78
71
  public static class HttpParser {
@@ -85,18 +78,9 @@ public class Http11Parser {
85
78
  int field_len;
86
79
  int query_start;
87
80
 
88
- Object data;
81
+ RubyHash data;
89
82
  ByteList buffer;
90
83
 
91
- public FieldCB http_field;
92
- public ElementCB request_method;
93
- public ElementCB request_uri;
94
- public ElementCB fragment;
95
- public ElementCB request_path;
96
- public ElementCB query_string;
97
- public ElementCB http_version;
98
- public ElementCB header_done;
99
-
100
84
  public void init() {
101
85
  cs = 0;
102
86
 
@@ -113,7 +97,7 @@ public class Http11Parser {
113
97
 
114
98
  public final HttpParser parser = new HttpParser();
115
99
 
116
- public int execute(ByteList buffer, int off) {
100
+ public int execute(Ruby runtime, Http11 http, ByteList buffer, int off) {
117
101
  int p, pe;
118
102
  int cs = parser.cs;
119
103
  int len = buffer.length();
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Copyright (c) 2005 Zed A. Shaw
3
3
  * You can redistribute it and/or modify it under the same terms as Ruby.
4
+ * License 3-clause BSD
4
5
  */
5
6
  #include "http11_parser.h"
6
7
  #include <stdio.h>
@@ -28,7 +29,7 @@ static void snake_upcase_char(char *c)
28
29
  /** Machine **/
29
30
 
30
31
  %%{
31
-
32
+
32
33
  machine puma_parser;
33
34
 
34
35
  action mark { MARK(mark, fpc); }
@@ -36,7 +37,7 @@ static void snake_upcase_char(char *c)
36
37
 
37
38
  action start_field { MARK(field_start, fpc); }
38
39
  action snake_upcase_field { snake_upcase_char((char *)fpc); }
39
- action write_field {
40
+ action write_field {
40
41
  parser->field_len = LEN(field_start, fpc);
41
42
  }
42
43
 
@@ -44,10 +45,10 @@ static void snake_upcase_char(char *c)
44
45
  action write_value {
45
46
  parser->http_field(parser, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
46
47
  }
47
- action request_method {
48
+ action request_method {
48
49
  parser->request_method(parser, PTR_TO(mark), LEN(mark, fpc));
49
50
  }
50
- action request_uri {
51
+ action request_uri {
51
52
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, fpc));
52
53
  }
53
54
  action fragment {
@@ -55,11 +56,11 @@ static void snake_upcase_char(char *c)
55
56
  }
56
57
 
57
58
  action start_query { MARK(query_start, fpc); }
58
- action query_string {
59
+ action query_string {
59
60
  parser->query_string(parser, PTR_TO(query_start), LEN(query_start, fpc));
60
61
  }
61
62
 
62
- action http_version {
63
+ action http_version {
63
64
  parser->http_version(parser, PTR_TO(mark), LEN(mark, fpc));
64
65
  }
65
66
 
@@ -67,8 +68,8 @@ static void snake_upcase_char(char *c)
67
68
  parser->request_path(parser, PTR_TO(mark), LEN(mark,fpc));
68
69
  }
69
70
 
70
- action done {
71
- parser->body_start = fpc - buffer + 1;
71
+ action done {
72
+ parser->body_start = fpc - buffer + 1;
72
73
  parser->header_done(parser, fpc + 1, pe - fpc - 1);
73
74
  fbreak;
74
75
  }
@@ -108,7 +109,7 @@ size_t puma_parser_execute(puma_parser *parser, const char *buffer, size_t len,
108
109
  pe = buffer+len;
109
110
 
110
111
  /* assert(*pe == '\0' && "pointer does not end on NUL"); */
111
- assert(pe - p == len - off && "pointers aren't same distance");
112
+ assert((size_t) (pe - p) == len - off && "pointers aren't same distance");
112
113
 
113
114
  %% write exec;
114
115
 
@@ -1,5 +1,5 @@
1
1
  %%{
2
-
2
+
3
3
  machine puma_parser_common;
4
4
 
5
5
  #### HTTP PROTOCOL GRAMMAR
@@ -15,8 +15,8 @@
15
15
  national = any -- (alpha | digit | reserved | extra | safe | unsafe);
16
16
  unreserved = (alpha | digit | safe | extra | national);
17
17
  escape = ("%" xdigit xdigit);
18
- uchar = (unreserved | escape);
19
- pchar = (uchar | ":" | "@" | "&" | "=" | "+");
18
+ uchar = (unreserved | escape | "%");
19
+ pchar = (uchar | ":" | "@" | "&" | "=" | "+" | ";");
20
20
  tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
21
21
 
22
22
  # elements
@@ -30,7 +30,7 @@
30
30
  query = ( uchar | reserved )* %query_string ;
31
31
  param = ( pchar | "/" )* ;
32
32
  params = ( param ( ";" param )* ) ;
33
- rel_path = ( path? %request_path (";" params)? ) ("?" %start_query query)?;
33
+ rel_path = ( path? %request_path ) ("?" %start_query query)?;
34
34
  absolute_path = ( "/"+ rel_path );
35
35
 
36
36
  Request_URI = ( "*" | absolute_uri | absolute_path ) >mark %request_uri;
@@ -1,7 +1,13 @@
1
1
  #define RSTRING_NOT_MODIFIED 1
2
2
 
3
3
  #include <ruby.h>
4
+ #include <ruby/version.h>
5
+
6
+ #if RUBY_API_VERSION_MAJOR == 1
4
7
  #include <rubyio.h>
8
+ #else
9
+ #include <ruby/io.h>
10
+ #endif
5
11
 
6
12
  #ifdef HAVE_OPENSSL_BIO_H
7
13
 
@@ -81,6 +87,8 @@ DH *get_dh1024() {
81
87
 
82
88
  DH *dh;
83
89
  dh = DH_new();
90
+
91
+ #if OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER)
84
92
  dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
85
93
  dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
86
94
 
@@ -88,6 +96,18 @@ DH *get_dh1024() {
88
96
  DH_free(dh);
89
97
  return NULL;
90
98
  }
99
+ #else
100
+ BIGNUM *p, *g;
101
+ p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
102
+ g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
103
+
104
+ if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) {
105
+ DH_free(dh);
106
+ BN_free(p);
107
+ BN_free(g);
108
+ return NULL;
109
+ }
110
+ #endif
91
111
 
92
112
  return dh;
93
113
  }
@@ -122,45 +142,105 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
122
142
  VALUE obj;
123
143
  SSL_CTX* ctx;
124
144
  SSL* ssl;
145
+ int min, ssl_options;
125
146
 
126
147
  ms_conn* conn = engine_alloc(self, &obj);
127
148
 
128
149
  ID sym_key = rb_intern("key");
129
150
  VALUE key = rb_funcall(mini_ssl_ctx, sym_key, 0);
130
151
 
152
+ StringValue(key);
153
+
131
154
  ID sym_cert = rb_intern("cert");
132
155
  VALUE cert = rb_funcall(mini_ssl_ctx, sym_cert, 0);
133
156
 
157
+ StringValue(cert);
158
+
134
159
  ID sym_ca = rb_intern("ca");
135
160
  VALUE ca = rb_funcall(mini_ssl_ctx, sym_ca, 0);
136
161
 
137
162
  ID sym_verify_mode = rb_intern("verify_mode");
138
163
  VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
139
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
140
177
  ctx = SSL_CTX_new(SSLv23_server_method());
178
+ #endif
141
179
  conn->ctx = ctx;
142
180
 
143
181
  SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
144
182
  SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM);
145
183
 
146
184
  if (!NIL_P(ca)) {
185
+ StringValue(ca);
147
186
  SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
148
187
  }
188
+
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
+ }
149
201
 
150
- 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);
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
+
151
219
  SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
152
220
 
153
- 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
+ }
154
228
 
155
229
  DH *dh = get_dh1024();
156
230
  SSL_CTX_set_tmp_dh(ctx, dh);
157
231
 
158
- #ifndef OPENSSL_NO_ECDH
159
- 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);
160
236
  if (ecdh) {
161
237
  SSL_CTX_set_tmp_ecdh(ctx, ecdh);
162
238
  EC_KEY_free(ecdh);
163
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);
164
244
  #endif
165
245
 
166
246
  ssl = SSL_new(ctx);
@@ -182,8 +262,11 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
182
262
  VALUE engine_init_client(VALUE klass) {
183
263
  VALUE obj;
184
264
  ms_conn* conn = engine_alloc(klass, &obj);
185
-
265
+ #ifdef HAVE_DTLS_METHOD
266
+ conn->ctx = SSL_CTX_new(DTLS_method());
267
+ #else
186
268
  conn->ctx = SSL_CTX_new(DTLSv1_method());
269
+ #endif
187
270
  conn->ssl = SSL_new(conn->ctx);
188
271
  SSL_set_app_data(conn->ssl, NULL);
189
272
  SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
@@ -219,7 +302,7 @@ void raise_error(SSL* ssl, int result) {
219
302
  const char* err_str;
220
303
  int err = errno;
221
304
  int ssl_err = SSL_get_error(ssl, result);
222
- int verify_err = SSL_get_verify_result(ssl);
305
+ int verify_err = (int) SSL_get_verify_result(ssl);
223
306
 
224
307
  if(SSL_ERROR_SYSCALL == ssl_err) {
225
308
  snprintf(msg, sizeof(msg), "System error: %s - %d", strerror(err), err);
@@ -232,7 +315,7 @@ void raise_error(SSL* ssl, int result) {
232
315
  err_str, verify_err);
233
316
 
234
317
  } else {
235
- err = ERR_get_error();
318
+ err = (int) ERR_get_error();
236
319
  ERR_error_string_n(err, buf, sizeof(buf));
237
320
  snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err);
238
321
 
@@ -316,6 +399,30 @@ VALUE engine_extract(VALUE self) {
316
399
  return Qnil;
317
400
  }
318
401
 
402
+ VALUE engine_shutdown(VALUE self) {
403
+ ms_conn* conn;
404
+ int ok;
405
+
406
+ Data_Get_Struct(self, ms_conn, conn);
407
+
408
+ ERR_clear_error();
409
+
410
+ ok = SSL_shutdown(conn->ssl);
411
+ if (ok == 0) {
412
+ return Qfalse;
413
+ }
414
+
415
+ return Qtrue;
416
+ }
417
+
418
+ VALUE engine_init(VALUE self) {
419
+ ms_conn* conn;
420
+
421
+ Data_Get_Struct(self, ms_conn, conn);
422
+
423
+ return SSL_in_init(conn->ssl) ? Qtrue : Qfalse;
424
+ }
425
+
319
426
  VALUE engine_peercert(VALUE self) {
320
427
  ms_conn* conn;
321
428
  X509* cert;
@@ -347,7 +454,7 @@ VALUE engine_peercert(VALUE self) {
347
454
  }
348
455
  }
349
456
 
350
- rb_cert_buf = rb_str_new(buf, bytes);
457
+ rb_cert_buf = rb_str_new((const char*)(buf), bytes);
351
458
  if(!cert_buf) {
352
459
  OPENSSL_free(buf);
353
460
  }
@@ -362,14 +469,52 @@ VALUE noop(VALUE self) {
362
469
  void Init_mini_ssl(VALUE puma) {
363
470
  VALUE mod, eng;
364
471
 
472
+ /* Fake operation for documentation (RDoc, YARD) */
473
+ #if 0 == 1
474
+ puma = rb_define_module("Puma");
475
+ #endif
476
+
365
477
  SSL_library_init();
366
478
  OpenSSL_add_ssl_algorithms();
367
479
  SSL_load_error_strings();
368
480
  ERR_load_crypto_strings();
369
-
481
+
370
482
  mod = rb_define_module_under(puma, "MiniSSL");
371
483
  eng = rb_define_class_under(mod, "Engine", rb_cObject);
372
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
+
373
518
  rb_define_singleton_method(mod, "check", noop, 0);
374
519
 
375
520
  eError = rb_define_class_under(mod, "SSLError", rb_eStandardError);
@@ -383,6 +528,10 @@ void Init_mini_ssl(VALUE puma) {
383
528
  rb_define_method(eng, "write", engine_write, 1);
384
529
  rb_define_method(eng, "extract", engine_extract, 0);
385
530
 
531
+ rb_define_method(eng, "shutdown", engine_shutdown, 0);
532
+
533
+ rb_define_method(eng, "init?", engine_init, 0);
534
+
386
535
  rb_define_method(eng, "peercert", engine_peercert, 0);
387
536
  }
388
537
 
@@ -394,7 +543,7 @@ VALUE raise_error(VALUE self) {
394
543
  }
395
544
 
396
545
  void Init_mini_ssl(VALUE puma) {
397
- VALUE mod, eng;
546
+ VALUE mod;
398
547
 
399
548
  mod = rb_define_module_under(puma, "MiniSSL");
400
549
  rb_define_class_under(mod, "SSLError", rb_eStandardError);