From c60bd0395c5b7466bda22b4de64ca82fed1803b9 Mon Sep 17 00:00:00 2001 From: Atul Bhosale Date: Tue, 11 Jun 2019 17:19:18 +0530 Subject: [PATCH 01/13] Remove known bugs section from README.md [skip ci] --- README.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/README.md b/README.md index 3bd0c5e6b8..d37fef6a66 100644 --- a/README.md +++ b/README.md @@ -238,19 +238,6 @@ Some platforms do not support all Puma features. * **JRuby**, **Windows**: server sockets are not seamless on restart, they must be closed and reopened. These platforms have no way to pass descriptors into a new process that is exposed to Ruby. Also, cluster mode is not supported due to a lack of fork(2). * **Windows**: daemon mode is not supported due to a lack of fork(2). -## Known Bugs - -For MRI versions 2.2.7, 2.2.8, 2.2.9, 2.2.10 2.3.4 and 2.4.1, you may see ```stream closed in another thread (IOError)```. It may be caused by a [Ruby bug](https://bugs.ruby-lang.org/issues/13632). It can be fixed with the gem https://rubygems.org/gems/stopgap_13632: - -```ruby -if %w(2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1).include? RUBY_VERSION - begin - require 'stopgap_13632' - rescue LoadError - end -end -``` - ## Deployment Puma has support for Capistrano with an [external gem](https://github.com/seuros/capistrano-puma). From 81201a176ea2e61e76130a4ce35125e6e17b24eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Burgos=20Maci=C3=A1?= Date: Tue, 11 Jun 2019 17:06:25 -0400 Subject: [PATCH 02/13] Updates docs, removes refs. to IO.select() [ci skip] --- lib/puma/client.rb | 7 ++++--- lib/puma/reactor.rb | 32 ++++++++++++++++---------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/puma/client.rb b/lib/puma/client.rb index 5084e3254e..0aa4425e5a 100644 --- a/lib/puma/client.rb +++ b/lib/puma/client.rb @@ -27,9 +27,10 @@ class ConnectionError < RuntimeError; end # For example a web request from a browser or from CURL. This # # An instance of `Puma::Client` can be used as if it were an IO object - # for example it is passed into `IO.select` inside of the `Puma::Reactor`. - # This is accomplished by the `to_io` method which gets called on any - # non-IO objects being used with the IO api such as `IO.select. + # by the reactor, that's because the latter is expected to call `#to_io` + # on any non-IO objects it polls. For example nio4r internally calls + # `IO::try_convert` (which may call `#to_io`) when a new socket is + # registered. # # Instances of this class are responsible for knowing if # the header and body are fully buffered via the `try_to_finish` method. diff --git a/lib/puma/reactor.rb b/lib/puma/reactor.rb index f4ec92ee83..a6245f52fb 100644 --- a/lib/puma/reactor.rb +++ b/lib/puma/reactor.rb @@ -20,10 +20,11 @@ module Puma # # ## Reactor Flow # - # A request comes into a `Puma::Server` instance, it is then passed to a `Puma::Reactor` instance. - # The reactor stores the request in an array and calls `IO.select` on the array in a loop. + # A connection comes into a `Puma::Server` instance, it is then passed to a `Puma::Reactor` instance, + # which stores it in an array and waits for any of the connections to be ready for reading. # - # When the request is written to by the client then the `IO.select` will "wake up" and + # The waiting/wake up is performed with nio4r, which will use the apropriate backend (libev, Java NIO or + # just plain IO#select). The call to `NIO::Selector#select` (hereinafter `select()`) will "wake up" and # return the references to any objects that caused it to "wake". The reactor # then loops through each of these request objects, and sees if they're complete. If they # have a full header and body then the reactor passes the request to a thread pool. @@ -69,19 +70,18 @@ def initialize(server, app_pool) private - # Until a request is added via the `add` method this method will internally # loop, waiting on the `sockets` array objects. The only object in this # array at first is the `@ready` IO object, which is the read end of a pipe # connected to `@trigger` object. When `@trigger` is written to, then the loop - # will break on `IO.select` and return an array. + # will break on `select()` and return an array. # # ## When a request is added: # # When the `add` method is called, an instance of `Puma::Client` is added to the `@input` array. # Next the `@ready` pipe is "woken" by writing a string of `"*"` to `@trigger`. # - # When that happens, the internal loop stops blocking at `IO.select` and returns a reference + # When that happens, the internal loop stops blocking at `select()` and returns a reference # to whatever "woke" it up. On the very first loop, the only thing in `sockets` is `@ready`. # When `@trigger` is written-to, the loop "wakes" and the `ready` # variable returns an array of arrays that looks like `[[#], [], []]` where the @@ -97,7 +97,7 @@ def initialize(server, app_pool) # to the `@ready` IO object. For example: `[#, #]`. # # Since the `Puma::Client` in this example has data that has not been read yet, - # the `IO.select` is immediately able to "wake" and read from the `Puma::Client`. At this point the + # the `select()` is immediately able to "wake" and read from the `Puma::Client`. At this point the # `ready` output looks like this: `[[#], [], []]`. # # Each element in the first entry is iterated over. The `Puma::Client` object is not @@ -109,12 +109,12 @@ def initialize(server, app_pool) # # If the request body is not present then nothing will happen, and the loop will iterate # again. When the client sends more data to the socket the `Puma::Client` object will - # wake up the `IO.select` and it can again be checked to see if it's ready to be + # wake up the `select()` and it can again be checked to see if it's ready to be # passed to the thread pool. # # ## Time Out Case # - # In addition to being woken via a write to one of the sockets the `IO.select` will + # In addition to being woken via a write to one of the sockets the `select()` will # periodically "time out" of the sleep. One of the functions of this is to check for # any requests that have "timed out". At the end of the loop it's checked to see if # the first element in the `@timeout` array has exceed its allowed time. If so, @@ -124,7 +124,7 @@ def initialize(server, app_pool) # # This behavior loops until all the objects that have timed out have been removed. # - # Once all the timeouts have been processed, the next duration of the `IO.select` sleep + # Once all the timeouts have been processed, the next duration of the `select()` sleep # will be set to be equal to the amount of time it will take for the next timeout to occur. # This calculation happens in `calculate_sleep`. def run_internal @@ -320,7 +320,7 @@ def run_in_thread end end - # The `calculate_sleep` sets the value that the `IO.select` will + # The `calculate_sleep` sets the value that the `select()` will # sleep for in the main reactor loop when no sockets are being written to. # # The values kept in `@timeouts` are sorted so that the first timeout @@ -351,18 +351,18 @@ def calculate_sleep # object. # # The main body of the reactor loop is in `run_internal` and it - # will sleep on `IO.select`. When a new connection is added to the + # will sleep on `select()`. When a new connection is added to the # reactor it cannot be added directly to the `sockets` array, because - # the `IO.select` will not be watching for it yet. + # the `select()` will not be watching for it yet. # - # Instead what needs to happen is that `IO.select` needs to be woken up, + # Instead what needs to happen is that `select()` needs to be woken up, # the contents of `@input` added to the `sockets` array, and then - # another call to `IO.select` needs to happen. Since the `Puma::Client` + # another call to `select()` needs to happen. Since the `Puma::Client` # object can be read immediately, it does not block, but instead returns # right away. # # This behavior is accomplished by writing to `@trigger` which wakes up - # the `IO.select` and then there is logic to detect the value of `*`, + # the `select()` and then there is logic to detect the value of `*`, # pull the contents from `@input` and add them to the sockets array. # # If the object passed in has a timeout value in `timeout_at` then From 7b0c13486acc17a9c52c25a461f857d67c96af80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Burgos=20Maci=C3=A1?= Date: Tue, 11 Jun 2019 18:54:32 -0400 Subject: [PATCH 03/13] Explicitly say that we use NIO's `#select` method [ci skip] --- lib/puma/reactor.rb | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/puma/reactor.rb b/lib/puma/reactor.rb index a6245f52fb..0d419cfd0c 100644 --- a/lib/puma/reactor.rb +++ b/lib/puma/reactor.rb @@ -24,7 +24,7 @@ module Puma # which stores it in an array and waits for any of the connections to be ready for reading. # # The waiting/wake up is performed with nio4r, which will use the apropriate backend (libev, Java NIO or - # just plain IO#select). The call to `NIO::Selector#select` (hereinafter `select()`) will "wake up" and + # just plain IO#select). The call to `NIO::Selector#select` will "wake up" and # return the references to any objects that caused it to "wake". The reactor # then loops through each of these request objects, and sees if they're complete. If they # have a full header and body then the reactor passes the request to a thread pool. @@ -74,14 +74,14 @@ def initialize(server, app_pool) # loop, waiting on the `sockets` array objects. The only object in this # array at first is the `@ready` IO object, which is the read end of a pipe # connected to `@trigger` object. When `@trigger` is written to, then the loop - # will break on `select()` and return an array. + # will break on `NIO::Selector#select` and return an array. # # ## When a request is added: # # When the `add` method is called, an instance of `Puma::Client` is added to the `@input` array. # Next the `@ready` pipe is "woken" by writing a string of `"*"` to `@trigger`. # - # When that happens, the internal loop stops blocking at `select()` and returns a reference + # When that happens, the internal loop stops blocking at `NIO::Selector#select` and returns a reference # to whatever "woke" it up. On the very first loop, the only thing in `sockets` is `@ready`. # When `@trigger` is written-to, the loop "wakes" and the `ready` # variable returns an array of arrays that looks like `[[#], [], []]` where the @@ -97,7 +97,7 @@ def initialize(server, app_pool) # to the `@ready` IO object. For example: `[#, #]`. # # Since the `Puma::Client` in this example has data that has not been read yet, - # the `select()` is immediately able to "wake" and read from the `Puma::Client`. At this point the + # the `NIO::Selector#select` is immediately able to "wake" and read from the `Puma::Client`. At this point the # `ready` output looks like this: `[[#], [], []]`. # # Each element in the first entry is iterated over. The `Puma::Client` object is not @@ -109,12 +109,12 @@ def initialize(server, app_pool) # # If the request body is not present then nothing will happen, and the loop will iterate # again. When the client sends more data to the socket the `Puma::Client` object will - # wake up the `select()` and it can again be checked to see if it's ready to be + # wake up the `NIO::Selector#select` and it can again be checked to see if it's ready to be # passed to the thread pool. # # ## Time Out Case # - # In addition to being woken via a write to one of the sockets the `select()` will + # In addition to being woken via a write to one of the sockets the `NIO::Selector#select` will # periodically "time out" of the sleep. One of the functions of this is to check for # any requests that have "timed out". At the end of the loop it's checked to see if # the first element in the `@timeout` array has exceed its allowed time. If so, @@ -124,7 +124,7 @@ def initialize(server, app_pool) # # This behavior loops until all the objects that have timed out have been removed. # - # Once all the timeouts have been processed, the next duration of the `select()` sleep + # Once all the timeouts have been processed, the next duration of the `NIO::Selector#select` sleep # will be set to be equal to the amount of time it will take for the next timeout to occur. # This calculation happens in `calculate_sleep`. def run_internal @@ -320,7 +320,7 @@ def run_in_thread end end - # The `calculate_sleep` sets the value that the `select()` will + # The `calculate_sleep` sets the value that the `NIO::Selector#select` will # sleep for in the main reactor loop when no sockets are being written to. # # The values kept in `@timeouts` are sorted so that the first timeout @@ -351,18 +351,18 @@ def calculate_sleep # object. # # The main body of the reactor loop is in `run_internal` and it - # will sleep on `select()`. When a new connection is added to the + # will sleep on `NIO::Selector#select`. When a new connection is added to the # reactor it cannot be added directly to the `sockets` array, because - # the `select()` will not be watching for it yet. + # the `NIO::Selector#select` will not be watching for it yet. # - # Instead what needs to happen is that `select()` needs to be woken up, + # Instead what needs to happen is that `NIO::Selector#select` needs to be woken up, # the contents of `@input` added to the `sockets` array, and then - # another call to `select()` needs to happen. Since the `Puma::Client` + # another call to `NIO::Selector#select` needs to happen. Since the `Puma::Client` # object can be read immediately, it does not block, but instead returns # right away. # # This behavior is accomplished by writing to `@trigger` which wakes up - # the `select()` and then there is logic to detect the value of `*`, + # the `NIO::Selector#select` and then there is logic to detect the value of `*`, # pull the contents from `@input` and add them to the sockets array. # # If the object passed in has a timeout value in `timeout_at` then From 0cd28f373a245eca4e717bff1415b97bbc2356d2 Mon Sep 17 00:00:00 2001 From: Richard Schneeman Date: Fri, 14 Jun 2019 14:00:54 -0500 Subject: [PATCH 04/13] Revert "[close #1811] Minimum Ruby version >= 2.5" --- .rubocop.yml | 2 +- .travis.yml | 9 ++++++++- History.md | 1 - lib/puma/binder.rb | 4 ++-- lib/puma/configuration.rb | 2 +- lib/puma/server.rb | 2 +- puma.gemspec | 5 +---- test/shell/t1.rb | 2 +- test/test_integration.rb | 2 +- test/test_persistent.rb | 2 +- win_gem_test/puma.ps1 | 2 +- 11 files changed, 18 insertions(+), 15 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index cfa17fa7bd..ca4bdf59dd 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,6 +1,6 @@ AllCops: DisabledByDefault: true - TargetRubyVersion: 2.5 + TargetRubyVersion: 2.2 DisplayCopNames: true StyleGuideCopsOnly: false Exclude: diff --git a/.travis.yml b/.travis.yml index db49344976..53302eab3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,8 @@ before_install: r_eng="$(ruby -e 'STDOUT.write RUBY_ENGINE')"; rv="$(ruby -e 'STDOUT.write RUBY_VERSION')"; if [ "$r_eng" == "ruby" ]; then - if [ "$rv" \< "2.6" ]; then gem update --system --no-document --conservative + if [ "$rv" \< "2.3" ]; then gem update --system 2.7.9 --no-document + elif [ "$rv" \< "2.6" ]; then gem update --system --no-document --conservative fi fi if [ "$TRAVIS_OS_NAME" == "osx" ]; then @@ -24,6 +25,9 @@ script: - bundle exec rake rvm: + - 2.2.10 + - 2.3.8 + - 2.4.6 - 2.5.5 - 2.6.3 - ruby-head @@ -33,6 +37,9 @@ matrix: include: - rvm: ruby-head env: RUBYOPT="--jit" + - rvm: 2.4.6 + os: osx + osx_image: xcode10.2 - rvm: 2.5.5 os: osx osx_image: xcode10.2 diff --git a/History.md b/History.md index 0914868ac1..b71b4cd049 100644 --- a/History.md +++ b/History.md @@ -9,7 +9,6 @@ * Add option to suppress SignalException on SIGTERM (#1690) * Allow mutual TLS CA to be set using `ssl_bind` DSL (#1689) * Reactor now uses nio4r instead of `select` (#1728) - * Minimum Ruby version now >= 2.5 (#1813) * x bugfixes * Do not accept new requests on shutdown (#1685, #1808) * Fix 3 corner cases when request body is chunked (#1508) diff --git a/lib/puma/binder.rb b/lib/puma/binder.rb index 34278cb223..42843b91b1 100644 --- a/lib/puma/binder.rb +++ b/lib/puma/binder.rb @@ -63,7 +63,7 @@ def import_from_env remove = [] ENV.each do |k,v| - if /PUMA_INHERIT_\d+/.match?(k) + if k =~ /PUMA_INHERIT_\d+/ fd, url = v.split(":", 2) @inherited_fds[url] = fd.to_i remove << k @@ -75,7 +75,7 @@ def import_from_env key = [ :unix, Socket.unpack_sockaddr_un(sock.getsockname) ] rescue ArgumentError port, addr = Socket.unpack_sockaddr_in(sock.getsockname) - if /\:/.match?(addr) + if addr =~ /\:/ addr = "[#{addr}]" end key = [ :tcp, addr, port ] diff --git a/lib/puma/configuration.rb b/lib/puma/configuration.rb index 877e3e0ed4..900a0105ee 100644 --- a/lib/puma/configuration.rb +++ b/lib/puma/configuration.rb @@ -348,7 +348,7 @@ def self.random_token end if bytes - token = +"" + token = "".dup bytes.each_byte { |b| token << b.to_s(16) } else token = (0..count).to_a.map { rand(255).to_s(16) }.join diff --git a/lib/puma/server.rb b/lib/puma/server.rb index 150458ec74..ac1e28674a 100644 --- a/lib/puma/server.rb +++ b/lib/puma/server.rb @@ -105,7 +105,7 @@ def tcp_mode! # On Linux, use TCP_CORK to better control how the TCP stack # packetizes our stream. This improves both latency and throughput. # - if RUBY_PLATFORM.match?(/linux/) + if RUBY_PLATFORM =~ /linux/ UNPACK_TCP_STATE_FROM_TCP_INFO = "C".freeze # 6 == Socket::IPPROTO_TCP diff --git a/puma.gemspec b/puma.gemspec index 49b1ae3cfb..b11ffec044 100644 --- a/puma.gemspec +++ b/puma.gemspec @@ -17,8 +17,5 @@ Gem::Specification.new do |s| %w[History.md LICENSE README.md] s.homepage = "http://puma.io" s.license = "BSD-3-Clause" - - # We will guarantee to support the last 2 major releases, - # and may choose to support further back as we see fit. - s.required_ruby_version = Gem::Requirement.new(">= 2.5") + s.required_ruby_version = Gem::Requirement.new(">= 2.2") end diff --git a/test/shell/t1.rb b/test/shell/t1.rb index 907a238e8c..25c523e426 100644 --- a/test/shell/t1.rb +++ b/test/shell/t1.rb @@ -11,7 +11,7 @@ File.unlink "t1-stdout" if File.file? "t1-stdout" File.unlink "t1-pid" if File.file? "t1-pid" -if %r!GET / HTTP/1\.1!.match?(log) +if log =~ %r!GET / HTTP/1\.1! exit 0 else exit 1 diff --git a/test/test_integration.rb b/test/test_integration.rb index 147d8c63a9..98522240fa 100644 --- a/test/test_integration.rb +++ b/test/test_integration.rb @@ -186,7 +186,7 @@ def test_phased_restart_via_pumactl until done @events.stdout.rewind log = @events.stdout.readlines.join("") - if /- Worker \d \(pid: \d+\) booted, phase: 1/.match?(log) + if log =~ /- Worker \d \(pid: \d+\) booted, phase: 1/ assert_match(/TERM sent/, log) assert_match(/- Worker \d \(pid: \d+\) booted, phase: 1/, log) done = true diff --git a/test/test_persistent.rb b/test/test_persistent.rb index 53539075ed..06ec90aa71 100644 --- a/test/test_persistent.rb +++ b/test/test_persistent.rb @@ -37,7 +37,7 @@ def teardown end def lines(count, s=@client) - str = +"" + str = "".dup Timeout.timeout(5) do count.times { str << s.gets } end diff --git a/win_gem_test/puma.ps1 b/win_gem_test/puma.ps1 index 71ad0480a5..60a6275353 100644 --- a/win_gem_test/puma.ps1 +++ b/win_gem_test/puma.ps1 @@ -13,7 +13,7 @@ Make-Const repo_name 'puma' Make-Const url_repo 'https://github.com/puma/puma.git' #———————————————————————————————————————————————————————————————— lowest ruby version -Make-Const ruby_vers_low 25 +Make-Const ruby_vers_low 22 # null = don't compile; false = compile, ignore test (allow failure); # true = compile & test Make-Const trunk $false ; Make-Const trunk_x64 $false From 10ce7e3dfa63b0f4ab5fb4d6ce64c524e0a3708b Mon Sep 17 00:00:00 2001 From: Richard Schneeman Date: Fri, 14 Jun 2019 14:01:34 -0500 Subject: [PATCH 05/13] Revert "Remove known bugs section from README.md" --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index d37fef6a66..3bd0c5e6b8 100644 --- a/README.md +++ b/README.md @@ -238,6 +238,19 @@ Some platforms do not support all Puma features. * **JRuby**, **Windows**: server sockets are not seamless on restart, they must be closed and reopened. These platforms have no way to pass descriptors into a new process that is exposed to Ruby. Also, cluster mode is not supported due to a lack of fork(2). * **Windows**: daemon mode is not supported due to a lack of fork(2). +## Known Bugs + +For MRI versions 2.2.7, 2.2.8, 2.2.9, 2.2.10 2.3.4 and 2.4.1, you may see ```stream closed in another thread (IOError)```. It may be caused by a [Ruby bug](https://bugs.ruby-lang.org/issues/13632). It can be fixed with the gem https://rubygems.org/gems/stopgap_13632: + +```ruby +if %w(2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1).include? RUBY_VERSION + begin + require 'stopgap_13632' + rescue LoadError + end +end +``` + ## Deployment Puma has support for Capistrano with an [external gem](https://github.com/seuros/capistrano-puma). From 5a2291ef1bc339138eecf6f736fb769c8c6891ac Mon Sep 17 00:00:00 2001 From: Laurent Arnoud Date: Mon, 24 Jun 2019 00:36:06 +0000 Subject: [PATCH 06/13] Add status to pumactl with pidfile (#1824) ref https://github.com/puma/puma/pull/1767 --- lib/puma/control_cli.rb | 10 ++++++++++ test/shell/t2.rb | 4 +++- test/test_pumactl.rb | 17 ++++++++++++----- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/lib/puma/control_cli.rb b/lib/puma/control_cli.rb index dc6fdce398..853b3da817 100644 --- a/lib/puma/control_cli.rb +++ b/lib/puma/control_cli.rb @@ -206,6 +206,16 @@ def send_signal when "phased-restart" Process.kill "SIGUSR1", @pid + when "status" + begin + Process.kill 0, @pid + puts "Puma is started" + rescue Errno::ESRCH + raise "Puma is not running" + end + + return + else return end diff --git a/test/shell/t2.rb b/test/shell/t2.rb index d48fc856cf..e173d9eb6f 100644 --- a/test/shell/t2.rb +++ b/test/shell/t2.rb @@ -2,6 +2,8 @@ sleep 5 system "curl http://localhost:10103/" +out=`ruby -rrubygems -Ilib bin/pumactl -F test/shell/t2_conf.rb status` + system "ruby -rrubygems -Ilib bin/pumactl -F test/shell/t2_conf.rb stop" sleep 1 @@ -10,7 +12,7 @@ File.unlink "t2-stdout" if File.file? "t2-stdout" -if log =~ %r(GET / HTTP/1\.1) && !File.file?("t2-pid") +if log =~ %r(GET / HTTP/1\.1) && !File.file?("t2-pid") && out == "Puma is started\n" exit 0 else exit 1 diff --git a/test/test_pumactl.rb b/test/test_pumactl.rb index e03c140610..db3c38e64e 100644 --- a/test/test_pumactl.rb +++ b/test/test_pumactl.rb @@ -39,7 +39,7 @@ def test_control_no_token assert_equal 'none', control_cli.instance_variable_get("@control_auth_token") end - def test_control_url + def test_control_url_and_status host = "127.0.0.1" port = find_open_port url = "tcp://#{host}:#{port}/" @@ -64,11 +64,18 @@ def test_control_url assert_match "200 OK", body assert_match "embedded app", body - shutdown_cmd = Puma::ControlCLI.new(opts + ["halt"]) - shutdown_cmd.run + status_cmd = Puma::ControlCLI.new(opts + ["status"]) + out, _ = capture_subprocess_io do + status_cmd.run + end + assert_match "Puma is started\n", out - # TODO: assert something about the stop command + shutdown_cmd = Puma::ControlCLI.new(opts + ["halt"]) + out, _ = capture_subprocess_io do + shutdown_cmd.run + end + assert_match "Command halt sent success\n", out - t.join + assert_kind_of Thread, t.join, "server didn't stop" end end From 3cad38295705829b82f740089b8aacc7b516c9f0 Mon Sep 17 00:00:00 2001 From: schneems Date: Tue, 25 Jun 2019 10:19:29 -0500 Subject: [PATCH 07/13] v4.0.0 --- History.md | 9 +++++++-- lib/puma/const.rb | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/History.md b/History.md index b71b4cd049..6f659118b7 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,11 @@ ## Master -* x features +x features +x bugfixes + +## 4.0.0 / 2019-06-25 + +9 features * Add support for disabling TLSv1.0 (#1562) * Request body read time metric (#1569) * Add out_of_band hook (#1648) @@ -9,7 +14,7 @@ * Add option to suppress SignalException on SIGTERM (#1690) * Allow mutual TLS CA to be set using `ssl_bind` DSL (#1689) * Reactor now uses nio4r instead of `select` (#1728) -* x bugfixes +9 x bugfixes * Do not accept new requests on shutdown (#1685, #1808) * Fix 3 corner cases when request body is chunked (#1508) * Change pid existence check's condition branches (#1650) diff --git a/lib/puma/const.rb b/lib/puma/const.rb index 396ca09176..15b9b7e169 100644 --- a/lib/puma/const.rb +++ b/lib/puma/const.rb @@ -100,8 +100,8 @@ class UnsupportedOption < RuntimeError # too taxing on performance. module Const - PUMA_VERSION = VERSION = "3.12.1".freeze - CODE_NAME = "Llamas in Pajamas".freeze + PUMA_VERSION = VERSION = "4.0.0".freeze + CODE_NAME = "4 Fast 4 Furious".freeze PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze FAST_TRACK_KA_TIMEOUT = 0.2 From 51a952b845359ab51bc774ef6f0a218a69fdfd51 Mon Sep 17 00:00:00 2001 From: schneems Date: Tue, 25 Jun 2019 13:04:13 -0500 Subject: [PATCH 08/13] Remove extra character --- History.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/History.md b/History.md index 6f659118b7..aabae2ae64 100644 --- a/History.md +++ b/History.md @@ -14,7 +14,7 @@ x bugfixes * Add option to suppress SignalException on SIGTERM (#1690) * Allow mutual TLS CA to be set using `ssl_bind` DSL (#1689) * Reactor now uses nio4r instead of `select` (#1728) -9 x bugfixes +9 bugfixes * Do not accept new requests on shutdown (#1685, #1808) * Fix 3 corner cases when request body is chunked (#1508) * Change pid existence check's condition branches (#1650) From 6d55a29b39e103f83d4e056a768e839b6b03ee11 Mon Sep 17 00:00:00 2001 From: Justin Reid Date: Wed, 26 Jun 2019 09:28:19 -0400 Subject: [PATCH 09/13] Clean up 4.0.0 changelog --- History.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index aabae2ae64..d4f2a8a3c9 100644 --- a/History.md +++ b/History.md @@ -5,7 +5,7 @@ x bugfixes ## 4.0.0 / 2019-06-25 -9 features +* 8 features * Add support for disabling TLSv1.0 (#1562) * Request body read time metric (#1569) * Add out_of_band hook (#1648) @@ -14,7 +14,8 @@ x bugfixes * Add option to suppress SignalException on SIGTERM (#1690) * Allow mutual TLS CA to be set using `ssl_bind` DSL (#1689) * Reactor now uses nio4r instead of `select` (#1728) -9 bugfixes + +* 9 bugfixes * Do not accept new requests on shutdown (#1685, #1808) * Fix 3 corner cases when request body is chunked (#1508) * Change pid existence check's condition branches (#1650) From a2cc0537a40c1b1c5dfca831a4e93d0967940b62 Mon Sep 17 00:00:00 2001 From: Amr El-Bakry Date: Fri, 28 Jun 2019 00:32:01 +0200 Subject: [PATCH 10/13] Remove RUBY_VERSION checks (#1827) --- lib/puma/launcher.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/puma/launcher.rb b/lib/puma/launcher.rb index 8d3f5b50a3..6fd5474483 100644 --- a/lib/puma/launcher.rb +++ b/lib/puma/launcher.rb @@ -252,7 +252,7 @@ def restart! argv = restart_args Dir.chdir(@restart_dir) - argv += [redirects] if RUBY_VERSION >= '1.9' + argv += [redirects] Kernel.exec(*argv) end end @@ -281,7 +281,7 @@ def prune_bundler wild = File.expand_path(File.join(puma_lib_dir, "../bin/puma-wild")) args = [Gem.ruby, wild, '-I', dirs.join(':'), deps.join(',')] + @original_argv # Ruby 2.0+ defaults to true which breaks socket activation - args += [{:close_others => false}] if RUBY_VERSION >= '2.0' + args += [{:close_others => false}] Kernel.exec(*args) end end From 12d1706ddc71b89ed2ee26275e31c788e94ff541 Mon Sep 17 00:00:00 2001 From: Laurent Arnoud Date: Tue, 2 Jul 2019 13:58:57 +0000 Subject: [PATCH 11/13] Add missing feature to history on v4.0.0 (#1830) --- History.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index d4f2a8a3c9..a397c0be75 100644 --- a/History.md +++ b/History.md @@ -5,7 +5,7 @@ x bugfixes ## 4.0.0 / 2019-06-25 -* 8 features +* 9 features * Add support for disabling TLSv1.0 (#1562) * Request body read time metric (#1569) * Add out_of_band hook (#1648) @@ -14,6 +14,7 @@ x bugfixes * Add option to suppress SignalException on SIGTERM (#1690) * Allow mutual TLS CA to be set using `ssl_bind` DSL (#1689) * Reactor now uses nio4r instead of `select` (#1728) + * Add status to pumactl with pidfile (#1824) * 9 bugfixes * Do not accept new requests on shutdown (#1685, #1808) From 18140082d6bccd58bbab1b5510ee29d60b76d90b Mon Sep 17 00:00:00 2001 From: MSP-Greg Date: Mon, 8 Jul 2019 14:49:45 -0500 Subject: [PATCH 12/13] Use OpenSSL DTLS_method & TLS_server_method when available (#1832) * Add extconf test for DTLS_method & use in mini_ssl.c * Rakefile - use require_relative for 'lib/puma/detect' * Add Trusty OpenSSL 1.0.1 job to Travis * Add extconf test for TLS_server_method & use in mini_ssl.c --- .travis.yml | 3 +++ History.md | 4 +++- Rakefile | 2 +- ext/puma_http11/extconf.rb | 8 ++++++++ ext/puma_http11/mini_ssl.c | 10 ++++++++-- 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 53302eab3c..776dab16c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,9 @@ rvm: matrix: fast_finish: true include: + - rvm: 2.2 + dist: trusty + env: NOTES="Trusty OpenSSL 1.0.1" - rvm: ruby-head env: RUBYOPT="--jit" - rvm: 2.4.6 diff --git a/History.md b/History.md index a397c0be75..cbdf90b15c 100644 --- a/History.md +++ b/History.md @@ -1,7 +1,9 @@ ## Master x features -x bugfixes + +* ? bugfixes + * Add extconf tests for DTLS_method & TLS_server_method, use in minissl.rb. (#1832) ## 4.0.0 / 2019-06-25 diff --git a/Rakefile b/Rakefile index 58873a657f..f56dce4a4f 100644 --- a/Rakefile +++ b/Rakefile @@ -3,7 +3,7 @@ require "rake/testtask" require "rake/extensiontask" require "rake/javaextensiontask" require "rubocop/rake_task" -require 'puma/detect' +require_relative 'lib/puma/detect' require 'rubygems/package_task' require 'bundler/gem_tasks' diff --git a/ext/puma_http11/extconf.rb b/ext/puma_http11/extconf.rb index 59c54f9c4b..ee6723061d 100644 --- a/ext/puma_http11/extconf.rb +++ b/ext/puma_http11/extconf.rb @@ -9,6 +9,14 @@ %w'ssl ssleay32'.find {|ssl| have_library(ssl, 'SSL_CTX_new')} have_header "openssl/bio.h" + + # below is yes for 1.0.2 & later + have_func "DTLS_method" , "openssl/ssl.h" + + # below are yes for 1.1.0 & later, may need to check func rather than macro + # with versions after 1.1.1 + have_func "TLS_server_method" , "openssl/ssl.h" + have_macro "SSL_CTX_set_min_proto_version", "openssl/ssl.h" end end diff --git a/ext/puma_http11/mini_ssl.c b/ext/puma_http11/mini_ssl.c index 120ab2275f..607f6ea8f3 100644 --- a/ext/puma_http11/mini_ssl.c +++ b/ext/puma_http11/mini_ssl.c @@ -168,8 +168,11 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) { ID sym_no_tlsv1 = rb_intern("no_tlsv1"); VALUE no_tlsv1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1, 0); - +#ifdef HAVE_TLS_SERVER_METHOD + ctx = SSL_CTX_new(TLS_server_method()); +#else ctx = SSL_CTX_new(SSLv23_server_method()); +#endif conn->ctx = ctx; SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert)); @@ -232,8 +235,11 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) { VALUE engine_init_client(VALUE klass) { VALUE obj; ms_conn* conn = engine_alloc(klass, &obj); - +#ifdef HAVE_DTLS_METHOD conn->ctx = SSL_CTX_new(DTLS_method()); +#else + conn->ctx = SSL_CTX_new(DTLSv1_method()); +#endif conn->ssl = SSL_new(conn->ctx); SSL_set_app_data(conn->ssl, NULL); SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); From 3b48d320b70b0e74a7ed9caeb1c38ee43d271bdb Mon Sep 17 00:00:00 2001 From: Yuri S Date: Tue, 9 Jul 2019 20:26:43 +0500 Subject: [PATCH 13/13] fix #1775 (#1829) * fix #1775 * Check socket file exist after restart * Add entry in HISTORY.md * link on PR --- History.md | 3 ++- lib/puma/binder.rb | 3 ++- test/test_integration.rb | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index cbdf90b15c..d67ea36162 100644 --- a/History.md +++ b/History.md @@ -2,7 +2,8 @@ x features -* ? bugfixes +* 2 bugfixes + * Socket removed after reload (#1829) * Add extconf tests for DTLS_method & TLS_server_method, use in minissl.rb. (#1832) ## 4.0.0 / 2019-06-25 diff --git a/lib/puma/binder.rb b/lib/puma/binder.rb index 42843b91b1..ec8d0a5531 100644 --- a/lib/puma/binder.rb +++ b/lib/puma/binder.rb @@ -53,7 +53,8 @@ def close @unix_paths.each do |i| # Errno::ENOENT is intermittently raised begin - File.unlink i + unix_socket = UNIXSocket.new i + unix_socket.close rescue Errno::ENOENT end end diff --git a/test/test_integration.rb b/test/test_integration.rb index 98522240fa..78f4f01d8f 100644 --- a/test/test_integration.rb +++ b/test/test_integration.rb @@ -197,6 +197,7 @@ def test_phased_restart_via_pumactl ccli.run assert_kind_of Thread, t.join, "server didn't stop" + assert File.exist? @bind_path end def test_kill_unknown_via_pumactl