Add geturl SSL tests

These don't test validation, only that IO::Socket::SSL is used.
This commit is contained in:
Richard Hansen 2020-07-05 18:08:34 -04:00
parent 593206ad7d
commit dd8e376784
4 changed files with 261 additions and 0 deletions

View file

@ -70,6 +70,7 @@ AM_PL_LOG_FLAGS = -Mstrict -w \
-I'$(abs_top_srcdir)'/t/lib -I'$(abs_top_srcdir)'/t/lib
handwritten_tests = \ handwritten_tests = \
t/geturl_connectivity.pl \ t/geturl_connectivity.pl \
t/geturl_ssl.pl \
t/parse_assignments.pl \ t/parse_assignments.pl \
t/write_cache.pl t/write_cache.pl
generated_tests = \ generated_tests = \

View file

@ -64,6 +64,8 @@ m4_foreach_w([_m], [
HTTP::Daemon=6.12 HTTP::Daemon=6.12
HTTP::Daemon::SSL HTTP::Daemon::SSL
HTTP::Message::PSGI HTTP::Message::PSGI
HTTP::Request
HTTP::Response
IO::Socket::IP IO::Socket::IP
Scalar::Util Scalar::Util
Test::TCP Test::TCP

View file

@ -2073,6 +2073,10 @@ sub geturl {
load_ipv6_support; load_ipv6_support;
$socket_class = 'IO::Socket::INET6'; $socket_class = 'IO::Socket::INET6';
} }
if (defined($params->{_testonly_socket_class})) {
$socket_args{original_socket_class} = $socket_class;
$socket_class = $params->{_testonly_socket_class};
}
if ($ipversion eq '4') { if ($ipversion eq '4') {
$socket_args{Domain} = PF_INET; $socket_args{Domain} = PF_INET;
$socket_args{Family} = AF_INET; $socket_args{Family} = AF_INET;

254
t/geturl_ssl.pl Normal file
View file

@ -0,0 +1,254 @@
use Test::More;
use Data::Dumper;
eval {
require HTTP::Request;
require HTTP::Response;
require IO::Socket::IP;
require ddclient::Test::Fake::HTTPD;
} or plan(skip_all => $@);
SKIP: { eval { require Test::Warnings; } or skip($@, 1); }
eval { require 'ddclient'; } or BAIL_OUT($@);
$Data::Dumper::Sortkeys = 1;
my $httpd = ddclient::Test::Fake::HTTPD->new();
$httpd->run(sub {
my $req = shift;
# Echo back the full request.
my $resp = [ 200, [ 'Content-Type' => 'application/octet-stream' ], [ $req->as_string() ] ];
if ($req->method() ne 'GET') {
# TODO: Add support for CONNECT to test https via proxy.
$resp->[0] = 501; # 501 == Not Implemented
}
return $resp;
});
my $args;
{
package InterceptSocket;
require base;
base->import(qw(IO::Socket::IP));
sub new {
my ($class, %args) = @_;
$args = \%args;
return $class->SUPER::new(%args, PeerAddr => $httpd->host(), PeerPort => $httpd->port());
}
}
# Keys:
# * name: Display name.
# * params: Parameters to pass to geturl.
# * opt_ssl: Value to return from opt('ssl'). Defaults to 0.
# * opt_ssl_ca_dir: Value to return from opt('ssl_ca_dir'). Defaults to undef.
# * opt_ssl_ca_file: Value to return from opt('ssl_ca_file'). Defaults to undef.
# * want_args: Args that should be passed to the socket constructor minus MultiHomed, Proto,
# Timeout, and original_socket_class.
# * want_req_method: The HTTP method geturl is expected to use. Defaults to 'GET'.
# * want_req_uri: URI that geturl is expected to request.
# * todo: If defined, mark this test as expected to fail.
my @test_cases = (
{
name => 'https',
params => {
url => 'https://hostname',
},
want_args => {
PeerAddr => 'hostname',
PeerPort => '443',
},
want_req_uri => '/',
},
{
name => 'http with ssl=true',
params => {
url => 'http://hostname',
},
opt_ssl => 1,
want_args => {
PeerAddr => 'hostname',
PeerPort => '443',
},
want_req_uri => '/',
},
{
name => 'https with port',
params => {
url => 'https://hostname:123',
},
want_args => {
PeerAddr => 'hostname',
PeerPort => '123',
},
want_req_uri => '/',
},
{
name => 'http with port and ssl=true',
params => {
url => 'https://hostname:123',
},
opt_ssl => 1,
want_args => {
PeerAddr => 'hostname',
PeerPort => '123',
},
want_req_uri => '/',
},
{
name => 'https proxy, http URL',
params => {
proxy => 'https://proxy',
url => 'http://hostname',
},
want_args => {
PeerAddr => 'proxy',
PeerPort => '443',
},
want_req_uri => 'http://hostname/',
todo => "broken",
},
{
name => 'http proxy, https URL',
params => {
proxy => 'http://proxy',
url => 'https://hostname',
},
want_args => {
PeerAddr => 'proxy',
PeerPort => '80',
SSL_startHandshake => 0,
},
want_req_method => 'CONNECT',
want_req_uri => 'hostname:443',
todo => "not yet supported; silently fails",
},
{
name => 'https proxy, https URL',
params => {
proxy => 'https://proxy',
url => 'https://hostname',
},
want_args => {
PeerAddr => 'proxy',
PeerPort => '443',
},
want_req_method => 'CONNECT',
want_req_uri => 'hostname:443',
todo => "not yet supported; silently fails",
},
{
name => 'http proxy, http URL, ssl=true',
params => {
proxy => 'http://proxy',
url => 'http://hostname',
},
opt_ssl => 1,
want_args => {
PeerAddr => 'proxy',
PeerPort => '443',
},
want_req_method => 'CONNECT',
want_req_uri => 'hostname:443',
todo => "not yet supported; silently fails",
},
{
name => 'https proxy with port, http URL with port',
params => {
proxy => 'https://proxy:123',
url => 'http://hostname:456',
},
want_args => {
PeerAddr => 'proxy',
PeerPort => '123',
},
want_req_uri => 'http://hostname:456/',
todo => "broken",
},
{
name => 'http proxy with port, https URL with port',
params => {
proxy => 'http://proxy:123',
url => 'https://hostname:456',
},
want_args => {
PeerAddr => 'proxy',
PeerPort => '123',
SSL_startHandshake => 0,
},
want_req_method => 'CONNECT',
want_req_uri => 'hostname:456',
todo => "not yet supported; silently fails",
},
{
name => 'CA dir',
params => {
url => 'https://hostname',
},
opt_ssl_ca_dir => '/ca/dir',
want_args => {
PeerAddr => 'hostname',
PeerPort => '443',
SSL_ca_path => '/ca/dir',
},
want_req_uri => '/',
},
{
name => 'CA file',
params => {
url => 'https://hostname',
},
opt_ssl_ca_file => '/ca/file',
want_args => {
PeerAddr => 'hostname',
PeerPort => '443',
SSL_ca_file => '/ca/file',
},
want_req_uri => '/',
},
{
name => 'CA dir and file',
params => {
url => 'https://hostname',
},
opt_ssl_ca_dir => '/ca/dir',
opt_ssl_ca_file => '/ca/file',
want_args => {
PeerAddr => 'hostname',
PeerPort => '443',
SSL_ca_file => '/ca/file',
SSL_ca_path => '/ca/dir',
},
want_req_uri => '/',
},
);
for my $tc (@test_cases) {
$args = undef;
$ddclient::globals{'ssl'} = $tc->{opt_ssl} // 0;
$ddclient::globals{'ssl_ca_dir'} = $tc->{opt_ssl_ca_dir};
$ddclient::globals{'ssl_ca_file'} = $tc->{opt_ssl_ca_file};
my $resp_str = ddclient::geturl({ _testonly_socket_class => 'InterceptSocket',
%{$tc->{params}} });
TODO: {
local $TODO = $tc->{todo};
subtest $tc->{name} => sub {
my %want_args = (
MultiHomed => 1,
Proto => 'tcp',
Timeout => ddclient::opt('timeout'),
original_socket_class => 'IO::Socket::SSL',
%{$tc->{want_args}},
);
is(Dumper($args), Dumper(\%want_args), "socket constructor args");
ok(defined($resp_str), "response is defined") or return;
ok(my $resp = HTTP::Response->parse($resp_str), "parse response") or return;
ok(my $req_str = $resp->decoded_content(), "decode request from response") or return;
ok(my $req = HTTP::Request->parse($req_str), "parse request") or return;
is($req->method(), $tc->{want_req_method} // 'GET', "request method");
is($req->uri(), $tc->{want_req_uri}, "request URI");
};
}
}
done_testing();