From d8e4bb6f6b2bd64b8a6dd07b5b7f11969cae27aa Mon Sep 17 00:00:00 2001 From: Daniel Colson Date: Wed, 23 Oct 2019 21:13:03 -0400 Subject: [PATCH] Add ssl support to the control_cli If I have a server running: ```sh bundle exec bin/puma test/rackup/hello.ru \ --control-url="ssl://127.0.0.1:9000?key=examples/puma/puma_keypair.pem&cert=examples/puma/cert_puma.pem" \ --control-token="token" ``` This commit will allow me to restart that server (or run any other control cli command) with: ```sh bundle exec bin/pumactl restart \ --control-url="ssl://127.0.0.1:9000" \ --control-token="token" ``` Before this commit the pumactl restart command would have raised an error: `"Invalid scheme: ssl"` --- History.md | 2 +- lib/puma/control_cli.rb | 6 +++++ test/test_pumactl.rb | 58 ++++++++++++++++++++++++++++++++--------- 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/History.md b/History.md index 8e2f1e4e37..70442df3b6 100644 --- a/History.md +++ b/History.md @@ -3,7 +3,7 @@ * Features * Strip whitespace at end of HTTP headers (#2010) * Optimize HTTP parser for JRuby (#2012) - * Add SSL support for the control app (#2046) + * Add SSL support for the control app and cli (#2046, #2052) * Bugfixes * Fix Errno::EINVAL when SSL is enabled and browser rejects cert (#1564) diff --git a/lib/puma/control_cli.rb b/lib/puma/control_cli.rb index 6bad828b88..6d4118f062 100644 --- a/lib/puma/control_cli.rb +++ b/lib/puma/control_cli.rb @@ -141,6 +141,12 @@ def send_request # create server object by scheme server = case uri.scheme + when "ssl" + require 'openssl' + OpenSSL::SSL::SSLSocket.new( + TCPSocket.new(uri.host, uri.port), + OpenSSL::SSL::SSLContext.new + ).tap(&:connect) when "tcp" TCPSocket.new uri.host, uri.port when "unix" diff --git a/test/test_pumactl.rb b/test/test_pumactl.rb index bb4c00b0a0..1c625c1552 100644 --- a/test/test_pumactl.rb +++ b/test/test_pumactl.rb @@ -1,9 +1,12 @@ require_relative "helper" require_relative "helpers/config_file" +require_relative "helpers/ssl" require 'puma/control_cli' class TestPumaControlCli < TestConfigFileBase + include SSLHelper + def setup # use a pipe to get info across thread boundary @wait, @ready = IO.pipe @@ -132,24 +135,53 @@ def test_control_url_and_status wait_booted - s = TCPSocket.new host, 9292 - s << "GET / HTTP/1.0\r\n\r\n" - body = s.read - assert_match "200 OK", body - assert_match "embedded app", body + assert_app_running host + assert_command_cli_output opts + ["status"], "Puma is started" + assert_command_cli_output opts + ["stop"], "Command stop sent success" - status_cmd = Puma::ControlCLI.new(opts + ["status"]) - out, _ = capture_subprocess_io do - status_cmd.run + assert_kind_of Thread, t.join, "server didn't stop" + end + + def test_control_ssl + host = "127.0.0.1" + port = find_open_port + url = "ssl://#{host}:#{port}?#{ssl_query}" + + opts = [ + "--control-url", url, + "--control-token", "ctrl", + "--config-file", "test/config/app.rb", + ] + + control_cli = Puma::ControlCLI.new (opts + ["start"]), @ready, @ready + t = Thread.new do + control_cli.run end - assert_match "Puma is started\n", out - shutdown_cmd = Puma::ControlCLI.new(opts + ["halt"]) + wait_booted + + assert_app_running host + assert_command_cli_output opts + ["status"], "Puma is started" + assert_command_cli_output opts + ["stop"], "Command stop sent success" + + assert_kind_of Thread, t.join, "server didn't stop" + end + + private + + def assert_command_cli_output(options, expected_out) + cmd = Puma::ControlCLI.new(options) out, _ = capture_subprocess_io do - shutdown_cmd.run + cmd.run end - assert_match "Command halt sent success\n", out + assert_match expected_out, out + end - assert_kind_of Thread, t.join, "server didn't stop" + def assert_app_running(host) + s = TCPSocket.new host, 9292 + s << "GET / HTTP/1.0\r\n\r\n" + body = s.read + assert_match "200 OK", body + assert_match "embedded app", body end end