# HG changeset patch # User Sergey Kandaurov # Date 1473937584 -10800 # Node ID 679cefd5896b1cefc44b166882aadb43ae368136 # Parent 45c80276d6918b65f5dc7dc7bd519a921153cd75 Tests: stream_ssl_preread module tests. diff --git a/stream_ssl_preread.t b/stream_ssl_preread.t new file mode 100644 --- /dev/null +++ b/stream_ssl_preread.t @@ -0,0 +1,206 @@ +#!/usr/bin/perl + +# (C) Sergey Kandaurov +# (C) Nginx, Inc. + +# Tests for stream_ssl_preread module. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/stream stream_map stream_ssl_preread/) + ->has(qw/http http_ssl stream_ssl/)->has_daemon('openssl') + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +stream { + log_format status $status; + + map $ssl_preread_server_name $name { + "" 127.0.0.1:8093; + default $ssl_preread_server_name; + } + + upstream foo { + server 127.0.0.1:8091; + } + + upstream bar { + server 127.0.0.1:8092; + } + + ssl_preread on; + + server { + listen 127.0.0.1:8080; + proxy_pass $name; + } + + server { + listen 127.0.0.1:8081; + proxy_pass $name; + ssl_preread off; + } + + ssl_certificate_key localhost.key; + ssl_certificate localhost.crt; + + server { + listen 127.0.0.1:8082 ssl; + proxy_pass $name; + proxy_ssl on; + } + + server { + listen 127.0.0.1:8083; + proxy_pass $name; + + preread_timeout 2s; + preread_buffer_size 42; + + access_log %%TESTDIR%%/status.log status; + } +} + +http { + %%TEST_GLOBALS_HTTP%% + + ssl_certificate_key localhost.key; + ssl_certificate localhost.crt; + + server { + listen 127.0.0.1:8091 ssl; + listen 127.0.0.1:8092 ssl; + listen 127.0.0.1:8093 ssl; + server_name localhost; + + location / { + add_header X-Port $server_port always; + } + } +} + +EOF + +eval { require IO::Socket::SSL; die if $IO::Socket::SSL::VERSION < 1.56; }; +plan(skip_all => 'IO::Socket::SSL version >= 1.56 required') if $@; + +eval { + if (IO::Socket::SSL->can('can_client_sni')) { + IO::Socket::SSL->can_client_sni() or die; + } +}; +plan(skip_all => 'IO::Socket::SSL with OpenSSL SNI support required') if $@; + +eval { + my $ctx = Net::SSLeay::CTX_new() or die; + my $ssl = Net::SSLeay::new($ctx) or die; + Net::SSLeay::set_tlsext_host_name($ssl, 'example.org') == 1 or die; +}; +plan(skip_all => 'Net::SSLeay with OpenSSL SNI support required') if $@; + +$t->plan(9); + +$t->write_file('openssl.conf', <testdir(); + +foreach my $name ('localhost') { + system('openssl req -x509 -new ' + . "-config '$d/openssl.conf' -subj '/CN=$name/' " + . "-out '$d/$name.crt' -keyout '$d/$name.key' " + . ">>$d/openssl.out 2>&1") == 0 + or die "Can't create certificate for $name: $!\n"; +} + +$t->run(); + +############################################################################### + +my ($p1, $p2, $p3) = (port(8091), port(8092), port(8093)); + +like(https_get_host('foo'), qr/$p1/, 'sni'); +like(https_get_host('foo'), qr/$p1/, 'sni again'); + +like(https_get_host('bar'), qr/$p2/, 'sni 2'); +like(https_get_host('bar'), qr/$p2/, 'sni 2 again'); + +# fallback to an empty value for some reason + +like(https_get_host('foo', ''), qr/$p3/, 'no sni'); +like(https_get_host('foo', 'foo', 8081), qr/$p3/, 'no preread'); +like(https_get_host('foo', 'foo', 8082), qr/$p3/, 'no handshake'); + +is(https_get_host('foo', 'foo', 8083), undef, 'preread buffer full'); + +$t->stop(); + +is($t->read_file('status.log'), "400\n", 'preread buffer full - log'); + +############################################################################### + +sub get_ssl_socket { + my ($host, $port) = @_; + my $s; + + eval { + local $SIG{ALRM} = sub { die "timeout\n" }; + local $SIG{PIPE} = sub { die "sigpipe\n" }; + alarm(2); + $s = IO::Socket::SSL->new( + Proto => 'tcp', + PeerAddr => '127.0.0.1:' . port($port || 8080), + SSL_hostname => $host, + SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE(), + SSL_error_trap => sub { die $_[1] } + ); + alarm(0); + }; + alarm(0); + + if ($@) { + log_in("died: $@"); + return undef; + } + + return $s; +} + +sub https_get_host { + my ($host, $sni, $port) = @_; + my $s = get_ssl_socket(defined $sni ? $sni : $host, $port) or return; + + return http(< $s); +GET / HTTP/1.0 +Host: $host + +EOF +} + +###############################################################################