puma 5.0.0.beta1 → 5.0.0.beta2
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 +23 -1
- data/README.md +3 -3
- data/docs/architecture.md +3 -3
- data/docs/deployment.md +6 -2
- data/docs/signals.md +4 -4
- data/ext/puma_http11/http11_parser.c +3 -1
- data/ext/puma_http11/http11_parser.rl +3 -1
- data/ext/puma_http11/mini_ssl.c +12 -2
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +37 -6
- data/ext/puma_http11/puma_http11.c +1 -1
- data/lib/puma.rb +1 -0
- data/lib/puma/app/status.rb +4 -2
- data/lib/puma/binder.rb +5 -4
- data/lib/puma/client.rb +36 -9
- data/lib/puma/cluster.rb +8 -4
- data/lib/puma/commonlogger.rb +2 -2
- data/lib/puma/const.rb +1 -1
- data/lib/puma/dsl.rb +3 -3
- data/lib/puma/error_logger.rb +96 -0
- data/lib/puma/events.rb +33 -31
- data/lib/puma/launcher.rb +5 -2
- data/lib/puma/minissl.rb +34 -2
- data/lib/puma/reactor.rb +2 -2
- data/lib/puma/runner.rb +1 -1
- data/lib/puma/server.rb +84 -44
- data/lib/puma/state_file.rb +1 -1
- data/lib/puma/thread_pool.rb +5 -2
- metadata +8 -7
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: b265505e1f4f00fe8c7de1c1d66103664bdd5920c2aed54b66e3303ded01c881
         | 
| 4 | 
            +
              data.tar.gz: 3c921f609fd679b3b8cfbbc807678c16d09b03f43a8104913f0e0dd54e7e93f1
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 74dce09aab280163c048a0c3ae3a81cd16b2ac32c7641fd43640d65797a61edf6e25a11f5111324111cd0068a98fc2ec13fcb3ac44154cef39d4bb3eb839a392
         | 
| 7 | 
            +
              data.tar.gz: c6cf2c5d6d29867130be2fa572d5aea12a45a50052841a2de26e0a4600004f6fffae80922a9c641e8a155c8967ea8349d759b62a7ae9c2f6cbc84433fd092d13
         | 
    
        data/History.md
    CHANGED
    
    | @@ -6,11 +6,12 @@ | |
| 6 6 | 
             
              * EXPERIMENTAL: Added `nakayoshi_fork` option. Reduce memory usage in preloaded cluster-mode apps by GCing before fork and compacting, where available. (#2093, #2256)
         | 
| 7 7 | 
             
              * Added pumactl `thread-backtraces` command to print thread backtraces (#2054)
         | 
| 8 8 | 
             
              * Added incrementing `requests_count` to `Puma.stats`. (#2106)
         | 
| 9 | 
            -
              * Increased maximum URI path length from 2048 to  | 
| 9 | 
            +
              * Increased maximum URI path length from 2048 to 8192 bytes (#2167, #2344)
         | 
| 10 10 | 
             
              * `lowlevel_error_handler` is now called during a forced threadpool shutdown, and if a callable with 3 arguments is set, we now also pass the status code (#2203)
         | 
| 11 11 | 
             
              * Faster phased restart and worker timeout (#2220)
         | 
| 12 12 | 
             
              * Added `state_permission` to config DSL to set state file permissions (#2238)
         | 
| 13 13 | 
             
              * Added `Puma.stats_hash`, which returns a stats in Hash instead of a JSON string (#2086, #2253)
         | 
| 14 | 
            +
              * `rack.multithread` and `rack.multiprocess` now dynamically resolved by `max_thread` and `workers` respectively (#2288)
         | 
| 14 15 |  | 
| 15 16 | 
             
            * Deprecations, Removals and Breaking API Changes
         | 
| 16 17 | 
             
              * `--control` has been removed. Use `--control-url` (#1487)
         | 
| @@ -24,8 +25,12 @@ | |
| 24 25 | 
             
              * Daemonization has been removed without replacement. (#2170)
         | 
| 25 26 | 
             
              * Changed #connected_port to #connected_ports (#2076)
         | 
| 26 27 | 
             
              * Configuration: `environment` is read from `RAILS_ENV`, if `RACK_ENV` can't be found (#2022)
         | 
| 28 | 
            +
              * Log binding on http:// for TCP bindings to make it clickable
         | 
| 27 29 |  | 
| 28 30 | 
             
            * Bugfixes
         | 
| 31 | 
            +
              * Fix JSON loading issues on phased-restarts (#2269)
         | 
| 32 | 
            +
              * Improve shutdown reliability (#2312, #2338)
         | 
| 33 | 
            +
              * Close client http connections made to an ssl server with TLSv1.3 (#2116)
         | 
| 29 34 | 
             
              * Do not set user_config to quiet by default to allow for file config (#2074)
         | 
| 30 35 | 
             
              * Always close SSL connection in Puma::ControlCLI (#2211)
         | 
| 31 36 | 
             
              * Windows update extconf.rb for use with ssp and varied Ruby/MSYS2 combinations (#2069)
         | 
| @@ -44,6 +49,15 @@ | |
| 44 49 | 
             
              * Fix `UserFileDefaultOptions#fetch` to properly use `default` (#2233)
         | 
| 45 50 | 
             
              * Improvements to `out_of_band` hook (#2234)
         | 
| 46 51 | 
             
              * Prefer the rackup file specified by the CLI (#2225)
         | 
| 52 | 
            +
              * Fix for spawning subprocesses with fork_worker option (#2267)
         | 
| 53 | 
            +
              * Set `CONTENT_LENGTH` for chunked requests (#2287)
         | 
| 54 | 
            +
              * JRuby - Add Puma::MiniSSL::Engine#init? and #teardown methods, run all SSL tests (#2317)
         | 
| 55 | 
            +
              * Improve shutdown reliability (#2312)
         | 
| 56 | 
            +
              * Resolve issue with threadpool waiting counter decrement when thread is killed
         | 
| 57 | 
            +
              * Constrain rake-compiler version to 0.9.4 to fix `ClassNotFound` exception when using MiniSSL with Java8.
         | 
| 58 | 
            +
              * Fix recursive `prune_bundler` (#2319).
         | 
| 59 | 
            +
              * Ensure that TCP_CORK is usable
         | 
| 60 | 
            +
              * Fix corner case when request body is chunked (#2326)
         | 
| 47 61 |  | 
| 48 62 | 
             
            * Refactor
         | 
| 49 63 | 
             
              * Remove unused loader argument from Plugin initializer (#2095)
         | 
| @@ -54,6 +68,14 @@ | |
| 54 68 | 
             
              * ThreadPool concurrency refactoring (#2220)
         | 
| 55 69 | 
             
              * JSON parse cluster worker stats instead of regex (#2124)
         | 
| 56 70 | 
             
              * Support parallel tests in verbose progress reporting (#2223)
         | 
| 71 | 
            +
              * Refactor error handling in server accept loop (#2239)
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            ## 4.3.4/4.3.5 and 3.12.5/3.12.6 / 2020-05-22
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            Each patchlevel release contains a separate security fix. We recommend simply upgrading to 4.3.5/3.12.6.
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            * Security
         | 
| 78 | 
            +
              * Fix: Fixed two separate HTTP smuggling vulnerabilities that used the Transfer-Encoding header. CVE-2020-11076 and CVE-2020-11077.
         | 
| 57 79 |  | 
| 58 80 | 
             
            ## 4.3.3 and 3.12.4 / 2020-02-28
         | 
| 59 81 |  | 
    
        data/README.md
    CHANGED
    
    | @@ -8,7 +8,7 @@ | |
| 8 8 |  | 
| 9 9 | 
             
            [](https://codeclimate.com/github/puma/puma)
         | 
| 10 10 | 
             
            [](https://dependabot.com/compatibility-score.html?dependency-name=puma&package-manager=bundler&version-scheme=semver)
         | 
| 11 | 
            -
            []( https://stackoverflow.com/questions/tagged/puma )
         | 
| 12 12 |  | 
| 13 13 | 
             
            Puma is a **simple, fast, multi-threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications**.
         | 
| 14 14 |  | 
| @@ -27,7 +27,7 @@ $ gem install puma | |
| 27 27 | 
             
            $ puma
         | 
| 28 28 | 
             
            ```
         | 
| 29 29 |  | 
| 30 | 
            -
            Without arguments, puma will look for a rackup (.ru) file in | 
| 30 | 
            +
            Without arguments, puma will look for a rackup (.ru) file in
         | 
| 31 31 | 
             
            working directory called `config.ru`.
         | 
| 32 32 |  | 
| 33 33 | 
             
            ## Frameworks
         | 
| @@ -135,7 +135,7 @@ Preloading can’t be used with phased restart, since phased restart kills and r | |
| 135 135 | 
             
            If puma encounters an error outside of the context of your application, it will respond with a 500 and a simple
         | 
| 136 136 | 
             
            textual error message (see `lowlevel_error` in [this file](https://github.com/puma/puma/blob/master/lib/puma/server.rb)).
         | 
| 137 137 | 
             
            You can specify custom behavior for this scenario. For example, you can report the error to your third-party
         | 
| 138 | 
            -
            error-tracking service (in this example, [rollbar]( | 
| 138 | 
            +
            error-tracking service (in this example, [rollbar](https://rollbar.com)):
         | 
| 139 139 |  | 
| 140 140 | 
             
            ```ruby
         | 
| 141 141 | 
             
            lowlevel_error_handler do |e|
         | 
    
        data/docs/architecture.md
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            ## Overview
         | 
| 4 4 |  | 
| 5 | 
            -
            
         | 
| 6 6 |  | 
| 7 7 | 
             
            Puma is a threaded web server, processing requests across a TCP or UNIX socket.
         | 
| 8 8 |  | 
| @@ -12,7 +12,7 @@ Clustered mode is shown/discussed here. Single mode is analogous to having a sin | |
| 12 12 |  | 
| 13 13 | 
             
            ## Connection pipeline
         | 
| 14 14 |  | 
| 15 | 
            -
            
         | 
| 16 16 |  | 
| 17 17 | 
             
            * Upon startup, Puma listens on a TCP or UNIX socket.
         | 
| 18 18 | 
             
              * The backlog of this socket is configured (with a default of 1024), determining how many established but unaccepted connections can exist concurrently.
         | 
| @@ -29,7 +29,7 @@ Clustered mode is shown/discussed here. Single mode is analogous to having a sin | |
| 29 29 |  | 
| 30 30 | 
             
            ### Disabling `queue_requests`
         | 
| 31 31 |  | 
| 32 | 
            -
            
         | 
| 33 33 |  | 
| 34 34 | 
             
            The `queue_requests` option is `true` by default, enabling the separate thread used to buffer requests as described above.
         | 
| 35 35 |  | 
    
        data/docs/deployment.md
    CHANGED
    
    | @@ -20,7 +20,10 @@ Welcome back! | |
| 20 20 | 
             
            Puma was originally conceived as a thread-only webserver, but grew the ability to
         | 
| 21 21 | 
             
            also use processes in version 2.
         | 
| 22 22 |  | 
| 23 | 
            -
             | 
| 23 | 
            +
            To run puma in single mode (e.g. for a development environment) you will need to
         | 
| 24 | 
            +
            set the number of workers to 0, anything above will run in cluster mode.
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            Here are some rules of thumb for cluster mode:
         | 
| 24 27 |  | 
| 25 28 | 
             
            ### MRI
         | 
| 26 29 |  | 
| @@ -66,7 +69,8 @@ thread to become available. | |
| 66 69 |  | 
| 67 70 | 
             
            * Have your upstream proxy set a header with the time it received the request:
         | 
| 68 71 | 
             
                * nginx: `proxy_set_header X-Request-Start "${msec}";`
         | 
| 69 | 
            -
                * haproxy: `http-request set-header X-Request-Start  | 
| 72 | 
            +
                * haproxy >= 1.9: `http-request set-header X-Request-Start t=%[date()]%[date_us()]`
         | 
| 73 | 
            +
                * haproxy < 1.9: `http-request set-header X-Request-Start t=%[date()]`
         | 
| 70 74 | 
             
            * In your Rack middleware, determine the amount of time elapsed since `X-Request-Start`.
         | 
| 71 75 | 
             
            * To improve accuracy, you will want to subtract time spent waiting for slow clients:
         | 
| 72 76 | 
             
                * `env['puma.request_body_wait']` contains the number of milliseconds Puma spent
         | 
    
        data/docs/signals.md
    CHANGED
    
    | @@ -1,8 +1,8 @@ | |
| 1 | 
            -
            The [unix signal]( | 
| 1 | 
            +
            The [unix signal](https://en.wikipedia.org/wiki/Unix_signal) is a method of sending messages between [processes](https://en.wikipedia.org/wiki/Process_(computing)). When a signal is sent, the operating system interrupts the target process's normal flow of execution. There are standard signals that are used to stop a process but there are also custom signals that can be used for other purposes. This document is an attempt to list all supported signals that Puma will respond to. In general, signals need only be sent to the master process of a cluster.
         | 
| 2 2 |  | 
| 3 3 | 
             
            ## Sending Signals
         | 
| 4 4 |  | 
| 5 | 
            -
            If you are new to signals it can be useful to see how they can be used. When a process is created in a *nix like operating system it will have a [PID - or process identifier]( | 
| 5 | 
            +
            If you are new to signals it can be useful to see how they can be used. When a process is created in a *nix like operating system it will have a [PID - or process identifier](https://en.wikipedia.org/wiki/Process_identifier) that can be used to send signals to the process. For demonstration we will create an infinitely running process by tailing a file:
         | 
| 6 6 |  | 
| 7 7 | 
             
            ```sh
         | 
| 8 8 | 
             
            $ echo "foo" >> my.log
         | 
| @@ -17,13 +17,13 @@ $ ps aux | grep tail | |
| 17 17 | 
             
            schneems        87152   0.0  0.0  2432772    492 s032  S+   12:46PM   0:00.00 tail -f my.log
         | 
| 18 18 | 
             
            ```
         | 
| 19 19 |  | 
| 20 | 
            -
            You can send a signal in Ruby using the [Process module]( | 
| 20 | 
            +
            You can send a signal in Ruby using the [Process module](https://www.ruby-doc.org/core-2.1.1/Process.html#kill-method):
         | 
| 21 21 |  | 
| 22 22 | 
             
            ```
         | 
| 23 23 | 
             
            $ irb
         | 
| 24 24 | 
             
            > puts pid
         | 
| 25 25 | 
             
            => 87152
         | 
| 26 | 
            -
            Process.detach(pid) #  | 
| 26 | 
            +
            Process.detach(pid) # https://ruby-doc.org/core-2.1.1/Process.html#method-c-detach
         | 
| 27 27 | 
             
            Process.kill("TERM", pid)
         | 
| 28 28 | 
             
            ```
         | 
| 29 29 |  | 
| @@ -14,12 +14,14 @@ | |
| 14 14 |  | 
| 15 15 | 
             
            /*
         | 
| 16 16 | 
             
             * capitalizes all lower-case ASCII characters,
         | 
| 17 | 
            -
             * converts dashes to underscores.
         | 
| 17 | 
            +
             * converts dashes to underscores, and underscores to commas.
         | 
| 18 18 | 
             
             */
         | 
| 19 19 | 
             
            static void snake_upcase_char(char *c)
         | 
| 20 20 | 
             
            {
         | 
| 21 21 | 
             
                if (*c >= 'a' && *c <= 'z')
         | 
| 22 22 | 
             
                  *c &= ~0x20;
         | 
| 23 | 
            +
                else if (*c == '_')
         | 
| 24 | 
            +
                  *c = ',';
         | 
| 23 25 | 
             
                else if (*c == '-')
         | 
| 24 26 | 
             
                  *c = '_';
         | 
| 25 27 | 
             
            }
         | 
| @@ -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 | 
             
            }
         | 
    
        data/ext/puma_http11/mini_ssl.c
    CHANGED
    
    | @@ -301,6 +301,7 @@ void raise_error(SSL* ssl, int result) { | |
| 301 301 | 
             
              char msg[512];
         | 
| 302 302 | 
             
              const char* err_str;
         | 
| 303 303 | 
             
              int err = errno;
         | 
| 304 | 
            +
              int mask = 4095;
         | 
| 304 305 | 
             
              int ssl_err = SSL_get_error(ssl, result);
         | 
| 305 306 | 
             
              int verify_err = (int) SSL_get_verify_result(ssl);
         | 
| 306 307 |  | 
| @@ -317,8 +318,8 @@ void raise_error(SSL* ssl, int result) { | |
| 317 318 | 
             
                } else {
         | 
| 318 319 | 
             
                  err = (int) ERR_get_error();
         | 
| 319 320 | 
             
                  ERR_error_string_n(err, buf, sizeof(buf));
         | 
| 320 | 
            -
                   | 
| 321 | 
            -
             | 
| 321 | 
            +
                  int errexp = err & mask;
         | 
| 322 | 
            +
                  snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, errexp);
         | 
| 322 323 | 
             
                }
         | 
| 323 324 | 
             
              } else {
         | 
| 324 325 | 
             
                snprintf(msg, sizeof(msg), "Unknown OpenSSL error: %d", ssl_err);
         | 
| @@ -462,6 +463,13 @@ VALUE engine_peercert(VALUE self) { | |
| 462 463 | 
             
              return rb_cert_buf;
         | 
| 463 464 | 
             
            }
         | 
| 464 465 |  | 
| 466 | 
            +
            static VALUE
         | 
| 467 | 
            +
            engine_ssl_vers_st(VALUE self) {
         | 
| 468 | 
            +
              ms_conn* conn;
         | 
| 469 | 
            +
              Data_Get_Struct(self, ms_conn, conn);
         | 
| 470 | 
            +
              return rb_ary_new3(2, rb_str_new2(SSL_get_version(conn->ssl)), rb_str_new2(SSL_state_string(conn->ssl)));
         | 
| 471 | 
            +
            }
         | 
| 472 | 
            +
             | 
| 465 473 | 
             
            VALUE noop(VALUE self) {
         | 
| 466 474 | 
             
              return Qnil;
         | 
| 467 475 | 
             
            }
         | 
| @@ -533,6 +541,8 @@ void Init_mini_ssl(VALUE puma) { | |
| 533 541 | 
             
              rb_define_method(eng, "init?", engine_init, 0);
         | 
| 534 542 |  | 
| 535 543 | 
             
              rb_define_method(eng, "peercert", engine_peercert, 0);
         | 
| 544 | 
            +
             | 
| 545 | 
            +
              rb_define_method(eng, "ssl_vers_st", engine_ssl_vers_st, 0);
         | 
| 536 546 | 
             
            }
         | 
| 537 547 |  | 
| 538 548 | 
             
            #else
         | 
| @@ -120,6 +120,8 @@ public class MiniSSL extends RubyObject { | |
| 120 120 | 
             
              }
         | 
| 121 121 |  | 
| 122 122 | 
             
              private SSLEngine engine;
         | 
| 123 | 
            +
              private boolean closed;
         | 
| 124 | 
            +
              private boolean handshake;
         | 
| 123 125 | 
             
              private MiniSSLBuffer inboundNetData;
         | 
| 124 126 | 
             
              private MiniSSLBuffer outboundAppData;
         | 
| 125 127 | 
             
              private MiniSSLBuffer outboundNetData;
         | 
| @@ -157,6 +159,8 @@ public class MiniSSL extends RubyObject { | |
| 157 159 | 
             
                SSLContext sslCtx = SSLContext.getInstance("TLS");
         | 
| 158 160 |  | 
| 159 161 | 
             
                sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
         | 
| 162 | 
            +
                closed = false;
         | 
| 163 | 
            +
                handshake = false;
         | 
| 160 164 | 
             
                engine = sslCtx.createSSLEngine();
         | 
| 161 165 |  | 
| 162 166 | 
             
                String[] protocols;
         | 
| @@ -173,7 +177,7 @@ public class MiniSSL extends RubyObject { | |
| 173 177 | 
             
                engine.setEnabledProtocols(protocols);
         | 
| 174 178 | 
             
                engine.setUseClientMode(false);
         | 
| 175 179 |  | 
| 176 | 
            -
                long verify_mode = miniSSLContext.callMethod(threadContext, "verify_mode").convertToInteger().getLongValue();
         | 
| 180 | 
            +
                long verify_mode = miniSSLContext.callMethod(threadContext, "verify_mode").convertToInteger("to_i").getLongValue();
         | 
| 177 181 | 
             
                if ((verify_mode & 0x1) != 0) { // 'peer'
         | 
| 178 182 | 
             
                    engine.setWantClientAuth(true);
         | 
| 179 183 | 
             
                }
         | 
| @@ -240,14 +244,21 @@ public class MiniSSL extends RubyObject { | |
| 240 244 | 
             
                      // need to wait for more data to come in before we retry
         | 
| 241 245 | 
             
                      retryOp = false;
         | 
| 242 246 | 
             
                      break;
         | 
| 247 | 
            +
                    case CLOSED:
         | 
| 248 | 
            +
                      closed = true;
         | 
| 249 | 
            +
                      retryOp = false;
         | 
| 250 | 
            +
                      break;
         | 
| 243 251 | 
             
                    default:
         | 
| 244 | 
            -
                      // other  | 
| 252 | 
            +
                      // other case is OK.  We're done here.
         | 
| 245 253 | 
             
                      retryOp = false;
         | 
| 246 254 | 
             
                  }
         | 
| 255 | 
            +
                  if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) {
         | 
| 256 | 
            +
                    handshake = true;
         | 
| 257 | 
            +
                  }
         | 
| 247 258 | 
             
                }
         | 
| 248 259 |  | 
| 249 260 | 
             
                // after each op, run any delegated tasks if needed
         | 
| 250 | 
            -
                if( | 
| 261 | 
            +
                if(res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
         | 
| 251 262 | 
             
                  Runnable runnable;
         | 
| 252 263 | 
             
                  while ((runnable = engine.getDelegatedTask()) != null) {
         | 
| 253 264 | 
             
                    runnable.run();
         | 
| @@ -271,13 +282,14 @@ public class MiniSSL extends RubyObject { | |
| 271 282 |  | 
| 272 283 | 
             
                  HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
         | 
| 273 284 | 
             
                  boolean done = false;
         | 
| 285 | 
            +
                  SSLEngineResult res = null;
         | 
| 274 286 | 
             
                  while (!done) {
         | 
| 275 287 | 
             
                    switch (handshakeStatus) {
         | 
| 276 288 | 
             
                      case NEED_WRAP:
         | 
| 277 | 
            -
                        doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
         | 
| 289 | 
            +
                        res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
         | 
| 278 290 | 
             
                        break;
         | 
| 279 291 | 
             
                      case NEED_UNWRAP:
         | 
| 280 | 
            -
                         | 
| 292 | 
            +
                        res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
         | 
| 281 293 | 
             
                        if (res.getStatus() == Status.BUFFER_UNDERFLOW) {
         | 
| 282 294 | 
             
                          // need more data before we can shake more hands
         | 
| 283 295 | 
             
                          done = true;
         | 
| @@ -286,7 +298,9 @@ public class MiniSSL extends RubyObject { | |
| 286 298 | 
             
                      default:
         | 
| 287 299 | 
             
                        done = true;
         | 
| 288 300 | 
             
                    }
         | 
| 289 | 
            -
                     | 
| 301 | 
            +
                    if (!done) {
         | 
| 302 | 
            +
                      handshakeStatus = res.getHandshakeStatus();
         | 
| 303 | 
            +
                    }
         | 
| 290 304 | 
             
                  }
         | 
| 291 305 |  | 
| 292 306 | 
             
                  if (inboundNetData.hasRemaining()) {
         | 
| @@ -360,4 +374,21 @@ public class MiniSSL extends RubyObject { | |
| 360 374 | 
             
                  return getRuntime().getNil();
         | 
| 361 375 | 
             
                }
         | 
| 362 376 | 
             
              }
         | 
| 377 | 
            +
             | 
| 378 | 
            +
              @JRubyMethod(name = "init?")
         | 
| 379 | 
            +
              public IRubyObject isInit(ThreadContext context) {
         | 
| 380 | 
            +
                return handshake ? getRuntime().getFalse() : getRuntime().getTrue();
         | 
| 381 | 
            +
              }
         | 
| 382 | 
            +
             | 
| 383 | 
            +
              @JRubyMethod
         | 
| 384 | 
            +
              public IRubyObject shutdown() {
         | 
| 385 | 
            +
                if (closed || engine.isInboundDone() && engine.isOutboundDone()) {
         | 
| 386 | 
            +
                  if (engine.isOutboundDone()) {
         | 
| 387 | 
            +
                    engine.closeOutbound();
         | 
| 388 | 
            +
                  }
         | 
| 389 | 
            +
                  return getRuntime().getTrue();
         | 
| 390 | 
            +
                } else {
         | 
| 391 | 
            +
                  return getRuntime().getFalse();
         | 
| 392 | 
            +
                }
         | 
| 393 | 
            +
              }
         | 
| 363 394 | 
             
            }
         | 
| @@ -54,7 +54,7 @@ DEF_MAX_LENGTH(FIELD_NAME, 256); | |
| 54 54 | 
             
            DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
         | 
| 55 55 | 
             
            DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
         | 
| 56 56 | 
             
            DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
         | 
| 57 | 
            -
            DEF_MAX_LENGTH(REQUEST_PATH,  | 
| 57 | 
            +
            DEF_MAX_LENGTH(REQUEST_PATH, 8192);
         | 
| 58 58 | 
             
            DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
         | 
| 59 59 | 
             
            DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
         | 
| 60 60 |  | 
    
        data/lib/puma.rb
    CHANGED
    
    
    
        data/lib/puma/app/status.rb
    CHANGED
    
    | @@ -1,7 +1,5 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require 'json'
         | 
| 4 | 
            -
             | 
| 5 3 | 
             
            module Puma
         | 
| 6 4 | 
             
              module App
         | 
| 7 5 | 
             
                # Check out {#call}'s source code to see what actions this web application
         | 
| @@ -19,6 +17,10 @@ module Puma | |
| 19 17 | 
             
                      return rack_response(403, 'Invalid auth token', 'text/plain')
         | 
| 20 18 | 
             
                    end
         | 
| 21 19 |  | 
| 20 | 
            +
                    if env['PATH_INFO'] =~ /\/(gc-stats|stats|thread-backtraces)$/
         | 
| 21 | 
            +
                      require 'json'
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
             | 
| 22 24 | 
             
                    case env['PATH_INFO']
         | 
| 23 25 | 
             
                    when /\/stop$/
         | 
| 24 26 | 
             
                      @cli.stop
         | 
    
        data/lib/puma/binder.rb
    CHANGED
    
    | @@ -6,6 +6,7 @@ require 'socket' | |
| 6 6 | 
             
            require 'puma/const'
         | 
| 7 7 | 
             
            require 'puma/util'
         | 
| 8 8 | 
             
            require 'puma/minissl/context_builder'
         | 
| 9 | 
            +
            require 'puma/configuration'
         | 
| 9 10 |  | 
| 10 11 | 
             
            module Puma
         | 
| 11 12 | 
             
              class Binder
         | 
| @@ -13,7 +14,7 @@ module Puma | |
| 13 14 |  | 
| 14 15 | 
             
                RACK_VERSION = [1,6].freeze
         | 
| 15 16 |  | 
| 16 | 
            -
                def initialize(events)
         | 
| 17 | 
            +
                def initialize(events, conf = Configuration.new)
         | 
| 17 18 | 
             
                  @events = events
         | 
| 18 19 | 
             
                  @listeners = []
         | 
| 19 20 | 
             
                  @inherited_fds = {}
         | 
| @@ -23,8 +24,8 @@ module Puma | |
| 23 24 | 
             
                  @proto_env = {
         | 
| 24 25 | 
             
                    "rack.version".freeze => RACK_VERSION,
         | 
| 25 26 | 
             
                    "rack.errors".freeze => events.stderr,
         | 
| 26 | 
            -
                    "rack.multithread".freeze =>  | 
| 27 | 
            -
                    "rack.multiprocess".freeze =>  | 
| 27 | 
            +
                    "rack.multithread".freeze => conf.options[:max_threads] > 1,
         | 
| 28 | 
            +
                    "rack.multiprocess".freeze => conf.options[:workers] >= 1,
         | 
| 28 29 | 
             
                    "rack.run_once".freeze => false,
         | 
| 29 30 | 
             
                    "SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",
         | 
| 30 31 |  | 
| @@ -113,7 +114,7 @@ module Puma | |
| 113 114 | 
             
                            i.local_address.ip_unpack.join(':')
         | 
| 114 115 | 
             
                          end
         | 
| 115 116 |  | 
| 116 | 
            -
                          logger.log "* #{log_msg} on  | 
| 117 | 
            +
                          logger.log "* #{log_msg} on http://#{addr}"
         | 
| 117 118 | 
             
                        end
         | 
| 118 119 | 
             
                      end
         | 
| 119 120 |  | 
    
        data/lib/puma/client.rb
    CHANGED
    
    | @@ -308,8 +308,16 @@ module Puma | |
| 308 308 |  | 
| 309 309 | 
             
                  te = @env[TRANSFER_ENCODING2]
         | 
| 310 310 |  | 
| 311 | 
            -
                  if te | 
| 312 | 
            -
                     | 
| 311 | 
            +
                  if te
         | 
| 312 | 
            +
                    if te.include?(",")
         | 
| 313 | 
            +
                      te.split(",").each do |part|
         | 
| 314 | 
            +
                        if CHUNKED.casecmp(part.strip) == 0
         | 
| 315 | 
            +
                          return setup_chunked_body(body)
         | 
| 316 | 
            +
                        end
         | 
| 317 | 
            +
                      end
         | 
| 318 | 
            +
                    elsif CHUNKED.casecmp(te) == 0
         | 
| 319 | 
            +
                      return setup_chunked_body(body)
         | 
| 320 | 
            +
                    end
         | 
| 313 321 | 
             
                  end
         | 
| 314 322 |  | 
| 315 323 | 
             
                  @chunked_body = false
         | 
| @@ -412,7 +420,10 @@ module Puma | |
| 412 420 | 
             
                      raise EOFError
         | 
| 413 421 | 
             
                    end
         | 
| 414 422 |  | 
| 415 | 
            -
                     | 
| 423 | 
            +
                    if decode_chunk(chunk)
         | 
| 424 | 
            +
                      @env[CONTENT_LENGTH] = @chunked_content_length
         | 
| 425 | 
            +
                      return true
         | 
| 426 | 
            +
                    end
         | 
| 416 427 | 
             
                  end
         | 
| 417 428 | 
             
                end
         | 
| 418 429 |  | 
| @@ -424,20 +435,36 @@ module Puma | |
| 424 435 | 
             
                  @body = Tempfile.new(Const::PUMA_TMP_BASE)
         | 
| 425 436 | 
             
                  @body.binmode
         | 
| 426 437 | 
             
                  @tempfile = @body
         | 
| 438 | 
            +
                  @chunked_content_length = 0
         | 
| 439 | 
            +
             | 
| 440 | 
            +
                  if decode_chunk(body)
         | 
| 441 | 
            +
                    @env[CONTENT_LENGTH] = @chunked_content_length
         | 
| 442 | 
            +
                    return true
         | 
| 443 | 
            +
                  end
         | 
| 444 | 
            +
                end
         | 
| 427 445 |  | 
| 428 | 
            -
             | 
| 446 | 
            +
                def write_chunk(str)
         | 
| 447 | 
            +
                  @chunked_content_length += @body.write(str)
         | 
| 429 448 | 
             
                end
         | 
| 430 449 |  | 
| 431 450 | 
             
                def decode_chunk(chunk)
         | 
| 432 451 | 
             
                  if @partial_part_left > 0
         | 
| 433 452 | 
             
                    if @partial_part_left <= chunk.size
         | 
| 434 453 | 
             
                      if @partial_part_left > 2
         | 
| 435 | 
            -
                         | 
| 454 | 
            +
                        write_chunk(chunk[0..(@partial_part_left-3)]) # skip the \r\n
         | 
| 436 455 | 
             
                      end
         | 
| 437 456 | 
             
                      chunk = chunk[@partial_part_left..-1]
         | 
| 438 457 | 
             
                      @partial_part_left = 0
         | 
| 439 458 | 
             
                    else
         | 
| 440 | 
            -
                       | 
| 459 | 
            +
                      if @partial_part_left > 2
         | 
| 460 | 
            +
                        if @partial_part_left == chunk.size + 1
         | 
| 461 | 
            +
                          # Don't include the last \r
         | 
| 462 | 
            +
                          write_chunk(chunk[0..(@partial_part_left-3)])
         | 
| 463 | 
            +
                        else
         | 
| 464 | 
            +
                          # don't include the last \r\n
         | 
| 465 | 
            +
                          write_chunk(chunk)
         | 
| 466 | 
            +
                        end
         | 
| 467 | 
            +
                      end
         | 
| 441 468 | 
             
                      @partial_part_left -= chunk.size
         | 
| 442 469 | 
             
                      return false
         | 
| 443 470 | 
             
                    end
         | 
| @@ -484,12 +511,12 @@ module Puma | |
| 484 511 |  | 
| 485 512 | 
             
                      case
         | 
| 486 513 | 
             
                      when got == len
         | 
| 487 | 
            -
                         | 
| 514 | 
            +
                        write_chunk(part[0..-3]) # to skip the ending \r\n
         | 
| 488 515 | 
             
                      when got <= len - 2
         | 
| 489 | 
            -
                         | 
| 516 | 
            +
                        write_chunk(part)
         | 
| 490 517 | 
             
                        @partial_part_left = len - part.size
         | 
| 491 518 | 
             
                      when got == len - 1 # edge where we get just \r but not \n
         | 
| 492 | 
            -
                         | 
| 519 | 
            +
                        write_chunk(part[0..-2])
         | 
| 493 520 | 
             
                        @partial_part_left = len - part.size
         | 
| 494 521 | 
             
                      end
         | 
| 495 522 | 
             
                    else
         |