puma 5.6.4-java → 6.0.0-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 +136 -3
- 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/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/extconf.rb +18 -10
- 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 +63 -24
- 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 +166 -65
- data/ext/puma_http11/puma_http11.c +17 -9
- data/lib/puma/app/status.rb +6 -3
- data/lib/puma/binder.rb +37 -43
- data/lib/puma/cli.rb +11 -17
- data/lib/puma/client.rb +22 -12
- 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 +21 -18
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +94 -49
- data/lib/puma/error_logger.rb +17 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +29 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +107 -156
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +23 -12
- data/lib/puma/minissl.rb +91 -15
- data/lib/puma/null_io.rb +5 -0
- 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 +3 -3
- data/lib/puma/request.rb +291 -156
- data/lib/puma/runner.rb +41 -20
- data/lib/puma/server.rb +53 -64
- data/lib/puma/single.rb +10 -10
- data/lib/puma/state_file.rb +2 -4
- data/lib/puma/systemd.rb +3 -2
- data/lib/puma/thread_pool.rb +16 -13
- data/lib/puma/util.rb +12 -14
- data/lib/puma.rb +11 -8
- data/lib/rack/handler/puma.rb +9 -9
- metadata +7 -3
- data/lib/puma/queue_close.rb +0 -26
| @@ -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
         | 
| @@ -39,6 +39,9 @@ module Puma | |
| 39 39 | 
             
                      when 'phased-restart'
         | 
| 40 40 | 
             
                        @launcher.phased_restart ? 200 : 404
         | 
| 41 41 |  | 
| 42 | 
            +
                      when 'refork'
         | 
| 43 | 
            +
                        @launcher.refork ? 200 : 404
         | 
| 44 | 
            +
             | 
| 42 45 | 
             
                      when 'reload-worker-directory'
         | 
| 43 46 | 
             
                        @launcher.send(:reload_worker_directory) ? 200 : 404
         | 
| 44 47 |  | 
| @@ -82,8 +85,8 @@ module Puma | |
| 82 85 |  | 
| 83 86 | 
             
                  def rack_response(status, body, content_type='application/json')
         | 
| 84 87 | 
             
                    headers = {
         | 
| 85 | 
            -
                      ' | 
| 86 | 
            -
                      ' | 
| 88 | 
            +
                      'content-type' => content_type,
         | 
| 89 | 
            +
                      'content-length' => body.bytesize.to_s
         | 
| 87 90 | 
             
                    }
         | 
| 88 91 |  | 
| 89 92 | 
             
                    [status, headers, [body]]
         | 
    
        data/lib/puma/binder.rb
    CHANGED
    
    | @@ -3,24 +3,15 @@ | |
| 3 3 | 
             
            require 'uri'
         | 
| 4 4 | 
             
            require 'socket'
         | 
| 5 5 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 6 | 
            +
            require_relative 'const'
         | 
| 7 | 
            +
            require_relative 'util'
         | 
| 8 | 
            +
            require_relative 'configuration'
         | 
| 9 9 |  | 
| 10 10 | 
             
            module Puma
         | 
| 11 11 |  | 
| 12 12 | 
             
              if HAS_SSL
         | 
| 13 | 
            -
                 | 
| 14 | 
            -
                 | 
| 15 | 
            -
             | 
| 16 | 
            -
                # Odd bug in 'pure Ruby' nio4r version 2.5.2, which installs with Ruby 2.3.
         | 
| 17 | 
            -
                # NIO doesn't create any OpenSSL objects, but it rescues an OpenSSL error.
         | 
| 18 | 
            -
                # The bug was that it did not require openssl.
         | 
| 19 | 
            -
                # @todo remove when Ruby 2.3 support is dropped
         | 
| 20 | 
            -
                #
         | 
| 21 | 
            -
                if windows? && RbConfig::CONFIG['ruby_version'] == '2.3.0'
         | 
| 22 | 
            -
                  require 'openssl'
         | 
| 23 | 
            -
                end
         | 
| 13 | 
            +
                require_relative 'minissl'
         | 
| 14 | 
            +
                require_relative 'minissl/context_builder'
         | 
| 24 15 | 
             
              end
         | 
| 25 16 |  | 
| 26 17 | 
             
              class Binder
         | 
| @@ -28,8 +19,8 @@ module Puma | |
| 28 19 |  | 
| 29 20 | 
             
                RACK_VERSION = [1,6].freeze
         | 
| 30 21 |  | 
| 31 | 
            -
                def initialize( | 
| 32 | 
            -
                  @ | 
| 22 | 
            +
                def initialize(log_writer, conf = Configuration.new)
         | 
| 23 | 
            +
                  @log_writer = log_writer
         | 
| 33 24 | 
             
                  @conf = conf
         | 
| 34 25 | 
             
                  @listeners = []
         | 
| 35 26 | 
             
                  @inherited_fds = {}
         | 
| @@ -38,7 +29,7 @@ module Puma | |
| 38 29 |  | 
| 39 30 | 
             
                  @proto_env = {
         | 
| 40 31 | 
             
                    "rack.version".freeze => RACK_VERSION,
         | 
| 41 | 
            -
                    "rack.errors".freeze =>  | 
| 32 | 
            +
                    "rack.errors".freeze => log_writer.stderr,
         | 
| 42 33 | 
             
                    "rack.multithread".freeze => conf.options[:max_threads] > 1,
         | 
| 43 34 | 
             
                    "rack.multiprocess".freeze => conf.options[:workers] >= 1,
         | 
| 44 35 | 
             
                    "rack.run_once".freeze => false,
         | 
| @@ -51,7 +42,6 @@ module Puma | |
| 51 42 | 
             
                    # infer properly.
         | 
| 52 43 |  | 
| 53 44 | 
             
                    "QUERY_STRING".freeze => "",
         | 
| 54 | 
            -
                    SERVER_PROTOCOL => HTTP_11,
         | 
| 55 45 | 
             
                    SERVER_SOFTWARE => PUMA_SERVER_STRING,
         | 
| 56 46 | 
             
                    GATEWAY_INTERFACE => CGI_VER
         | 
| 57 47 | 
             
                  }
         | 
| @@ -80,7 +70,7 @@ module Puma | |
| 80 70 | 
             
                # @!attribute [r] connected_ports
         | 
| 81 71 | 
             
                # @version 5.0.0
         | 
| 82 72 | 
             
                def connected_ports
         | 
| 83 | 
            -
                  ios.map { |io| io.addr[1] }.uniq
         | 
| 73 | 
            +
                  t = ios.map { |io| io.addr[1] }; t.uniq!; t
         | 
| 84 74 | 
             
                end
         | 
| 85 75 |  | 
| 86 76 | 
             
                # @version 5.0.0
         | 
| @@ -98,7 +88,7 @@ module Puma | |
| 98 88 | 
             
                # @version 5.0.0
         | 
| 99 89 | 
             
                #
         | 
| 100 90 | 
             
                def create_activated_fds(env_hash)
         | 
| 101 | 
            -
                  @ | 
| 91 | 
            +
                  @log_writer.debug "ENV['LISTEN_FDS'] #{ENV['LISTEN_FDS'].inspect}  env_hash['LISTEN_PID'] #{env_hash['LISTEN_PID'].inspect}"
         | 
| 102 92 | 
             
                  return [] unless env_hash['LISTEN_FDS'] && env_hash['LISTEN_PID'].to_i == $$
         | 
| 103 93 | 
             
                  env_hash['LISTEN_FDS'].to_i.times do |index|
         | 
| 104 94 | 
             
                    sock = TCPServer.for_fd(socket_activation_fd(index))
         | 
| @@ -106,11 +96,11 @@ module Puma | |
| 106 96 | 
             
                      [:unix, Socket.unpack_sockaddr_un(sock.getsockname)]
         | 
| 107 97 | 
             
                    rescue ArgumentError # Try to parse as a port/ip
         | 
| 108 98 | 
             
                      port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
         | 
| 109 | 
            -
                      addr = "[#{addr}]" if addr  | 
| 99 | 
            +
                      addr = "[#{addr}]" if addr&.include? ':'
         | 
| 110 100 | 
             
                      [:tcp, addr, port]
         | 
| 111 101 | 
             
                    end
         | 
| 112 102 | 
             
                    @activated_sockets[key] = sock
         | 
| 113 | 
            -
                    @ | 
| 103 | 
            +
                    @log_writer.debug "Registered #{key.join ':'} for activation from LISTEN_FDS"
         | 
| 114 104 | 
             
                  end
         | 
| 115 105 | 
             
                  ["LISTEN_FDS", "LISTEN_PID"] # Signal to remove these keys from ENV
         | 
| 116 106 | 
             
                end
         | 
| @@ -152,17 +142,18 @@ module Puma | |
| 152 142 | 
             
                  end
         | 
| 153 143 | 
             
                end
         | 
| 154 144 |  | 
| 155 | 
            -
                def parse(binds,  | 
| 145 | 
            +
                def parse(binds, log_writer = nil, log_msg = 'Listening')
         | 
| 146 | 
            +
                  log_writer ||= @log_writer
         | 
| 156 147 | 
             
                  binds.each do |str|
         | 
| 157 148 | 
             
                    uri = URI.parse str
         | 
| 158 149 | 
             
                    case uri.scheme
         | 
| 159 150 | 
             
                    when "tcp"
         | 
| 160 151 | 
             
                      if fd = @inherited_fds.delete(str)
         | 
| 161 152 | 
             
                        io = inherit_tcp_listener uri.host, uri.port, fd
         | 
| 162 | 
            -
                         | 
| 153 | 
            +
                        log_writer.log "* Inherited #{str}"
         | 
| 163 154 | 
             
                      elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
         | 
| 164 155 | 
             
                        io = inherit_tcp_listener uri.host, uri.port, sock
         | 
| 165 | 
            -
                         | 
| 156 | 
            +
                        log_writer.log "* Activated #{str}"
         | 
| 166 157 | 
             
                      else
         | 
| 167 158 | 
             
                        ios_len = @ios.length
         | 
| 168 159 | 
             
                        params = Util.parse_query uri.query
         | 
| @@ -174,7 +165,7 @@ module Puma | |
| 174 165 |  | 
| 175 166 | 
             
                        @ios[ios_len..-1].each do |i|
         | 
| 176 167 | 
             
                          addr = loc_addr_str i
         | 
| 177 | 
            -
                           | 
| 168 | 
            +
                          log_writer.log "* #{log_msg} on http://#{addr}"
         | 
| 178 169 | 
             
                        end
         | 
| 179 170 | 
             
                      end
         | 
| 180 171 |  | 
| @@ -189,14 +180,14 @@ module Puma | |
| 189 180 | 
             
                      end
         | 
| 190 181 |  | 
| 191 182 | 
             
                      if fd = @inherited_fds.delete(str)
         | 
| 192 | 
            -
                        @unix_paths << path unless abstract
         | 
| 183 | 
            +
                        @unix_paths << path unless abstract || File.exist?(path)
         | 
| 193 184 | 
             
                        io = inherit_unix_listener path, fd
         | 
| 194 | 
            -
                         | 
| 185 | 
            +
                        log_writer.log "* Inherited #{str}"
         | 
| 195 186 | 
             
                      elsif sock = @activated_sockets.delete([ :unix, path ]) ||
         | 
| 196 187 | 
             
                          @activated_sockets.delete([ :unix, File.realdirpath(path) ])
         | 
| 197 188 | 
             
                        @unix_paths << path unless abstract || File.exist?(path)
         | 
| 198 189 | 
             
                        io = inherit_unix_listener path, sock
         | 
| 199 | 
            -
                         | 
| 190 | 
            +
                        log_writer.log "* Activated #{str}"
         | 
| 200 191 | 
             
                      else
         | 
| 201 192 | 
             
                        umask = nil
         | 
| 202 193 | 
             
                        mode = nil
         | 
| @@ -220,11 +211,12 @@ module Puma | |
| 220 211 |  | 
| 221 212 | 
             
                        @unix_paths << path unless abstract || File.exist?(path)
         | 
| 222 213 | 
             
                        io = add_unix_listener path, umask, mode, backlog
         | 
| 223 | 
            -
                         | 
| 214 | 
            +
                        log_writer.log "* #{log_msg} on #{str}"
         | 
| 224 215 | 
             
                      end
         | 
| 225 216 |  | 
| 226 217 | 
             
                      @listeners << [str, io]
         | 
| 227 218 | 
             
                    when "ssl"
         | 
| 219 | 
            +
                      cert_key = %w[cert key]
         | 
| 228 220 |  | 
| 229 221 | 
             
                      raise "Puma compiled without SSL support" unless HAS_SSL
         | 
| 230 222 |  | 
| @@ -233,28 +225,29 @@ module Puma | |
| 233 225 | 
             
                      # If key and certs are not defined and localhost gem is required.
         | 
| 234 226 | 
             
                      # localhost gem will be used for self signed
         | 
| 235 227 | 
             
                      # Load localhost authority if not loaded.
         | 
| 236 | 
            -
                       | 
| 228 | 
            +
                      # Ruby 3 `values_at` accepts an array, earlier do not
         | 
| 229 | 
            +
                      if params.values_at(*cert_key).all? { |v| v.to_s.empty? }
         | 
| 237 230 | 
             
                        ctx = localhost_authority && localhost_authority_context
         | 
| 238 231 | 
             
                      end
         | 
| 239 232 |  | 
| 240 233 | 
             
                      ctx ||=
         | 
| 241 234 | 
             
                        begin
         | 
| 242 235 | 
             
                          # Extract cert_pem and key_pem from options[:store] if present
         | 
| 243 | 
            -
                           | 
| 244 | 
            -
                            if params[v] | 
| 236 | 
            +
                          cert_key.each do |v|
         | 
| 237 | 
            +
                            if params[v]&.start_with?('store:')
         | 
| 245 238 | 
             
                              index = Integer(params.delete(v).split('store:').last)
         | 
| 246 239 | 
             
                              params["#{v}_pem"] = @conf.options[:store][index]
         | 
| 247 240 | 
             
                            end
         | 
| 248 241 | 
             
                          end
         | 
| 249 | 
            -
                          MiniSSL::ContextBuilder.new(params, @ | 
| 242 | 
            +
                          MiniSSL::ContextBuilder.new(params, @log_writer).context
         | 
| 250 243 | 
             
                        end
         | 
| 251 244 |  | 
| 252 245 | 
             
                      if fd = @inherited_fds.delete(str)
         | 
| 253 | 
            -
                         | 
| 246 | 
            +
                        log_writer.log "* Inherited #{str}"
         | 
| 254 247 | 
             
                        io = inherit_ssl_listener fd, ctx
         | 
| 255 248 | 
             
                      elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
         | 
| 256 249 | 
             
                        io = inherit_ssl_listener sock, ctx
         | 
| 257 | 
            -
                         | 
| 250 | 
            +
                        log_writer.log "* Activated #{str}"
         | 
| 258 251 | 
             
                      else
         | 
| 259 252 | 
             
                        ios_len = @ios.length
         | 
| 260 253 | 
             
                        backlog = params.fetch('backlog', 1024).to_i
         | 
| @@ -262,20 +255,20 @@ module Puma | |
| 262 255 |  | 
| 263 256 | 
             
                        @ios[ios_len..-1].each do |i|
         | 
| 264 257 | 
             
                          addr = loc_addr_str i
         | 
| 265 | 
            -
                           | 
| 258 | 
            +
                          log_writer.log "* #{log_msg} on ssl://#{addr}?#{uri.query}"
         | 
| 266 259 | 
             
                        end
         | 
| 267 260 | 
             
                      end
         | 
| 268 261 |  | 
| 269 262 | 
             
                      @listeners << [str, io] if io
         | 
| 270 263 | 
             
                    else
         | 
| 271 | 
            -
                       | 
| 264 | 
            +
                      log_writer.error "Invalid URI: #{str}"
         | 
| 272 265 | 
             
                    end
         | 
| 273 266 | 
             
                  end
         | 
| 274 267 |  | 
| 275 268 | 
             
                  # If we inherited fds but didn't use them (because of a
         | 
| 276 269 | 
             
                  # configuration change), then be sure to close them.
         | 
| 277 270 | 
             
                  @inherited_fds.each do |str, fd|
         | 
| 278 | 
            -
                     | 
| 271 | 
            +
                    log_writer.log "* Closing unused inherited connection: #{str}"
         | 
| 279 272 |  | 
| 280 273 | 
             
                    begin
         | 
| 281 274 | 
             
                      IO.for_fd(fd).close
         | 
| @@ -295,7 +288,7 @@ module Puma | |
| 295 288 | 
             
                    fds = @ios.map(&:to_i)
         | 
| 296 289 | 
             
                    @activated_sockets.each do |key, sock|
         | 
| 297 290 | 
             
                      next if fds.include? sock.to_i
         | 
| 298 | 
            -
                       | 
| 291 | 
            +
                      log_writer.log "* Closing unused activated socket: #{key.first}://#{key[1..-1].join ':'}"
         | 
| 299 292 | 
             
                      begin
         | 
| 300 293 | 
             
                        sock.close
         | 
| 301 294 | 
             
                      rescue SystemCallError
         | 
| @@ -319,7 +312,7 @@ module Puma | |
| 319 312 | 
             
                    local_certificates_path = File.expand_path("~/.localhost")
         | 
| 320 313 | 
             
                    [File.join(local_certificates_path, "localhost.key"), File.join(local_certificates_path, "localhost.crt")]
         | 
| 321 314 | 
             
                  end
         | 
| 322 | 
            -
                  MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @ | 
| 315 | 
            +
                  MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @log_writer).context
         | 
| 323 316 | 
             
                end
         | 
| 324 317 |  | 
| 325 318 | 
             
                # Tell the server to listen on host +host+, port +port+.
         | 
| @@ -482,9 +475,10 @@ module Puma | |
| 482 475 |  | 
| 483 476 | 
             
                # @!attribute [r] loopback_addresses
         | 
| 484 477 | 
             
                def loopback_addresses
         | 
| 485 | 
            -
                  Socket.ip_address_list.select do |addrinfo|
         | 
| 478 | 
            +
                  t = Socket.ip_address_list.select do |addrinfo|
         | 
| 486 479 | 
             
                    addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
         | 
| 487 | 
            -
                  end | 
| 480 | 
            +
                  end
         | 
| 481 | 
            +
                  t.map! { |addrinfo| addrinfo.ip_address }; t.uniq!; t
         | 
| 488 482 | 
             
                end
         | 
| 489 483 |  | 
| 490 484 | 
             
                def loc_addr_str(io)
         | 
    
        data/lib/puma/cli.rb
    CHANGED
    
    | @@ -3,11 +3,11 @@ | |
| 3 3 | 
             
            require 'optparse'
         | 
| 4 4 | 
             
            require 'uri'
         | 
| 5 5 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 6 | 
            +
            require_relative '../puma'
         | 
| 7 | 
            +
            require_relative 'configuration'
         | 
| 8 | 
            +
            require_relative 'launcher'
         | 
| 9 | 
            +
            require_relative 'const'
         | 
| 10 | 
            +
            require_relative 'log_writer'
         | 
| 11 11 |  | 
| 12 12 | 
             
            module Puma
         | 
| 13 13 | 
             
              class << self
         | 
| @@ -21,19 +21,13 @@ module Puma | |
| 21 21 | 
             
              # Handles invoke a Puma::Server in a command line style.
         | 
| 22 22 | 
             
              #
         | 
| 23 23 | 
             
              class CLI
         | 
| 24 | 
            -
                # @deprecated 6.0.0
         | 
| 25 | 
            -
                KEYS_NOT_TO_PERSIST_IN_STATE = Launcher::KEYS_NOT_TO_PERSIST_IN_STATE
         | 
| 26 | 
            -
             | 
| 27 24 | 
             
                # Create a new CLI object using +argv+ as the command line
         | 
| 28 25 | 
             
                # arguments.
         | 
| 29 26 | 
             
                #
         | 
| 30 | 
            -
                 | 
| 31 | 
            -
                # this object will report status on.
         | 
| 32 | 
            -
                #
         | 
| 33 | 
            -
                def initialize(argv, events=Events.stdio)
         | 
| 27 | 
            +
                def initialize(argv, log_writer = LogWriter.stdio, events = Events.new)
         | 
| 34 28 | 
             
                  @debug = false
         | 
| 35 29 | 
             
                  @argv = argv.dup
         | 
| 36 | 
            -
             | 
| 30 | 
            +
                  @log_writer = log_writer
         | 
| 37 31 | 
             
                  @events = events
         | 
| 38 32 |  | 
| 39 33 | 
             
                  @conf = nil
         | 
| @@ -69,7 +63,7 @@ module Puma | |
| 69 63 | 
             
                    end
         | 
| 70 64 | 
             
                  end
         | 
| 71 65 |  | 
| 72 | 
            -
                  @launcher = Puma::Launcher.new(@conf, :events => @events, :argv => argv)
         | 
| 66 | 
            +
                  @launcher = Puma::Launcher.new(@conf, :log_writer => @log_writer, :events => @events, :argv => argv)
         | 
| 73 67 | 
             
                end
         | 
| 74 68 |  | 
| 75 69 | 
             
                attr_reader :launcher
         | 
| @@ -83,7 +77,7 @@ module Puma | |
| 83 77 |  | 
| 84 78 | 
             
                private
         | 
| 85 79 | 
             
                def unsupported(str)
         | 
| 86 | 
            -
                  @ | 
| 80 | 
            +
                  @log_writer.error(str)
         | 
| 87 81 | 
             
                  raise UnsupportedOption
         | 
| 88 82 | 
             
                end
         | 
| 89 83 |  | 
| @@ -152,7 +146,7 @@ module Puma | |
| 152 146 |  | 
| 153 147 | 
             
                      o.on "-p", "--port PORT", "Define the TCP port to bind to",
         | 
| 154 148 | 
             
                        "Use -b for more advanced options" do |arg|
         | 
| 155 | 
            -
                        user_config.bind "tcp://#{Configuration:: | 
| 149 | 
            +
                        user_config.bind "tcp://#{Configuration::DEFAULTS[:tcp_host]}:#{arg}"
         | 
| 156 150 | 
             
                      end
         | 
| 157 151 |  | 
| 158 152 | 
             
                      o.on "--pidfile PATH", "Use PATH as a pidfile" do |arg|
         | 
| @@ -186,7 +180,7 @@ module Puma | |
| 186 180 | 
             
                      end
         | 
| 187 181 |  | 
| 188 182 | 
             
                      o.on "-s", "--silent", "Do not log prompt messages other than errors" do
         | 
| 189 | 
            -
                        @ | 
| 183 | 
            +
                        @log_writer = LogWriter.new(NullIO.new, $stderr)
         | 
| 190 184 | 
             
                      end
         | 
| 191 185 |  | 
| 192 186 | 
             
                      o.on "-S", "--state PATH", "Where to store the state details" do |arg|
         | 
    
        data/lib/puma/client.rb
    CHANGED
    
    | @@ -8,7 +8,7 @@ class IO | |
| 8 8 | 
             
              end
         | 
| 9 9 | 
             
            end
         | 
| 10 10 |  | 
| 11 | 
            -
             | 
| 11 | 
            +
            require_relative 'detect'
         | 
| 12 12 | 
             
            require 'tempfile'
         | 
| 13 13 | 
             
            require 'forwardable'
         | 
| 14 14 |  | 
| @@ -25,6 +25,9 @@ module Puma | |
| 25 25 |  | 
| 26 26 | 
             
              class HttpParserError501 < IOError; end
         | 
| 27 27 |  | 
| 28 | 
            +
              #———————————————————————— DO NOT USE — this class is for internal use only ———
         | 
| 29 | 
            +
             | 
| 30 | 
            +
             | 
| 28 31 | 
             
              # An instance of this class represents a unique request from a client.
         | 
| 29 32 | 
             
              # For example, this could be a web request from a browser or from CURL.
         | 
| 30 33 | 
             
              #
         | 
| @@ -38,7 +41,7 @@ module Puma | |
| 38 41 | 
             
              # the header and body are fully buffered via the `try_to_finish` method.
         | 
| 39 42 | 
             
              # They can be used to "time out" a response via the `timeout_at` reader.
         | 
| 40 43 | 
             
              #
         | 
| 41 | 
            -
              class Client
         | 
| 44 | 
            +
              class Client # :nodoc:
         | 
| 42 45 |  | 
| 43 46 | 
             
                # this tests all values but the last, which must be chunked
         | 
| 44 47 | 
             
                ALLOWED_TRANSFER_ENCODING = %w[compress deflate gzip].freeze
         | 
| @@ -63,11 +66,7 @@ module Puma | |
| 63 66 | 
             
                  @io = io
         | 
| 64 67 | 
             
                  @to_io = io.to_io
         | 
| 65 68 | 
             
                  @proto_env = env
         | 
| 66 | 
            -
                   | 
| 67 | 
            -
                    @env = nil
         | 
| 68 | 
            -
                  else
         | 
| 69 | 
            -
                    @env = env.dup
         | 
| 70 | 
            -
                  end
         | 
| 69 | 
            +
                  @env = env ? env.dup : nil
         | 
| 71 70 |  | 
| 72 71 | 
             
                  @parser = HttpParser.new
         | 
| 73 72 | 
             
                  @parsed_bytes = 0
         | 
| @@ -86,6 +85,7 @@ module Puma | |
| 86 85 | 
             
                  @hijacked = false
         | 
| 87 86 |  | 
| 88 87 | 
             
                  @peerip = nil
         | 
| 88 | 
            +
                  @peer_family = nil
         | 
| 89 89 | 
             
                  @listener = nil
         | 
| 90 90 | 
             
                  @remote_addr_header = nil
         | 
| 91 91 | 
             
                  @expect_proxy_proto = false
         | 
| @@ -273,7 +273,7 @@ module Puma | |
| 273 273 | 
             
                  return @peerip if @peerip
         | 
| 274 274 |  | 
| 275 275 | 
             
                  if @remote_addr_header
         | 
| 276 | 
            -
                    hdr = (@env[@remote_addr_header] ||  | 
| 276 | 
            +
                    hdr = (@env[@remote_addr_header] || @io.peeraddr.last).split(/[\s,]/).first
         | 
| 277 277 | 
             
                    @peerip = hdr
         | 
| 278 278 | 
             
                    return hdr
         | 
| 279 279 | 
             
                  end
         | 
| @@ -281,6 +281,16 @@ module Puma | |
| 281 281 | 
             
                  @peerip ||= @io.peeraddr.last
         | 
| 282 282 | 
             
                end
         | 
| 283 283 |  | 
| 284 | 
            +
                def peer_family
         | 
| 285 | 
            +
                  return @peer_family if @peer_family
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                  @peer_family ||= begin
         | 
| 288 | 
            +
                                     @io.local_address.afamily
         | 
| 289 | 
            +
                                   rescue
         | 
| 290 | 
            +
                                     Socket::AF_INET
         | 
| 291 | 
            +
                                   end
         | 
| 292 | 
            +
                end
         | 
| 293 | 
            +
             | 
| 284 294 | 
             
                # Returns true if the persistent connection can be closed immediately
         | 
| 285 295 | 
             
                # without waiting for the configured idle/shutdown timeout.
         | 
| 286 296 | 
             
                # @version 5.0.0
         | 
| @@ -304,7 +314,7 @@ module Puma | |
| 304 314 | 
             
                private
         | 
| 305 315 |  | 
| 306 316 | 
             
                def setup_body
         | 
| 307 | 
            -
                  @body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, : | 
| 317 | 
            +
                  @body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
         | 
| 308 318 |  | 
| 309 319 | 
             
                  if @env[HTTP_EXPECT] == CONTINUE
         | 
| 310 320 | 
             
                    # TODO allow a hook here to check the headers before
         | 
| @@ -348,7 +358,7 @@ module Puma | |
| 348 358 |  | 
| 349 359 | 
             
                  if cl
         | 
| 350 360 | 
             
                    # cannot contain characters that are not \d
         | 
| 351 | 
            -
                    if cl | 
| 361 | 
            +
                    if CONTENT_LENGTH_VALUE_INVALID.match? cl
         | 
| 352 362 | 
             
                      raise HttpParserError, "Invalid Content-Length: #{cl.inspect}"
         | 
| 353 363 | 
             
                    end
         | 
| 354 364 | 
             
                  else
         | 
| @@ -513,7 +523,7 @@ module Puma | |
| 513 523 | 
             
                      # Puma doesn't process chunk extensions, but should parse if they're
         | 
| 514 524 | 
             
                      # present, which is the reason for the semicolon regex
         | 
| 515 525 | 
             
                      chunk_hex = line.strip[/\A[^;]+/]
         | 
| 516 | 
            -
                      if chunk_hex | 
| 526 | 
            +
                      if CHUNK_SIZE_INVALID.match? chunk_hex
         | 
| 517 527 | 
             
                        raise HttpParserError, "Invalid chunk size: '#{chunk_hex}'"
         | 
| 518 528 | 
             
                      end
         | 
| 519 529 | 
             
                      len = chunk_hex.to_i(16)
         | 
| @@ -576,7 +586,7 @@ module Puma | |
| 576 586 |  | 
| 577 587 | 
             
                def set_ready
         | 
| 578 588 | 
             
                  if @body_read_start
         | 
| 579 | 
            -
                    @env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, : | 
| 589 | 
            +
                    @env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - @body_read_start
         | 
| 580 590 | 
             
                  end
         | 
| 581 591 | 
             
                  @requests_served += 1
         | 
| 582 592 | 
             
                  @ready = true
         | 
    
        data/lib/puma/cluster/worker.rb
    CHANGED
    
    | @@ -2,27 +2,29 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module Puma
         | 
| 4 4 | 
             
              class Cluster < Puma::Runner
         | 
| 5 | 
            +
                #—————————————————————— DO NOT USE — this class is for internal use only ———
         | 
| 6 | 
            +
             | 
| 7 | 
            +
             | 
| 5 8 | 
             
                # This class is instantiated by the `Puma::Cluster` and represents a single
         | 
| 6 9 | 
             
                # worker process.
         | 
| 7 10 | 
             
                #
         | 
| 8 11 | 
             
                # At the core of this class is running an instance of `Puma::Server` which
         | 
| 9 12 | 
             
                # gets created via the `start_server` method from the `Puma::Runner` class
         | 
| 10 13 | 
             
                # that this inherits from.
         | 
| 11 | 
            -
                class Worker < Puma::Runner
         | 
| 14 | 
            +
                class Worker < Puma::Runner # :nodoc:
         | 
| 12 15 | 
             
                  attr_reader :index, :master
         | 
| 13 16 |  | 
| 14 17 | 
             
                  def initialize(index:, master:, launcher:, pipes:, server: nil)
         | 
| 15 | 
            -
                    super | 
| 18 | 
            +
                    super(launcher)
         | 
| 16 19 |  | 
| 17 20 | 
             
                    @index = index
         | 
| 18 21 | 
             
                    @master = master
         | 
| 19 | 
            -
                    @launcher = launcher
         | 
| 20 | 
            -
                    @options = launcher.options
         | 
| 21 22 | 
             
                    @check_pipe = pipes[:check_pipe]
         | 
| 22 23 | 
             
                    @worker_write = pipes[:worker_write]
         | 
| 23 24 | 
             
                    @fork_pipe = pipes[:fork_pipe]
         | 
| 24 25 | 
             
                    @wakeup = pipes[:wakeup]
         | 
| 25 26 | 
             
                    @server = server
         | 
| 27 | 
            +
                    @hook_data = {}
         | 
| 26 28 | 
             
                  end
         | 
| 27 29 |  | 
| 28 30 | 
             
                  def run
         | 
| @@ -52,13 +54,14 @@ module Puma | |
| 52 54 |  | 
| 53 55 | 
             
                    # Invoke any worker boot hooks so they can get
         | 
| 54 56 | 
             
                    # things in shape before booting the app.
         | 
| 55 | 
            -
                    @ | 
| 57 | 
            +
                    @config.run_hooks(:before_worker_boot, index, @log_writer, @hook_data)
         | 
| 56 58 |  | 
| 57 59 | 
             
                    begin
         | 
| 58 60 | 
             
                    server = @server ||= start_server
         | 
| 59 61 | 
             
                    rescue Exception => e
         | 
| 60 62 | 
             
                      log "! Unable to start worker"
         | 
| 61 | 
            -
                      log e | 
| 63 | 
            +
                      log e
         | 
| 64 | 
            +
                      log e.backtrace.join("\n    ")
         | 
| 62 65 | 
             
                      exit 1
         | 
| 63 66 | 
             
                    end
         | 
| 64 67 |  | 
| @@ -83,8 +86,7 @@ module Puma | |
| 83 86 | 
             
                            if restart_server.length > 0
         | 
| 84 87 | 
             
                              restart_server.clear
         | 
| 85 88 | 
             
                              server.begin_restart(true)
         | 
| 86 | 
            -
                              @ | 
| 87 | 
            -
                              Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
         | 
| 89 | 
            +
                              @config.run_hooks(:before_refork, nil, @log_writer, @hook_data)
         | 
| 88 90 | 
             
                            end
         | 
| 89 91 | 
             
                          elsif idx == 0 # restart server
         | 
| 90 92 | 
             
                            restart_server << true << false
         | 
| @@ -138,7 +140,7 @@ module Puma | |
| 138 140 |  | 
| 139 141 | 
             
                    # Invoke any worker shutdown hooks so they can prevent the worker
         | 
| 140 142 | 
             
                    # exiting until any background operations are completed
         | 
| 141 | 
            -
                    @ | 
| 143 | 
            +
                    @config.run_hooks(:before_worker_shutdown, index, @log_writer, @hook_data)
         | 
| 142 144 | 
             
                  ensure
         | 
| 143 145 | 
             
                    @worker_write << "t#{Process.pid}\n" rescue nil
         | 
| 144 146 | 
             
                    @worker_write.close
         | 
| @@ -147,7 +149,7 @@ module Puma | |
| 147 149 | 
             
                  private
         | 
| 148 150 |  | 
| 149 151 | 
             
                  def spawn_worker(idx)
         | 
| 150 | 
            -
                    @ | 
| 152 | 
            +
                    @config.run_hooks(:before_worker_fork, idx, @log_writer, @hook_data)
         | 
| 151 153 |  | 
| 152 154 | 
             
                    pid = fork do
         | 
| 153 155 | 
             
                      new_worker = Worker.new index: idx,
         | 
| @@ -165,7 +167,7 @@ module Puma | |
| 165 167 | 
             
                      exit! 1
         | 
| 166 168 | 
             
                    end
         | 
| 167 169 |  | 
| 168 | 
            -
                    @ | 
| 170 | 
            +
                    @config.run_hooks(:after_worker_fork, idx, @log_writer, @hook_data)
         | 
| 169 171 | 
             
                    pid
         | 
| 170 172 | 
             
                  end
         | 
| 171 173 | 
             
                end
         | 
| @@ -2,12 +2,15 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module Puma
         | 
| 4 4 | 
             
              class Cluster < Runner
         | 
| 5 | 
            +
                #—————————————————————— DO NOT USE — this class is for internal use only ———
         | 
| 6 | 
            +
             | 
| 7 | 
            +
             | 
| 5 8 | 
             
                # This class represents a worker process from the perspective of the puma
         | 
| 6 9 | 
             
                # master process. It contains information about the process and its health
         | 
| 7 10 | 
             
                # and it exposes methods to control the process via IPC. It does not
         | 
| 8 11 | 
             
                # include the actual logic executed by the worker process itself. For that,
         | 
| 9 12 | 
             
                # see Puma::Cluster::Worker.
         | 
| 10 | 
            -
                class WorkerHandle
         | 
| 13 | 
            +
                class WorkerHandle # :nodoc:
         | 
| 11 14 | 
             
                  def initialize(idx, pid, phase, options)
         | 
| 12 15 | 
             
                    @index = idx
         | 
| 13 16 | 
             
                    @pid = pid
         |