puma 3.12.6 → 6.3.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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1806 -451
  3. data/LICENSE +23 -20
  4. data/README.md +217 -65
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +59 -21
  7. data/docs/compile_options.md +55 -0
  8. data/docs/deployment.md +69 -58
  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 +9 -0
  14. data/{tools → docs}/jungle/rc.d/README.md +1 -1
  15. data/{tools → docs}/jungle/rc.d/puma +2 -2
  16. data/docs/kubernetes.md +66 -0
  17. data/docs/nginx.md +2 -2
  18. data/docs/plugins.md +22 -12
  19. data/docs/rails_dev_mode.md +28 -0
  20. data/docs/restart.md +47 -22
  21. data/docs/signals.md +13 -11
  22. data/docs/stats.md +142 -0
  23. data/docs/systemd.md +94 -120
  24. data/docs/testing_benchmarks_local_files.md +150 -0
  25. data/docs/testing_test_rackup_ci_files.md +36 -0
  26. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  27. data/ext/puma_http11/ext_help.h +1 -1
  28. data/ext/puma_http11/extconf.rb +61 -3
  29. data/ext/puma_http11/http11_parser.c +103 -117
  30. data/ext/puma_http11/http11_parser.h +2 -2
  31. data/ext/puma_http11/http11_parser.java.rl +22 -38
  32. data/ext/puma_http11/http11_parser.rl +3 -3
  33. data/ext/puma_http11/http11_parser_common.rl +6 -6
  34. data/ext/puma_http11/mini_ssl.c +389 -99
  35. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  36. data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
  37. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +84 -99
  38. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +248 -92
  39. data/ext/puma_http11/puma_http11.c +49 -57
  40. data/lib/puma/app/status.rb +71 -49
  41. data/lib/puma/binder.rb +244 -150
  42. data/lib/puma/cli.rb +38 -34
  43. data/lib/puma/client.rb +388 -244
  44. data/lib/puma/cluster/worker.rb +180 -0
  45. data/lib/puma/cluster/worker_handle.rb +97 -0
  46. data/lib/puma/cluster.rb +261 -243
  47. data/lib/puma/commonlogger.rb +21 -14
  48. data/lib/puma/configuration.rb +116 -88
  49. data/lib/puma/const.rb +154 -104
  50. data/lib/puma/control_cli.rb +115 -70
  51. data/lib/puma/detect.rb +33 -2
  52. data/lib/puma/dsl.rb +764 -134
  53. data/lib/puma/error_logger.rb +113 -0
  54. data/lib/puma/events.rb +16 -112
  55. data/lib/puma/io_buffer.rb +42 -5
  56. data/lib/puma/jruby_restart.rb +2 -59
  57. data/lib/puma/json_serialization.rb +96 -0
  58. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  59. data/lib/puma/launcher.rb +184 -133
  60. data/lib/puma/log_writer.rb +147 -0
  61. data/lib/puma/minissl/context_builder.rb +93 -0
  62. data/lib/puma/minissl.rb +263 -70
  63. data/lib/puma/null_io.rb +18 -1
  64. data/lib/puma/plugin/systemd.rb +90 -0
  65. data/lib/puma/plugin/tmp_restart.rb +3 -1
  66. data/lib/puma/plugin.rb +7 -13
  67. data/lib/puma/rack/builder.rb +9 -11
  68. data/lib/puma/rack/urlmap.rb +2 -0
  69. data/lib/puma/rack_default.rb +21 -4
  70. data/lib/puma/reactor.rb +93 -315
  71. data/lib/puma/request.rb +671 -0
  72. data/lib/puma/runner.rb +94 -69
  73. data/lib/puma/sd_notify.rb +149 -0
  74. data/lib/puma/server.rb +327 -772
  75. data/lib/puma/single.rb +20 -74
  76. data/lib/puma/state_file.rb +45 -8
  77. data/lib/puma/thread_pool.rb +146 -92
  78. data/lib/puma/util.rb +22 -10
  79. data/lib/puma.rb +60 -5
  80. data/lib/rack/handler/puma.rb +116 -90
  81. data/tools/Dockerfile +16 -0
  82. data/tools/trickletest.rb +0 -1
  83. metadata +54 -32
  84. data/ext/puma_http11/io_buffer.c +0 -155
  85. data/lib/puma/accept_nonblock.rb +0 -23
  86. data/lib/puma/compat.rb +0 -14
  87. data/lib/puma/convenient.rb +0 -25
  88. data/lib/puma/daemon_ext.rb +0 -33
  89. data/lib/puma/delegation.rb +0 -13
  90. data/lib/puma/java_io_buffer.rb +0 -47
  91. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
  92. data/lib/puma/tcp_logger.rb +0 -41
  93. data/tools/jungle/README.md +0 -19
  94. data/tools/jungle/init.d/README.md +0 -61
  95. data/tools/jungle/init.d/puma +0 -421
  96. data/tools/jungle/init.d/run-puma +0 -18
  97. data/tools/jungle/upstart/README.md +0 -61
  98. data/tools/jungle/upstart/puma-manager.conf +0 -31
  99. data/tools/jungle/upstart/puma.conf +0 -69
  100. /data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
@@ -2,12 +2,7 @@
2
2
 
3
3
  #include <ruby.h>
4
4
  #include <ruby/version.h>
5
-
6
- #if RUBY_API_VERSION_MAJOR == 1
7
- #include <rubyio.h>
8
- #else
9
5
  #include <ruby/io.h>
10
- #endif
11
6
 
12
7
  #ifdef HAVE_OPENSSL_BIO_H
13
8
 
@@ -33,7 +28,16 @@ typedef struct {
33
28
  int bytes;
34
29
  } ms_cert_buf;
35
30
 
36
- void engine_free(ms_conn* conn) {
31
+ VALUE eError;
32
+
33
+ NORETURN(void raise_file_error(const char* caller, const char *filename));
34
+
35
+ void raise_file_error(const char* caller, const char *filename) {
36
+ rb_raise(eError, "%s: error in file '%s': %s", caller, filename, ERR_error_string(ERR_get_error(), NULL));
37
+ }
38
+
39
+ void engine_free(void *ptr) {
40
+ ms_conn *conn = ptr;
37
41
  ms_cert_buf* cert_buf = (ms_cert_buf*)SSL_get_app_data(conn->ssl);
38
42
  if(cert_buf) {
39
43
  OPENSSL_free(cert_buf->buf);
@@ -45,61 +49,72 @@ void engine_free(ms_conn* conn) {
45
49
  free(conn);
46
50
  }
47
51
 
48
- ms_conn* engine_alloc(VALUE klass, VALUE* obj) {
49
- ms_conn* conn;
52
+ const rb_data_type_t engine_data_type = {
53
+ "MiniSSL/ENGINE",
54
+ { 0, engine_free, 0 },
55
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
56
+ };
50
57
 
51
- *obj = Data_Make_Struct(klass, ms_conn, 0, engine_free, conn);
52
-
53
- conn->read = BIO_new(BIO_s_mem());
54
- BIO_set_nbio(conn->read, 1);
55
-
56
- conn->write = BIO_new(BIO_s_mem());
57
- BIO_set_nbio(conn->write, 1);
58
-
59
- conn->ssl = 0;
60
- conn->ctx = 0;
61
-
62
- return conn;
63
- }
64
-
65
- DH *get_dh1024() {
66
- /* `openssl dhparam 1024 -C`
58
+ #ifndef HAVE_SSL_CTX_SET_DH_AUTO
59
+ DH *get_dh2048(void) {
60
+ /* `openssl dhparam -C 2048`
67
61
  * -----BEGIN DH PARAMETERS-----
68
- * MIGHAoGBALPwcEv0OstmQCZdfHw0N5r+07lmXMxkpQacy1blwj0LUqC+Divp6pBk
69
- * usTJ9W2/dOYr1X7zi6yXNLp4oLzc/31PUL3D9q8CpGS7vPz5gijKSw9BwCTT5z9+
70
- * KF9v46qw8XqT5HHV87sWFlGQcVFq+pEkA2kPikkKZ/X/CCcpCAV7AgEC
62
+ * MIIBCAKCAQEAjmh1uQHdTfxOyxEbKAV30fUfzqMDF/ChPzjfyzl2jcrqQMhrk76o
63
+ * 2NPNXqxHwsddMZ1RzvU8/jl+uhRuPWjXCFZbhET4N1vrviZM3VJhV8PPHuiVOACO
64
+ * y32jFd+Szx4bo2cXSK83hJ6jRd+0asP1awWjz9/06dFkrILCXMIfQLo0D8rqmppn
65
+ * EfDDAwuudCpM9kcDmBRAm9JsKbQ6gzZWjkc5+QWSaQofojIHbjvj3xzguaCJn+oQ
66
+ * vHWM+hsAnaOgEwCyeZ3xqs+/5lwSbkE/tqJW98cEZGygBUVo9jxZRZx6KOfjpdrb
67
+ * yenO9LJr/qtyrZB31WJbqxI0m0AKTAO8UwIBAg==
71
68
  * -----END DH PARAMETERS-----
72
69
  */
73
- static unsigned char dh1024_p[] = {
74
- 0xB3,0xF0,0x70,0x4B,0xF4,0x3A,0xCB,0x66,0x40,0x26,0x5D,0x7C,
75
- 0x7C,0x34,0x37,0x9A,0xFE,0xD3,0xB9,0x66,0x5C,0xCC,0x64,0xA5,
76
- 0x06,0x9C,0xCB,0x56,0xE5,0xC2,0x3D,0x0B,0x52,0xA0,0xBE,0x0E,
77
- 0x2B,0xE9,0xEA,0x90,0x64,0xBA,0xC4,0xC9,0xF5,0x6D,0xBF,0x74,
78
- 0xE6,0x2B,0xD5,0x7E,0xF3,0x8B,0xAC,0x97,0x34,0xBA,0x78,0xA0,
79
- 0xBC,0xDC,0xFF,0x7D,0x4F,0x50,0xBD,0xC3,0xF6,0xAF,0x02,0xA4,
80
- 0x64,0xBB,0xBC,0xFC,0xF9,0x82,0x28,0xCA,0x4B,0x0F,0x41,0xC0,
81
- 0x24,0xD3,0xE7,0x3F,0x7E,0x28,0x5F,0x6F,0xE3,0xAA,0xB0,0xF1,
82
- 0x7A,0x93,0xE4,0x71,0xD5,0xF3,0xBB,0x16,0x16,0x51,0x90,0x71,
83
- 0x51,0x6A,0xFA,0x91,0x24,0x03,0x69,0x0F,0x8A,0x49,0x0A,0x67,
84
- 0xF5,0xFF,0x08,0x27,0x29,0x08,0x05,0x7B
70
+ static unsigned char dh2048_p[] = {
71
+ 0x8E, 0x68, 0x75, 0xB9, 0x01, 0xDD, 0x4D, 0xFC, 0x4E, 0xCB,
72
+ 0x11, 0x1B, 0x28, 0x05, 0x77, 0xD1, 0xF5, 0x1F, 0xCE, 0xA3,
73
+ 0x03, 0x17, 0xF0, 0xA1, 0x3F, 0x38, 0xDF, 0xCB, 0x39, 0x76,
74
+ 0x8D, 0xCA, 0xEA, 0x40, 0xC8, 0x6B, 0x93, 0xBE, 0xA8, 0xD8,
75
+ 0xD3, 0xCD, 0x5E, 0xAC, 0x47, 0xC2, 0xC7, 0x5D, 0x31, 0x9D,
76
+ 0x51, 0xCE, 0xF5, 0x3C, 0xFE, 0x39, 0x7E, 0xBA, 0x14, 0x6E,
77
+ 0x3D, 0x68, 0xD7, 0x08, 0x56, 0x5B, 0x84, 0x44, 0xF8, 0x37,
78
+ 0x5B, 0xEB, 0xBE, 0x26, 0x4C, 0xDD, 0x52, 0x61, 0x57, 0xC3,
79
+ 0xCF, 0x1E, 0xE8, 0x95, 0x38, 0x00, 0x8E, 0xCB, 0x7D, 0xA3,
80
+ 0x15, 0xDF, 0x92, 0xCF, 0x1E, 0x1B, 0xA3, 0x67, 0x17, 0x48,
81
+ 0xAF, 0x37, 0x84, 0x9E, 0xA3, 0x45, 0xDF, 0xB4, 0x6A, 0xC3,
82
+ 0xF5, 0x6B, 0x05, 0xA3, 0xCF, 0xDF, 0xF4, 0xE9, 0xD1, 0x64,
83
+ 0xAC, 0x82, 0xC2, 0x5C, 0xC2, 0x1F, 0x40, 0xBA, 0x34, 0x0F,
84
+ 0xCA, 0xEA, 0x9A, 0x9A, 0x67, 0x11, 0xF0, 0xC3, 0x03, 0x0B,
85
+ 0xAE, 0x74, 0x2A, 0x4C, 0xF6, 0x47, 0x03, 0x98, 0x14, 0x40,
86
+ 0x9B, 0xD2, 0x6C, 0x29, 0xB4, 0x3A, 0x83, 0x36, 0x56, 0x8E,
87
+ 0x47, 0x39, 0xF9, 0x05, 0x92, 0x69, 0x0A, 0x1F, 0xA2, 0x32,
88
+ 0x07, 0x6E, 0x3B, 0xE3, 0xDF, 0x1C, 0xE0, 0xB9, 0xA0, 0x89,
89
+ 0x9F, 0xEA, 0x10, 0xBC, 0x75, 0x8C, 0xFA, 0x1B, 0x00, 0x9D,
90
+ 0xA3, 0xA0, 0x13, 0x00, 0xB2, 0x79, 0x9D, 0xF1, 0xAA, 0xCF,
91
+ 0xBF, 0xE6, 0x5C, 0x12, 0x6E, 0x41, 0x3F, 0xB6, 0xA2, 0x56,
92
+ 0xF7, 0xC7, 0x04, 0x64, 0x6C, 0xA0, 0x05, 0x45, 0x68, 0xF6,
93
+ 0x3C, 0x59, 0x45, 0x9C, 0x7A, 0x28, 0xE7, 0xE3, 0xA5, 0xDA,
94
+ 0xDB, 0xC9, 0xE9, 0xCE, 0xF4, 0xB2, 0x6B, 0xFE, 0xAB, 0x72,
95
+ 0xAD, 0x90, 0x77, 0xD5, 0x62, 0x5B, 0xAB, 0x12, 0x34, 0x9B,
96
+ 0x40, 0x0A, 0x4C, 0x03, 0xBC, 0x53
85
97
  };
86
- static unsigned char dh1024_g[] = { 0x02 };
98
+ static unsigned char dh2048_g[] = { 0x02 };
87
99
 
88
100
  DH *dh;
101
+ #if !(OPENSSL_VERSION_NUMBER < 0x10100005L)
102
+ BIGNUM *p, *g;
103
+ #endif
104
+
89
105
  dh = DH_new();
90
106
 
91
- #if OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER)
92
- dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
93
- dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
107
+ #if OPENSSL_VERSION_NUMBER < 0x10100005L
108
+ dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
109
+ dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
94
110
 
95
111
  if ((dh->p == NULL) || (dh->g == NULL)) {
96
112
  DH_free(dh);
97
113
  return NULL;
98
114
  }
99
115
  #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);
116
+ p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
117
+ g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
103
118
 
104
119
  if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) {
105
120
  DH_free(dh);
@@ -111,6 +126,38 @@ DH *get_dh1024() {
111
126
 
112
127
  return dh;
113
128
  }
129
+ #endif
130
+
131
+ static void
132
+ sslctx_free(void *ptr) {
133
+ SSL_CTX *ctx = ptr;
134
+ SSL_CTX_free(ctx);
135
+ }
136
+
137
+ static const rb_data_type_t sslctx_type = {
138
+ "MiniSSL/SSLContext",
139
+ {
140
+ 0, sslctx_free,
141
+ },
142
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
143
+ };
144
+
145
+ ms_conn* engine_alloc(VALUE klass, VALUE* obj) {
146
+ ms_conn* conn;
147
+
148
+ *obj = TypedData_Make_Struct(klass, ms_conn, &engine_data_type, conn);
149
+
150
+ conn->read = BIO_new(BIO_s_mem());
151
+ BIO_set_nbio(conn->read, 1);
152
+
153
+ conn->write = BIO_new(BIO_s_mem());
154
+ BIO_set_nbio(conn->write, 1);
155
+
156
+ conn->ssl = 0;
157
+ conn->ctx = 0;
158
+
159
+ return conn;
160
+ }
114
161
 
115
162
  static int engine_verify_callback(int preverify_ok, X509_STORE_CTX* ctx) {
116
163
  X509* err_cert;
@@ -138,45 +185,201 @@ static int engine_verify_callback(int preverify_ok, X509_STORE_CTX* ctx) {
138
185
  return preverify_ok;
139
186
  }
140
187
 
141
- VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
142
- VALUE obj;
188
+ static int password_callback(char *buf, int size, int rwflag, void *userdata) {
189
+ const char *password = (const char *) userdata;
190
+ size_t len = strlen(password);
191
+
192
+ if (len > (size_t) size) {
193
+ return 0;
194
+ }
195
+
196
+ memcpy(buf, password, len);
197
+ return (int) len;
198
+ }
199
+
200
+ static VALUE
201
+ sslctx_alloc(VALUE klass) {
202
+ SSL_CTX *ctx;
203
+ long mode = 0 |
204
+ SSL_MODE_ENABLE_PARTIAL_WRITE |
205
+ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
206
+ SSL_MODE_RELEASE_BUFFERS;
207
+
208
+ #ifdef HAVE_TLS_SERVER_METHOD
209
+ ctx = SSL_CTX_new(TLS_method());
210
+ // printf("\nctx using TLS_method security_level %d\n", SSL_CTX_get_security_level(ctx));
211
+ #else
212
+ ctx = SSL_CTX_new(SSLv23_method());
213
+ #endif
214
+ if (!ctx) {
215
+ rb_raise(eError, "SSL_CTX_new");
216
+ }
217
+ SSL_CTX_set_mode(ctx, mode);
218
+
219
+ return TypedData_Wrap_Struct(klass, &sslctx_type, ctx);
220
+ }
221
+
222
+ VALUE
223
+ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
143
224
  SSL_CTX* ctx;
144
- SSL* ssl;
225
+ int ssl_options;
226
+ VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1,
227
+ verification_flags, session_id_bytes, cert_pem, key_pem, key_password_command, key_password;
228
+ BIO *bio;
229
+ X509 *x509;
230
+ EVP_PKEY *pkey;
231
+ pem_password_cb *password_cb = NULL;
232
+ const char *password = NULL;
233
+ #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
234
+ int min;
235
+ #endif
236
+ #ifndef HAVE_SSL_CTX_SET_DH_AUTO
237
+ DH *dh;
238
+ #endif
239
+ #if OPENSSL_VERSION_NUMBER < 0x10002000L
240
+ EC_KEY *ecdh;
241
+ #endif
242
+ #ifdef HAVE_SSL_CTX_SET_SESSION_CACHE_MODE
243
+ VALUE reuse, reuse_cache_size, reuse_timeout;
244
+
245
+ reuse = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse"), 0);
246
+ reuse_cache_size = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse_cache_size"), 0);
247
+ reuse_timeout = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse_timeout"), 0);
248
+ #endif
249
+
250
+ key = rb_funcall(mini_ssl_ctx, rb_intern_const("key"), 0);
251
+
252
+ key_password_command = rb_funcall(mini_ssl_ctx, rb_intern_const("key_password_command"), 0);
253
+
254
+ cert = rb_funcall(mini_ssl_ctx, rb_intern_const("cert"), 0);
255
+
256
+ ca = rb_funcall(mini_ssl_ctx, rb_intern_const("ca"), 0);
257
+
258
+ cert_pem = rb_funcall(mini_ssl_ctx, rb_intern_const("cert_pem"), 0);
259
+
260
+ key_pem = rb_funcall(mini_ssl_ctx, rb_intern_const("key_pem"), 0);
145
261
 
146
- ms_conn* conn = engine_alloc(self, &obj);
262
+ verify_mode = rb_funcall(mini_ssl_ctx, rb_intern_const("verify_mode"), 0);
147
263
 
148
- ID sym_key = rb_intern("key");
149
- VALUE key = rb_funcall(mini_ssl_ctx, sym_key, 0);
264
+ ssl_cipher_filter = rb_funcall(mini_ssl_ctx, rb_intern_const("ssl_cipher_filter"), 0);
265
+
266
+ no_tlsv1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1"), 0);
267
+
268
+ no_tlsv1_1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1_1"), 0);
269
+
270
+ TypedData_Get_Struct(self, SSL_CTX, &sslctx_type, ctx);
271
+
272
+ if (!NIL_P(cert)) {
273
+ StringValue(cert);
274
+
275
+ if (SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert)) != 1) {
276
+ raise_file_error("SSL_CTX_use_certificate_chain_file", RSTRING_PTR(cert));
277
+ }
278
+ }
279
+
280
+ if (!NIL_P(key_password_command)) {
281
+ key_password = rb_funcall(mini_ssl_ctx, rb_intern_const("key_password"), 0);
282
+
283
+ if (!NIL_P(key_password)) {
284
+ StringValue(key_password);
285
+ password_cb = password_callback;
286
+ password = RSTRING_PTR(key_password);
287
+ SSL_CTX_set_default_passwd_cb(ctx, password_cb);
288
+ SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) password);
289
+ }
290
+ }
150
291
 
151
- StringValue(key);
292
+ if (!NIL_P(key)) {
293
+ StringValue(key);
152
294
 
153
- ID sym_cert = rb_intern("cert");
154
- VALUE cert = rb_funcall(mini_ssl_ctx, sym_cert, 0);
295
+ if (SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM) != 1) {
296
+ raise_file_error("SSL_CTX_use_PrivateKey_file", RSTRING_PTR(key));
297
+ }
298
+ }
155
299
 
156
- StringValue(cert);
300
+ if (!NIL_P(cert_pem)) {
301
+ bio = BIO_new(BIO_s_mem());
302
+ BIO_puts(bio, RSTRING_PTR(cert_pem));
303
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
157
304
 
158
- ID sym_ca = rb_intern("ca");
159
- VALUE ca = rb_funcall(mini_ssl_ctx, sym_ca, 0);
305
+ if (SSL_CTX_use_certificate(ctx, x509) != 1) {
306
+ BIO_free(bio);
307
+ raise_file_error("SSL_CTX_use_certificate", RSTRING_PTR(cert_pem));
308
+ }
309
+ X509_free(x509);
310
+ BIO_free(bio);
311
+ }
160
312
 
161
- ID sym_verify_mode = rb_intern("verify_mode");
162
- VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
313
+ if (!NIL_P(key_pem)) {
314
+ bio = BIO_new(BIO_s_mem());
315
+ BIO_puts(bio, RSTRING_PTR(key_pem));
316
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, password_cb, (void *) password);
163
317
 
164
- ID sym_ssl_cipher_filter = rb_intern("ssl_cipher_filter");
165
- VALUE ssl_cipher_filter = rb_funcall(mini_ssl_ctx, sym_ssl_cipher_filter, 0);
318
+ if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
319
+ BIO_free(bio);
320
+ raise_file_error("SSL_CTX_use_PrivateKey", RSTRING_PTR(key_pem));
321
+ }
322
+ EVP_PKEY_free(pkey);
323
+ BIO_free(bio);
324
+ }
166
325
 
167
- ctx = SSL_CTX_new(SSLv23_server_method());
168
- conn->ctx = ctx;
326
+ verification_flags = rb_funcall(mini_ssl_ctx, rb_intern_const("verification_flags"), 0);
169
327
 
170
- SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
171
- SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM);
328
+ if (!NIL_P(verification_flags)) {
329
+ X509_VERIFY_PARAM *param = SSL_CTX_get0_param(ctx);
330
+ X509_VERIFY_PARAM_set_flags(param, NUM2INT(verification_flags));
331
+ SSL_CTX_set1_param(ctx, param);
332
+ }
172
333
 
173
334
  if (!NIL_P(ca)) {
174
335
  StringValue(ca);
175
- SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
336
+ if (SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL) != 1) {
337
+ raise_file_error("SSL_CTX_load_verify_locations", RSTRING_PTR(ca));
338
+ }
176
339
  }
177
340
 
178
- 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);
179
- SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
341
+ ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
342
+
343
+ #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
344
+ if (RTEST(no_tlsv1_1)) {
345
+ min = TLS1_2_VERSION;
346
+ }
347
+ else if (RTEST(no_tlsv1)) {
348
+ min = TLS1_1_VERSION;
349
+ }
350
+ else {
351
+ min = TLS1_VERSION;
352
+ }
353
+
354
+ SSL_CTX_set_min_proto_version(ctx, min);
355
+
356
+ #else
357
+ /* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */
358
+ ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE;
359
+
360
+ if (RTEST(no_tlsv1)) {
361
+ ssl_options |= SSL_OP_NO_TLSv1;
362
+ }
363
+ if(RTEST(no_tlsv1_1)) {
364
+ ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
365
+ }
366
+ #endif
367
+
368
+ #ifdef HAVE_SSL_CTX_SET_SESSION_CACHE_MODE
369
+ if (!NIL_P(reuse)) {
370
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
371
+ if (!NIL_P(reuse_cache_size)) {
372
+ SSL_CTX_sess_set_cache_size(ctx, NUM2INT(reuse_cache_size));
373
+ }
374
+ if (!NIL_P(reuse_timeout)) {
375
+ SSL_CTX_set_timeout(ctx, NUM2INT(reuse_timeout));
376
+ }
377
+ } else {
378
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
379
+ }
380
+ #endif
381
+
382
+ SSL_CTX_set_options(ctx, ssl_options);
180
383
 
181
384
  if (!NIL_P(ssl_cipher_filter)) {
182
385
  StringValue(ssl_cipher_filter);
@@ -186,29 +389,65 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
186
389
  SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
187
390
  }
188
391
 
189
- DH *dh = get_dh1024();
190
- SSL_CTX_set_tmp_dh(ctx, dh);
191
-
192
- #ifndef OPENSSL_NO_ECDH
193
- EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
392
+ #if OPENSSL_VERSION_NUMBER < 0x10002000L
393
+ // Remove this case if OpenSSL 1.0.1 (now EOL) support is no longer needed.
394
+ ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
194
395
  if (ecdh) {
195
396
  SSL_CTX_set_tmp_ecdh(ctx, ecdh);
196
397
  EC_KEY_free(ecdh);
197
398
  }
399
+ #elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
400
+ SSL_CTX_set_ecdh_auto(ctx, 1);
198
401
  #endif
199
402
 
200
- ssl = SSL_new(ctx);
201
- conn->ssl = ssl;
202
- SSL_set_app_data(ssl, NULL);
203
-
204
403
  if (NIL_P(verify_mode)) {
205
- /* SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); */
404
+ /* SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); */
206
405
  } else {
207
- SSL_set_verify(ssl, NUM2INT(verify_mode), engine_verify_callback);
406
+ SSL_CTX_set_verify(ctx, NUM2INT(verify_mode), engine_verify_callback);
208
407
  }
209
408
 
210
- SSL_set_bio(ssl, conn->read, conn->write);
409
+ // Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
410
+ session_id_bytes = rb_funcall(
411
+ #ifdef HAVE_RANDOM_BYTES
412
+ rb_cRandom,
413
+ #else
414
+ rb_const_get(rb_cRandom, rb_intern_const("DEFAULT")),
415
+ #endif
416
+ rb_intern_const("bytes"),
417
+ 1, ULL2NUM(SSL_MAX_SSL_SESSION_ID_LENGTH));
418
+
419
+ SSL_CTX_set_session_id_context(ctx,
420
+ (unsigned char *) RSTRING_PTR(session_id_bytes),
421
+ SSL_MAX_SSL_SESSION_ID_LENGTH);
422
+
423
+ // printf("\ninitialize end security_level %d\n", SSL_CTX_get_security_level(ctx));
211
424
 
425
+ #ifdef HAVE_SSL_CTX_SET_DH_AUTO
426
+ // https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_dh_auto.html
427
+ SSL_CTX_set_dh_auto(ctx, 1);
428
+ #else
429
+ dh = get_dh2048();
430
+ SSL_CTX_set_tmp_dh(ctx, dh);
431
+ #endif
432
+
433
+ rb_obj_freeze(self);
434
+ return self;
435
+ }
436
+
437
+ VALUE engine_init_server(VALUE self, VALUE sslctx) {
438
+ ms_conn* conn;
439
+ VALUE obj;
440
+ SSL_CTX* ctx;
441
+ SSL* ssl;
442
+
443
+ conn = engine_alloc(self, &obj);
444
+
445
+ TypedData_Get_Struct(sslctx, SSL_CTX, &sslctx_type, ctx);
446
+
447
+ ssl = SSL_new(ctx);
448
+ conn->ssl = ssl;
449
+ SSL_set_app_data(ssl, NULL);
450
+ SSL_set_bio(ssl, conn->read, conn->write);
212
451
  SSL_set_accept_state(ssl);
213
452
  return obj;
214
453
  }
@@ -216,8 +455,11 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
216
455
  VALUE engine_init_client(VALUE klass) {
217
456
  VALUE obj;
218
457
  ms_conn* conn = engine_alloc(klass, &obj);
219
-
458
+ #ifdef HAVE_DTLS_METHOD
459
+ conn->ctx = SSL_CTX_new(DTLS_method());
460
+ #else
220
461
  conn->ctx = SSL_CTX_new(DTLSv1_method());
462
+ #endif
221
463
  conn->ssl = SSL_new(conn->ctx);
222
464
  SSL_set_app_data(conn->ssl, NULL);
223
465
  SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
@@ -232,7 +474,7 @@ VALUE engine_inject(VALUE self, VALUE str) {
232
474
  ms_conn* conn;
233
475
  long used;
234
476
 
235
- Data_Get_Struct(self, ms_conn, conn);
477
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
236
478
 
237
479
  StringValue(str);
238
480
 
@@ -245,13 +487,14 @@ VALUE engine_inject(VALUE self, VALUE str) {
245
487
  return INT2FIX(used);
246
488
  }
247
489
 
248
- static VALUE eError;
490
+ NORETURN(void raise_error(SSL* ssl, int result));
249
491
 
250
492
  void raise_error(SSL* ssl, int result) {
251
493
  char buf[512];
252
494
  char msg[512];
253
495
  const char* err_str;
254
496
  int err = errno;
497
+ int mask = 4095;
255
498
  int ssl_err = SSL_get_error(ssl, result);
256
499
  int verify_err = (int) SSL_get_verify_result(ssl);
257
500
 
@@ -268,8 +511,7 @@ void raise_error(SSL* ssl, int result) {
268
511
  } else {
269
512
  err = (int) ERR_get_error();
270
513
  ERR_error_string_n(err, buf, sizeof(buf));
271
- snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err);
272
-
514
+ snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err & mask);
273
515
  }
274
516
  } else {
275
517
  snprintf(msg, sizeof(msg), "Unknown OpenSSL error: %d", ssl_err);
@@ -284,7 +526,7 @@ VALUE engine_read(VALUE self) {
284
526
  char buf[512];
285
527
  int bytes, error;
286
528
 
287
- Data_Get_Struct(self, ms_conn, conn);
529
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
288
530
 
289
531
  ERR_clear_error();
290
532
 
@@ -311,7 +553,7 @@ VALUE engine_write(VALUE self, VALUE str) {
311
553
  ms_conn* conn;
312
554
  int bytes;
313
555
 
314
- Data_Get_Struct(self, ms_conn, conn);
556
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
315
557
 
316
558
  StringValue(str);
317
559
 
@@ -333,9 +575,11 @@ VALUE engine_extract(VALUE self) {
333
575
  ms_conn* conn;
334
576
  int bytes;
335
577
  size_t pending;
336
- char buf[512];
578
+ // https://www.openssl.org/docs/manmaster/man3/BIO_f_buffer.html
579
+ // crypto/bio/bf_buff.c DEFAULT_BUFFER_SIZE
580
+ char buf[4096];
337
581
 
338
- Data_Get_Struct(self, ms_conn, conn);
582
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
339
583
 
340
584
  pending = BIO_pending(conn->write);
341
585
  if(pending > 0) {
@@ -354,7 +598,7 @@ VALUE engine_shutdown(VALUE self) {
354
598
  ms_conn* conn;
355
599
  int ok;
356
600
 
357
- Data_Get_Struct(self, ms_conn, conn);
601
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
358
602
 
359
603
  ERR_clear_error();
360
604
 
@@ -369,7 +613,7 @@ VALUE engine_shutdown(VALUE self) {
369
613
  VALUE engine_init(VALUE self) {
370
614
  ms_conn* conn;
371
615
 
372
- Data_Get_Struct(self, ms_conn, conn);
616
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
373
617
 
374
618
  return SSL_in_init(conn->ssl) ? Qtrue : Qfalse;
375
619
  }
@@ -382,9 +626,13 @@ VALUE engine_peercert(VALUE self) {
382
626
  ms_cert_buf* cert_buf = NULL;
383
627
  VALUE rb_cert_buf;
384
628
 
385
- Data_Get_Struct(self, ms_conn, conn);
629
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
386
630
 
631
+ #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
632
+ cert = SSL_get1_peer_certificate(conn->ssl);
633
+ #else
387
634
  cert = SSL_get_peer_certificate(conn->ssl);
635
+ #endif
388
636
  if(!cert) {
389
637
  /*
390
638
  * See if there was a failed certificate associated with this client.
@@ -413,12 +661,22 @@ VALUE engine_peercert(VALUE self) {
413
661
  return rb_cert_buf;
414
662
  }
415
663
 
664
+ /* @see Puma::MiniSSL::Socket#ssl_version_state
665
+ * @version 5.0.0
666
+ */
667
+ static VALUE
668
+ engine_ssl_vers_st(VALUE self) {
669
+ ms_conn* conn;
670
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
671
+ return rb_ary_new3(2, rb_str_new2(SSL_get_version(conn->ssl)), rb_str_new2(SSL_state_string(conn->ssl)));
672
+ }
673
+
416
674
  VALUE noop(VALUE self) {
417
675
  return Qnil;
418
676
  }
419
677
 
420
678
  void Init_mini_ssl(VALUE puma) {
421
- VALUE mod, eng;
679
+ VALUE mod, eng, sslctx;
422
680
 
423
681
  /* Fake operation for documentation (RDoc, YARD) */
424
682
  #if 0 == 1
@@ -431,18 +689,47 @@ void Init_mini_ssl(VALUE puma) {
431
689
  ERR_load_crypto_strings();
432
690
 
433
691
  mod = rb_define_module_under(puma, "MiniSSL");
692
+
434
693
  eng = rb_define_class_under(mod, "Engine", rb_cObject);
694
+ rb_undef_alloc_func(eng);
695
+
696
+ sslctx = rb_define_class_under(mod, "SSLContext", rb_cObject);
697
+ rb_define_alloc_func(sslctx, sslctx_alloc);
698
+ rb_define_method(sslctx, "initialize", sslctx_initialize, 1);
699
+ rb_undef_method(sslctx, "initialize_copy");
700
+
435
701
 
436
702
  // OpenSSL Build / Runtime/Load versions
437
703
 
438
704
  /* Version of OpenSSL that Puma was compiled with */
439
- rb_define_const(mod, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
705
+ rb_define_const(mod, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
440
706
 
441
707
  #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
442
- /* Version of OpenSSL that Puma loaded with */
443
- rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
708
+ /* Version of OpenSSL that Puma loaded with */
709
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
710
+ #else
711
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
712
+ #endif
713
+
714
+ #if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
715
+ /* True if SSL3 is not available */
716
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qtrue);
717
+ #else
718
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qfalse);
719
+ #endif
720
+
721
+ #if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
722
+ /* True if TLS1 is not available */
723
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qtrue);
724
+ #else
725
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qfalse);
726
+ #endif
727
+
728
+ #if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
729
+ /* True if TLS1_1 is not available */
730
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qtrue);
444
731
  #else
445
- rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
732
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qfalse);
446
733
  #endif
447
734
 
448
735
  rb_define_singleton_method(mod, "check", noop, 0);
@@ -463,13 +750,16 @@ void Init_mini_ssl(VALUE puma) {
463
750
  rb_define_method(eng, "init?", engine_init, 0);
464
751
 
465
752
  rb_define_method(eng, "peercert", engine_peercert, 0);
753
+
754
+ rb_define_method(eng, "ssl_vers_st", engine_ssl_vers_st, 0);
466
755
  }
467
756
 
468
757
  #else
469
758
 
759
+ NORETURN(VALUE raise_error(VALUE self));
760
+
470
761
  VALUE raise_error(VALUE self) {
471
762
  rb_raise(rb_eStandardError, "SSL not available in this build");
472
- return Qnil;
473
763
  }
474
764
 
475
765
  void Init_mini_ssl(VALUE puma) {