2019-07-16 18:53:28 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-05-12 15:16:55 -04:00
|
|
|
require_relative "helper"
|
2019-10-20 21:35:15 -04:00
|
|
|
require_relative "helpers/ssl"
|
2016-11-21 09:40:56 -05:00
|
|
|
|
2016-11-22 10:05:49 -05:00
|
|
|
require "puma/binder"
|
|
|
|
require "puma/puma_http11"
|
2020-03-07 08:34:35 -05:00
|
|
|
require "puma/events"
|
2016-11-21 09:40:56 -05:00
|
|
|
|
2019-07-16 18:53:28 -04:00
|
|
|
class TestBinderBase < Minitest::Test
|
2019-10-20 21:35:15 -04:00
|
|
|
include SSLHelper
|
|
|
|
|
2016-11-21 09:40:56 -05:00
|
|
|
def setup
|
2019-09-11 08:01:24 -04:00
|
|
|
@events = Puma::Events.strings
|
2016-11-21 09:40:56 -05:00
|
|
|
@binder = Puma::Binder.new(@events)
|
|
|
|
end
|
|
|
|
|
2019-07-16 18:53:28 -04:00
|
|
|
private
|
|
|
|
|
2019-10-11 13:31:41 -04:00
|
|
|
def ssl_context_for_binder(binder = @binder)
|
|
|
|
binder.ios[0].instance_variable_get(:@ctx)
|
2019-09-11 08:01:24 -04:00
|
|
|
end
|
2019-07-16 18:53:28 -04:00
|
|
|
end
|
2016-11-21 09:40:56 -05:00
|
|
|
|
2019-07-16 18:53:28 -04:00
|
|
|
class TestBinder < TestBinderBase
|
2020-03-07 13:44:52 -05:00
|
|
|
parallelize_me!
|
|
|
|
|
2019-07-16 18:53:28 -04:00
|
|
|
def test_localhost_addresses_dont_alter_listeners_for_tcp_addresses
|
2020-03-07 13:44:52 -05:00
|
|
|
@binder.parse ["tcp://localhost:0"], @events
|
2019-10-11 13:31:41 -04:00
|
|
|
|
2020-03-07 08:34:35 -05:00
|
|
|
assert_empty @binder.listeners
|
2019-10-11 13:31:41 -04:00
|
|
|
end
|
|
|
|
|
2020-03-07 13:44:52 -05:00
|
|
|
def test_home_alters_listeners_for_tcp_addresses
|
|
|
|
port = UniquePort.call
|
|
|
|
@binder.parse ["tcp://127.0.0.1:#{port}"], @events
|
|
|
|
|
|
|
|
assert_equal "tcp://127.0.0.1:#{port}", @binder.listeners[0][0]
|
|
|
|
assert_kind_of TCPServer, @binder.listeners[0][1]
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_connected_ports
|
|
|
|
ports = (1..3).map { |_| UniquePort.call }
|
|
|
|
|
|
|
|
@binder.parse(ports.map { |p| "tcp://localhost:#{p}" }, @events)
|
|
|
|
|
|
|
|
assert_equal ports, @binder.connected_ports
|
|
|
|
end
|
|
|
|
|
2019-10-11 13:31:41 -04:00
|
|
|
def test_localhost_addresses_dont_alter_listeners_for_ssl_addresses
|
2020-03-07 13:44:52 -05:00
|
|
|
@binder.parse ["ssl://localhost:0?#{ssl_query}"], @events
|
2016-11-21 09:40:56 -05:00
|
|
|
|
2020-03-07 08:34:35 -05:00
|
|
|
assert_empty @binder.listeners
|
2016-11-21 09:40:56 -05:00
|
|
|
end
|
2019-09-11 08:01:24 -04:00
|
|
|
|
2020-03-07 13:44:52 -05:00
|
|
|
def test_home_alters_listeners_for_ssl_addresses
|
|
|
|
port = UniquePort.call
|
|
|
|
@binder.parse ["ssl://127.0.0.1:#{port}?#{ssl_query}"], @events
|
|
|
|
|
|
|
|
assert_equal "ssl://127.0.0.1:#{port}?#{ssl_query}", @binder.listeners[0][0]
|
|
|
|
assert_kind_of TCPServer, @binder.listeners[0][1]
|
|
|
|
end
|
|
|
|
|
2019-09-11 08:01:24 -04:00
|
|
|
def test_correct_zero_port
|
2019-10-11 13:31:41 -04:00
|
|
|
@binder.parse ["tcp://localhost:0"], @events
|
2019-09-11 08:01:24 -04:00
|
|
|
|
|
|
|
m = %r!tcp://127.0.0.1:(\d+)!.match(@events.stdout.string)
|
|
|
|
port = m[1].to_i
|
|
|
|
|
|
|
|
refute_equal 0, port
|
|
|
|
end
|
|
|
|
|
2019-09-26 06:54:15 -04:00
|
|
|
def test_correct_zero_port_ssl
|
2020-03-07 08:34:35 -05:00
|
|
|
skip("Implement later")
|
|
|
|
ssl_regex = %r!ssl://127.0.0.1:(\d+)!
|
|
|
|
|
2019-10-11 13:31:41 -04:00
|
|
|
@binder.parse ["ssl://localhost:0?#{ssl_query}"], @events
|
2019-09-26 06:54:15 -04:00
|
|
|
|
2020-03-07 08:34:35 -05:00
|
|
|
port = ssl_regex.match(@events.stdout.string)[1].to_i
|
2019-09-26 06:54:15 -04:00
|
|
|
|
|
|
|
refute_equal 0, port
|
|
|
|
end
|
2019-09-26 06:55:23 -04:00
|
|
|
|
2020-03-07 08:34:35 -05:00
|
|
|
def test_logs_all_localhost_bindings
|
|
|
|
@binder.parse ["tcp://localhost:0"], @events
|
|
|
|
|
|
|
|
assert_match %r!tcp://127.0.0.1:(\d+)!, @events.stdout.string
|
2020-03-07 13:44:52 -05:00
|
|
|
if Socket.ip_address_list.any? {|i| i.ipv6_loopback? }
|
2020-03-07 08:34:35 -05:00
|
|
|
assert_match %r!tcp://\[::1\]:(\d+)!, @events.stdout.string
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-03-07 08:34:35 -05:00
|
|
|
def test_logs_all_localhost_bindings_ssl
|
|
|
|
skip("Incorrectly logs localhost, not 127.0.0.1")
|
|
|
|
@binder.parse ["ssl://localhost:0?#{ssl_query}"], @events
|
|
|
|
|
|
|
|
assert_match %r!ssl://127.0.0.1:(\d+)!, @events.stdout.string
|
2020-03-07 13:44:52 -05:00
|
|
|
if Socket.ip_address_list.any? {|i| i.ipv6_loopback? }
|
2020-03-07 08:34:35 -05:00
|
|
|
assert_match %r!ssl://\[::1\]:(\d+)!, @events.stdout.string
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-10-01 05:33:00 -04:00
|
|
|
def test_allows_both_ssl_and_tcp
|
|
|
|
assert_parsing_logs_uri [:ssl, :tcp]
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_allows_both_unix_and_tcp
|
|
|
|
assert_parsing_logs_uri [:unix, :tcp]
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_allows_both_tcp_and_unix
|
|
|
|
assert_parsing_logs_uri [:tcp, :unix]
|
|
|
|
end
|
|
|
|
|
2019-10-01 10:01:45 -04:00
|
|
|
def test_pre_existing_unix
|
|
|
|
skip UNIX_SKT_MSG unless UNIX_SKT_EXIST
|
|
|
|
unix_path = "test/#{name}_server.sock"
|
|
|
|
|
2019-10-01 12:28:33 -04:00
|
|
|
File.open(unix_path, mode: 'wb') { |f| f.puts 'pre existing' }
|
2019-10-01 10:01:45 -04:00
|
|
|
@binder.parse ["unix://#{unix_path}"], @events
|
|
|
|
|
|
|
|
assert_match %r!unix://#{unix_path}!, @events.stdout.string
|
|
|
|
|
2020-03-07 08:34:35 -05:00
|
|
|
refute_includes @binder.unix_paths, unix_path
|
2019-10-01 10:01:45 -04:00
|
|
|
|
2020-03-03 15:09:08 -05:00
|
|
|
@binder.close_listeners
|
2019-10-01 12:28:33 -04:00
|
|
|
|
|
|
|
assert File.exist?(unix_path)
|
|
|
|
|
2019-10-01 10:01:45 -04:00
|
|
|
ensure
|
|
|
|
if UNIX_SKT_EXIST
|
|
|
|
File.unlink unix_path if File.exist? unix_path
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-10-11 13:31:41 -04:00
|
|
|
def test_binder_parses_tlsv1_disabled
|
|
|
|
@binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1=true"], @events
|
|
|
|
|
|
|
|
assert ssl_context_for_binder.no_tlsv1
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_binder_parses_tlsv1_enabled
|
|
|
|
@binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1=false"], @events
|
|
|
|
|
|
|
|
refute ssl_context_for_binder.no_tlsv1
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_binder_parses_tlsv1_tlsv1_1_unspecified_defaults_to_enabled
|
|
|
|
@binder.parse ["ssl://0.0.0.0:0?#{ssl_query}"], @events
|
|
|
|
|
|
|
|
refute ssl_context_for_binder.no_tlsv1
|
|
|
|
refute ssl_context_for_binder.no_tlsv1_1
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_binder_parses_tlsv1_1_disabled
|
|
|
|
@binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1_1=true"], @events
|
|
|
|
|
|
|
|
assert ssl_context_for_binder.no_tlsv1_1
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_binder_parses_tlsv1_1_enabled
|
|
|
|
@binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1_1=false"], @events
|
|
|
|
|
|
|
|
refute ssl_context_for_binder.no_tlsv1_1
|
|
|
|
end
|
|
|
|
|
2020-03-07 08:34:35 -05:00
|
|
|
def test_env_contains_protoenv
|
|
|
|
@binder.parse ["ssl://localhost:0?#{ssl_query}"], @events
|
|
|
|
|
|
|
|
env_hash = @binder.envs[@binder.ios.first]
|
|
|
|
|
|
|
|
@binder.proto_env.each do |k,v|
|
|
|
|
assert_equal env_hash[k], v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_env_contains_stderr
|
|
|
|
@binder.parse ["ssl://localhost:0?#{ssl_query}"], @events
|
|
|
|
|
|
|
|
env_hash = @binder.envs[@binder.ios.first]
|
|
|
|
|
|
|
|
assert_equal @events.stderr, env_hash["rack.errors"]
|
|
|
|
end
|
|
|
|
|
2020-03-07 13:44:52 -05:00
|
|
|
def test_close_calls_close_on_ios
|
|
|
|
@mocked_ios = [Minitest::Mock.new, Minitest::Mock.new]
|
|
|
|
@mocked_ios.each { |m| m.expect(:close, true) }
|
|
|
|
@binder.ios = @mocked_ios
|
|
|
|
|
|
|
|
@binder.close
|
|
|
|
|
2020-03-09 12:12:19 -04:00
|
|
|
assert @mocked_ios.map(&:verify).all?
|
2020-03-07 13:44:52 -05:00
|
|
|
end
|
|
|
|
|
2020-03-08 12:06:42 -04:00
|
|
|
def test_redirects_for_restart_creates_a_hash
|
|
|
|
@binder.parse ["tcp://127.0.0.1:0"], @events
|
|
|
|
|
|
|
|
result = @binder.redirects_for_restart
|
|
|
|
ios = @binder.listeners.map { |_l, io| io.to_i }
|
|
|
|
|
|
|
|
ios.each { |int| assert_equal int, result[int] }
|
|
|
|
assert result[:close_others]
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_redirects_for_restart_env
|
|
|
|
@binder.parse ["tcp://127.0.0.1:0"], @events
|
|
|
|
|
|
|
|
result = @binder.redirects_for_restart_env
|
|
|
|
|
|
|
|
@binder.listeners.each_with_index do |l, i|
|
|
|
|
assert_equal "#{l[1].to_i}:#{l[0]}", result["PUMA_INHERIT_#{i}"]
|
|
|
|
end
|
|
|
|
end
|
2020-03-07 13:44:52 -05:00
|
|
|
|
|
|
|
def test_close_listeners_closes_ios
|
|
|
|
@binder.parse ["tcp://127.0.0.1:#{UniquePort.call}"], @events
|
|
|
|
|
|
|
|
refute @binder.listeners.any? { |u, l| l.closed? }
|
|
|
|
|
|
|
|
@binder.close_listeners
|
|
|
|
|
|
|
|
assert @binder.listeners.all? { |u, l| l.closed? }
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_close_listeners_closes_ios_unless_closed?
|
|
|
|
@binder.parse ["tcp://127.0.0.1:0"], @events
|
|
|
|
|
|
|
|
bomb = @binder.listeners.first[1]
|
|
|
|
bomb.close
|
|
|
|
def bomb.close; raise "Boom!"; end # the bomb has been planted
|
|
|
|
|
|
|
|
assert @binder.listeners.any? { |u, l| l.closed? }
|
|
|
|
|
|
|
|
@binder.close_listeners
|
|
|
|
|
|
|
|
assert @binder.listeners.all? { |u, l| l.closed? }
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_listeners_file_unlink_if_unix_listener
|
|
|
|
skip UNIX_SKT_MSG unless UNIX_SKT_EXIST
|
|
|
|
|
|
|
|
@binder.parse ["unix://test/#{name}_server.sock"], @events
|
|
|
|
|
|
|
|
assert File.socket?("test/#{name}_server.sock")
|
|
|
|
|
|
|
|
@binder.close_listeners
|
|
|
|
|
|
|
|
refute File.socket?("test/#{name}_server.sock")
|
|
|
|
end
|
|
|
|
|
2020-03-08 12:06:42 -04:00
|
|
|
def test_import_from_env_listen_inherit
|
|
|
|
@binder.parse ["tcp://127.0.0.1:0"], @events
|
|
|
|
removals = @binder.import_from_env(@binder.redirects_for_restart_env)
|
|
|
|
|
|
|
|
@binder.listeners.each do |url, io|
|
|
|
|
assert_equal io.to_i, @binder.inherited_fds[url]
|
|
|
|
end
|
|
|
|
assert_includes removals, "PUMA_INHERIT_0"
|
|
|
|
end
|
|
|
|
|
|
|
|
# test socket activation with tcp
|
|
|
|
# test socket activation with IPv6
|
|
|
|
# test socket activation with Unix
|
|
|
|
# test socket activation logs to events
|
|
|
|
# test socket activation returns the right keys to remove
|
|
|
|
|
2019-10-01 05:33:00 -04:00
|
|
|
private
|
|
|
|
|
|
|
|
def assert_parsing_logs_uri(order = [:unix, :tcp])
|
|
|
|
skip UNIX_SKT_MSG if order.include?(:unix) && !UNIX_SKT_EXIST
|
|
|
|
|
|
|
|
prepared_paths = {
|
2019-10-11 13:31:41 -04:00
|
|
|
ssl: "ssl://127.0.0.1:#{UniquePort.call}?#{ssl_query}",
|
2019-10-01 05:33:00 -04:00
|
|
|
tcp: "tcp://127.0.0.1:#{UniquePort.call}",
|
|
|
|
unix: "unix://test/#{name}_server.sock"
|
|
|
|
}
|
|
|
|
|
|
|
|
tested_paths = [prepared_paths[order[0]], prepared_paths[order[1]]]
|
2019-09-26 06:55:23 -04:00
|
|
|
|
2019-10-11 13:31:41 -04:00
|
|
|
@binder.parse tested_paths, @events
|
2019-09-26 06:55:23 -04:00
|
|
|
stdout = @events.stdout.string
|
|
|
|
|
2020-03-07 08:42:38 -05:00
|
|
|
order.each do |prot|
|
|
|
|
assert_match prepared_paths[prot], stdout
|
|
|
|
end
|
2019-10-01 05:33:00 -04:00
|
|
|
ensure
|
2020-03-03 15:09:08 -05:00
|
|
|
@binder.close_listeners if order.include?(:unix) && UNIX_SKT_EXIST
|
2019-09-26 06:55:23 -04:00
|
|
|
end
|
2019-07-16 18:53:28 -04:00
|
|
|
end
|
2016-11-21 09:40:56 -05:00
|
|
|
|
2019-07-16 18:53:28 -04:00
|
|
|
class TestBinderJRuby < TestBinderBase
|
|
|
|
def test_binder_parses_jruby_ssl_options
|
|
|
|
keystore = File.expand_path "../../examples/puma/keystore.jks", __FILE__
|
|
|
|
ssl_cipher_list = "TLS_DHE_RSA_WITH_DES_CBC_SHA,TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"
|
2016-11-21 09:40:56 -05:00
|
|
|
|
2019-10-11 13:31:41 -04:00
|
|
|
@binder.parse ["ssl://0.0.0.0:8080?#{ssl_query}"], @events
|
2016-11-21 09:40:56 -05:00
|
|
|
|
2019-10-11 13:31:41 -04:00
|
|
|
assert_equal keystore, ssl_context_for_binder.keystore
|
|
|
|
assert_equal ssl_cipher_list, ssl_context_for_binder.ssl_cipher_list
|
2016-11-21 09:40:56 -05:00
|
|
|
end
|
2019-10-11 13:31:41 -04:00
|
|
|
end if ::Puma::IS_JRUBY
|
2017-12-01 13:56:48 -05:00
|
|
|
|
2019-07-16 18:53:28 -04:00
|
|
|
class TestBinderMRI < TestBinderBase
|
|
|
|
def test_binder_parses_ssl_cipher_filter
|
|
|
|
ssl_cipher_filter = "AES@STRENGTH"
|
2017-12-01 14:06:33 -05:00
|
|
|
|
2019-10-11 13:31:41 -04:00
|
|
|
@binder.parse ["ssl://0.0.0.0?#{ssl_query}&ssl_cipher_filter=#{ssl_cipher_filter}"], @events
|
2019-08-03 15:56:30 -04:00
|
|
|
|
2019-10-11 13:31:41 -04:00
|
|
|
assert_equal ssl_cipher_filter, ssl_context_for_binder.ssl_cipher_filter
|
2018-04-17 09:25:22 -04:00
|
|
|
end
|
2019-10-11 13:31:41 -04:00
|
|
|
end unless ::Puma::IS_JRUBY
|