puma 3.8.2 → 4.3.12

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

Potentially problematic release.


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

Files changed (91) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +305 -0
  3. data/LICENSE +0 -0
  4. data/README.md +162 -224
  5. data/bin/puma-wild +0 -0
  6. data/docs/architecture.md +37 -0
  7. data/{DEPLOYMENT.md → docs/deployment.md} +24 -4
  8. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  9. data/docs/images/puma-connection-flow.png +0 -0
  10. data/docs/images/puma-general-arch.png +0 -0
  11. data/docs/nginx.md +0 -0
  12. data/docs/plugins.md +38 -0
  13. data/docs/restart.md +41 -0
  14. data/docs/signals.md +56 -3
  15. data/docs/systemd.md +130 -37
  16. data/docs/tcp_mode.md +96 -0
  17. data/ext/puma_http11/PumaHttp11Service.java +2 -0
  18. data/ext/puma_http11/ext_help.h +0 -0
  19. data/ext/puma_http11/extconf.rb +21 -0
  20. data/ext/puma_http11/http11_parser.c +134 -144
  21. data/ext/puma_http11/http11_parser.h +0 -0
  22. data/ext/puma_http11/http11_parser.java.rl +21 -37
  23. data/ext/puma_http11/http11_parser.rl +12 -10
  24. data/ext/puma_http11/http11_parser_common.rl +4 -4
  25. data/ext/puma_http11/io_buffer.c +0 -0
  26. data/ext/puma_http11/mini_ssl.c +165 -34
  27. data/ext/puma_http11/org/jruby/puma/Http11.java +106 -114
  28. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +85 -101
  29. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +72 -0
  30. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +30 -6
  31. data/ext/puma_http11/puma_http11.c +3 -0
  32. data/lib/puma/accept_nonblock.rb +7 -1
  33. data/lib/puma/app/status.rb +42 -26
  34. data/lib/puma/binder.rb +57 -74
  35. data/lib/puma/cli.rb +26 -7
  36. data/lib/puma/client.rb +307 -191
  37. data/lib/puma/cluster.rb +78 -34
  38. data/lib/puma/commonlogger.rb +2 -0
  39. data/lib/puma/configuration.rb +24 -16
  40. data/lib/puma/const.rb +41 -20
  41. data/lib/puma/control_cli.rb +46 -19
  42. data/lib/puma/detect.rb +2 -0
  43. data/lib/puma/dsl.rb +329 -68
  44. data/lib/puma/events.rb +6 -2
  45. data/lib/puma/io_buffer.rb +3 -6
  46. data/lib/puma/jruby_restart.rb +2 -1
  47. data/lib/puma/launcher.rb +125 -61
  48. data/lib/puma/minissl/context_builder.rb +76 -0
  49. data/lib/puma/minissl.rb +85 -28
  50. data/lib/puma/null_io.rb +2 -0
  51. data/lib/puma/plugin/tmp_restart.rb +2 -1
  52. data/lib/puma/plugin.rb +7 -2
  53. data/lib/puma/rack/builder.rb +4 -1
  54. data/lib/puma/rack/urlmap.rb +2 -0
  55. data/lib/puma/rack_default.rb +2 -0
  56. data/lib/puma/reactor.rb +224 -34
  57. data/lib/puma/runner.rb +27 -6
  58. data/lib/puma/server.rb +212 -68
  59. data/lib/puma/single.rb +16 -5
  60. data/lib/puma/state_file.rb +2 -0
  61. data/lib/puma/tcp_logger.rb +2 -0
  62. data/lib/puma/thread_pool.rb +67 -36
  63. data/lib/puma/util.rb +2 -6
  64. data/lib/puma.rb +16 -0
  65. data/lib/rack/handler/puma.rb +16 -5
  66. data/tools/docker/Dockerfile +16 -0
  67. data/tools/jungle/README.md +12 -2
  68. data/tools/jungle/init.d/README.md +2 -0
  69. data/tools/jungle/init.d/puma +8 -8
  70. data/tools/jungle/init.d/run-puma +1 -1
  71. data/tools/jungle/rc.d/README.md +74 -0
  72. data/tools/jungle/rc.d/puma +61 -0
  73. data/tools/jungle/rc.d/puma.conf +10 -0
  74. data/tools/jungle/upstart/README.md +0 -0
  75. data/tools/jungle/upstart/puma-manager.conf +0 -0
  76. data/tools/jungle/upstart/puma.conf +0 -0
  77. data/tools/trickletest.rb +1 -2
  78. metadata +32 -93
  79. data/.github/issue_template.md +0 -20
  80. data/Gemfile +0 -12
  81. data/Manifest.txt +0 -78
  82. data/Rakefile +0 -158
  83. data/Release.md +0 -9
  84. data/gemfiles/2.1-Gemfile +0 -12
  85. data/lib/puma/compat.rb +0 -14
  86. data/lib/puma/convenient.rb +0 -23
  87. data/lib/puma/daemon_ext.rb +0 -31
  88. data/lib/puma/delegation.rb +0 -11
  89. data/lib/puma/java_io_buffer.rb +0 -45
  90. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
  91. data/puma.gemspec +0 -52
@@ -1,5 +1,7 @@
1
1
  package org.jruby.puma;
2
2
 
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyHash;
3
5
  import org.jruby.util.ByteList;
4
6
 
5
7
  public class Http11Parser {
@@ -19,44 +21,35 @@ public class Http11Parser {
19
21
  }
20
22
 
21
23
  action start_value { parser.mark = fpc; }
22
- action write_value {
23
- if(parser.http_field != null) {
24
- parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, fpc-parser.mark);
25
- }
24
+ action write_value {
25
+ Http11.http_field(runtime, parser.data, parser.buffer, parser.field_start, parser.field_len, parser.mark, fpc-parser.mark);
26
26
  }
27
- action request_method {
28
- if(parser.request_method != null)
29
- parser.request_method.call(parser.data, parser.mark, fpc-parser.mark);
27
+ action request_method {
28
+ Http11.request_method(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
30
29
  }
31
- action request_uri {
32
- if(parser.request_uri != null)
33
- parser.request_uri.call(parser.data, parser.mark, fpc-parser.mark);
30
+ action request_uri {
31
+ Http11.request_uri(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
34
32
  }
35
- action fragment {
36
- if(parser.fragment != null)
37
- parser.fragment.call(parser.data, parser.mark, fpc-parser.mark);
33
+ action fragment {
34
+ Http11.fragment(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
38
35
  }
39
36
 
40
37
  action start_query {parser.query_start = fpc; }
41
- action query_string {
42
- if(parser.query_string != null)
43
- parser.query_string.call(parser.data, parser.query_start, fpc-parser.query_start);
38
+ action query_string {
39
+ Http11.query_string(runtime, parser.data, parser.buffer, parser.query_start, fpc-parser.query_start);
44
40
  }
45
41
 
46
- action http_version {
47
- if(parser.http_version != null)
48
- parser.http_version.call(parser.data, parser.mark, fpc-parser.mark);
42
+ action http_version {
43
+ Http11.http_version(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
49
44
  }
50
45
 
51
46
  action request_path {
52
- if(parser.request_path != null)
53
- parser.request_path.call(parser.data, parser.mark, fpc-parser.mark);
47
+ Http11.request_path(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark);
54
48
  }
55
49
 
56
50
  action done {
57
- parser.body_start = fpc + 1;
58
- if(parser.header_done != null)
59
- parser.header_done.call(parser.data, fpc + 1, pe - fpc - 1);
51
+ parser.body_start = fpc + 1;
52
+ http.header_done(runtime, parser.data, parser.buffer, fpc + 1, pe - fpc - 1);
60
53
  fbreak;
61
54
  }
62
55
 
@@ -68,11 +61,11 @@ public class Http11Parser {
68
61
  %% write data;
69
62
 
70
63
  public static interface ElementCB {
71
- public void call(Object data, int at, int length);
64
+ public void call(Ruby runtime, RubyHash data, ByteList buffer, int at, int length);
72
65
  }
73
66
 
74
67
  public static interface FieldCB {
75
- public void call(Object data, int field, int flen, int value, int vlen);
68
+ public void call(Ruby runtime, RubyHash data, ByteList buffer, int field, int flen, int value, int vlen);
76
69
  }
77
70
 
78
71
  public static class HttpParser {
@@ -85,18 +78,9 @@ public class Http11Parser {
85
78
  int field_len;
86
79
  int query_start;
87
80
 
88
- Object data;
81
+ RubyHash data;
89
82
  ByteList buffer;
90
83
 
91
- public FieldCB http_field;
92
- public ElementCB request_method;
93
- public ElementCB request_uri;
94
- public ElementCB fragment;
95
- public ElementCB request_path;
96
- public ElementCB query_string;
97
- public ElementCB http_version;
98
- public ElementCB header_done;
99
-
100
84
  public void init() {
101
85
  cs = 0;
102
86
 
@@ -113,7 +97,7 @@ public class Http11Parser {
113
97
 
114
98
  public final HttpParser parser = new HttpParser();
115
99
 
116
- public int execute(ByteList buffer, int off) {
100
+ public int execute(Ruby runtime, Http11 http, ByteList buffer, int off) {
117
101
  int p, pe;
118
102
  int cs = parser.cs;
119
103
  int len = buffer.length();
@@ -12,12 +12,14 @@
12
12
 
13
13
  /*
14
14
  * capitalizes all lower-case ASCII characters,
15
- * converts dashes to underscores.
15
+ * converts dashes to underscores, and underscores to commas.
16
16
  */
17
17
  static void snake_upcase_char(char *c)
18
18
  {
19
19
  if (*c >= 'a' && *c <= 'z')
20
20
  *c &= ~0x20;
21
+ else if (*c == '_')
22
+ *c = ',';
21
23
  else if (*c == '-')
22
24
  *c = '_';
23
25
  }
@@ -29,7 +31,7 @@ static void snake_upcase_char(char *c)
29
31
  /** Machine **/
30
32
 
31
33
  %%{
32
-
34
+
33
35
  machine puma_parser;
34
36
 
35
37
  action mark { MARK(mark, fpc); }
@@ -37,7 +39,7 @@ static void snake_upcase_char(char *c)
37
39
 
38
40
  action start_field { MARK(field_start, fpc); }
39
41
  action snake_upcase_field { snake_upcase_char((char *)fpc); }
40
- action write_field {
42
+ action write_field {
41
43
  parser->field_len = LEN(field_start, fpc);
42
44
  }
43
45
 
@@ -45,10 +47,10 @@ static void snake_upcase_char(char *c)
45
47
  action write_value {
46
48
  parser->http_field(parser, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
47
49
  }
48
- action request_method {
50
+ action request_method {
49
51
  parser->request_method(parser, PTR_TO(mark), LEN(mark, fpc));
50
52
  }
51
- action request_uri {
53
+ action request_uri {
52
54
  parser->request_uri(parser, PTR_TO(mark), LEN(mark, fpc));
53
55
  }
54
56
  action fragment {
@@ -56,11 +58,11 @@ static void snake_upcase_char(char *c)
56
58
  }
57
59
 
58
60
  action start_query { MARK(query_start, fpc); }
59
- action query_string {
61
+ action query_string {
60
62
  parser->query_string(parser, PTR_TO(query_start), LEN(query_start, fpc));
61
63
  }
62
64
 
63
- action http_version {
65
+ action http_version {
64
66
  parser->http_version(parser, PTR_TO(mark), LEN(mark, fpc));
65
67
  }
66
68
 
@@ -68,8 +70,8 @@ static void snake_upcase_char(char *c)
68
70
  parser->request_path(parser, PTR_TO(mark), LEN(mark,fpc));
69
71
  }
70
72
 
71
- action done {
72
- parser->body_start = fpc - buffer + 1;
73
+ action done {
74
+ parser->body_start = fpc - buffer + 1;
73
75
  parser->header_done(parser, fpc + 1, pe - fpc - 1);
74
76
  fbreak;
75
77
  }
@@ -109,7 +111,7 @@ size_t puma_parser_execute(puma_parser *parser, const char *buffer, size_t len,
109
111
  pe = buffer+len;
110
112
 
111
113
  /* assert(*pe == '\0' && "pointer does not end on NUL"); */
112
- assert(pe - p == len - off && "pointers aren't same distance");
114
+ assert((size_t) (pe - p) == len - off && "pointers aren't same distance");
113
115
 
114
116
  %% write exec;
115
117
 
@@ -1,5 +1,5 @@
1
1
  %%{
2
-
2
+
3
3
  machine puma_parser_common;
4
4
 
5
5
  #### HTTP PROTOCOL GRAMMAR
@@ -16,7 +16,7 @@
16
16
  unreserved = (alpha | digit | safe | extra | national);
17
17
  escape = ("%" xdigit xdigit);
18
18
  uchar = (unreserved | escape | "%");
19
- pchar = (uchar | ":" | "@" | "&" | "=" | "+");
19
+ pchar = (uchar | ":" | "@" | "&" | "=" | "+" | ";");
20
20
  tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
21
21
 
22
22
  # elements
@@ -30,7 +30,7 @@
30
30
  query = ( uchar | reserved )* %query_string ;
31
31
  param = ( pchar | "/" )* ;
32
32
  params = ( param ( ";" param )* ) ;
33
- rel_path = ( path? %request_path (";" params)? ) ("?" %start_query query)?;
33
+ rel_path = ( path? %request_path ) ("?" %start_query query)?;
34
34
  absolute_path = ( "/"+ rel_path );
35
35
 
36
36
  Request_URI = ( "*" | absolute_uri | absolute_path ) >mark %request_uri;
@@ -43,7 +43,7 @@
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
 
File without changes
@@ -62,44 +62,65 @@ ms_conn* engine_alloc(VALUE klass, VALUE* obj) {
62
62
  return conn;
63
63
  }
64
64
 
65
- DH *get_dh1024() {
66
- /* `openssl dhparam 1024 -C`
65
+ DH *get_dh2048(void) {
66
+ /* `openssl dhparam -C 2048`
67
67
  * -----BEGIN DH PARAMETERS-----
68
- * MIGHAoGBALPwcEv0OstmQCZdfHw0N5r+07lmXMxkpQacy1blwj0LUqC+Divp6pBk
69
- * usTJ9W2/dOYr1X7zi6yXNLp4oLzc/31PUL3D9q8CpGS7vPz5gijKSw9BwCTT5z9+
70
- * KF9v46qw8XqT5HHV87sWFlGQcVFq+pEkA2kPikkKZ/X/CCcpCAV7AgEC
68
+ * MIIBCAKCAQEAjmh1uQHdTfxOyxEbKAV30fUfzqMDF/ChPzjfyzl2jcrqQMhrk76o
69
+ * 2NPNXqxHwsddMZ1RzvU8/jl+uhRuPWjXCFZbhET4N1vrviZM3VJhV8PPHuiVOACO
70
+ * y32jFd+Szx4bo2cXSK83hJ6jRd+0asP1awWjz9/06dFkrILCXMIfQLo0D8rqmppn
71
+ * EfDDAwuudCpM9kcDmBRAm9JsKbQ6gzZWjkc5+QWSaQofojIHbjvj3xzguaCJn+oQ
72
+ * vHWM+hsAnaOgEwCyeZ3xqs+/5lwSbkE/tqJW98cEZGygBUVo9jxZRZx6KOfjpdrb
73
+ * yenO9LJr/qtyrZB31WJbqxI0m0AKTAO8UwIBAg==
71
74
  * -----END DH PARAMETERS-----
72
75
  */
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
76
+ static unsigned char dh2048_p[] = {
77
+ 0x8E, 0x68, 0x75, 0xB9, 0x01, 0xDD, 0x4D, 0xFC, 0x4E, 0xCB,
78
+ 0x11, 0x1B, 0x28, 0x05, 0x77, 0xD1, 0xF5, 0x1F, 0xCE, 0xA3,
79
+ 0x03, 0x17, 0xF0, 0xA1, 0x3F, 0x38, 0xDF, 0xCB, 0x39, 0x76,
80
+ 0x8D, 0xCA, 0xEA, 0x40, 0xC8, 0x6B, 0x93, 0xBE, 0xA8, 0xD8,
81
+ 0xD3, 0xCD, 0x5E, 0xAC, 0x47, 0xC2, 0xC7, 0x5D, 0x31, 0x9D,
82
+ 0x51, 0xCE, 0xF5, 0x3C, 0xFE, 0x39, 0x7E, 0xBA, 0x14, 0x6E,
83
+ 0x3D, 0x68, 0xD7, 0x08, 0x56, 0x5B, 0x84, 0x44, 0xF8, 0x37,
84
+ 0x5B, 0xEB, 0xBE, 0x26, 0x4C, 0xDD, 0x52, 0x61, 0x57, 0xC3,
85
+ 0xCF, 0x1E, 0xE8, 0x95, 0x38, 0x00, 0x8E, 0xCB, 0x7D, 0xA3,
86
+ 0x15, 0xDF, 0x92, 0xCF, 0x1E, 0x1B, 0xA3, 0x67, 0x17, 0x48,
87
+ 0xAF, 0x37, 0x84, 0x9E, 0xA3, 0x45, 0xDF, 0xB4, 0x6A, 0xC3,
88
+ 0xF5, 0x6B, 0x05, 0xA3, 0xCF, 0xDF, 0xF4, 0xE9, 0xD1, 0x64,
89
+ 0xAC, 0x82, 0xC2, 0x5C, 0xC2, 0x1F, 0x40, 0xBA, 0x34, 0x0F,
90
+ 0xCA, 0xEA, 0x9A, 0x9A, 0x67, 0x11, 0xF0, 0xC3, 0x03, 0x0B,
91
+ 0xAE, 0x74, 0x2A, 0x4C, 0xF6, 0x47, 0x03, 0x98, 0x14, 0x40,
92
+ 0x9B, 0xD2, 0x6C, 0x29, 0xB4, 0x3A, 0x83, 0x36, 0x56, 0x8E,
93
+ 0x47, 0x39, 0xF9, 0x05, 0x92, 0x69, 0x0A, 0x1F, 0xA2, 0x32,
94
+ 0x07, 0x6E, 0x3B, 0xE3, 0xDF, 0x1C, 0xE0, 0xB9, 0xA0, 0x89,
95
+ 0x9F, 0xEA, 0x10, 0xBC, 0x75, 0x8C, 0xFA, 0x1B, 0x00, 0x9D,
96
+ 0xA3, 0xA0, 0x13, 0x00, 0xB2, 0x79, 0x9D, 0xF1, 0xAA, 0xCF,
97
+ 0xBF, 0xE6, 0x5C, 0x12, 0x6E, 0x41, 0x3F, 0xB6, 0xA2, 0x56,
98
+ 0xF7, 0xC7, 0x04, 0x64, 0x6C, 0xA0, 0x05, 0x45, 0x68, 0xF6,
99
+ 0x3C, 0x59, 0x45, 0x9C, 0x7A, 0x28, 0xE7, 0xE3, 0xA5, 0xDA,
100
+ 0xDB, 0xC9, 0xE9, 0xCE, 0xF4, 0xB2, 0x6B, 0xFE, 0xAB, 0x72,
101
+ 0xAD, 0x90, 0x77, 0xD5, 0x62, 0x5B, 0xAB, 0x12, 0x34, 0x9B,
102
+ 0x40, 0x0A, 0x4C, 0x03, 0xBC, 0x53
85
103
  };
86
- static unsigned char dh1024_g[] = { 0x02 };
104
+ static unsigned char dh2048_g[] = { 0x02 };
87
105
 
88
106
  DH *dh;
107
+ #if !(OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER))
108
+ BIGNUM *p, *g;
109
+ #endif
110
+
89
111
  dh = DH_new();
90
112
 
91
- #if OPENSSL_VERSION_NUMBER < 0x10100005L
92
- dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
93
- dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
113
+ #if OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER)
114
+ dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
115
+ dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
94
116
 
95
117
  if ((dh->p == NULL) || (dh->g == NULL)) {
96
118
  DH_free(dh);
97
119
  return NULL;
98
120
  }
99
121
  #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);
122
+ p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
123
+ g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
103
124
 
104
125
  if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) {
105
126
  DH_free(dh);
@@ -139,9 +160,10 @@ static int engine_verify_callback(int preverify_ok, X509_STORE_CTX* ctx) {
139
160
  }
140
161
 
141
162
  VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
142
- VALUE obj;
163
+ VALUE obj, session_id_bytes;
143
164
  SSL_CTX* ctx;
144
165
  SSL* ssl;
166
+ int min, ssl_options;
145
167
 
146
168
  ms_conn* conn = engine_alloc(self, &obj);
147
169
 
@@ -161,7 +183,20 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
161
183
  ID sym_verify_mode = rb_intern("verify_mode");
162
184
  VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
163
185
 
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);
188
+
189
+ ID sym_no_tlsv1 = rb_intern("no_tlsv1");
190
+ VALUE no_tlsv1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1, 0);
191
+
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);
194
+
195
+ #ifdef HAVE_TLS_SERVER_METHOD
196
+ ctx = SSL_CTX_new(TLS_server_method());
197
+ #else
164
198
  ctx = SSL_CTX_new(SSLv23_server_method());
199
+ #endif
165
200
  conn->ctx = ctx;
166
201
 
167
202
  SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
@@ -172,20 +207,75 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
172
207
  SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
173
208
  }
174
209
 
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);
210
+ ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
211
+
212
+ #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
213
+ if (RTEST(no_tlsv1_1)) {
214
+ min = TLS1_2_VERSION;
215
+ }
216
+ else if (RTEST(no_tlsv1)) {
217
+ min = TLS1_1_VERSION;
218
+ }
219
+ else {
220
+ min = TLS1_VERSION;
221
+ }
222
+
223
+ SSL_CTX_set_min_proto_version(ctx, min);
224
+
225
+ SSL_CTX_set_options(ctx, ssl_options);
226
+
227
+ #else
228
+ /* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */
229
+ ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE;
230
+
231
+ if (RTEST(no_tlsv1)) {
232
+ ssl_options |= SSL_OP_NO_TLSv1;
233
+ }
234
+ if(RTEST(no_tlsv1_1)) {
235
+ ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
236
+ }
237
+ SSL_CTX_set_options(ctx, ssl_options);
238
+ #endif
239
+
176
240
  SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
177
241
 
178
- SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
242
+ if (!NIL_P(ssl_cipher_filter)) {
243
+ StringValue(ssl_cipher_filter);
244
+ SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(ssl_cipher_filter));
245
+ }
246
+ else {
247
+ SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
248
+ }
179
249
 
180
- DH *dh = get_dh1024();
250
+ // Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
251
+ session_id_bytes = rb_funcall(
252
+ #ifdef HAVE_RANDOM_BYTES
253
+ rb_cRandom,
254
+ #else
255
+ rb_const_get(rb_cRandom, rb_intern_const("DEFAULT")),
256
+ #endif
257
+ rb_intern_const("bytes"),
258
+ 1, ULL2NUM(SSL_MAX_SSL_SESSION_ID_LENGTH));
259
+
260
+ SSL_CTX_set_session_id_context(ctx,
261
+ (unsigned char *) RSTRING_PTR(session_id_bytes),
262
+ SSL_MAX_SSL_SESSION_ID_LENGTH);
263
+
264
+ DH *dh = get_dh2048();
181
265
  SSL_CTX_set_tmp_dh(ctx, dh);
182
266
 
183
- #ifndef OPENSSL_NO_ECDH
184
- EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
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);
185
271
  if (ecdh) {
186
272
  SSL_CTX_set_tmp_ecdh(ctx, ecdh);
187
273
  EC_KEY_free(ecdh);
188
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);
189
279
  #endif
190
280
 
191
281
  ssl = SSL_new(ctx);
@@ -207,8 +297,11 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
207
297
  VALUE engine_init_client(VALUE klass) {
208
298
  VALUE obj;
209
299
  ms_conn* conn = engine_alloc(klass, &obj);
210
-
300
+ #ifdef HAVE_DTLS_METHOD
301
+ conn->ctx = SSL_CTX_new(DTLS_method());
302
+ #else
211
303
  conn->ctx = SSL_CTX_new(DTLSv1_method());
304
+ #endif
212
305
  conn->ssl = SSL_new(conn->ctx);
213
306
  SSL_set_app_data(conn->ssl, NULL);
214
307
  SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
@@ -244,7 +337,7 @@ void raise_error(SSL* ssl, int result) {
244
337
  const char* err_str;
245
338
  int err = errno;
246
339
  int ssl_err = SSL_get_error(ssl, result);
247
- int verify_err = SSL_get_verify_result(ssl);
340
+ int verify_err = (int) SSL_get_verify_result(ssl);
248
341
 
249
342
  if(SSL_ERROR_SYSCALL == ssl_err) {
250
343
  snprintf(msg, sizeof(msg), "System error: %s - %d", strerror(err), err);
@@ -257,7 +350,7 @@ void raise_error(SSL* ssl, int result) {
257
350
  err_str, verify_err);
258
351
 
259
352
  } else {
260
- err = ERR_get_error();
353
+ err = (int) ERR_get_error();
261
354
  ERR_error_string_n(err, buf, sizeof(buf));
262
355
  snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err);
263
356
 
@@ -411,6 +504,11 @@ VALUE noop(VALUE self) {
411
504
  void Init_mini_ssl(VALUE puma) {
412
505
  VALUE mod, eng;
413
506
 
507
+ /* Fake operation for documentation (RDoc, YARD) */
508
+ #if 0 == 1
509
+ puma = rb_define_module("Puma");
510
+ #endif
511
+
414
512
  SSL_library_init();
415
513
  OpenSSL_add_ssl_algorithms();
416
514
  SSL_load_error_strings();
@@ -419,6 +517,39 @@ void Init_mini_ssl(VALUE puma) {
419
517
  mod = rb_define_module_under(puma, "MiniSSL");
420
518
  eng = rb_define_class_under(mod, "Engine", rb_cObject);
421
519
 
520
+ // OpenSSL Build / Runtime/Load versions
521
+
522
+ /* Version of OpenSSL that Puma was compiled with */
523
+ rb_define_const(mod, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
524
+
525
+ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
526
+ /* Version of OpenSSL that Puma loaded with */
527
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
528
+ #else
529
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
530
+ #endif
531
+
532
+ #if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
533
+ /* True if SSL3 is not available */
534
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qtrue);
535
+ #else
536
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qfalse);
537
+ #endif
538
+
539
+ #if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
540
+ /* True if TLS1 is not available */
541
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qtrue);
542
+ #else
543
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qfalse);
544
+ #endif
545
+
546
+ #if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
547
+ /* True if TLS1_1 is not available */
548
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qtrue);
549
+ #else
550
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qfalse);
551
+ #endif
552
+
422
553
  rb_define_singleton_method(mod, "check", noop, 0);
423
554
 
424
555
  eError = rb_define_class_under(mod, "SSLError", rb_eStandardError);
@@ -447,7 +578,7 @@ VALUE raise_error(VALUE self) {
447
578
  }
448
579
 
449
580
  void Init_mini_ssl(VALUE puma) {
450
- VALUE mod, eng;
581
+ VALUE mod;
451
582
 
452
583
  mod = rb_define_module_under(puma, "MiniSSL");
453
584
  rb_define_class_under(mod, "SSLError", rb_eStandardError);