puma 5.6.5-java → 6.0.1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +120 -11
- data/README.md +21 -17
- data/bin/puma-wild +1 -1
- data/docs/compile_options.md +34 -0
- data/docs/fork_worker.md +1 -3
- data/docs/nginx.md +1 -1
- 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 +11 -8
- data/ext/puma_http11/http11_parser.c +1 -1
- data/ext/puma_http11/http11_parser.h +1 -1
- 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 +2 -2
- data/ext/puma_http11/mini_ssl.c +36 -15
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +156 -53
- data/ext/puma_http11/puma_http11.c +17 -9
- data/lib/puma/app/status.rb +3 -3
- data/lib/puma/binder.rb +36 -42
- data/lib/puma/cli.rb +11 -17
- data/lib/puma/client.rb +26 -13
- data/lib/puma/cluster/worker.rb +13 -11
- data/lib/puma/cluster/worker_handle.rb +4 -1
- data/lib/puma/cluster.rb +28 -25
- data/lib/puma/configuration.rb +74 -58
- data/lib/puma/const.rb +14 -18
- data/lib/puma/control_cli.rb +3 -6
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +96 -52
- data/lib/puma/error_logger.rb +17 -9
- 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/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +96 -156
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +23 -12
- data/lib/puma/minissl.rb +82 -11
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/rack/builder.rb +4 -4
- data/lib/puma/rack_default.rb +1 -1
- data/lib/puma/reactor.rb +4 -4
- data/lib/puma/request.rb +334 -166
- data/lib/puma/runner.rb +41 -20
- data/lib/puma/server.rb +55 -71
- data/lib/puma/single.rb +10 -10
- data/lib/puma/state_file.rb +1 -4
- data/lib/puma/systemd.rb +3 -2
- data/lib/puma/thread_pool.rb +16 -16
- data/lib/puma/util.rb +0 -11
- data/lib/puma.rb +12 -9
- data/lib/rack/handler/puma.rb +9 -9
- metadata +8 -4
- data/lib/puma/queue_close.rb +0 -26
| @@ -38,8 +38,8 @@ | |
| 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 |  | 
    
        data/ext/puma_http11/mini_ssl.c
    CHANGED
    
    | @@ -210,25 +210,28 @@ sslctx_alloc(VALUE klass) { | |
| 210 210 | 
             
            VALUE
         | 
| 211 211 | 
             
            sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) {
         | 
| 212 212 | 
             
              SSL_CTX* ctx;
         | 
| 213 | 
            -
             | 
| 214 | 
            -
            #ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
         | 
| 215 | 
            -
              int min;
         | 
| 216 | 
            -
            #endif
         | 
| 217 213 | 
             
              int ssl_options;
         | 
| 218 214 | 
             
              VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1,
         | 
| 219 215 | 
             
                verification_flags, session_id_bytes, cert_pem, key_pem;
         | 
| 220 | 
            -
            #ifndef HAVE_SSL_CTX_SET_DH_AUTO
         | 
| 221 | 
            -
              DH *dh;
         | 
| 222 | 
            -
            #endif
         | 
| 223 216 | 
             
              BIO *bio;
         | 
| 224 217 | 
             
              X509 *x509;
         | 
| 225 218 | 
             
              EVP_PKEY *pkey;
         | 
| 226 | 
            -
             | 
| 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
         | 
| 227 225 | 
             
            #if OPENSSL_VERSION_NUMBER < 0x10002000L
         | 
| 228 226 | 
             
              EC_KEY *ecdh;
         | 
| 229 227 | 
             
            #endif
         | 
| 228 | 
            +
            #ifdef HAVE_SSL_CTX_SET_SESSION_CACHE_MODE
         | 
| 229 | 
            +
              VALUE reuse, reuse_cache_size, reuse_timeout;
         | 
| 230 230 |  | 
| 231 | 
            -
               | 
| 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
         | 
| 232 235 |  | 
| 233 236 | 
             
              key = rb_funcall(mini_ssl_ctx, rb_intern_const("key"), 0);
         | 
| 234 237 |  | 
| @@ -248,6 +251,8 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { | |
| 248 251 |  | 
| 249 252 | 
             
              no_tlsv1_1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1_1"), 0);
         | 
| 250 253 |  | 
| 254 | 
            +
              TypedData_Get_Struct(self, SSL_CTX, &sslctx_type, ctx);
         | 
| 255 | 
            +
             | 
| 251 256 | 
             
              if (!NIL_P(cert)) {
         | 
| 252 257 | 
             
                StringValue(cert);
         | 
| 253 258 |  | 
| @@ -270,8 +275,11 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { | |
| 270 275 | 
             
                x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
         | 
| 271 276 |  | 
| 272 277 | 
             
                if (SSL_CTX_use_certificate(ctx, x509) != 1) {
         | 
| 278 | 
            +
                  BIO_free(bio);
         | 
| 273 279 | 
             
                  raise_file_error("SSL_CTX_use_certificate", RSTRING_PTR(cert_pem));
         | 
| 274 280 | 
             
                }
         | 
| 281 | 
            +
                X509_free(x509);
         | 
| 282 | 
            +
                BIO_free(bio);
         | 
| 275 283 | 
             
              }
         | 
| 276 284 |  | 
| 277 285 | 
             
              if (!NIL_P(key_pem)) {
         | 
| @@ -280,8 +288,11 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { | |
| 280 288 | 
             
                pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
         | 
| 281 289 |  | 
| 282 290 | 
             
                if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
         | 
| 291 | 
            +
                  BIO_free(bio);
         | 
| 283 292 | 
             
                  raise_file_error("SSL_CTX_use_PrivateKey", RSTRING_PTR(key_pem));
         | 
| 284 293 | 
             
                }
         | 
| 294 | 
            +
                EVP_PKEY_free(pkey);
         | 
| 295 | 
            +
                BIO_free(bio);
         | 
| 285 296 | 
             
              }
         | 
| 286 297 |  | 
| 287 298 | 
             
              verification_flags = rb_funcall(mini_ssl_ctx, rb_intern_const("verification_flags"), 0);
         | 
| @@ -314,8 +325,6 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { | |
| 314 325 |  | 
| 315 326 | 
             
              SSL_CTX_set_min_proto_version(ctx, min);
         | 
| 316 327 |  | 
| 317 | 
            -
              SSL_CTX_set_options(ctx, ssl_options);
         | 
| 318 | 
            -
             | 
| 319 328 | 
             
            #else
         | 
| 320 329 | 
             
              /* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */
         | 
| 321 330 | 
             
              ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE;
         | 
| @@ -326,10 +335,23 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { | |
| 326 335 | 
             
              if(RTEST(no_tlsv1_1)) {
         | 
| 327 336 | 
             
                ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
         | 
| 328 337 | 
             
              }
         | 
| 329 | 
            -
              SSL_CTX_set_options(ctx, ssl_options);
         | 
| 330 338 | 
             
            #endif
         | 
| 331 339 |  | 
| 332 | 
            -
             | 
| 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
         | 
| 353 | 
            +
             | 
| 354 | 
            +
              SSL_CTX_set_options(ctx, ssl_options);
         | 
| 333 355 |  | 
| 334 356 | 
             
              if (!NIL_P(ssl_cipher_filter)) {
         | 
| 335 357 | 
             
                StringValue(ssl_cipher_filter);
         | 
| @@ -340,8 +362,7 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { | |
| 340 362 | 
             
              }
         | 
| 341 363 |  | 
| 342 364 | 
             
            #if OPENSSL_VERSION_NUMBER < 0x10002000L
         | 
| 343 | 
            -
              // Remove this case if OpenSSL 1.0.1 (now EOL) support is no
         | 
| 344 | 
            -
              // longer needed.
         | 
| 365 | 
            +
              // Remove this case if OpenSSL 1.0.1 (now EOL) support is no longer needed.
         | 
| 345 366 | 
             
              ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
         | 
| 346 367 | 
             
              if (ecdh) {
         | 
| 347 368 | 
             
                SSL_CTX_set_tmp_ecdh(ctx, ecdh);
         | 
| @@ -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) {
         | 
| @@ -383,7 +383,7 @@ case 1: | |
| 383 383 | 
             
            	case 11:
         | 
| 384 384 | 
             
            // line 42 "ext/puma_http11/http11_parser.java.rl"
         | 
| 385 385 | 
             
            	{
         | 
| 386 | 
            -
                Http11. | 
| 386 | 
            +
                Http11.server_protocol(runtime, parser.data, parser.buffer, parser.mark, p-parser.mark);
         | 
| 387 387 | 
             
              }
         | 
| 388 388 | 
             
            	break;
         | 
| 389 389 | 
             
            	case 12:
         | 
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            package org.jruby.puma;
         | 
| 2 2 |  | 
| 3 3 | 
             
            import org.jruby.Ruby;
         | 
| 4 | 
            +
            import org.jruby.RubyArray;
         | 
| 4 5 | 
             
            import org.jruby.RubyClass;
         | 
| 5 6 | 
             
            import org.jruby.RubyModule;
         | 
| 6 7 | 
             
            import org.jruby.RubyObject;
         | 
| @@ -15,6 +16,7 @@ import org.jruby.runtime.builtin.IRubyObject; | |
| 15 16 | 
             
            import org.jruby.util.ByteList;
         | 
| 16 17 |  | 
| 17 18 | 
             
            import javax.net.ssl.KeyManagerFactory;
         | 
| 19 | 
            +
            import javax.net.ssl.TrustManager;
         | 
| 18 20 | 
             
            import javax.net.ssl.TrustManagerFactory;
         | 
| 19 21 | 
             
            import javax.net.ssl.SSLContext;
         | 
| 20 22 | 
             
            import javax.net.ssl.SSLEngine;
         | 
| @@ -22,6 +24,7 @@ import javax.net.ssl.SSLEngineResult; | |
| 22 24 | 
             
            import javax.net.ssl.SSLException;
         | 
| 23 25 | 
             
            import javax.net.ssl.SSLPeerUnverifiedException;
         | 
| 24 26 | 
             
            import javax.net.ssl.SSLSession;
         | 
| 27 | 
            +
            import javax.net.ssl.X509TrustManager;
         | 
| 25 28 | 
             
            import java.io.FileInputStream;
         | 
| 26 29 | 
             
            import java.io.InputStream;
         | 
| 27 30 | 
             
            import java.io.IOException;
         | 
| @@ -32,15 +35,18 @@ import java.security.KeyStore; | |
| 32 35 | 
             
            import java.security.KeyStoreException;
         | 
| 33 36 | 
             
            import java.security.NoSuchAlgorithmException;
         | 
| 34 37 | 
             
            import java.security.UnrecoverableKeyException;
         | 
| 38 | 
            +
            import java.security.cert.Certificate;
         | 
| 35 39 | 
             
            import java.security.cert.CertificateEncodingException;
         | 
| 36 40 | 
             
            import java.security.cert.CertificateException;
         | 
| 41 | 
            +
            import java.security.cert.X509Certificate;
         | 
| 37 42 | 
             
            import java.util.concurrent.ConcurrentHashMap;
         | 
| 38 43 | 
             
            import java.util.Map;
         | 
| 44 | 
            +
            import java.util.function.Supplier;
         | 
| 39 45 |  | 
| 40 46 | 
             
            import static javax.net.ssl.SSLEngineResult.Status;
         | 
| 41 47 | 
             
            import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
         | 
| 42 48 |  | 
| 43 | 
            -
            public class MiniSSL extends RubyObject {
         | 
| 49 | 
            +
            public class MiniSSL extends RubyObject { // MiniSSL::Engine
         | 
| 44 50 | 
             
              private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
         | 
| 45 51 | 
             
                public IRubyObject allocate(Ruby runtime, RubyClass klass) {
         | 
| 46 52 | 
             
                  return new MiniSSL(runtime, klass);
         | 
| @@ -51,11 +57,10 @@ public class MiniSSL extends RubyObject { | |
| 51 57 | 
             
                RubyModule mPuma = runtime.defineModule("Puma");
         | 
| 52 58 | 
             
                RubyModule ssl = mPuma.defineModuleUnder("MiniSSL");
         | 
| 53 59 |  | 
| 54 | 
            -
                 | 
| 55 | 
            -
             | 
| 56 | 
            -
                                       runtime.getClass("IOError").getAllocator());
         | 
| 60 | 
            +
                // Puma::MiniSSL::SSLError
         | 
| 61 | 
            +
                ssl.defineClassUnder("SSLError", runtime.getStandardError(), runtime.getStandardError().getAllocator());
         | 
| 57 62 |  | 
| 58 | 
            -
                RubyClass eng = ssl.defineClassUnder("Engine",runtime.getObject(),ALLOCATOR);
         | 
| 63 | 
            +
                RubyClass eng = ssl.defineClassUnder("Engine", runtime.getObject(), ALLOCATOR);
         | 
| 59 64 | 
             
                eng.defineAnnotatedMethods(MiniSSL.class);
         | 
| 60 65 | 
             
              }
         | 
| 61 66 |  | 
| @@ -137,74 +142,116 @@ public class MiniSSL extends RubyObject { | |
| 137 142 | 
             
              private static Map<String, KeyManagerFactory> keyManagerFactoryMap = new ConcurrentHashMap<String, KeyManagerFactory>();
         | 
| 138 143 | 
             
              private static Map<String, TrustManagerFactory> trustManagerFactoryMap = new ConcurrentHashMap<String, TrustManagerFactory>();
         | 
| 139 144 |  | 
| 140 | 
            -
              @JRubyMethod(meta = true)
         | 
| 145 | 
            +
              @JRubyMethod(meta = true) // Engine.server
         | 
| 141 146 | 
             
              public static synchronized IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext)
         | 
| 142 147 | 
             
                  throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
         | 
| 143 148 | 
             
                // Create the KeyManagerFactory and TrustManagerFactory for this server
         | 
| 144 | 
            -
                String keystoreFile = miniSSLContext.callMethod(context, "keystore") | 
| 145 | 
            -
                char[]  | 
| 149 | 
            +
                String keystoreFile = asStringValue(miniSSLContext.callMethod(context, "keystore"), null);
         | 
| 150 | 
            +
                char[] keystorePass = asStringValue(miniSSLContext.callMethod(context, "keystore_pass"), null).toCharArray();
         | 
| 151 | 
            +
                String keystoreType = asStringValue(miniSSLContext.callMethod(context, "keystore_type"), KeyStore::getDefaultType);
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                String truststoreFile;
         | 
| 154 | 
            +
                char[] truststorePass;
         | 
| 155 | 
            +
                String truststoreType;
         | 
| 156 | 
            +
                IRubyObject truststore = miniSSLContext.callMethod(context, "truststore");
         | 
| 157 | 
            +
                if (truststore.isNil()) {
         | 
| 158 | 
            +
                  truststoreFile = keystoreFile;
         | 
| 159 | 
            +
                  truststorePass = keystorePass;
         | 
| 160 | 
            +
                  truststoreType = keystoreType;
         | 
| 161 | 
            +
                } else if (!isDefaultSymbol(context, truststore)) {
         | 
| 162 | 
            +
                  truststoreFile = truststore.convertToString().asJavaString();
         | 
| 163 | 
            +
                  IRubyObject pass = miniSSLContext.callMethod(context, "truststore_pass");
         | 
| 164 | 
            +
                  if (pass.isNil()) {
         | 
| 165 | 
            +
                    truststorePass = null;
         | 
| 166 | 
            +
                  } else {
         | 
| 167 | 
            +
                    truststorePass = asStringValue(pass, null).toCharArray();
         | 
| 168 | 
            +
                  }
         | 
| 169 | 
            +
                  truststoreType = asStringValue(miniSSLContext.callMethod(context, "truststore_type"), KeyStore::getDefaultType);
         | 
| 170 | 
            +
                } else { // self.truststore = :default
         | 
| 171 | 
            +
                  truststoreFile = null;
         | 
| 172 | 
            +
                  truststorePass = null;
         | 
| 173 | 
            +
                  truststoreType = null;
         | 
| 174 | 
            +
                }
         | 
| 146 175 |  | 
| 147 | 
            -
                KeyStore ks = KeyStore.getInstance( | 
| 176 | 
            +
                KeyStore ks = KeyStore.getInstance(keystoreType);
         | 
| 148 177 | 
             
                InputStream is = new FileInputStream(keystoreFile);
         | 
| 149 178 | 
             
                try {
         | 
| 150 | 
            -
                  ks.load(is,  | 
| 179 | 
            +
                  ks.load(is, keystorePass);
         | 
| 151 180 | 
             
                } finally {
         | 
| 152 181 | 
             
                  is.close();
         | 
| 153 182 | 
             
                }
         | 
| 154 183 | 
             
                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
         | 
| 155 | 
            -
                kmf.init(ks,  | 
| 184 | 
            +
                kmf.init(ks, keystorePass);
         | 
| 156 185 | 
             
                keyManagerFactoryMap.put(keystoreFile, kmf);
         | 
| 157 186 |  | 
| 158 | 
            -
                 | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
                   | 
| 162 | 
            -
             | 
| 163 | 
            -
                   | 
| 187 | 
            +
                if (truststoreFile != null) {
         | 
| 188 | 
            +
                  KeyStore ts = KeyStore.getInstance(truststoreType);
         | 
| 189 | 
            +
                  is = new FileInputStream(truststoreFile);
         | 
| 190 | 
            +
                  try {
         | 
| 191 | 
            +
                    ts.load(is, truststorePass);
         | 
| 192 | 
            +
                  } finally {
         | 
| 193 | 
            +
                    is.close();
         | 
| 194 | 
            +
                  }
         | 
| 195 | 
            +
                  TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
         | 
| 196 | 
            +
                  tmf.init(ts);
         | 
| 197 | 
            +
                  trustManagerFactoryMap.put(truststoreFile, tmf);
         | 
| 164 198 | 
             
                }
         | 
| 165 | 
            -
                TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
         | 
| 166 | 
            -
                tmf.init(ts);
         | 
| 167 | 
            -
                trustManagerFactoryMap.put(keystoreFile, tmf);
         | 
| 168 199 |  | 
| 169 200 | 
             
                RubyClass klass = (RubyClass) recv;
         | 
| 170 | 
            -
                return klass.newInstance(context,
         | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 201 | 
            +
                return klass.newInstance(context, miniSSLContext, Block.NULL_BLOCK);
         | 
| 202 | 
            +
              }
         | 
| 203 | 
            +
             | 
| 204 | 
            +
              private static String asStringValue(IRubyObject value, Supplier<String> defaultValue) {
         | 
| 205 | 
            +
                if (defaultValue != null && value.isNil()) return defaultValue.get();
         | 
| 206 | 
            +
                return value.convertToString().asJavaString();
         | 
| 207 | 
            +
              }
         | 
| 208 | 
            +
             | 
| 209 | 
            +
              private static boolean isDefaultSymbol(ThreadContext context, IRubyObject truststore) {
         | 
| 210 | 
            +
                return context.runtime.newSymbol("default").equals(truststore);
         | 
| 173 211 | 
             
              }
         | 
| 174 212 |  | 
| 175 213 | 
             
              @JRubyMethod
         | 
| 176 | 
            -
              public IRubyObject initialize(ThreadContext  | 
| 214 | 
            +
              public IRubyObject initialize(ThreadContext context, IRubyObject miniSSLContext)
         | 
| 177 215 | 
             
                  throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
         | 
| 178 216 |  | 
| 179 | 
            -
                String keystoreFile = miniSSLContext.callMethod( | 
| 217 | 
            +
                String keystoreFile = miniSSLContext.callMethod(context, "keystore").convertToString().asJavaString();
         | 
| 180 218 | 
             
                KeyManagerFactory kmf = keyManagerFactoryMap.get(keystoreFile);
         | 
| 181 | 
            -
                 | 
| 182 | 
            -
                 | 
| 183 | 
            -
             | 
| 219 | 
            +
                IRubyObject truststore = miniSSLContext.callMethod(context, "truststore");
         | 
| 220 | 
            +
                String truststoreFile = isDefaultSymbol(context, truststore) ? "" : asStringValue(truststore, () -> keystoreFile);
         | 
| 221 | 
            +
                TrustManagerFactory tmf = trustManagerFactoryMap.get(truststoreFile); // null if self.truststore = :default
         | 
| 222 | 
            +
                if (kmf == null) {
         | 
| 223 | 
            +
                  throw new KeyStoreException("Could not find KeyManagerFactory for keystore: " + keystoreFile + " truststore: " + truststoreFile);
         | 
| 184 224 | 
             
                }
         | 
| 185 225 |  | 
| 186 226 | 
             
                SSLContext sslCtx = SSLContext.getInstance("TLS");
         | 
| 187 227 |  | 
| 188 | 
            -
                sslCtx.init(kmf.getKeyManagers(),  | 
| 228 | 
            +
                sslCtx.init(kmf.getKeyManagers(), getTrustManagers(tmf), null);
         | 
| 189 229 | 
             
                closed = false;
         | 
| 190 230 | 
             
                handshake = false;
         | 
| 191 231 | 
             
                engine = sslCtx.createSSLEngine();
         | 
| 192 232 |  | 
| 193 | 
            -
                String[]  | 
| 194 | 
            -
                 | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 197 | 
            -
                     | 
| 198 | 
            -
             | 
| 233 | 
            +
                String[] enabledProtocols;
         | 
| 234 | 
            +
                IRubyObject protocols = miniSSLContext.callMethod(context, "protocols");
         | 
| 235 | 
            +
                if (protocols.isNil()) {
         | 
| 236 | 
            +
                  if (miniSSLContext.callMethod(context, "no_tlsv1").isTrue()) {
         | 
| 237 | 
            +
                    enabledProtocols = new String[] { "TLSv1.1", "TLSv1.2", "TLSv1.3" };
         | 
| 238 | 
            +
                  } else {
         | 
| 239 | 
            +
                    enabledProtocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" };
         | 
| 240 | 
            +
                  }
         | 
| 199 241 |  | 
| 200 | 
            -
             | 
| 201 | 
            -
                     | 
| 242 | 
            +
                  if (miniSSLContext.callMethod(context, "no_tlsv1_1").isTrue()) {
         | 
| 243 | 
            +
                    enabledProtocols = new String[] { "TLSv1.2", "TLSv1.3" };
         | 
| 244 | 
            +
                  }
         | 
| 245 | 
            +
                } else if (protocols instanceof RubyArray) {
         | 
| 246 | 
            +
                  enabledProtocols = (String[]) ((RubyArray) protocols).toArray(new String[0]);
         | 
| 247 | 
            +
                } else {
         | 
| 248 | 
            +
                  throw context.runtime.newTypeError(protocols, context.runtime.getArray());
         | 
| 202 249 | 
             
                }
         | 
| 250 | 
            +
                engine.setEnabledProtocols(enabledProtocols);
         | 
| 203 251 |  | 
| 204 | 
            -
                engine.setEnabledProtocols(protocols);
         | 
| 205 252 | 
             
                engine.setUseClientMode(false);
         | 
| 206 253 |  | 
| 207 | 
            -
                long verify_mode = miniSSLContext.callMethod( | 
| 254 | 
            +
                long verify_mode = miniSSLContext.callMethod(context, "verify_mode").convertToInteger("to_i").getLongValue();
         | 
| 208 255 | 
             
                if ((verify_mode & 0x1) != 0) { // 'peer'
         | 
| 209 256 | 
             
                    engine.setWantClientAuth(true);
         | 
| 210 257 | 
             
                }
         | 
| @@ -212,10 +259,11 @@ public class MiniSSL extends RubyObject { | |
| 212 259 | 
             
                    engine.setNeedClientAuth(true);
         | 
| 213 260 | 
             
                }
         | 
| 214 261 |  | 
| 215 | 
            -
                IRubyObject  | 
| 216 | 
            -
                if ( | 
| 217 | 
            -
                  String[]  | 
| 218 | 
            -
             | 
| 262 | 
            +
                IRubyObject cipher_suites = miniSSLContext.callMethod(context, "cipher_suites");
         | 
| 263 | 
            +
                if (cipher_suites instanceof RubyArray) {
         | 
| 264 | 
            +
                  engine.setEnabledCipherSuites((String[]) ((RubyArray) cipher_suites).toArray(new String[0]));
         | 
| 265 | 
            +
                } else if (!cipher_suites.isNil()) {
         | 
| 266 | 
            +
                  throw context.runtime.newTypeError(cipher_suites, context.runtime.getArray());
         | 
| 219 267 | 
             
                }
         | 
| 220 268 |  | 
| 221 269 | 
             
                SSLSession session = engine.getSession();
         | 
| @@ -227,6 +275,48 @@ public class MiniSSL extends RubyObject { | |
| 227 275 | 
             
                return this;
         | 
| 228 276 | 
             
              }
         | 
| 229 277 |  | 
| 278 | 
            +
              private TrustManager[] getTrustManagers(TrustManagerFactory factory) {
         | 
| 279 | 
            +
                if (factory == null) return null; // use JDK trust defaults
         | 
| 280 | 
            +
                final TrustManager[] tms = factory.getTrustManagers();
         | 
| 281 | 
            +
                if (tms != null) {
         | 
| 282 | 
            +
                  for (int i=0; i<tms.length; i++) {
         | 
| 283 | 
            +
                    final TrustManager tm = tms[i];
         | 
| 284 | 
            +
                    if (tm instanceof X509TrustManager) {
         | 
| 285 | 
            +
                      tms[i] = new TrustManagerWrapper((X509TrustManager) tm);
         | 
| 286 | 
            +
                    }
         | 
| 287 | 
            +
                  }
         | 
| 288 | 
            +
                }
         | 
| 289 | 
            +
                return tms;
         | 
| 290 | 
            +
              }
         | 
| 291 | 
            +
             | 
| 292 | 
            +
              private volatile transient X509Certificate lastCheckedCert0;
         | 
| 293 | 
            +
             | 
| 294 | 
            +
              private class TrustManagerWrapper implements X509TrustManager {
         | 
| 295 | 
            +
             | 
| 296 | 
            +
                private final X509TrustManager delegate;
         | 
| 297 | 
            +
             | 
| 298 | 
            +
                TrustManagerWrapper(X509TrustManager delegate) {
         | 
| 299 | 
            +
                  this.delegate = delegate;
         | 
| 300 | 
            +
                }
         | 
| 301 | 
            +
             | 
| 302 | 
            +
                @Override
         | 
| 303 | 
            +
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
         | 
| 304 | 
            +
                  lastCheckedCert0 = chain.length > 0 ? chain[0] : null;
         | 
| 305 | 
            +
                  delegate.checkClientTrusted(chain, authType);
         | 
| 306 | 
            +
                }
         | 
| 307 | 
            +
             | 
| 308 | 
            +
                @Override
         | 
| 309 | 
            +
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
         | 
| 310 | 
            +
                  delegate.checkServerTrusted(chain, authType);
         | 
| 311 | 
            +
                }
         | 
| 312 | 
            +
             | 
| 313 | 
            +
                @Override
         | 
| 314 | 
            +
                public X509Certificate[] getAcceptedIssuers() {
         | 
| 315 | 
            +
                  return delegate.getAcceptedIssuers();
         | 
| 316 | 
            +
                }
         | 
| 317 | 
            +
             | 
| 318 | 
            +
              }
         | 
| 319 | 
            +
             | 
| 230 320 | 
             
              @JRubyMethod
         | 
| 231 321 | 
             
              public IRubyObject inject(IRubyObject arg) {
         | 
| 232 322 | 
             
                ByteList bytes = arg.convertToString().getByteList();
         | 
| @@ -251,7 +341,7 @@ public class MiniSSL extends RubyObject { | |
| 251 341 | 
             
                      res = engine.unwrap(src.getRawBuffer(), dst.getRawBuffer());
         | 
| 252 342 | 
             
                      break;
         | 
| 253 343 | 
             
                    default:
         | 
| 254 | 
            -
                      throw new  | 
| 344 | 
            +
                      throw new AssertionError("Unknown SSLOperation: " + sslOp);
         | 
| 255 345 | 
             
                  }
         | 
| 256 346 |  | 
| 257 347 | 
             
                  switch (res.getStatus()) {
         | 
| @@ -336,9 +426,7 @@ public class MiniSSL extends RubyObject { | |
| 336 426 |  | 
| 337 427 | 
             
                  return RubyString.newString(getRuntime(), appDataByteList);
         | 
| 338 428 | 
             
                } catch (SSLException e) {
         | 
| 339 | 
            -
                   | 
| 340 | 
            -
                  re.initCause(e);
         | 
| 341 | 
            -
                  throw re;
         | 
| 429 | 
            +
                  throw newSSLError(getRuntime(), e);
         | 
| 342 430 | 
             
                }
         | 
| 343 431 | 
             
              }
         | 
| 344 432 |  | 
| @@ -371,19 +459,19 @@ public class MiniSSL extends RubyObject { | |
| 371 459 |  | 
| 372 460 | 
             
                  return RubyString.newString(context.runtime, dataByteList);
         | 
| 373 461 | 
             
                } catch (SSLException e) {
         | 
| 374 | 
            -
                   | 
| 375 | 
            -
                  ex.initCause(e);
         | 
| 376 | 
            -
                  throw ex;
         | 
| 462 | 
            +
                  throw newSSLError(getRuntime(), e);
         | 
| 377 463 | 
             
                }
         | 
| 378 464 | 
             
              }
         | 
| 379 465 |  | 
| 380 466 | 
             
              @JRubyMethod
         | 
| 381 | 
            -
              public IRubyObject peercert() throws CertificateEncodingException {
         | 
| 467 | 
            +
              public IRubyObject peercert(ThreadContext context) throws CertificateEncodingException {
         | 
| 468 | 
            +
                Certificate peerCert;
         | 
| 382 469 | 
             
                try {
         | 
| 383 | 
            -
                   | 
| 470 | 
            +
                  peerCert = engine.getSession().getPeerCertificates()[0];
         | 
| 384 471 | 
             
                } catch (SSLPeerUnverifiedException e) {
         | 
| 385 | 
            -
                   | 
| 472 | 
            +
                  peerCert = lastCheckedCert0; // null if trust check did not happen
         | 
| 386 473 | 
             
                }
         | 
| 474 | 
            +
                return peerCert == null ? context.nil : JavaEmbedUtils.javaToRuby(context.runtime, peerCert.getEncoded());
         | 
| 387 475 | 
             
              }
         | 
| 388 476 |  | 
| 389 477 | 
             
              @JRubyMethod(name = "init?")
         | 
| @@ -402,4 +490,19 @@ public class MiniSSL extends RubyObject { | |
| 402 490 | 
             
                  return getRuntime().getFalse();
         | 
| 403 491 | 
             
                }
         | 
| 404 492 | 
             
              }
         | 
| 493 | 
            +
             | 
| 494 | 
            +
              private static RubyClass getSSLError(Ruby runtime) {
         | 
| 495 | 
            +
                return (RubyClass) ((RubyModule) runtime.getModule("Puma").getConstantAt("MiniSSL")).getConstantAt("SSLError");
         | 
| 496 | 
            +
              }
         | 
| 497 | 
            +
             | 
| 498 | 
            +
              private static RaiseException newSSLError(Ruby runtime, SSLException cause) {
         | 
| 499 | 
            +
                return newError(runtime, getSSLError(runtime), cause.toString(), cause);
         | 
| 500 | 
            +
              }
         | 
| 501 | 
            +
             | 
| 502 | 
            +
              private static RaiseException newError(Ruby runtime, RubyClass errorClass, String message, Throwable cause) {
         | 
| 503 | 
            +
                RaiseException ex = new RaiseException(runtime, errorClass, message, true);
         | 
| 504 | 
            +
                ex.initCause(cause);
         | 
| 505 | 
            +
                return ex;
         | 
| 506 | 
            +
              }
         | 
| 507 | 
            +
             | 
| 405 508 | 
             
            }
         | 
| @@ -36,13 +36,13 @@ static VALUE global_request_method; | |
| 36 36 | 
             
            static VALUE global_request_uri;
         | 
| 37 37 | 
             
            static VALUE global_fragment;
         | 
| 38 38 | 
             
            static VALUE global_query_string;
         | 
| 39 | 
            -
            static VALUE  | 
| 39 | 
            +
            static VALUE global_server_protocol;
         | 
| 40 40 | 
             
            static VALUE global_request_path;
         | 
| 41 41 |  | 
| 42 42 | 
             
            /** Defines common length and error messages for input length validation. */
         | 
| 43 43 | 
             
            #define QUOTE(s) #s
         | 
| 44 | 
            -
            #define  | 
| 45 | 
            -
            #define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N  " is longer than the "  | 
| 44 | 
            +
            #define EXPAND_MAX_LENGTH_VALUE(s) QUOTE(s)
         | 
| 45 | 
            +
            #define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N  " is longer than the " EXPAND_MAX_LENGTH_VALUE(length) " allowed length (was %d)"
         | 
| 46 46 |  | 
| 47 47 | 
             
            /** Validates the max length of given input and throws an HttpParserError exception if over. */
         | 
| 48 48 | 
             
            #define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR, len); }
         | 
| @@ -52,15 +52,23 @@ static VALUE global_request_path; | |
| 52 52 |  | 
| 53 53 |  | 
| 54 54 | 
             
            /* Defines the maximum allowed lengths for various input elements.*/
         | 
| 55 | 
            +
            #ifndef PUMA_REQUEST_URI_MAX_LENGTH
         | 
| 56 | 
            +
            #define PUMA_REQUEST_URI_MAX_LENGTH (1024 * 12)
         | 
| 57 | 
            +
            #endif
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            #ifndef PUMA_REQUEST_PATH_MAX_LENGTH
         | 
| 60 | 
            +
            #define PUMA_REQUEST_PATH_MAX_LENGTH (8192)
         | 
| 61 | 
            +
            #endif
         | 
| 62 | 
            +
             | 
| 55 63 | 
             
            #ifndef PUMA_QUERY_STRING_MAX_LENGTH
         | 
| 56 64 | 
             
            #define PUMA_QUERY_STRING_MAX_LENGTH (1024 * 10)
         | 
| 57 65 | 
             
            #endif
         | 
| 58 66 |  | 
| 59 67 | 
             
            DEF_MAX_LENGTH(FIELD_NAME, 256);
         | 
| 60 68 | 
             
            DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
         | 
| 61 | 
            -
            DEF_MAX_LENGTH(REQUEST_URI,  | 
| 69 | 
            +
            DEF_MAX_LENGTH(REQUEST_URI, PUMA_REQUEST_URI_MAX_LENGTH);
         | 
| 62 70 | 
             
            DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
         | 
| 63 | 
            -
            DEF_MAX_LENGTH(REQUEST_PATH,  | 
| 71 | 
            +
            DEF_MAX_LENGTH(REQUEST_PATH, PUMA_REQUEST_PATH_MAX_LENGTH);
         | 
| 64 72 | 
             
            DEF_MAX_LENGTH(QUERY_STRING, PUMA_QUERY_STRING_MAX_LENGTH);
         | 
| 65 73 | 
             
            DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
         | 
| 66 74 |  | 
| @@ -236,10 +244,10 @@ void query_string(puma_parser* hp, const char *at, size_t length) | |
| 236 244 | 
             
              rb_hash_aset(hp->request, global_query_string, val);
         | 
| 237 245 | 
             
            }
         | 
| 238 246 |  | 
| 239 | 
            -
            void  | 
| 247 | 
            +
            void server_protocol(puma_parser* hp, const char *at, size_t length)
         | 
| 240 248 | 
             
            {
         | 
| 241 249 | 
             
              VALUE val = rb_str_new(at, length);
         | 
| 242 | 
            -
              rb_hash_aset(hp->request,  | 
| 250 | 
            +
              rb_hash_aset(hp->request, global_server_protocol, val);
         | 
| 243 251 | 
             
            }
         | 
| 244 252 |  | 
| 245 253 | 
             
            /** Finalizes the request header to have a bunch of stuff that's
         | 
| @@ -281,7 +289,7 @@ VALUE HttpParser_alloc(VALUE klass) | |
| 281 289 | 
             
              hp->fragment = fragment;
         | 
| 282 290 | 
             
              hp->request_path = request_path;
         | 
| 283 291 | 
             
              hp->query_string = query_string;
         | 
| 284 | 
            -
              hp-> | 
| 292 | 
            +
              hp->server_protocol = server_protocol;
         | 
| 285 293 | 
             
              hp->header_done = header_done;
         | 
| 286 294 | 
             
              hp->request = Qnil;
         | 
| 287 295 |  | 
| @@ -461,7 +469,7 @@ void Init_puma_http11(void) | |
| 461 469 | 
             
              DEF_GLOBAL(request_uri, "REQUEST_URI");
         | 
| 462 470 | 
             
              DEF_GLOBAL(fragment, "FRAGMENT");
         | 
| 463 471 | 
             
              DEF_GLOBAL(query_string, "QUERY_STRING");
         | 
| 464 | 
            -
              DEF_GLOBAL( | 
| 472 | 
            +
              DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
         | 
| 465 473 | 
             
              DEF_GLOBAL(request_path, "REQUEST_PATH");
         | 
| 466 474 |  | 
| 467 475 | 
             
              eHttpParserError = rb_define_class_under(mPuma, "HttpParserError", rb_eIOError);
         | 
    
        data/lib/puma/app/status.rb
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 2 | 
            +
            require_relative '../json_serialization'
         | 
| 3 3 |  | 
| 4 4 | 
             
            module Puma
         | 
| 5 5 | 
             
              module App
         | 
| @@ -85,8 +85,8 @@ module Puma | |
| 85 85 |  | 
| 86 86 | 
             
                  def rack_response(status, body, content_type='application/json')
         | 
| 87 87 | 
             
                    headers = {
         | 
| 88 | 
            -
                      ' | 
| 89 | 
            -
                      ' | 
| 88 | 
            +
                      'content-type' => content_type,
         | 
| 89 | 
            +
                      'content-length' => body.bytesize.to_s
         | 
| 90 90 | 
             
                    }
         | 
| 91 91 |  | 
| 92 92 | 
             
                    [status, headers, [body]]
         |