|
|
@ -1,12 +1,10 @@ |
|
|
|
package LightyTest; |
|
|
|
|
|
|
|
use strict; |
|
|
|
use IO::Socket; |
|
|
|
use Test::More; |
|
|
|
use IO::Socket (); |
|
|
|
use Test::More; # diag() |
|
|
|
use Socket; |
|
|
|
use Cwd 'abs_path'; |
|
|
|
use POSIX qw(:sys_wait_h dup2); |
|
|
|
use Errno qw(EADDRINUSE); |
|
|
|
|
|
|
|
sub find_program { |
|
|
|
my @DEFAULT_PATHS = ('/usr/bin/', '/usr/local/bin/'); |
|
|
@ -80,7 +78,6 @@ sub new { |
|
|
|
if (exists $ENV{LIGHTTPD_EXE_PATH}) { |
|
|
|
$self->{LIGHTTPD_PATH} = $ENV{LIGHTTPD_EXE_PATH}; |
|
|
|
} |
|
|
|
$self->{PORT} = 2048; |
|
|
|
|
|
|
|
my ($name, $aliases, $addrtype, $net) = gethostbyaddr(inet_aton("127.0.0.1"), AF_INET); |
|
|
|
|
|
|
@ -131,7 +128,8 @@ sub wait_for_port_with_proc { |
|
|
|
$timeout--; |
|
|
|
|
|
|
|
# the process is gone, we failed |
|
|
|
if (0 != waitpid($child, WNOHANG)) { |
|
|
|
require POSIX; |
|
|
|
if (0 != waitpid($child, POSIX::WNOHANG)) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
if (0 >= $timeout) { |
|
|
@ -144,15 +142,32 @@ sub wait_for_port_with_proc { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
sub bind_ephemeral_tcp_socket { |
|
|
|
my $SOCK; |
|
|
|
socket($SOCK, PF_INET, SOCK_STREAM, 0) || die "socket: $!"; |
|
|
|
setsockopt($SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!"; |
|
|
|
bind($SOCK, sockaddr_in(0, INADDR_LOOPBACK)) || die "bind: $!"; |
|
|
|
my($port) = sockaddr_in(getsockname($SOCK)); |
|
|
|
return ($SOCK, $port); |
|
|
|
} |
|
|
|
|
|
|
|
sub get_ephemeral_tcp_port { |
|
|
|
# bind to an ephemeral port, close() it, and return port that was used |
|
|
|
# (While there is a race condition before caller may reuse the port, |
|
|
|
# the port is likely to remain available for the serialized tests) |
|
|
|
my $port; |
|
|
|
(undef, $port) = bind_ephemeral_tcp_socket(); |
|
|
|
return $port; |
|
|
|
} |
|
|
|
|
|
|
|
sub start_proc { |
|
|
|
my $self = shift; |
|
|
|
# kill old proc if necessary |
|
|
|
#$self->stop_proc; |
|
|
|
|
|
|
|
if ($self->listening_on($self->{PORT})) { |
|
|
|
diag("\nPort ".$self->{PORT}." already in use"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
# listen on localhost and kernel-assigned ephemeral port |
|
|
|
my $SOCK; |
|
|
|
($SOCK, $self->{PORT}) = bind_ephemeral_tcp_socket(); |
|
|
|
|
|
|
|
# pre-process configfile if necessary |
|
|
|
# |
|
|
@ -175,11 +190,26 @@ sub start_proc { |
|
|
|
my $child = fork(); |
|
|
|
if (not defined $child) { |
|
|
|
diag("\nFork failed"); |
|
|
|
close($SOCK); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
if ($child == 0) { |
|
|
|
# set up systemd socket activation env vars |
|
|
|
$ENV{LISTEN_FDS} = "1"; |
|
|
|
$ENV{LISTEN_PID} = $$; |
|
|
|
listen($SOCK, 1024) || die "listen: $!"; |
|
|
|
if (fileno($SOCK) != 3) { # SD_LISTEN_FDS_START 3 |
|
|
|
require POSIX; |
|
|
|
POSIX::dup2(fileno($SOCK), 3) || die "dup2: $!"; |
|
|
|
close($SOCK); |
|
|
|
} |
|
|
|
else { |
|
|
|
require Fcntl; |
|
|
|
fcntl($SOCK, Fcntl::F_SETFD, 0); # clr FD_CLOEXEC |
|
|
|
} |
|
|
|
exec @cmdline or die($?); |
|
|
|
} |
|
|
|
close($SOCK); |
|
|
|
|
|
|
|
if (0 != $self->wait_for_port_with_proc($self->{PORT}, $child)) { |
|
|
|
diag(sprintf('\nThe process %i is not up', $child)); |
|
|
@ -237,15 +267,15 @@ sub handle_http { |
|
|
|
|
|
|
|
print $remote $_; |
|
|
|
diag("<< ".$_."\n") if $is_debug; |
|
|
|
select(undef, undef, undef, 0.001); |
|
|
|
select(undef, undef, undef, 0.0001); |
|
|
|
print $remote "\015"; |
|
|
|
select(undef, undef, undef, 0.001); |
|
|
|
select(undef, undef, undef, 0.0001); |
|
|
|
print $remote "\012"; |
|
|
|
select(undef, undef, undef, 0.001); |
|
|
|
select(undef, undef, undef, 0.0001); |
|
|
|
print $remote "\015"; |
|
|
|
select(undef, undef, undef, 0.001); |
|
|
|
select(undef, undef, undef, 0.0001); |
|
|
|
print $remote "\012"; |
|
|
|
select(undef, undef, undef, 0.001); |
|
|
|
select(undef, undef, undef, 0.0001); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
@ -428,7 +458,8 @@ sub spawnfcgi { |
|
|
|
setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!"; |
|
|
|
bind(SOCK, sockaddr_in($port, $iaddr)) || die "bind: $!"; |
|
|
|
listen(SOCK, 1024) || die "listen: $!"; |
|
|
|
dup2(fileno(SOCK), 0) || die "dup2: $!"; |
|
|
|
require POSIX; |
|
|
|
POSIX::dup2(fileno(SOCK), 0) || die "dup2: $!"; |
|
|
|
exec { $binary } ($binary) or die($?); |
|
|
|
} else { |
|
|
|
if (0 != $self->wait_for_port_with_proc($port, $child)) { |
|
|
@ -467,7 +498,7 @@ sub has_crypto { |
|
|
|
my $FH; |
|
|
|
open($FH, "-|",$self->{LIGHTTPD_PATH}, "-V") || return 0; |
|
|
|
while (<$FH>) { |
|
|
|
return 1 if (/[+] (?i:OpenSSL|mbedTLS|GnuTLS|WolfSSL|Nettle) support/); |
|
|
|
return 1 if (/[+] (?i:OpenSSL|mbedTLS|GnuTLS|WolfSSL|Nettle|NSS crypto) support/); |
|
|
|
} |
|
|
|
close $FH; |
|
|
|
return 0; |
|
|
|