puma 3.11.4 → 6.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puma might be problematic. Click here for more details.

Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1717 -432
  3. data/LICENSE +23 -20
  4. data/README.md +190 -64
  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/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  17. data/docs/kubernetes.md +66 -0
  18. data/docs/nginx.md +2 -2
  19. data/docs/plugins.md +22 -12
  20. data/docs/rails_dev_mode.md +28 -0
  21. data/docs/restart.md +47 -22
  22. data/docs/signals.md +13 -11
  23. data/docs/stats.md +142 -0
  24. data/docs/systemd.md +95 -120
  25. data/docs/testing_benchmarks_local_files.md +150 -0
  26. data/docs/testing_test_rackup_ci_files.md +36 -0
  27. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  28. data/ext/puma_http11/ext_help.h +1 -1
  29. data/ext/puma_http11/extconf.rb +61 -3
  30. data/ext/puma_http11/http11_parser.c +106 -118
  31. data/ext/puma_http11/http11_parser.h +2 -2
  32. data/ext/puma_http11/http11_parser.java.rl +22 -38
  33. data/ext/puma_http11/http11_parser.rl +6 -4
  34. data/ext/puma_http11/http11_parser_common.rl +6 -6
  35. data/ext/puma_http11/mini_ssl.c +376 -93
  36. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  37. data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
  38. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +84 -99
  39. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +250 -88
  40. data/ext/puma_http11/puma_http11.c +49 -57
  41. data/lib/puma/app/status.rb +71 -49
  42. data/lib/puma/binder.rb +243 -148
  43. data/lib/puma/cli.rb +50 -36
  44. data/lib/puma/client.rb +373 -233
  45. data/lib/puma/cluster/worker.rb +175 -0
  46. data/lib/puma/cluster/worker_handle.rb +97 -0
  47. data/lib/puma/cluster.rb +268 -235
  48. data/lib/puma/commonlogger.rb +4 -2
  49. data/lib/puma/configuration.rb +116 -88
  50. data/lib/puma/const.rb +49 -30
  51. data/lib/puma/control_cli.rb +123 -76
  52. data/lib/puma/detect.rb +33 -2
  53. data/lib/puma/dsl.rb +685 -135
  54. data/lib/puma/error_logger.rb +112 -0
  55. data/lib/puma/events.rb +17 -111
  56. data/lib/puma/io_buffer.rb +44 -5
  57. data/lib/puma/jruby_restart.rb +4 -59
  58. data/lib/puma/json_serialization.rb +96 -0
  59. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  60. data/lib/puma/launcher.rb +196 -130
  61. data/lib/puma/log_writer.rb +137 -0
  62. data/lib/puma/minissl/context_builder.rb +92 -0
  63. data/lib/puma/minissl.rb +249 -69
  64. data/lib/puma/null_io.rb +20 -1
  65. data/lib/puma/plugin/tmp_restart.rb +3 -1
  66. data/lib/puma/plugin.rb +9 -13
  67. data/lib/puma/rack/builder.rb +8 -9
  68. data/lib/puma/rack/urlmap.rb +2 -0
  69. data/lib/puma/rack_default.rb +3 -1
  70. data/lib/puma/reactor.rb +90 -187
  71. data/lib/puma/request.rb +644 -0
  72. data/lib/puma/runner.rb +94 -71
  73. data/lib/puma/server.rb +337 -715
  74. data/lib/puma/single.rb +27 -72
  75. data/lib/puma/state_file.rb +46 -7
  76. data/lib/puma/systemd.rb +47 -0
  77. data/lib/puma/thread_pool.rb +184 -93
  78. data/lib/puma/util.rb +23 -10
  79. data/lib/puma.rb +60 -3
  80. data/lib/rack/handler/puma.rb +17 -15
  81. data/tools/Dockerfile +16 -0
  82. data/tools/trickletest.rb +0 -1
  83. metadata +53 -33
  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 -23
  88. data/lib/puma/daemon_ext.rb +0 -31
  89. data/lib/puma/delegation.rb +0 -11
  90. data/lib/puma/java_io_buffer.rb +0 -45
  91. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
  92. data/lib/puma/tcp_logger.rb +0 -39
  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
@@ -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;
50
-
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
- }
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
+ };
64
57
 
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,68 +185,241 @@ 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 VALUE
189
+ sslctx_alloc(VALUE klass) {
190
+ SSL_CTX *ctx;
191
+ long mode = 0 |
192
+ SSL_MODE_ENABLE_PARTIAL_WRITE |
193
+ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
194
+ SSL_MODE_RELEASE_BUFFERS;
195
+
196
+ #ifdef HAVE_TLS_SERVER_METHOD
197
+ ctx = SSL_CTX_new(TLS_method());
198
+ // printf("\nctx using TLS_method security_level %d\n", SSL_CTX_get_security_level(ctx));
199
+ #else
200
+ ctx = SSL_CTX_new(SSLv23_method());
201
+ #endif
202
+ if (!ctx) {
203
+ rb_raise(eError, "SSL_CTX_new");
204
+ }
205
+ SSL_CTX_set_mode(ctx, mode);
206
+
207
+ return TypedData_Wrap_Struct(klass, &sslctx_type, ctx);
208
+ }
209
+
210
+ VALUE
211
+ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
143
212
  SSL_CTX* ctx;
144
- SSL* ssl;
213
+ int ssl_options;
214
+ VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1,
215
+ verification_flags, session_id_bytes, cert_pem, key_pem;
216
+ BIO *bio;
217
+ X509 *x509;
218
+ EVP_PKEY *pkey;
219
+ #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
220
+ int min;
221
+ #endif
222
+ #ifndef HAVE_SSL_CTX_SET_DH_AUTO
223
+ DH *dh;
224
+ #endif
225
+ #if OPENSSL_VERSION_NUMBER < 0x10002000L
226
+ EC_KEY *ecdh;
227
+ #endif
228
+ #ifdef HAVE_SSL_CTX_SET_SESSION_CACHE_MODE
229
+ VALUE reuse, reuse_cache_size, reuse_timeout;
230
+
231
+ reuse = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse"), 0);
232
+ reuse_cache_size = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse_cache_size"), 0);
233
+ reuse_timeout = rb_funcall(mini_ssl_ctx, rb_intern_const("reuse_timeout"), 0);
234
+ #endif
145
235
 
146
- ms_conn* conn = engine_alloc(self, &obj);
236
+ key = rb_funcall(mini_ssl_ctx, rb_intern_const("key"), 0);
147
237
 
148
- ID sym_key = rb_intern("key");
149
- VALUE key = rb_funcall(mini_ssl_ctx, sym_key, 0);
238
+ cert = rb_funcall(mini_ssl_ctx, rb_intern_const("cert"), 0);
150
239
 
151
- StringValue(key);
240
+ ca = rb_funcall(mini_ssl_ctx, rb_intern_const("ca"), 0);
152
241
 
153
- ID sym_cert = rb_intern("cert");
154
- VALUE cert = rb_funcall(mini_ssl_ctx, sym_cert, 0);
242
+ cert_pem = rb_funcall(mini_ssl_ctx, rb_intern_const("cert_pem"), 0);
155
243
 
156
- StringValue(cert);
244
+ key_pem = rb_funcall(mini_ssl_ctx, rb_intern_const("key_pem"), 0);
157
245
 
158
- ID sym_ca = rb_intern("ca");
159
- VALUE ca = rb_funcall(mini_ssl_ctx, sym_ca, 0);
246
+ verify_mode = rb_funcall(mini_ssl_ctx, rb_intern_const("verify_mode"), 0);
160
247
 
161
- ID sym_verify_mode = rb_intern("verify_mode");
162
- VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
248
+ ssl_cipher_filter = rb_funcall(mini_ssl_ctx, rb_intern_const("ssl_cipher_filter"), 0);
163
249
 
164
- ctx = SSL_CTX_new(SSLv23_server_method());
165
- conn->ctx = ctx;
250
+ no_tlsv1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1"), 0);
166
251
 
167
- SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
168
- SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM);
252
+ no_tlsv1_1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1_1"), 0);
253
+
254
+ TypedData_Get_Struct(self, SSL_CTX, &sslctx_type, ctx);
255
+
256
+ if (!NIL_P(cert)) {
257
+ StringValue(cert);
258
+
259
+ if (SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert)) != 1) {
260
+ raise_file_error("SSL_CTX_use_certificate_chain_file", RSTRING_PTR(cert));
261
+ }
262
+ }
263
+
264
+ if (!NIL_P(key)) {
265
+ StringValue(key);
266
+
267
+ if (SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM) != 1) {
268
+ raise_file_error("SSL_CTX_use_PrivateKey_file", RSTRING_PTR(key));
269
+ }
270
+ }
271
+
272
+ if (!NIL_P(cert_pem)) {
273
+ bio = BIO_new(BIO_s_mem());
274
+ BIO_puts(bio, RSTRING_PTR(cert_pem));
275
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
276
+
277
+ if (SSL_CTX_use_certificate(ctx, x509) != 1) {
278
+ BIO_free(bio);
279
+ raise_file_error("SSL_CTX_use_certificate", RSTRING_PTR(cert_pem));
280
+ }
281
+ X509_free(x509);
282
+ BIO_free(bio);
283
+ }
284
+
285
+ if (!NIL_P(key_pem)) {
286
+ bio = BIO_new(BIO_s_mem());
287
+ BIO_puts(bio, RSTRING_PTR(key_pem));
288
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
289
+
290
+ if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
291
+ BIO_free(bio);
292
+ raise_file_error("SSL_CTX_use_PrivateKey", RSTRING_PTR(key_pem));
293
+ }
294
+ EVP_PKEY_free(pkey);
295
+ BIO_free(bio);
296
+ }
297
+
298
+ verification_flags = rb_funcall(mini_ssl_ctx, rb_intern_const("verification_flags"), 0);
299
+
300
+ if (!NIL_P(verification_flags)) {
301
+ X509_VERIFY_PARAM *param = SSL_CTX_get0_param(ctx);
302
+ X509_VERIFY_PARAM_set_flags(param, NUM2INT(verification_flags));
303
+ SSL_CTX_set1_param(ctx, param);
304
+ }
169
305
 
170
306
  if (!NIL_P(ca)) {
171
307
  StringValue(ca);
172
- SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
308
+ if (SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL) != 1) {
309
+ raise_file_error("SSL_CTX_load_verify_locations", RSTRING_PTR(ca));
310
+ }
311
+ }
312
+
313
+ ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
314
+
315
+ #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
316
+ if (RTEST(no_tlsv1_1)) {
317
+ min = TLS1_2_VERSION;
318
+ }
319
+ else if (RTEST(no_tlsv1)) {
320
+ min = TLS1_1_VERSION;
321
+ }
322
+ else {
323
+ min = TLS1_VERSION;
173
324
  }
174
325
 
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);
176
- SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
326
+ SSL_CTX_set_min_proto_version(ctx, min);
177
327
 
178
- SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
328
+ #else
329
+ /* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */
330
+ ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE;
179
331
 
180
- DH *dh = get_dh1024();
181
- SSL_CTX_set_tmp_dh(ctx, dh);
332
+ if (RTEST(no_tlsv1)) {
333
+ ssl_options |= SSL_OP_NO_TLSv1;
334
+ }
335
+ if(RTEST(no_tlsv1_1)) {
336
+ ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
337
+ }
338
+ #endif
339
+
340
+ #ifdef HAVE_SSL_CTX_SET_SESSION_CACHE_MODE
341
+ if (!NIL_P(reuse)) {
342
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
343
+ if (!NIL_P(reuse_cache_size)) {
344
+ SSL_CTX_sess_set_cache_size(ctx, NUM2INT(reuse_cache_size));
345
+ }
346
+ if (!NIL_P(reuse_timeout)) {
347
+ SSL_CTX_set_timeout(ctx, NUM2INT(reuse_timeout));
348
+ }
349
+ } else {
350
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
351
+ }
352
+ #endif
182
353
 
183
- #ifndef OPENSSL_NO_ECDH
184
- EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
354
+ SSL_CTX_set_options(ctx, ssl_options);
355
+
356
+ if (!NIL_P(ssl_cipher_filter)) {
357
+ StringValue(ssl_cipher_filter);
358
+ SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(ssl_cipher_filter));
359
+ }
360
+ else {
361
+ SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
362
+ }
363
+
364
+ #if OPENSSL_VERSION_NUMBER < 0x10002000L
365
+ // Remove this case if OpenSSL 1.0.1 (now EOL) support is no longer needed.
366
+ ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
185
367
  if (ecdh) {
186
368
  SSL_CTX_set_tmp_ecdh(ctx, ecdh);
187
369
  EC_KEY_free(ecdh);
188
370
  }
371
+ #elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
372
+ SSL_CTX_set_ecdh_auto(ctx, 1);
189
373
  #endif
190
374
 
191
- ssl = SSL_new(ctx);
192
- conn->ssl = ssl;
193
- SSL_set_app_data(ssl, NULL);
194
-
195
375
  if (NIL_P(verify_mode)) {
196
- /* SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); */
376
+ /* SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); */
197
377
  } else {
198
- SSL_set_verify(ssl, NUM2INT(verify_mode), engine_verify_callback);
378
+ SSL_CTX_set_verify(ctx, NUM2INT(verify_mode), engine_verify_callback);
199
379
  }
200
380
 
201
- SSL_set_bio(ssl, conn->read, conn->write);
381
+ // Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
382
+ session_id_bytes = rb_funcall(
383
+ #ifdef HAVE_RANDOM_BYTES
384
+ rb_cRandom,
385
+ #else
386
+ rb_const_get(rb_cRandom, rb_intern_const("DEFAULT")),
387
+ #endif
388
+ rb_intern_const("bytes"),
389
+ 1, ULL2NUM(SSL_MAX_SSL_SESSION_ID_LENGTH));
390
+
391
+ SSL_CTX_set_session_id_context(ctx,
392
+ (unsigned char *) RSTRING_PTR(session_id_bytes),
393
+ SSL_MAX_SSL_SESSION_ID_LENGTH);
394
+
395
+ // printf("\ninitialize end security_level %d\n", SSL_CTX_get_security_level(ctx));
396
+
397
+ #ifdef HAVE_SSL_CTX_SET_DH_AUTO
398
+ // https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_dh_auto.html
399
+ SSL_CTX_set_dh_auto(ctx, 1);
400
+ #else
401
+ dh = get_dh2048();
402
+ SSL_CTX_set_tmp_dh(ctx, dh);
403
+ #endif
404
+
405
+ rb_obj_freeze(self);
406
+ return self;
407
+ }
408
+
409
+ VALUE engine_init_server(VALUE self, VALUE sslctx) {
410
+ ms_conn* conn;
411
+ VALUE obj;
412
+ SSL_CTX* ctx;
413
+ SSL* ssl;
414
+
415
+ conn = engine_alloc(self, &obj);
416
+
417
+ TypedData_Get_Struct(sslctx, SSL_CTX, &sslctx_type, ctx);
202
418
 
419
+ ssl = SSL_new(ctx);
420
+ conn->ssl = ssl;
421
+ SSL_set_app_data(ssl, NULL);
422
+ SSL_set_bio(ssl, conn->read, conn->write);
203
423
  SSL_set_accept_state(ssl);
204
424
  return obj;
205
425
  }
@@ -207,8 +427,11 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
207
427
  VALUE engine_init_client(VALUE klass) {
208
428
  VALUE obj;
209
429
  ms_conn* conn = engine_alloc(klass, &obj);
210
-
430
+ #ifdef HAVE_DTLS_METHOD
431
+ conn->ctx = SSL_CTX_new(DTLS_method());
432
+ #else
211
433
  conn->ctx = SSL_CTX_new(DTLSv1_method());
434
+ #endif
212
435
  conn->ssl = SSL_new(conn->ctx);
213
436
  SSL_set_app_data(conn->ssl, NULL);
214
437
  SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
@@ -223,7 +446,7 @@ VALUE engine_inject(VALUE self, VALUE str) {
223
446
  ms_conn* conn;
224
447
  long used;
225
448
 
226
- Data_Get_Struct(self, ms_conn, conn);
449
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
227
450
 
228
451
  StringValue(str);
229
452
 
@@ -236,13 +459,14 @@ VALUE engine_inject(VALUE self, VALUE str) {
236
459
  return INT2FIX(used);
237
460
  }
238
461
 
239
- static VALUE eError;
462
+ NORETURN(void raise_error(SSL* ssl, int result));
240
463
 
241
464
  void raise_error(SSL* ssl, int result) {
242
465
  char buf[512];
243
466
  char msg[512];
244
467
  const char* err_str;
245
468
  int err = errno;
469
+ int mask = 4095;
246
470
  int ssl_err = SSL_get_error(ssl, result);
247
471
  int verify_err = (int) SSL_get_verify_result(ssl);
248
472
 
@@ -259,8 +483,7 @@ void raise_error(SSL* ssl, int result) {
259
483
  } else {
260
484
  err = (int) ERR_get_error();
261
485
  ERR_error_string_n(err, buf, sizeof(buf));
262
- snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err);
263
-
486
+ snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err & mask);
264
487
  }
265
488
  } else {
266
489
  snprintf(msg, sizeof(msg), "Unknown OpenSSL error: %d", ssl_err);
@@ -275,7 +498,7 @@ VALUE engine_read(VALUE self) {
275
498
  char buf[512];
276
499
  int bytes, error;
277
500
 
278
- Data_Get_Struct(self, ms_conn, conn);
501
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
279
502
 
280
503
  ERR_clear_error();
281
504
 
@@ -302,7 +525,7 @@ VALUE engine_write(VALUE self, VALUE str) {
302
525
  ms_conn* conn;
303
526
  int bytes;
304
527
 
305
- Data_Get_Struct(self, ms_conn, conn);
528
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
306
529
 
307
530
  StringValue(str);
308
531
 
@@ -324,9 +547,11 @@ VALUE engine_extract(VALUE self) {
324
547
  ms_conn* conn;
325
548
  int bytes;
326
549
  size_t pending;
327
- char buf[512];
550
+ // https://www.openssl.org/docs/manmaster/man3/BIO_f_buffer.html
551
+ // crypto/bio/bf_buff.c DEFAULT_BUFFER_SIZE
552
+ char buf[4096];
328
553
 
329
- Data_Get_Struct(self, ms_conn, conn);
554
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
330
555
 
331
556
  pending = BIO_pending(conn->write);
332
557
  if(pending > 0) {
@@ -345,7 +570,7 @@ VALUE engine_shutdown(VALUE self) {
345
570
  ms_conn* conn;
346
571
  int ok;
347
572
 
348
- Data_Get_Struct(self, ms_conn, conn);
573
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
349
574
 
350
575
  ERR_clear_error();
351
576
 
@@ -360,7 +585,7 @@ VALUE engine_shutdown(VALUE self) {
360
585
  VALUE engine_init(VALUE self) {
361
586
  ms_conn* conn;
362
587
 
363
- Data_Get_Struct(self, ms_conn, conn);
588
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
364
589
 
365
590
  return SSL_in_init(conn->ssl) ? Qtrue : Qfalse;
366
591
  }
@@ -373,9 +598,13 @@ VALUE engine_peercert(VALUE self) {
373
598
  ms_cert_buf* cert_buf = NULL;
374
599
  VALUE rb_cert_buf;
375
600
 
376
- Data_Get_Struct(self, ms_conn, conn);
601
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
377
602
 
603
+ #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
604
+ cert = SSL_get1_peer_certificate(conn->ssl);
605
+ #else
378
606
  cert = SSL_get_peer_certificate(conn->ssl);
607
+ #endif
379
608
  if(!cert) {
380
609
  /*
381
610
  * See if there was a failed certificate associated with this client.
@@ -404,12 +633,22 @@ VALUE engine_peercert(VALUE self) {
404
633
  return rb_cert_buf;
405
634
  }
406
635
 
636
+ /* @see Puma::MiniSSL::Socket#ssl_version_state
637
+ * @version 5.0.0
638
+ */
639
+ static VALUE
640
+ engine_ssl_vers_st(VALUE self) {
641
+ ms_conn* conn;
642
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
643
+ return rb_ary_new3(2, rb_str_new2(SSL_get_version(conn->ssl)), rb_str_new2(SSL_state_string(conn->ssl)));
644
+ }
645
+
407
646
  VALUE noop(VALUE self) {
408
647
  return Qnil;
409
648
  }
410
649
 
411
650
  void Init_mini_ssl(VALUE puma) {
412
- VALUE mod, eng;
651
+ VALUE mod, eng, sslctx;
413
652
 
414
653
  /* Fake operation for documentation (RDoc, YARD) */
415
654
  #if 0 == 1
@@ -422,7 +661,48 @@ void Init_mini_ssl(VALUE puma) {
422
661
  ERR_load_crypto_strings();
423
662
 
424
663
  mod = rb_define_module_under(puma, "MiniSSL");
664
+
425
665
  eng = rb_define_class_under(mod, "Engine", rb_cObject);
666
+ rb_undef_alloc_func(eng);
667
+
668
+ sslctx = rb_define_class_under(mod, "SSLContext", rb_cObject);
669
+ rb_define_alloc_func(sslctx, sslctx_alloc);
670
+ rb_define_method(sslctx, "initialize", sslctx_initialize, 1);
671
+ rb_undef_method(sslctx, "initialize_copy");
672
+
673
+
674
+ // OpenSSL Build / Runtime/Load versions
675
+
676
+ /* Version of OpenSSL that Puma was compiled with */
677
+ rb_define_const(mod, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
678
+
679
+ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
680
+ /* Version of OpenSSL that Puma loaded with */
681
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
682
+ #else
683
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
684
+ #endif
685
+
686
+ #if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
687
+ /* True if SSL3 is not available */
688
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qtrue);
689
+ #else
690
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qfalse);
691
+ #endif
692
+
693
+ #if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
694
+ /* True if TLS1 is not available */
695
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qtrue);
696
+ #else
697
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qfalse);
698
+ #endif
699
+
700
+ #if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
701
+ /* True if TLS1_1 is not available */
702
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qtrue);
703
+ #else
704
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qfalse);
705
+ #endif
426
706
 
427
707
  rb_define_singleton_method(mod, "check", noop, 0);
428
708
 
@@ -442,13 +722,16 @@ void Init_mini_ssl(VALUE puma) {
442
722
  rb_define_method(eng, "init?", engine_init, 0);
443
723
 
444
724
  rb_define_method(eng, "peercert", engine_peercert, 0);
725
+
726
+ rb_define_method(eng, "ssl_vers_st", engine_ssl_vers_st, 0);
445
727
  }
446
728
 
447
729
  #else
448
730
 
731
+ NORETURN(VALUE raise_error(VALUE self));
732
+
449
733
  VALUE raise_error(VALUE self) {
450
734
  rb_raise(rb_eStandardError, "SSL not available in this build");
451
- return Qnil;
452
735
  }
453
736
 
454
737
  void Init_mini_ssl(VALUE puma) {
@@ -0,0 +1,15 @@
1
+ package puma;
2
+
3
+ import java.io.IOException;
4
+
5
+ import org.jruby.Ruby;
6
+ import org.jruby.runtime.load.BasicLibraryService;
7
+
8
+ import org.jruby.puma.Http11;
9
+
10
+ public class PumaHttp11Service implements BasicLibraryService {
11
+ public boolean basicLoad(final Ruby runtime) throws IOException {
12
+ Http11.createHttp11(runtime);
13
+ return true;
14
+ }
15
+ }