|
|
|
@ -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;
|
|
|
|
|