puma 4.3.12 → 6.3.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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1729 -521
  3. data/LICENSE +23 -20
  4. data/README.md +169 -45
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +63 -26
  7. data/docs/compile_options.md +55 -0
  8. data/docs/deployment.md +60 -69
  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 +15 -15
  20. data/docs/rails_dev_mode.md +28 -0
  21. data/docs/restart.md +46 -23
  22. data/docs/signals.md +13 -11
  23. data/docs/stats.md +142 -0
  24. data/docs/systemd.md +84 -128
  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 -4
  28. data/ext/puma_http11/ext_help.h +1 -1
  29. data/ext/puma_http11/extconf.rb +49 -12
  30. data/ext/puma_http11/http11_parser.c +46 -48
  31. data/ext/puma_http11/http11_parser.h +2 -2
  32. data/ext/puma_http11/http11_parser.java.rl +3 -3
  33. data/ext/puma_http11/http11_parser.rl +3 -3
  34. data/ext/puma_http11/http11_parser_common.rl +2 -2
  35. data/ext/puma_http11/mini_ssl.c +278 -93
  36. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  37. data/ext/puma_http11/org/jruby/puma/Http11.java +6 -6
  38. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +4 -6
  39. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +241 -96
  40. data/ext/puma_http11/puma_http11.c +46 -57
  41. data/lib/puma/app/status.rb +53 -39
  42. data/lib/puma/binder.rb +237 -121
  43. data/lib/puma/cli.rb +34 -34
  44. data/lib/puma/client.rb +172 -98
  45. data/lib/puma/cluster/worker.rb +180 -0
  46. data/lib/puma/cluster/worker_handle.rb +97 -0
  47. data/lib/puma/cluster.rb +226 -231
  48. data/lib/puma/commonlogger.rb +21 -14
  49. data/lib/puma/configuration.rb +114 -87
  50. data/lib/puma/const.rb +139 -95
  51. data/lib/puma/control_cli.rb +99 -79
  52. data/lib/puma/detect.rb +33 -2
  53. data/lib/puma/dsl.rb +516 -110
  54. data/lib/puma/error_logger.rb +113 -0
  55. data/lib/puma/events.rb +16 -115
  56. data/lib/puma/io_buffer.rb +44 -2
  57. data/lib/puma/jruby_restart.rb +2 -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 +164 -155
  61. data/lib/puma/log_writer.rb +147 -0
  62. data/lib/puma/minissl/context_builder.rb +36 -19
  63. data/lib/puma/minissl.rb +230 -55
  64. data/lib/puma/null_io.rb +18 -1
  65. data/lib/puma/plugin/systemd.rb +90 -0
  66. data/lib/puma/plugin/tmp_restart.rb +1 -1
  67. data/lib/puma/plugin.rb +3 -12
  68. data/lib/puma/rack/builder.rb +7 -11
  69. data/lib/puma/rack/urlmap.rb +0 -0
  70. data/lib/puma/rack_default.rb +19 -4
  71. data/lib/puma/reactor.rb +93 -368
  72. data/lib/puma/request.rb +671 -0
  73. data/lib/puma/runner.rb +92 -75
  74. data/lib/puma/sd_notify.rb +149 -0
  75. data/lib/puma/server.rb +321 -794
  76. data/lib/puma/single.rb +20 -74
  77. data/lib/puma/state_file.rb +45 -8
  78. data/lib/puma/thread_pool.rb +140 -68
  79. data/lib/puma/util.rb +21 -4
  80. data/lib/puma.rb +54 -7
  81. data/lib/rack/handler/puma.rb +113 -87
  82. data/tools/{docker/Dockerfile → Dockerfile} +1 -1
  83. data/tools/trickletest.rb +0 -0
  84. metadata +33 -24
  85. data/docs/tcp_mode.md +0 -96
  86. data/ext/puma_http11/io_buffer.c +0 -155
  87. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  88. data/lib/puma/accept_nonblock.rb +0 -29
  89. data/lib/puma/tcp_logger.rb +0 -41
  90. data/tools/jungle/README.md +0 -19
  91. data/tools/jungle/init.d/README.md +0 -61
  92. data/tools/jungle/init.d/puma +0 -421
  93. data/tools/jungle/init.d/run-puma +0 -18
  94. data/tools/jungle/upstart/README.md +0 -61
  95. data/tools/jungle/upstart/puma-manager.conf +0 -31
  96. 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,23 +49,13 @@ 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
 
58
+ #ifndef HAVE_SSL_CTX_SET_DH_AUTO
65
59
  DH *get_dh2048(void) {
66
60
  /* `openssl dhparam -C 2048`
67
61
  * -----BEGIN DH PARAMETERS-----
@@ -104,13 +98,13 @@ DH *get_dh2048(void) {
104
98
  static unsigned char dh2048_g[] = { 0x02 };
105
99
 
106
100
  DH *dh;
107
- #if !(OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER))
101
+ #if !(OPENSSL_VERSION_NUMBER < 0x10100005L)
108
102
  BIGNUM *p, *g;
109
103
  #endif
110
104
 
111
105
  dh = DH_new();
112
106
 
113
- #if OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER)
107
+ #if OPENSSL_VERSION_NUMBER < 0x10100005L
114
108
  dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
115
109
  dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
116
110
 
@@ -132,6 +126,38 @@ DH *get_dh2048(void) {
132
126
 
133
127
  return dh;
134
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
+ }
135
161
 
136
162
  static int engine_verify_callback(int preverify_ok, X509_STORE_CTX* ctx) {
137
163
  X509* err_cert;
@@ -159,52 +185,157 @@ static int engine_verify_callback(int preverify_ok, X509_STORE_CTX* ctx) {
159
185
  return preverify_ok;
160
186
  }
161
187
 
162
- VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
163
- VALUE obj, session_id_bytes;
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) {
164
224
  SSL_CTX* ctx;
165
- SSL* ssl;
166
- int min, ssl_options;
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;
167
244
 
168
- ms_conn* conn = engine_alloc(self, &obj);
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
169
249
 
170
- ID sym_key = rb_intern("key");
171
- VALUE key = rb_funcall(mini_ssl_ctx, sym_key, 0);
250
+ key = rb_funcall(mini_ssl_ctx, rb_intern_const("key"), 0);
172
251
 
173
- StringValue(key);
252
+ key_password_command = rb_funcall(mini_ssl_ctx, rb_intern_const("key_password_command"), 0);
174
253
 
175
- ID sym_cert = rb_intern("cert");
176
- VALUE cert = rb_funcall(mini_ssl_ctx, sym_cert, 0);
254
+ cert = rb_funcall(mini_ssl_ctx, rb_intern_const("cert"), 0);
177
255
 
178
- StringValue(cert);
256
+ ca = rb_funcall(mini_ssl_ctx, rb_intern_const("ca"), 0);
179
257
 
180
- ID sym_ca = rb_intern("ca");
181
- VALUE ca = rb_funcall(mini_ssl_ctx, sym_ca, 0);
258
+ cert_pem = rb_funcall(mini_ssl_ctx, rb_intern_const("cert_pem"), 0);
182
259
 
183
- ID sym_verify_mode = rb_intern("verify_mode");
184
- VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
260
+ key_pem = rb_funcall(mini_ssl_ctx, rb_intern_const("key_pem"), 0);
185
261
 
186
- ID sym_ssl_cipher_filter = rb_intern("ssl_cipher_filter");
187
- VALUE ssl_cipher_filter = rb_funcall(mini_ssl_ctx, sym_ssl_cipher_filter, 0);
262
+ verify_mode = rb_funcall(mini_ssl_ctx, rb_intern_const("verify_mode"), 0);
188
263
 
189
- ID sym_no_tlsv1 = rb_intern("no_tlsv1");
190
- VALUE no_tlsv1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1, 0);
264
+ ssl_cipher_filter = rb_funcall(mini_ssl_ctx, rb_intern_const("ssl_cipher_filter"), 0);
191
265
 
192
- ID sym_no_tlsv1_1 = rb_intern("no_tlsv1_1");
193
- VALUE no_tlsv1_1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1_1, 0);
266
+ no_tlsv1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1"), 0);
194
267
 
195
- #ifdef HAVE_TLS_SERVER_METHOD
196
- ctx = SSL_CTX_new(TLS_server_method());
197
- #else
198
- ctx = SSL_CTX_new(SSLv23_server_method());
199
- #endif
200
- conn->ctx = ctx;
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);
201
271
 
202
- SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
203
- SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM);
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
+ }
291
+
292
+ if (!NIL_P(key)) {
293
+ StringValue(key);
294
+
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
+ }
299
+
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);
304
+
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
+ }
312
+
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);
317
+
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
+ }
325
+
326
+ verification_flags = rb_funcall(mini_ssl_ctx, rb_intern_const("verification_flags"), 0);
327
+
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
+ }
204
333
 
205
334
  if (!NIL_P(ca)) {
206
335
  StringValue(ca);
207
- 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
+ }
208
339
  }
209
340
 
210
341
  ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
@@ -222,8 +353,6 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
222
353
 
223
354
  SSL_CTX_set_min_proto_version(ctx, min);
224
355
 
225
- SSL_CTX_set_options(ctx, ssl_options);
226
-
227
356
  #else
228
357
  /* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */
229
358
  ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE;
@@ -234,10 +363,23 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
234
363
  if(RTEST(no_tlsv1_1)) {
235
364
  ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
236
365
  }
237
- SSL_CTX_set_options(ctx, ssl_options);
238
366
  #endif
239
367
 
240
- SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
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);
241
383
 
242
384
  if (!NIL_P(ssl_cipher_filter)) {
243
385
  StringValue(ssl_cipher_filter);
@@ -247,6 +389,23 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
247
389
  SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
248
390
  }
249
391
 
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);
395
+ if (ecdh) {
396
+ SSL_CTX_set_tmp_ecdh(ctx, ecdh);
397
+ EC_KEY_free(ecdh);
398
+ }
399
+ #elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
400
+ SSL_CTX_set_ecdh_auto(ctx, 1);
401
+ #endif
402
+
403
+ if (NIL_P(verify_mode)) {
404
+ /* SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); */
405
+ } else {
406
+ SSL_CTX_set_verify(ctx, NUM2INT(verify_mode), engine_verify_callback);
407
+ }
408
+
250
409
  // Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
251
410
  session_id_bytes = rb_funcall(
252
411
  #ifdef HAVE_RANDOM_BYTES
@@ -261,35 +420,34 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
261
420
  (unsigned char *) RSTRING_PTR(session_id_bytes),
262
421
  SSL_MAX_SSL_SESSION_ID_LENGTH);
263
422
 
264
- DH *dh = get_dh2048();
265
- SSL_CTX_set_tmp_dh(ctx, dh);
423
+ // printf("\ninitialize end security_level %d\n", SSL_CTX_get_security_level(ctx));
266
424
 
267
- #if OPENSSL_VERSION_NUMBER < 0x10002000L
268
- // Remove this case if OpenSSL 1.0.1 (now EOL) support is no
269
- // longer needed.
270
- EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
271
- if (ecdh) {
272
- SSL_CTX_set_tmp_ecdh(ctx, ecdh);
273
- EC_KEY_free(ecdh);
274
- }
275
- #elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
276
- // Prior to OpenSSL 1.1.0, servers must manually enable server-side ECDH
277
- // negotiation.
278
- SSL_CTX_set_ecdh_auto(ctx, 1);
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);
279
431
  #endif
280
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
+
281
447
  ssl = SSL_new(ctx);
282
448
  conn->ssl = ssl;
283
449
  SSL_set_app_data(ssl, NULL);
284
-
285
- if (NIL_P(verify_mode)) {
286
- /* SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); */
287
- } else {
288
- SSL_set_verify(ssl, NUM2INT(verify_mode), engine_verify_callback);
289
- }
290
-
291
450
  SSL_set_bio(ssl, conn->read, conn->write);
292
-
293
451
  SSL_set_accept_state(ssl);
294
452
  return obj;
295
453
  }
@@ -316,7 +474,7 @@ VALUE engine_inject(VALUE self, VALUE str) {
316
474
  ms_conn* conn;
317
475
  long used;
318
476
 
319
- Data_Get_Struct(self, ms_conn, conn);
477
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
320
478
 
321
479
  StringValue(str);
322
480
 
@@ -329,13 +487,14 @@ VALUE engine_inject(VALUE self, VALUE str) {
329
487
  return INT2FIX(used);
330
488
  }
331
489
 
332
- static VALUE eError;
490
+ NORETURN(void raise_error(SSL* ssl, int result));
333
491
 
334
492
  void raise_error(SSL* ssl, int result) {
335
493
  char buf[512];
336
494
  char msg[512];
337
495
  const char* err_str;
338
496
  int err = errno;
497
+ int mask = 4095;
339
498
  int ssl_err = SSL_get_error(ssl, result);
340
499
  int verify_err = (int) SSL_get_verify_result(ssl);
341
500
 
@@ -352,8 +511,7 @@ void raise_error(SSL* ssl, int result) {
352
511
  } else {
353
512
  err = (int) ERR_get_error();
354
513
  ERR_error_string_n(err, buf, sizeof(buf));
355
- snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err);
356
-
514
+ snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err & mask);
357
515
  }
358
516
  } else {
359
517
  snprintf(msg, sizeof(msg), "Unknown OpenSSL error: %d", ssl_err);
@@ -368,7 +526,7 @@ VALUE engine_read(VALUE self) {
368
526
  char buf[512];
369
527
  int bytes, error;
370
528
 
371
- Data_Get_Struct(self, ms_conn, conn);
529
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
372
530
 
373
531
  ERR_clear_error();
374
532
 
@@ -395,7 +553,7 @@ VALUE engine_write(VALUE self, VALUE str) {
395
553
  ms_conn* conn;
396
554
  int bytes;
397
555
 
398
- Data_Get_Struct(self, ms_conn, conn);
556
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
399
557
 
400
558
  StringValue(str);
401
559
 
@@ -417,9 +575,11 @@ VALUE engine_extract(VALUE self) {
417
575
  ms_conn* conn;
418
576
  int bytes;
419
577
  size_t pending;
420
- 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];
421
581
 
422
- Data_Get_Struct(self, ms_conn, conn);
582
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
423
583
 
424
584
  pending = BIO_pending(conn->write);
425
585
  if(pending > 0) {
@@ -438,7 +598,7 @@ VALUE engine_shutdown(VALUE self) {
438
598
  ms_conn* conn;
439
599
  int ok;
440
600
 
441
- Data_Get_Struct(self, ms_conn, conn);
601
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
442
602
 
443
603
  ERR_clear_error();
444
604
 
@@ -453,7 +613,7 @@ VALUE engine_shutdown(VALUE self) {
453
613
  VALUE engine_init(VALUE self) {
454
614
  ms_conn* conn;
455
615
 
456
- Data_Get_Struct(self, ms_conn, conn);
616
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
457
617
 
458
618
  return SSL_in_init(conn->ssl) ? Qtrue : Qfalse;
459
619
  }
@@ -466,9 +626,13 @@ VALUE engine_peercert(VALUE self) {
466
626
  ms_cert_buf* cert_buf = NULL;
467
627
  VALUE rb_cert_buf;
468
628
 
469
- Data_Get_Struct(self, ms_conn, conn);
629
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
470
630
 
631
+ #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
632
+ cert = SSL_get1_peer_certificate(conn->ssl);
633
+ #else
471
634
  cert = SSL_get_peer_certificate(conn->ssl);
635
+ #endif
472
636
  if(!cert) {
473
637
  /*
474
638
  * See if there was a failed certificate associated with this client.
@@ -497,12 +661,22 @@ VALUE engine_peercert(VALUE self) {
497
661
  return rb_cert_buf;
498
662
  }
499
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
+
500
674
  VALUE noop(VALUE self) {
501
675
  return Qnil;
502
676
  }
503
677
 
504
678
  void Init_mini_ssl(VALUE puma) {
505
- VALUE mod, eng;
679
+ VALUE mod, eng, sslctx;
506
680
 
507
681
  /* Fake operation for documentation (RDoc, YARD) */
508
682
  #if 0 == 1
@@ -515,7 +689,15 @@ void Init_mini_ssl(VALUE puma) {
515
689
  ERR_load_crypto_strings();
516
690
 
517
691
  mod = rb_define_module_under(puma, "MiniSSL");
692
+
518
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
+
519
701
 
520
702
  // OpenSSL Build / Runtime/Load versions
521
703
 
@@ -568,13 +750,16 @@ void Init_mini_ssl(VALUE puma) {
568
750
  rb_define_method(eng, "init?", engine_init, 0);
569
751
 
570
752
  rb_define_method(eng, "peercert", engine_peercert, 0);
753
+
754
+ rb_define_method(eng, "ssl_vers_st", engine_ssl_vers_st, 0);
571
755
  }
572
756
 
573
757
  #else
574
758
 
759
+ NORETURN(VALUE raise_error(VALUE self));
760
+
575
761
  VALUE raise_error(VALUE self) {
576
762
  rb_raise(rb_eStandardError, "SSL not available in this build");
577
- return Qnil;
578
763
  }
579
764
 
580
765
  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
+ }
@@ -30,8 +30,8 @@ public class Http11 extends RubyObject {
30
30
  public final static String MAX_REQUEST_URI_LENGTH_ERR = "HTTP element REQUEST_URI is longer than the 12288 allowed length.";
31
31
  public final static int MAX_FRAGMENT_LENGTH = 1024;
32
32
  public final static String MAX_FRAGMENT_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 1024 allowed length.";
33
- public final static int MAX_REQUEST_PATH_LENGTH = 2048;
34
- public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 2048 allowed length.";
33
+ public final static int MAX_REQUEST_PATH_LENGTH = 8192;
34
+ public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 8192 allowed length.";
35
35
  public final static int MAX_QUERY_STRING_LENGTH = 1024 * 10;
36
36
  public final static String MAX_QUERY_STRING_LENGTH_ERR = "HTTP element QUERY_STRING is longer than the 10240 allowed length.";
37
37
  public final static int MAX_HEADER_LENGTH = 1024 * (80 + 32);
@@ -46,7 +46,7 @@ public class Http11 extends RubyObject {
46
46
  public static final ByteList FRAGMENT_BYTELIST = new ByteList(ByteList.plain("FRAGMENT"));
47
47
  public static final ByteList REQUEST_PATH_BYTELIST = new ByteList(ByteList.plain("REQUEST_PATH"));
48
48
  public static final ByteList QUERY_STRING_BYTELIST = new ByteList(ByteList.plain("QUERY_STRING"));
49
- public static final ByteList HTTP_VERSION_BYTELIST = new ByteList(ByteList.plain("HTTP_VERSION"));
49
+ public static final ByteList SERVER_PROTOCOL_BYTELIST = new ByteList(ByteList.plain("SERVER_PROTOCOL"));
50
50
 
51
51
  private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
52
52
  public IRubyObject allocate(Ruby runtime, RubyClass klass) {
@@ -153,9 +153,9 @@ public class Http11 extends RubyObject {
153
153
  req.fastASet(RubyString.newStringShared(runtime, QUERY_STRING_BYTELIST),val);
154
154
  }
155
155
 
156
- public static void http_version(Ruby runtime, RubyHash req, ByteList buffer, int at, int length) {
156
+ public static void server_protocol(Ruby runtime, RubyHash req, ByteList buffer, int at, int length) {
157
157
  RubyString val = RubyString.newString(runtime,new ByteList(buffer,at,length));
158
- req.fastASet(RubyString.newStringShared(runtime, HTTP_VERSION_BYTELIST),val);
158
+ req.fastASet(RubyString.newStringShared(runtime, SERVER_PROTOCOL_BYTELIST),val);
159
159
  }
160
160
 
161
161
  public void header_done(Ruby runtime, RubyHash req, ByteList buffer, int at, int length) {
@@ -197,7 +197,7 @@ public class Http11 extends RubyObject {
197
197
  validateMaxLength(runtime, parser.nread,MAX_HEADER_LENGTH, MAX_HEADER_LENGTH_ERR);
198
198
 
199
199
  if(hp.has_error()) {
200
- throw newHTTPParserError(runtime, "Invalid HTTP format, parsing fails.");
200
+ throw newHTTPParserError(runtime, "Invalid HTTP format, parsing fails. Are you trying to open an SSL connection to a non-SSL Puma?");
201
201
  } else {
202
202
  return runtime.newFixnum(parser.nread);
203
203
  }
@@ -184,8 +184,6 @@ static final int puma_parser_start = 1;
184
184
  static final int puma_parser_first_final = 46;
185
185
  static final int puma_parser_error = 0;
186
186
 
187
- static final int puma_parser_en_main = 1;
188
-
189
187
 
190
188
  // line 62 "ext/puma_http11/http11_parser.java.rl"
191
189
 
@@ -214,7 +212,7 @@ static final int puma_parser_en_main = 1;
214
212
  cs = 0;
215
213
 
216
214
 
217
- // line 218 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
215
+ // line 216 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
218
216
  {
219
217
  cs = puma_parser_start;
220
218
  }
@@ -246,7 +244,7 @@ static final int puma_parser_en_main = 1;
246
244
  parser.buffer = buffer;
247
245
 
248
246
 
249
- // line 250 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
247
+ // line 248 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
250
248
  {
251
249
  int _klen;
252
250
  int _trans = 0;
@@ -385,7 +383,7 @@ case 1:
385
383
  case 11:
386
384
  // line 42 "ext/puma_http11/http11_parser.java.rl"
387
385
  {
388
- Http11.http_version(runtime, parser.data, parser.buffer, parser.mark, p-parser.mark);
386
+ Http11.server_protocol(runtime, parser.data, parser.buffer, parser.mark, p-parser.mark);
389
387
  }
390
388
  break;
391
389
  case 12:
@@ -402,7 +400,7 @@ case 1:
402
400
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
403
401
  }
404
402
  break;
405
- // line 406 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
403
+ // line 404 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
406
404
  }
407
405
  }
408
406
  }