puma 5.2.2 → 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.
- checksums.yaml +4 -4
- data/History.md +483 -4
- data/README.md +101 -20
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +50 -16
- data/docs/compile_options.md +38 -2
- data/docs/deployment.md +53 -67
- data/docs/fork_worker.md +1 -3
- data/docs/jungle/rc.d/README.md +1 -1
- data/docs/kubernetes.md +1 -1
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +15 -15
- data/docs/rails_dev_mode.md +2 -3
- data/docs/restart.md +7 -7
- data/docs/signals.md +11 -10
- data/docs/stats.md +8 -8
- data/docs/systemd.md +65 -69
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/extconf.rb +44 -13
- data/ext/puma_http11/http11_parser.c +24 -11
- data/ext/puma_http11/http11_parser.h +2 -2
- data/ext/puma_http11/http11_parser.java.rl +2 -2
- data/ext/puma_http11/http11_parser.rl +2 -2
- data/ext/puma_http11/http11_parser_common.rl +3 -3
- data/ext/puma_http11/mini_ssl.c +150 -23
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +50 -48
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +188 -102
- data/ext/puma_http11/puma_http11.c +18 -10
- data/lib/puma/app/status.rb +10 -7
- data/lib/puma/binder.rb +112 -62
- data/lib/puma/cli.rb +24 -20
- data/lib/puma/client.rb +162 -36
- data/lib/puma/cluster/worker.rb +31 -27
- data/lib/puma/cluster/worker_handle.rb +12 -1
- data/lib/puma/cluster.rb +102 -61
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +78 -54
- data/lib/puma/const.rb +135 -97
- data/lib/puma/control_cli.rb +25 -20
- data/lib/puma/detect.rb +12 -2
- data/lib/puma/dsl.rb +308 -58
- data/lib/puma/error_logger.rb +20 -11
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +39 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/{json.rb → json_serialization.rb} +1 -1
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +114 -173
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +30 -16
- data/lib/puma/minissl.rb +132 -38
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +2 -2
- data/lib/puma/rack/builder.rb +7 -7
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +373 -153
- data/lib/puma/runner.rb +74 -28
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +127 -136
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +39 -7
- data/lib/puma/thread_pool.rb +33 -26
- data/lib/puma/util.rb +20 -15
- data/lib/puma.rb +28 -11
- data/lib/rack/handler/puma.rb +113 -86
- data/tools/Dockerfile +1 -1
- metadata +15 -10
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
@@ -0,0 +1,36 @@
|
|
1
|
+
# Testing - test/rackup/ci-*.ru files
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
Puma should efficiently handle a variety of response bodies, varying both by size
|
6
|
+
and by the type of object used for the body.
|
7
|
+
|
8
|
+
Five rackup files are located in 'test/rackup' that can be used. All have their
|
9
|
+
request body size (in kB) set via `Body-Conf` header or with `ENV['CI_BODY_CONF']`.
|
10
|
+
Additionally, the ci_select.ru file can have it's body type set via a starting
|
11
|
+
character.
|
12
|
+
|
13
|
+
* **ci_array.ru** - body is an `Array` of 1kB strings. `Content-Length` is not set.
|
14
|
+
* **ci_chunked.ru** - body is an `Enumerator` of 1kB strings. `Content-Length` is not set.
|
15
|
+
* **ci_io.ru** - body is a File/IO object. `Content-Length` is set.
|
16
|
+
* **ci_string.ru** - body is a single string. `Content-Length` is set.
|
17
|
+
* **ci_select.ru** - can be any of the above.
|
18
|
+
|
19
|
+
All responses have 25 headers, total length approx 1kB. ci_array.ru and ci_chunked.ru
|
20
|
+
contain 1kB items.
|
21
|
+
|
22
|
+
All can be delayed by a float value (seconds) specified by the `Dly` header
|
23
|
+
|
24
|
+
Note that rhe `Body-Conf` header takes precedence, and `ENV['CI_BODY_CONF']` is
|
25
|
+
only read on load.
|
26
|
+
|
27
|
+
## ci_select.ru
|
28
|
+
|
29
|
+
The ci_select.ru file allows a starting character to specify the body type in the
|
30
|
+
`Body-Conf` header or with `ENV['CI_BODY_CONF']`.
|
31
|
+
* **a** - array of strings
|
32
|
+
* **c** - chunked (enum)
|
33
|
+
* **s** - single string
|
34
|
+
* **i** - File/IO
|
35
|
+
|
36
|
+
A value of `a100` would return a body as an array of 100 1kB strings.
|
data/ext/puma_http11/extconf.rb
CHANGED
@@ -2,40 +2,71 @@ require 'mkmf'
|
|
2
2
|
|
3
3
|
dir_config("puma_http11")
|
4
4
|
|
5
|
-
if $mingw
|
5
|
+
if $mingw
|
6
6
|
append_cflags '-fstack-protector-strong -D_FORTIFY_SOURCE=2'
|
7
7
|
append_ldflags '-fstack-protector-strong -l:libssp.a'
|
8
8
|
have_library 'ssp'
|
9
9
|
end
|
10
10
|
|
11
|
-
unless ENV["
|
12
|
-
|
11
|
+
unless ENV["PUMA_DISABLE_SSL"]
|
12
|
+
# don't use pkg_config('openssl') if '--with-openssl-dir' is used
|
13
|
+
has_openssl_dir = dir_config('openssl').any?
|
14
|
+
found_pkg_config = !has_openssl_dir && pkg_config('openssl')
|
13
15
|
|
14
|
-
|
16
|
+
found_ssl = if !$mingw && found_pkg_config
|
17
|
+
puts 'using OpenSSL pkgconfig (openssl.pc)'
|
18
|
+
true
|
19
|
+
elsif have_library('libcrypto', 'BIO_read') && have_library('libssl', 'SSL_CTX_new')
|
20
|
+
true
|
21
|
+
elsif %w'crypto libeay32'.find {|crypto| have_library(crypto, 'BIO_read')} &&
|
15
22
|
%w'ssl ssleay32'.find {|ssl| have_library(ssl, 'SSL_CTX_new')}
|
23
|
+
true
|
24
|
+
else
|
25
|
+
puts '** Puma will be compiled without SSL support'
|
26
|
+
false
|
27
|
+
end
|
16
28
|
|
29
|
+
if found_ssl
|
17
30
|
have_header "openssl/bio.h"
|
18
31
|
|
19
32
|
# below is yes for 1.0.2 & later
|
20
|
-
have_func
|
33
|
+
have_func "DTLS_method" , "openssl/ssl.h"
|
34
|
+
have_func "SSL_CTX_set_session_cache_mode(NULL, 0)", "openssl/ssl.h"
|
21
35
|
|
22
36
|
# below are yes for 1.1.0 & later
|
23
|
-
have_func
|
24
|
-
have_func
|
37
|
+
have_func "TLS_server_method" , "openssl/ssl.h"
|
38
|
+
have_func "SSL_CTX_set_min_proto_version(NULL, 0)" , "openssl/ssl.h"
|
39
|
+
|
40
|
+
have_func "X509_STORE_up_ref"
|
41
|
+
have_func "SSL_CTX_set_ecdh_auto(NULL, 0)" , "openssl/ssl.h"
|
42
|
+
|
43
|
+
# below exists in 1.1.0 and later, but isn't documented until 3.0.0
|
44
|
+
have_func "SSL_CTX_set_dh_auto(NULL, 0)" , "openssl/ssl.h"
|
45
|
+
|
46
|
+
# below is yes for 3.0.0 & later
|
47
|
+
have_func "SSL_get1_peer_certificate" , "openssl/ssl.h"
|
25
48
|
|
26
|
-
|
27
|
-
|
49
|
+
# Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
|
50
|
+
if Random.respond_to?(:bytes)
|
51
|
+
$defs.push "-DHAVE_RANDOM_BYTES"
|
52
|
+
puts "checking for Random.bytes... yes"
|
53
|
+
else
|
54
|
+
puts "checking for Random.bytes... no"
|
55
|
+
end
|
28
56
|
end
|
29
57
|
end
|
30
58
|
|
31
|
-
if ENV["
|
59
|
+
if ENV["PUMA_MAKE_WARNINGS_INTO_ERRORS"]
|
32
60
|
# Make all warnings into errors
|
33
61
|
# Except `implicit-fallthrough` since most failures comes from ragel state machine generated code
|
34
|
-
if respond_to?
|
35
|
-
append_cflags
|
62
|
+
if respond_to?(:append_cflags, true) # Ruby 2.5 and later
|
63
|
+
append_cflags(config_string('WERRORFLAG') || '-Werror')
|
36
64
|
append_cflags '-Wno-implicit-fallthrough'
|
37
65
|
else
|
38
|
-
|
66
|
+
# flag may not exist on some platforms, -Werror may not be defined on some platforms, but
|
67
|
+
# works with all in current CI
|
68
|
+
$CFLAGS << " #{config_string('WERRORFLAG') || '-Werror'}"
|
69
|
+
$CFLAGS << ' -Wno-implicit-fallthrough'
|
39
70
|
end
|
40
71
|
end
|
41
72
|
|
@@ -297,7 +297,7 @@ case 13:
|
|
297
297
|
tr18:
|
298
298
|
#line 65 "ext/puma_http11/http11_parser.rl"
|
299
299
|
{
|
300
|
-
parser->
|
300
|
+
parser->server_protocol(parser, PTR_TO(mark), LEN(mark, p));
|
301
301
|
}
|
302
302
|
goto st14;
|
303
303
|
tr26:
|
@@ -428,7 +428,13 @@ case 18:
|
|
428
428
|
switch( (*p) ) {
|
429
429
|
case 13: goto tr26;
|
430
430
|
case 32: goto tr27;
|
431
|
+
case 127: goto st0;
|
431
432
|
}
|
433
|
+
if ( (*p) > 8 ) {
|
434
|
+
if ( 10 <= (*p) && (*p) <= 31 )
|
435
|
+
goto st0;
|
436
|
+
} else if ( (*p) >= 0 )
|
437
|
+
goto st0;
|
432
438
|
goto tr25;
|
433
439
|
tr25:
|
434
440
|
#line 46 "ext/puma_http11/http11_parser.rl"
|
@@ -438,9 +444,16 @@ st19:
|
|
438
444
|
if ( ++p == pe )
|
439
445
|
goto _test_eof19;
|
440
446
|
case 19:
|
441
|
-
#line
|
442
|
-
|
443
|
-
goto tr29;
|
447
|
+
#line 448 "ext/puma_http11/http11_parser.c"
|
448
|
+
switch( (*p) ) {
|
449
|
+
case 13: goto tr29;
|
450
|
+
case 127: goto st0;
|
451
|
+
}
|
452
|
+
if ( (*p) > 8 ) {
|
453
|
+
if ( 10 <= (*p) && (*p) <= 31 )
|
454
|
+
goto st0;
|
455
|
+
} else if ( (*p) >= 0 )
|
456
|
+
goto st0;
|
444
457
|
goto st19;
|
445
458
|
tr9:
|
446
459
|
#line 53 "ext/puma_http11/http11_parser.rl"
|
@@ -484,7 +497,7 @@ st20:
|
|
484
497
|
if ( ++p == pe )
|
485
498
|
goto _test_eof20;
|
486
499
|
case 20:
|
487
|
-
#line
|
500
|
+
#line 501 "ext/puma_http11/http11_parser.c"
|
488
501
|
switch( (*p) ) {
|
489
502
|
case 32: goto tr31;
|
490
503
|
case 60: goto st0;
|
@@ -505,7 +518,7 @@ st21:
|
|
505
518
|
if ( ++p == pe )
|
506
519
|
goto _test_eof21;
|
507
520
|
case 21:
|
508
|
-
#line
|
521
|
+
#line 522 "ext/puma_http11/http11_parser.c"
|
509
522
|
switch( (*p) ) {
|
510
523
|
case 32: goto tr33;
|
511
524
|
case 60: goto st0;
|
@@ -526,7 +539,7 @@ st22:
|
|
526
539
|
if ( ++p == pe )
|
527
540
|
goto _test_eof22;
|
528
541
|
case 22:
|
529
|
-
#line
|
542
|
+
#line 543 "ext/puma_http11/http11_parser.c"
|
530
543
|
switch( (*p) ) {
|
531
544
|
case 43: goto st22;
|
532
545
|
case 58: goto st23;
|
@@ -551,7 +564,7 @@ st23:
|
|
551
564
|
if ( ++p == pe )
|
552
565
|
goto _test_eof23;
|
553
566
|
case 23:
|
554
|
-
#line
|
567
|
+
#line 568 "ext/puma_http11/http11_parser.c"
|
555
568
|
switch( (*p) ) {
|
556
569
|
case 32: goto tr8;
|
557
570
|
case 34: goto st0;
|
@@ -571,7 +584,7 @@ st24:
|
|
571
584
|
if ( ++p == pe )
|
572
585
|
goto _test_eof24;
|
573
586
|
case 24:
|
574
|
-
#line
|
587
|
+
#line 588 "ext/puma_http11/http11_parser.c"
|
575
588
|
switch( (*p) ) {
|
576
589
|
case 32: goto tr37;
|
577
590
|
case 34: goto st0;
|
@@ -594,7 +607,7 @@ st25:
|
|
594
607
|
if ( ++p == pe )
|
595
608
|
goto _test_eof25;
|
596
609
|
case 25:
|
597
|
-
#line
|
610
|
+
#line 611 "ext/puma_http11/http11_parser.c"
|
598
611
|
switch( (*p) ) {
|
599
612
|
case 32: goto tr41;
|
600
613
|
case 34: goto st0;
|
@@ -614,7 +627,7 @@ st26:
|
|
614
627
|
if ( ++p == pe )
|
615
628
|
goto _test_eof26;
|
616
629
|
case 26:
|
617
|
-
#line
|
630
|
+
#line 631 "ext/puma_http11/http11_parser.c"
|
618
631
|
switch( (*p) ) {
|
619
632
|
case 32: goto tr44;
|
620
633
|
case 34: goto st0;
|
@@ -29,8 +29,8 @@ typedef void (*field_cb)(struct puma_parser* hp,
|
|
29
29
|
|
30
30
|
typedef struct puma_parser {
|
31
31
|
int cs;
|
32
|
-
size_t body_start;
|
33
32
|
int content_len;
|
33
|
+
size_t body_start;
|
34
34
|
size_t nread;
|
35
35
|
size_t mark;
|
36
36
|
size_t field_start;
|
@@ -46,7 +46,7 @@ typedef struct puma_parser {
|
|
46
46
|
element_cb fragment;
|
47
47
|
element_cb request_path;
|
48
48
|
element_cb query_string;
|
49
|
-
element_cb
|
49
|
+
element_cb server_protocol;
|
50
50
|
element_cb header_done;
|
51
51
|
|
52
52
|
char buf[BUFFER_LEN];
|
@@ -39,8 +39,8 @@ public class Http11Parser {
|
|
39
39
|
Http11.query_string(runtime, parser.data, parser.buffer, parser.query_start, fpc-parser.query_start);
|
40
40
|
}
|
41
41
|
|
42
|
-
action
|
43
|
-
Http11.
|
42
|
+
action server_protocol {
|
43
|
+
Http11.server_protocol(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
|
44
44
|
}
|
45
45
|
|
46
46
|
action request_path {
|
@@ -62,8 +62,8 @@ static void snake_upcase_char(char *c)
|
|
62
62
|
parser->query_string(parser, PTR_TO(query_start), LEN(query_start, fpc));
|
63
63
|
}
|
64
64
|
|
65
|
-
action
|
66
|
-
parser->
|
65
|
+
action server_protocol {
|
66
|
+
parser->server_protocol(parser, PTR_TO(mark), LEN(mark, fpc));
|
67
67
|
}
|
68
68
|
|
69
69
|
action request_path {
|
@@ -38,12 +38,12 @@
|
|
38
38
|
Method = ( upper | digit | safe ){1,20} >mark %request_method;
|
39
39
|
|
40
40
|
http_number = ( digit+ "." digit+ ) ;
|
41
|
-
|
42
|
-
Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " "
|
41
|
+
Server_Protocol = ( "HTTP/" http_number ) >mark %server_protocol ;
|
42
|
+
Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " Server_Protocol CRLF ) ;
|
43
43
|
|
44
44
|
field_name = ( token -- ":" )+ >start_field $snake_upcase_field %write_field;
|
45
45
|
|
46
|
-
field_value = any* >start_value %write_value;
|
46
|
+
field_value = ( (any -- CTL) | "\t" )* >start_value %write_value;
|
47
47
|
|
48
48
|
message_header = field_name ":" " "* field_value :> CRLF;
|
49
49
|
|
data/ext/puma_http11/mini_ssl.c
CHANGED
@@ -30,6 +30,12 @@ typedef struct {
|
|
30
30
|
|
31
31
|
VALUE eError;
|
32
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
|
+
|
33
39
|
void engine_free(void *ptr) {
|
34
40
|
ms_conn *conn = ptr;
|
35
41
|
ms_cert_buf* cert_buf = (ms_cert_buf*)SSL_get_app_data(conn->ssl);
|
@@ -49,7 +55,8 @@ const rb_data_type_t engine_data_type = {
|
|
49
55
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
|
50
56
|
};
|
51
57
|
|
52
|
-
|
58
|
+
#ifndef HAVE_SSL_CTX_SET_DH_AUTO
|
59
|
+
DH *get_dh2048(void) {
|
53
60
|
/* `openssl dhparam -C 2048`
|
54
61
|
* -----BEGIN DH PARAMETERS-----
|
55
62
|
* MIIBCAKCAQEAjmh1uQHdTfxOyxEbKAV30fUfzqMDF/ChPzjfyzl2jcrqQMhrk76o
|
@@ -91,13 +98,13 @@ DH *get_dh2048() {
|
|
91
98
|
static unsigned char dh2048_g[] = { 0x02 };
|
92
99
|
|
93
100
|
DH *dh;
|
94
|
-
#if !(OPENSSL_VERSION_NUMBER < 0x10100005L
|
101
|
+
#if !(OPENSSL_VERSION_NUMBER < 0x10100005L)
|
95
102
|
BIGNUM *p, *g;
|
96
103
|
#endif
|
97
104
|
|
98
105
|
dh = DH_new();
|
99
106
|
|
100
|
-
#if OPENSSL_VERSION_NUMBER < 0x10100005L
|
107
|
+
#if OPENSSL_VERSION_NUMBER < 0x10100005L
|
101
108
|
dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
|
102
109
|
dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
|
103
110
|
|
@@ -119,6 +126,7 @@ DH *get_dh2048() {
|
|
119
126
|
|
120
127
|
return dh;
|
121
128
|
}
|
129
|
+
#endif
|
122
130
|
|
123
131
|
static void
|
124
132
|
sslctx_free(void *ptr) {
|
@@ -177,6 +185,18 @@ static int engine_verify_callback(int preverify_ok, X509_STORE_CTX* ctx) {
|
|
177
185
|
return preverify_ok;
|
178
186
|
}
|
179
187
|
|
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
|
+
|
180
200
|
static VALUE
|
181
201
|
sslctx_alloc(VALUE klass) {
|
182
202
|
SSL_CTX *ctx;
|
@@ -202,29 +222,43 @@ sslctx_alloc(VALUE klass) {
|
|
202
222
|
VALUE
|
203
223
|
sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
204
224
|
SSL_CTX* ctx;
|
205
|
-
|
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;
|
206
233
|
#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
|
207
234
|
int min;
|
208
235
|
#endif
|
209
|
-
|
210
|
-
VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1,
|
211
|
-
verification_flags;
|
236
|
+
#ifndef HAVE_SSL_CTX_SET_DH_AUTO
|
212
237
|
DH *dh;
|
213
|
-
|
238
|
+
#endif
|
214
239
|
#if OPENSSL_VERSION_NUMBER < 0x10002000L
|
215
240
|
EC_KEY *ecdh;
|
216
241
|
#endif
|
242
|
+
#ifdef HAVE_SSL_CTX_SET_SESSION_CACHE_MODE
|
243
|
+
VALUE reuse, reuse_cache_size, reuse_timeout;
|
217
244
|
|
218
|
-
|
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
|
219
249
|
|
220
250
|
key = rb_funcall(mini_ssl_ctx, rb_intern_const("key"), 0);
|
221
|
-
|
251
|
+
|
252
|
+
key_password_command = rb_funcall(mini_ssl_ctx, rb_intern_const("key_password_command"), 0);
|
222
253
|
|
223
254
|
cert = rb_funcall(mini_ssl_ctx, rb_intern_const("cert"), 0);
|
224
|
-
StringValue(cert);
|
225
255
|
|
226
256
|
ca = rb_funcall(mini_ssl_ctx, rb_intern_const("ca"), 0);
|
227
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);
|
261
|
+
|
228
262
|
verify_mode = rb_funcall(mini_ssl_ctx, rb_intern_const("verify_mode"), 0);
|
229
263
|
|
230
264
|
ssl_cipher_filter = rb_funcall(mini_ssl_ctx, rb_intern_const("ssl_cipher_filter"), 0);
|
@@ -233,8 +267,61 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
233
267
|
|
234
268
|
no_tlsv1_1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1_1"), 0);
|
235
269
|
|
236
|
-
|
237
|
-
|
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
|
+
}
|
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
|
+
}
|
238
325
|
|
239
326
|
verification_flags = rb_funcall(mini_ssl_ctx, rb_intern_const("verification_flags"), 0);
|
240
327
|
|
@@ -246,7 +333,9 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
246
333
|
|
247
334
|
if (!NIL_P(ca)) {
|
248
335
|
StringValue(ca);
|
249
|
-
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
|
+
}
|
250
339
|
}
|
251
340
|
|
252
341
|
ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
|
@@ -264,8 +353,6 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
264
353
|
|
265
354
|
SSL_CTX_set_min_proto_version(ctx, min);
|
266
355
|
|
267
|
-
SSL_CTX_set_options(ctx, ssl_options);
|
268
|
-
|
269
356
|
#else
|
270
357
|
/* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */
|
271
358
|
ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE;
|
@@ -276,10 +363,23 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
276
363
|
if(RTEST(no_tlsv1_1)) {
|
277
364
|
ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
|
278
365
|
}
|
279
|
-
SSL_CTX_set_options(ctx, ssl_options);
|
280
366
|
#endif
|
281
367
|
|
282
|
-
|
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);
|
283
383
|
|
284
384
|
if (!NIL_P(ssl_cipher_filter)) {
|
285
385
|
StringValue(ssl_cipher_filter);
|
@@ -289,12 +389,8 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
289
389
|
SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
|
290
390
|
}
|
291
391
|
|
292
|
-
dh = get_dh2048();
|
293
|
-
SSL_CTX_set_tmp_dh(ctx, dh);
|
294
|
-
|
295
392
|
#if OPENSSL_VERSION_NUMBER < 0x10002000L
|
296
|
-
// Remove this case if OpenSSL 1.0.1 (now EOL) support is no
|
297
|
-
// longer needed.
|
393
|
+
// Remove this case if OpenSSL 1.0.1 (now EOL) support is no longer needed.
|
298
394
|
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
299
395
|
if (ecdh) {
|
300
396
|
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
@@ -309,7 +405,31 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
|
|
309
405
|
} else {
|
310
406
|
SSL_CTX_set_verify(ctx, NUM2INT(verify_mode), engine_verify_callback);
|
311
407
|
}
|
408
|
+
|
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
|
+
|
312
423
|
// printf("\ninitialize end security_level %d\n", SSL_CTX_get_security_level(ctx));
|
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
|
+
|
313
433
|
rb_obj_freeze(self);
|
314
434
|
return self;
|
315
435
|
}
|
@@ -508,7 +628,11 @@ VALUE engine_peercert(VALUE self) {
|
|
508
628
|
|
509
629
|
TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
|
510
630
|
|
631
|
+
#ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
|
632
|
+
cert = SSL_get1_peer_certificate(conn->ssl);
|
633
|
+
#else
|
511
634
|
cert = SSL_get_peer_certificate(conn->ssl);
|
635
|
+
#endif
|
512
636
|
if(!cert) {
|
513
637
|
/*
|
514
638
|
* See if there was a failed certificate associated with this client.
|
@@ -565,7 +689,10 @@ void Init_mini_ssl(VALUE puma) {
|
|
565
689
|
ERR_load_crypto_strings();
|
566
690
|
|
567
691
|
mod = rb_define_module_under(puma, "MiniSSL");
|
692
|
+
|
568
693
|
eng = rb_define_class_under(mod, "Engine", rb_cObject);
|
694
|
+
rb_undef_alloc_func(eng);
|
695
|
+
|
569
696
|
sslctx = rb_define_class_under(mod, "SSLContext", rb_cObject);
|
570
697
|
rb_define_alloc_func(sslctx, sslctx_alloc);
|
571
698
|
rb_define_method(sslctx, "initialize", sslctx_initialize, 1);
|
@@ -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
|
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
|
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,
|
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) {
|