Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ssl support to the control_cli #2052

Merged
merged 1 commit into from Nov 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion History.md
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions lib/puma/control_cli.rb
Expand Up @@ -141,6 +141,12 @@ def send_request

# create server object by scheme
server = case uri.scheme
when "ssl"
require 'openssl'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not totally sure if this was the right thing to have done here. I started out with:

require 'puma/puma_http11'
require 'puma/minissl'
MiniSSL.check
MiniSSL::Socket.new(
  TCPSocket.new(uri.host, uri.port),
  MiniSSL::Engine.client
)

but that was raising an "Unknown OpenSSL error: 2" at

snprintf(msg, sizeof(msg), "Unknown OpenSSL error: %d", ssl_err);
and both my C and SSL knowledge are probably a bit too limited to know what to do with that without some help.

MiniSSL::Socket doesn't have a read method either, so there would still be some things to work out if that is the path we should go down.

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"
Expand Down
48 changes: 38 additions & 10 deletions test/test_pumactl.rb
@@ -1,16 +1,19 @@
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
end

def wait_booted
line = @wait.gets until line =~ /Listening on/
line = @wait.gets until line =~ /Use Ctrl-C to stop/
end

def teardown
Expand Down Expand Up @@ -138,18 +141,43 @@ def test_control_url_and_status
assert_match "200 OK", body
assert_match "embedded app", body

status_cmd = Puma::ControlCLI.new(opts + ["status"])
out, _ = capture_subprocess_io do
status_cmd.run
end
assert_match "Puma is started\n", out
assert_command_cli_output opts + ["status"], "Puma is started"
assert_command_cli_output opts + ["stop"], "Command stop sent success"

shutdown_cmd = Puma::ControlCLI.new(opts + ["halt"])
out, _ = capture_subprocess_io do
shutdown_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 "Command halt sent success\n", out

wait_booted

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
cmd.run
end
assert_match expected_out, out
end
end