[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Bug-wget] [PATCH] Stylistic and idiomatic cleanups in Perl tests
From: |
Pär Karlsson |
Subject: |
Re: [Bug-wget] [PATCH] Stylistic and idiomatic cleanups in Perl tests |
Date: |
Fri, 31 Oct 2014 18:44:03 +0100 |
Oh, and the test suite works on all stable versions of perl from 5.6
through 5.20.
No problems with any of these versions:
perl-5.6.2
perl-5.8.9
perl-5.10.1
perl-5.12.5
perl-5.14.4
perl-5.16.3
perl-5.18.4
perl-5.20.1
And I realize now I probably need some guidance how to format patches
properly for git format-patch/send-email. Sorry about the spam :-/
Best regards,
/Pär
2014-10-30 20:54 GMT+01:00 <address@hidden>:
> From: Pär Karlsson <address@hidden>
>
> ---
> tests/ChangeLog | 12 +
> tests/FTPServer.pm | 597
> +++++++++++++++++++++++----------------
> tests/FTPTest.pm | 36 +--
> tests/HTTPServer.pm | 208 +++++++++-----
> tests/HTTPTest.pm | 28 +-
> tests/Makefile.am | 2 +-
> tests/Test-proxied-https-auth.px | 2 +-
> tests/WgetFeature.pm | 41 ++-
> tests/WgetTest.pm | 423 +++++++++++++++++++++++++++
> tests/WgetTests.pm | 334 ----------------------
> 10 files changed, 993 insertions(+), 690 deletions(-)
>
> diff --git a/tests/ChangeLog b/tests/ChangeLog
> index 5f37f63..a05d65c 100644
> --- a/tests/ChangeLog
> +++ b/tests/ChangeLog
> @@ -1,3 +1,15 @@
> +2014-10-30 Pär Karlsson <address@hidden>
> + * WgetTests.pm: Renamed to WgetTest.pm to match package definition
> + * WgetTest.pm: Proper conditional operators, tidied up code,
> idiomatic
> + improvements as per modern Perl best practices.
> + * WgetFeature.pm: Tidied up code, idiomatic improvements for
> readability
> + * FTPServer.pm: Tidied up code (perltidy -gnu)
> + * FTPTest.pm: Likewise
> + * HTTPServer.pm: Likewise
> + * HTTPTest.pm: Likewise
> + * Makefile.am: Track name change of WgetTests.pm => WgetTest.pm
> + * Test-proxied-https-auth.px: Tidied up code
> +
> 2014-10-30 Mike Frysinger <address@hidden>
>
> * WgetFeature.pm: fix skip exit code to 77
> diff --git a/tests/FTPServer.pm b/tests/FTPServer.pm
> index 1603caa..6d8ad72 100644
> --- a/tests/FTPServer.pm
> +++ b/tests/FTPServer.pm
> @@ -19,43 +19,40 @@ my $GOT_SIGURG = 0;
>
> # connection states
> my %_connection_states = (
> - 'NEWCONN' => 0x01,
> - 'WAIT4PWD' => 0x02,
> - 'LOGGEDIN' => 0x04,
> - 'TWOSOCKS' => 0x08,
> -);
> + 'NEWCONN' => 0x01,
> + 'WAIT4PWD' => 0x02,
> + 'LOGGEDIN' => 0x04,
> + 'TWOSOCKS' => 0x08,
> + );
>
> # subset of FTP commands supported by these server and the respective
> # connection states in which they are allowed
> my %_commands = (
> +
> # Standard commands from RFC 959.
> - 'CWD' => $_connection_states{LOGGEDIN} |
> - $_connection_states{TWOSOCKS},
> -# 'EPRT' => $_connection_states{LOGGEDIN},
> -# 'EPSV' => $_connection_states{LOGGEDIN},
> + 'CWD' => $_connection_states{LOGGEDIN} |
> $_connection_states{TWOSOCKS},
> +
> + # 'EPRT' => $_connection_states{LOGGEDIN},
> + # 'EPSV' => $_connection_states{LOGGEDIN},
> 'LIST' => $_connection_states{TWOSOCKS},
> -# 'LPRT' => $_connection_states{LOGGEDIN},
> -# 'LPSV' => $_connection_states{LOGGEDIN},
> +
> + # 'LPRT' => $_connection_states{LOGGEDIN},
> + # 'LPSV' => $_connection_states{LOGGEDIN},
> 'PASS' => $_connection_states{WAIT4PWD},
> 'PASV' => $_connection_states{LOGGEDIN},
> 'PORT' => $_connection_states{LOGGEDIN},
> - 'PWD' => $_connection_states{LOGGEDIN} |
> - $_connection_states{TWOSOCKS},
> - 'QUIT' => $_connection_states{LOGGEDIN} |
> - $_connection_states{TWOSOCKS},
> + 'PWD' => $_connection_states{LOGGEDIN} |
> $_connection_states{TWOSOCKS},
> + 'QUIT' => $_connection_states{LOGGEDIN} |
> $_connection_states{TWOSOCKS},
> 'REST' => $_connection_states{TWOSOCKS},
> 'RETR' => $_connection_states{TWOSOCKS},
> 'SYST' => $_connection_states{LOGGEDIN},
> - 'TYPE' => $_connection_states{LOGGEDIN} |
> - $_connection_states{TWOSOCKS},
> + 'TYPE' => $_connection_states{LOGGEDIN} |
> $_connection_states{TWOSOCKS},
> 'USER' => $_connection_states{NEWCONN},
> +
> # From ftpexts Internet Draft.
> - 'SIZE' => $_connection_states{LOGGEDIN} |
> - $_connection_states{TWOSOCKS},
> + 'SIZE' => $_connection_states{LOGGEDIN} |
> $_connection_states{TWOSOCKS},
> );
>
> -
> -
> # COMMAND-HANDLING ROUTINES
>
> sub _CWD_command
> @@ -67,7 +64,8 @@ sub _CWD_command
> my $new_path = FTPPaths::path_merge($conn->{'dir'}, $path);
>
> # Split the path into its component parts and process each separately.
> - if (! $paths->dir_exists($new_path)) {
> + if (!$paths->dir_exists($new_path))
> + {
> print {$conn->{socket}} "550 Directory not found.\r\n";
> return;
> }
> @@ -81,25 +79,24 @@ sub _LIST_command
> my ($conn, $cmd, $path) = @_;
> my $paths = $conn->{'paths'};
>
> - my $ReturnEmptyList = ( $paths->GetBehavior('list_empty_if_list_a') &&
> - $path eq '-a');
> - my $SkipHiddenFiles = ( $paths->GetBehavior('list_no_hidden_if_list')
> &&
> - ( ! $path ) );
> + my $ReturnEmptyList =
> + ($paths->GetBehavior('list_empty_if_list_a') && $path eq '-a');
> + my $SkipHiddenFiles =
> + ($paths->GetBehavior('list_no_hidden_if_list') && (!$path));
>
> if ($paths->GetBehavior('list_fails_if_list_a') && $path eq '-a')
> - {
> - print {$conn->{socket}} "500 Unknown command\r\n";
> - return;
> - }
> -
> + {
> + print {$conn->{socket}} "500 Unknown command\r\n";
> + return;
> + }
>
> if (!$paths->GetBehavior('list_dont_clean_path'))
> - {
> + {
> # This is something of a hack. Some clients expect a Unix server
> # to respond to flags on the 'ls command line'. Remove these flags
> # and ignore them. This is particularly an issue with ncftp 2.4.3.
> $path =~ s/^-[a-zA-Z0-9]+\s?//;
> - }
> + }
>
> my $dir = $conn->{'dir'};
>
> @@ -111,39 +108,44 @@ sub _LIST_command
>
> my $listing;
> if (!$ReturnEmptyList)
> - {
> + {
> $dir = FTPPaths::path_merge($dir, $path);
> - $listing = $paths->get_list($dir,$SkipHiddenFiles);
> - unless ($listing) {
> + $listing = $paths->get_list($dir, $SkipHiddenFiles);
> + unless ($listing)
> + {
> print {$conn->{socket}} "550 File or directory not
> found.\r\n";
> return;
> }
> - }
> + }
>
> print STDERR "_LIST_command - dir is: $dir\n" if $log;
>
> print {$conn->{socket}} "150 Opening data connection for file
> listing.\r\n";
>
> # Open a path back to the client.
> - my $sock = __open_data_connection ($conn);
> - unless ($sock) {
> + my $sock = __open_data_connection($conn);
> + unless ($sock)
> + {
> print {$conn->{socket}} "425 Can't open data connection.\r\n";
> return;
> }
>
> if (!$ReturnEmptyList)
> - {
> - for my $item (@$listing) {
> + {
> + for my $item (@$listing)
> + {
> print $sock "$item\r\n";
> }
> - }
> + }
>
> - unless ($sock->close) {
> + unless ($sock->close)
> + {
> print {$conn->{socket}} "550 Error closing data connection:
> $!\r\n";
> return;
> }
>
> - print {$conn->{socket}} "226 Listing complete. Data connection has
> been closed.\r\n";
> + print {$conn->{socket}}
> + "226 Listing complete. Data connection has been closed.\r\n";
> }
>
> sub _PASS_command
> @@ -155,10 +157,15 @@ sub _PASS_command
> print STDERR "switching to LOGGEDIN state\n" if $log;
> $conn->{state} = $_connection_states{LOGGEDIN};
>
> - if ($conn->{username} eq "anonymous") {
> - print {$conn->{socket}} "202 Anonymous user access is always
> granted.\r\n";
> - } else {
> - print {$conn->{socket}} "230 Authentication not implemented yet,
> access is always granted.\r\n";
> + if ($conn->{username} eq "anonymous")
> + {
> + print {$conn->{socket}}
> + "202 Anonymous user access is always granted.\r\n";
> + }
> + else
> + {
> + print {$conn->{socket}}
> + "230 Authentication not implemented yet, access is always
> granted.\r\n";
> }
> }
>
> @@ -167,28 +174,31 @@ sub _PASV_command
> my ($conn, $cmd, $rest) = @_;
>
> # Open a listening socket - but don't actually accept on it yet.
> - "0" =~ /(0)/; # Perl 5.7 / IO::Socket::INET bug workaround.
> - my $sock = IO::Socket::INET->new (LocalHost => '127.0.0.1',
> - LocalPort => '0',
> - Listen => 1,
> - Reuse => 1,
> - Proto => 'tcp',
> - Type => SOCK_STREAM);
> -
> - unless ($sock) {
> + "0" =~ /(0)/; # Perl 5.7 / IO::Socket::INET bug workaround.
> + my $sock = IO::Socket::INET->new(
> + LocalHost => '127.0.0.1',
> + LocalPort => '0',
> + Listen => 1,
> + Reuse => 1,
> + Proto => 'tcp',
> + Type => SOCK_STREAM
> + );
> +
> + unless ($sock)
> + {
> # Return a code 550 here, even though this is not in the RFC. XXX
> print {$conn->{socket}} "550 Can't open a listening socket.\r\n";
> return;
> }
>
> - $conn->{passive} = 1;
> + $conn->{passive} = 1;
> $conn->{passive_socket} = $sock;
>
> # Get our port number.
> my $sockport = $sock->sockport;
>
> # Split the port number into high and low components.
> - my $p1 = int ($sockport / 256);
> + my $p1 = int($sockport / 256);
> my $p2 = $sockport % 256;
>
> $conn->{state} = $_connection_states{TWOSOCKS};
> @@ -204,33 +214,42 @@ sub _PORT_command
> # The arguments to PORT are a1,a2,a3,a4,p1,p2 where a1 is the
> # most significant part of the address (eg. 127,0,0,1) and
> # p1 is the most significant part of the port.
> - unless ($rest =~
> /^\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})/)
> {
> + unless ($rest =~
> +
> /^\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})/
> + )
> + {
> print {$conn->{socket}} "501 Syntax error in PORT command.\r\n";
> return;
> }
>
> # Check host address.
> - unless ($1 > 0 && $1 < 224 &&
> - $2 >= 0 && $2 < 256 &&
> - $3 >= 0 && $3 < 256 &&
> - $4 >= 0 && $4 < 256) {
> + unless ( $1 > 0
> + && $1 < 224
> + && $2 >= 0
> + && $2 < 256
> + && $3 >= 0
> + && $3 < 256
> + && $4 >= 0
> + && $4 < 256)
> + {
> print {$conn->{socket}} "501 Invalid host address.\r\n";
> return;
> }
>
> # Construct host address and port number.
> my $peeraddrstring = "$1.$2.$3.$4";
> - my $peerport = $5 * 256 + $6;
> + my $peerport = $5 * 256 + $6;
>
> # Check port number.
> - unless ($peerport > 0 && $peerport < 65536) {
> + unless ($peerport > 0 && $peerport < 65536)
> + {
> print {$conn->{socket}} "501 Invalid port number.\r\n";
> }
>
> $conn->{peeraddrstring} = $peeraddrstring;
> - $conn->{peeraddr} = inet_aton ($peeraddrstring);
> - $conn->{peerport} = $peerport;
> - $conn->{passive} = 0;
> + $conn->{peeraddr} = inet_aton($peeraddrstring);
> + $conn->{peerport} = $peerport;
> + $conn->{passive} = 0;
>
> $conn->{state} = $_connection_states{TWOSOCKS};
>
> @@ -253,8 +272,10 @@ sub _REST_command
> {
> my ($conn, $cmd, $restart_from) = @_;
>
> - unless ($restart_from =~ /^([1-9][0-9]*|0)$/) {
> - print {$conn->{socket}} "501 REST command needs a numeric
> argument.\r\n";
> + unless ($restart_from =~ /^([1-9][0-9]*|0)$/)
> + {
> + print {$conn->{socket}}
> + "501 REST command needs a numeric argument.\r\n";
> return;
> }
>
> @@ -270,19 +291,21 @@ sub _RETR_command
> $path = FTPPaths::path_merge($conn->{dir}, $path);
> my $info = $conn->{'paths'}->get_info($path);
>
> - unless ($info->{'_type'} eq 'f') {
> + unless ($info->{'_type'} eq 'f')
> + {
> print {$conn->{socket}} "550 File not found.\r\n";
> return;
> }
>
> - print {$conn->{socket}} "150 Opening " .
> - ($conn->{type} eq 'A' ? "ASCII mode" : "BINARY mode") .
> - " data connection.\r\n";
> + print {$conn->{socket}} "150 Opening "
> + . ($conn->{type} eq 'A' ? "ASCII mode" : "BINARY mode")
> + . " data connection.\r\n";
>
> # Open a path back to the client.
> - my $sock = __open_data_connection ($conn);
> + my $sock = __open_data_connection($conn);
>
> - unless ($sock) {
> + unless ($sock)
> + {
> print {$conn->{socket}} "425 Can't open data connection.\r\n";
> return;
> }
> @@ -290,13 +313,14 @@ sub _RETR_command
> my $content = $info->{'content'};
>
> # Restart the connection from previous point?
> - if ($conn->{restart}) {
> + if ($conn->{restart})
> + {
> $content = substr($content, $conn->{restart});
> $conn->{restart} = 0;
> }
>
> # What mode are we sending this file in?
> - unless ($conn->{type} eq 'A') # Binary type.
> + unless ($conn->{type} eq 'A') # Binary type.
> {
> my ($r, $buffer, $n, $w, $sent);
>
> @@ -310,14 +334,16 @@ sub _RETR_command
> # Restart alarm clock timer.
> alarm $conn->{idle_timeout};
>
> - for ($n = 0; $n < $r; )
> + for ($n = 0 ; $n < $r ;)
> {
> - $w = syswrite ($sock, $buffer, $r - $n, $n);
> + $w = syswrite($sock, $buffer, $r - $n, $n);
>
> # Cleanup and exit if there was an error.
> - unless (defined $w) {
> + unless (defined $w)
> + {
> close $sock;
> - print {$conn->{socket}} "426 File retrieval error:
> $!. Data connection has been closed.\r\n";
> + print {$conn->{socket}}
> + "426 File retrieval error: $!. Data connection has
> been closed.\r\n";
> return;
> }
>
> @@ -325,25 +351,32 @@ sub _RETR_command
> }
>
> # Transfer aborted by client?
> - if ($GOT_SIGURG) {
> + if ($GOT_SIGURG)
> + {
> $GOT_SIGURG = 0;
> close $sock;
> - print {$conn->{socket}} "426 Transfer aborted. Data
> connection closed.\r\n";
> + print {$conn->{socket}}
> + "426 Transfer aborted. Data connection closed.\r\n";
> return;
> }
> $sent += $r;
> }
>
> # Cleanup and exit if there was an error.
> - unless (defined $r) {
> + unless (defined $r)
> + {
> close $sock;
> - print {$conn->{socket}} "426 File retrieval error: $!. Data
> connection has been closed.\r\n";
> + print {$conn->{socket}}
> + "426 File retrieval error: $!. Data connection has been
> closed.\r\n";
> return;
> }
> - } else { # ASCII type.
> - # Copy data.
> + }
> + else
> + { # ASCII type.
> + # Copy data.
> my @lines = split /\r\n?|\n/, $content;
> - for (@lines) {
> + for (@lines)
> + {
> # Remove any native line endings.
> s/[\n\r]+$//;
>
> @@ -354,21 +387,25 @@ sub _RETR_command
> print $sock "$_\r\n";
>
> # Transfer aborted by client?
> - if ($GOT_SIGURG) {
> + if ($GOT_SIGURG)
> + {
> $GOT_SIGURG = 0;
> close $sock;
> - print {$conn->{socket}} "426 Transfer aborted. Data
> connection closed.\r\n";
> + print {$conn->{socket}}
> + "426 Transfer aborted. Data connection closed.\r\n";
> return;
> }
> }
> }
>
> - unless (close ($sock)) {
> + unless (close($sock))
> + {
> print {$conn->{socket}} "550 File retrieval error: $!.\r\n";
> return;
> }
>
> - print {$conn->{socket}} "226 File retrieval complete. Data connection
> has been closed.\r\n";
> + print {$conn->{socket}}
> + "226 File retrieval complete. Data connection has been closed.\r\n";
> }
>
> sub _SIZE_command
> @@ -377,13 +414,16 @@ sub _SIZE_command
>
> $path = FTPPaths::path_merge($conn->{dir}, $path);
> my $info = $conn->{'paths'}->get_info($path);
> - unless ($info) {
> + unless ($info)
> + {
> print {$conn->{socket}} "550 File or directory not found.\r\n";
> return;
> }
>
> - if ($info->{'_type'} eq 'd') {
> - print {$conn->{socket}} "550 SIZE command is not supported on
> directories.\r\n";
> + if ($info->{'_type'} eq 'd')
> + {
> + print {$conn->{socket}}
> + "550 SIZE command is not supported on directories.\r\n";
> return;
> }
>
> @@ -397,13 +437,14 @@ sub _SYST_command
> my ($conn, $cmd, $dummy) = @_;
>
> if ($conn->{'paths'}->GetBehavior('syst_response'))
> - {
> - print {$conn->{socket}}
> $conn->{'paths'}->GetBehavior('syst_response') . "\r\n";
> - }
> + {
> + print {$conn->{socket}}
> $conn->{'paths'}->GetBehavior('syst_response')
> + . "\r\n";
> + }
> else
> - {
> + {
> print {$conn->{socket}} "215 UNIX Type: L8\r\n";
> - }
> + }
> }
>
> sub _TYPE_command
> @@ -411,14 +452,22 @@ sub _TYPE_command
> my ($conn, $cmd, $type) = @_;
>
> # See RFC 959 section 5.3.2.
> - if ($type =~ /^([AI])$/i) {
> + if ($type =~ /^([AI])$/i)
> + {
> $conn->{type} = $1;
> - } elsif ($type =~ /^([AI])\sN$/i) {
> + }
> + elsif ($type =~ /^([AI])\sN$/i)
> + {
> $conn->{type} = $1;
> - } elsif ($type =~ /^L\s8$/i) {
> + }
> + elsif ($type =~ /^L\s8$/i)
> + {
> $conn->{type} = 'L8';
> - } else {
> - print {$conn->{socket}} "504 This server does not support TYPE
> $type.\r\n";
> + }
> + else
> + {
> + print {$conn->{socket}}
> + "504 This server does not support TYPE $type.\r\n";
> return;
> }
>
> @@ -435,14 +484,16 @@ sub _USER_command
> print STDERR "switching to WAIT4PWD state\n" if $log;
> $conn->{state} = $_connection_states{WAIT4PWD};
>
> - if ($conn->{username} eq "anonymous") {
> + if ($conn->{username} eq "anonymous")
> + {
> print {$conn->{socket}} "230 Anonymous user access granted.\r\n";
> - } else {
> + }
> + else
> + {
> print {$conn->{socket}} "331 Password required.\r\n";
> }
> }
>
> -
> # HELPER ROUTINES
>
> sub __open_data_connection
> @@ -451,36 +502,41 @@ sub __open_data_connection
>
> my $sock;
>
> - if ($conn->{passive}) {
> + if ($conn->{passive})
> + {
> # Passive mode - wait for a connection from the client.
> - accept ($sock, $conn->{passive_socket}) or return undef;
> - } else {
> + accept($sock, $conn->{passive_socket}) or return undef;
> + }
> + else
> + {
> # Active mode - connect back to the client.
> - "0" =~ /(0)/; # Perl 5.7 / IO::Socket::INET bug workaround.
> - $sock = IO::Socket::INET->new (LocalAddr => '127.0.0.1',
> - PeerAddr =>
> $conn->{peeraddrstring},
> - PeerPort => $conn->{peerport},
> - Proto => 'tcp',
> - Type => SOCK_STREAM) or return
> undef;
> + "0" =~ /(0)/; # Perl 5.7 / IO::Socket::INET bug workaround.
> + $sock = IO::Socket::INET->new(
> + LocalAddr => '127.0.0.1',
> + PeerAddr =>
> $conn->{peeraddrstring},
> + PeerPort => $conn->{peerport},
> + Proto => 'tcp',
> + Type => SOCK_STREAM
> + )
> + or return undef;
> }
>
> return $sock;
> }
>
> -
>
> ###########################################################################
> # FTPSERVER CLASS
>
> ###########################################################################
>
> {
> - my %_attr_data = ( # DEFAULT
> - _input => undef,
> - _localAddr => 'localhost',
> - _localPort => undef,
> - _reuseAddr => 1,
> - _rootDir => Cwd::getcwd(),
> - _server_behavior => {},
> - );
> + my %_attr_data = ( # DEFAULT
> + _input => undef,
> + _localAddr => 'localhost',
> + _localPort => undef,
> + _reuseAddr => 1,
> + _rootDir => Cwd::getcwd(),
> + _server_behavior => {},
> + );
>
> sub _default_for
> {
> @@ -494,34 +550,44 @@ sub __open_data_connection
> }
> }
>
> -
> -sub new {
> +sub new
> +{
> my ($caller, %args) = @_;
> my $caller_is_obj = ref($caller);
> - my $class = $caller_is_obj || $caller;
> - my $self = bless {}, $class;
> - foreach my $attrname ($self->_standard_keys()) {
> + my $class = $caller_is_obj || $caller;
> + my $self = bless {}, $class;
> + foreach my $attrname ($self->_standard_keys())
> + {
> my ($argname) = ($attrname =~ /^_(.*)/);
> - if (exists $args{$argname}) {
> + if (exists $args{$argname})
> + {
> $self->{$attrname} = $args{$argname};
> - } elsif ($caller_is_obj) {
> + }
> + elsif ($caller_is_obj)
> + {
> $self->{$attrname} = $caller->{$attrname};
> - } else {
> + }
> + else
> + {
> $self->{$attrname} = $self->_default_for($attrname);
> }
> }
> +
> # create server socket
> - "0" =~ /(0)/; # Perl 5.7 / IO::Socket::INET bug workaround.
> - $self->{_server_sock}
> - = IO::Socket::INET->new (LocalHost =>
> $self->{_localAddr},
> - LocalPort =>
> $self->{_localPort},
> - Listen => 1,
> - Reuse => $self->{_reuseAddr},
> - Proto => 'tcp',
> - Type => SOCK_STREAM)
> - or die "bind: $!";
> -
> - foreach my $file (keys %{$self->{_input}}) {
> + "0" =~ /(0)/; # Perl 5.7 / IO::Socket::INET bug workaround.
> + $self->{_server_sock} =
> + IO::Socket::INET->new(
> + LocalHost => $self->{_localAddr},
> + LocalPort => $self->{_localPort},
> + Listen => 1,
> + Reuse => $self->{_reuseAddr},
> + Proto => 'tcp',
> + Type => SOCK_STREAM
> + )
> + or die "bind: $!";
> +
> + foreach my $file (keys %{$self->{_input}})
> + {
> my $ref = \$self->{_input}{$file}{content};
> $$ref =~ s/{{port}}/$self->sockport/eg;
> }
> @@ -529,18 +595,18 @@ sub new {
> return $self;
> }
>
> -
> sub run
> {
> my ($self, $synch_callback) = @_;
> my $initialized = 0;
>
> # turn buffering off on STDERR
> - select((select(STDERR), $|=1)[0]);
> + select((select(STDERR), $| = 1)[0]);
>
> # initialize command table
> my $command_table = {};
> - foreach (keys %_commands) {
> + foreach (keys %_commands)
> + {
> my $subname = "_${_}_command";
> $command_table->{$_} = \&$subname;
> }
> @@ -548,7 +614,8 @@ sub run
> my $old_ils = $/;
> $/ = "\r\n";
>
> - if (!$initialized) {
> + if (!$initialized)
> + {
> $synch_callback->();
> $initialized = 1;
> }
> @@ -557,14 +624,14 @@ sub run
> my $server_sock = $self->{_server_sock};
>
> # the accept loop
> - while (my $client_addr = accept (my $socket, $server_sock))
> + while (my $client_addr = accept(my $socket, $server_sock))
> {
> # turn buffering off on $socket
> - select((select($socket), $|=1)[0]);
> + select((select($socket), $| = 1)[0]);
>
> # find out who connected
> - my ($client_port, $client_ip) = sockaddr_in ($client_addr);
> - my $client_ipnum = inet_ntoa ($client_ip);
> + my ($client_port, $client_ip) = sockaddr_in($client_addr);
> + my $client_ipnum = inet_ntoa($client_ip);
>
> # print who connected
> print STDERR "got a connection from: $client_ipnum\n" if $log;
> @@ -577,11 +644,12 @@ sub run
> # next;
> # }
>
> - if (1) { # Child process.
> + if (1)
> + { # Child process.
>
> # install signals
> - $SIG{URG} = sub {
> - $GOT_SIGURG = 1;
> + $SIG{URG} = sub {
> + $GOT_SIGURG = 1;
> };
>
> $SIG{PIPE} = sub {
> @@ -590,33 +658,35 @@ sub run
> };
>
> $SIG{ALRM} = sub {
> - print STDERR "Connection idle timeout expired. Closing
> server.\n";
> + print STDERR
> + "Connection idle timeout expired. Closing server.\n";
> exit;
> };
>
> #$SIG{CHLD} = 'IGNORE';
>
> -
> print STDERR "in child\n" if $log;
>
> my $conn = {
> - 'paths' => FTPPaths->new($self->{'_input'},
> - $self->{'_server_behavior'}),
> - 'socket' => $socket,
> - 'state' => $_connection_states{NEWCONN},
> - 'dir' => '/',
> - 'restart' => 0,
> - 'idle_timeout' => 60, # 1 minute timeout
> - 'rootdir' => $self->{_rootDir},
> - };
> -
> - print {$conn->{socket}} "220 GNU Wget Testing FTP Server
> ready.\r\n";
> + 'paths' =>
> + FTPPaths->new($self->{'_input'},
> $self->{'_server_behavior'}),
> + 'socket' => $socket,
> + 'state' => $_connection_states{NEWCONN},
> + 'dir' => '/',
> + 'restart' => 0,
> + 'idle_timeout' => 60, # 1 minute timeout
> + 'rootdir' => $self->{_rootDir},
> + };
> +
> + print {$conn->{socket}}
> + "220 GNU Wget Testing FTP Server ready.\r\n";
>
> # command handling loop
> - for (;;) {
> + for (; ;)
> + {
> print STDERR "waiting for request\n" if $log;
>
> - last unless defined (my $req = <$socket>);
> + last unless defined(my $req = <$socket>);
>
> # Remove trailing CRLF.
> $req =~ s/[\n\r]+$//;
> @@ -625,7 +695,8 @@ sub run
>
> # Get the command.
> # See also RFC 2640 section 3.1.
> - unless ($req =~ m/^([A-Z]{3,4})\s?(.*)/i) {
> + unless ($req =~ m/^([A-Z]{3,4})\s?(.*)/i)
> + {
> # badly formed command
> exit 0;
> }
> @@ -640,34 +711,41 @@ sub run
> my ($cmd, $rest) = (uc $1, $2);
>
> # Got a command which matches in the table?
> - unless (exists $command_table->{$cmd}) {
> + unless (exists $command_table->{$cmd})
> + {
> print {$conn->{socket}} "500 Unrecognized
> command.\r\n";
> next;
> }
>
> # Command requires user to be authenticated?
> - unless ($_commands{$cmd} | $conn->{state}) {
> + unless ($_commands{$cmd} | $conn->{state})
> + {
> print {$conn->{socket}} "530 Not logged in.\r\n";
> next;
> }
>
> # Handle the QUIT command specially.
> - if ($cmd eq "QUIT") {
> - print {$conn->{socket}} "221 Goodbye. Service closing
> connection.\r\n";
> + if ($cmd eq "QUIT")
> + {
> + print {$conn->{socket}}
> + "221 Goodbye. Service closing connection.\r\n";
> last;
> }
>
> - if (defined ($self->{_server_behavior}{fail_on_pasv})
> - && $cmd eq 'PASV') {
> + if (defined($self->{_server_behavior}{fail_on_pasv})
> + && $cmd eq 'PASV')
> + {
> undef $self->{_server_behavior}{fail_on_pasv};
> close $socket;
> last;
> }
>
> # Run the command.
> - &{$command_table->{$cmd}} ($conn, $cmd, $rest);
> + &{$command_table->{$cmd}}($conn, $cmd, $rest);
> }
> - } else { # Father
> + }
> + else
> + { # Father
> close $socket;
> }
> }
> @@ -675,18 +753,19 @@ sub run
> $/ = $old_ils;
> }
>
> -sub sockport {
> +sub sockport
> +{
> my $self = shift;
> return $self->{_server_sock}->sockport;
> }
>
> -
> package FTPPaths;
>
> use POSIX qw(strftime);
>
> # not a method
> -sub final_component {
> +sub final_component
> +{
> my $path = shift;
>
> $path =~ s|.*/||;
> @@ -694,34 +773,48 @@ sub final_component {
> }
>
> # not a method
> -sub path_merge {
> - my ($a, $b) = @_;
> +sub path_merge
> +{
> + my ($path_a, $path_b) = @_;
>
> - return $a unless $b;
> + if (!$path_b)
> + {
> + return $path_a;
> + }
>
> - if ($b =~ m.^/.) {
> - $a = '';
> - $b =~ s.^/..;
> + if ($path_b =~ m.^/.)
> + {
> + $path_a = '';
> + $path_b =~ s.^/..;
> }
> - $a =~ s./$..;
> + $path_a =~ s./$..;
>
> - my @components = split('/', $b);
> + my @components = split m{/}msx, $path_b;
>
> - foreach my $c (@components) {
> - if ($c =~ /^\.?$/) {
> + foreach my $c (@components)
> + {
> + if ($c =~ /^\.?$/)
> + {
> next;
> - } elsif ($c eq '..') {
> - next if $a eq '';
> - $a =~ s|/[^/]*$||;
> - } else {
> - $a .= "/$c";
> + }
> + elsif ($c eq '..')
> + {
> + if (!$path_a) {
> + next;
> + }
> + $path_a =~ s|/[^/]*$||;
> + }
> + else
> + {
> + $path_a .= "/$c";
> }
> }
>
> - return $a;
> + return $path_a;
> }
>
> -sub new {
> +sub new
> +{
> my ($this, @args) = @_;
> my $class = ref($this) || $this;
> my $self = {};
> @@ -730,19 +823,23 @@ sub new {
> return $self;
> }
>
> -sub initialize {
> +sub initialize
> +{
> my ($self, $urls, $behavior) = @_;
> my $paths = {_type => 'd'};
>
> # From a path like '/foo/bar/baz.txt', construct $paths such that
> # $paths->{'foo'}->{'bar'}->{'baz.txt'} is
> # $urls->{'/foo/bar/baz.txt'}.
> - for my $path (keys %$urls) {
> - my @components = split('/', $path);
> + for my $path (keys %$urls)
> + {
> + my @components = split m{/}msx, $path;
> shift @components;
> my $x = $paths;
> - for my $c (@components) {
> - unless (exists $x->{$c}) {
> + for my $c (@components)
> + {
> + if (!exists $x->{$c})
> + {
> $x->{$c} = {_type => 'd'};
> }
> $x = $x->{$c};
> @@ -751,32 +848,40 @@ sub initialize {
> $x->{_type} = 'f';
> }
>
> - $self->{'_paths'} = $paths;
> + $self->{'_paths'} = $paths;
> $self->{'_behavior'} = $behavior;
> + return 1;
> }
>
> -sub get_info {
> +sub get_info
> +{
> my ($self, $path, $node) = @_;
> $node = $self->{'_paths'} unless $node;
> my @components = split('/', $path);
> shift @components if @components && $components[0] eq '';
>
> - for my $c (@components) {
> - if ($node->{'_type'} eq 'd') {
> + for my $c (@components)
> + {
> + if ($node->{'_type'} eq 'd')
> + {
> $node = $node->{$c};
> - } else {
> - return undef;
> + }
> + else
> + {
> + return;
> }
> }
> return $node;
> }
>
> -sub dir_exists {
> +sub dir_exists
> +{
> my ($self, $path) = @_;
> - return $self->exists($path, 'd');
> + return $self->path_exists($path, 'd');
> }
>
> -sub exists {
> +sub path_exists
> +{
> # type is optional, in which case we don't check it.
> my ($self, $path, $type) = @_;
> my $paths = $self->{'_paths'};
> @@ -788,52 +893,67 @@ sub exists {
> return 1;
> }
>
> -sub _format_for_list {
> +sub _format_for_list
> +{
> my ($self, $name, $info) = @_;
>
> # XXX: mode should be specifyable as part of the node info.
> my $mode_str;
> - if ($info->{'_type'} eq 'd') {
> + if ($info->{'_type'} eq 'd')
> + {
> $mode_str = 'dr-xr-xr-x';
> - } else {
> + }
> + else
> + {
> $mode_str = '-r--r--r--';
> }
>
> my $size = 0;
> - if ($info->{'_type'} eq 'f') {
> - $size = length $info->{'content'};
> - if ($self->{'_behavior'}{'bad_list'}) {
> + if ($info->{'_type'} eq 'f')
> + {
> + $size = length $info->{'content'};
> + if ($self->{'_behavior'}{'bad_list'})
> + {
> $size = 0;
> }
> }
> - my $date = strftime ("%b %e %H:%M", localtime);
> + my $date = strftime("%b %e %H:%M", localtime);
> return "$mode_str 1 0 0 $size $date $name";
> }
>
> -sub get_list {
> +sub get_list
> +{
> my ($self, $path, $no_hidden) = @_;
> my $info = $self->get_info($path);
> - return undef unless defined $info;
> + if ( !defined $info )
> + {
> + return;
> + }
> my $list = [];
>
> - if ($info->{'_type'} eq 'd') {
> - for my $item (keys %$info) {
> + if ($info->{'_type'} eq 'd')
> + {
> + for my $item (keys %$info)
> + {
> next if $item =~ /^_/;
> +
> # 2013-10-17 Andrea Urbani (matfanjol)
> # I skip the hidden files if requested
> - if (($no_hidden) &&
> - (defined($info->{$item}->{'attr'})) &&
> - (index($info->{$item}->{'attr'}, "H")>=0))
> - {
> + if ( ($no_hidden)
> + && (defined($info->{$item}->{'attr'}))
> + && (index($info->{$item}->{'attr'}, "H") >= 0))
> + {
> # This is an hidden file and I don't want to see it!
> print STDERR "get_list: Skipped hidden file [$item]\n";
> - }
> + }
> else
> - {
> + {
> push @$list, $self->_format_for_list($item,
> $info->{$item});
> - }
> + }
> }
> - } else {
> + }
> + else
> + {
> push @$list, $self->_format_for_list(final_component($path),
> $info);
> }
>
> @@ -858,9 +978,10 @@ sub get_list {
> # to the url files
> # syst_response : if defined, its content is printed
> # out as SYST response
> -sub GetBehavior {
> - my ($self, $name) = @_;
> - return $self->{'_behavior'}{$name};
> +sub GetBehavior
> +{
> + my ($self, $name) = @_;
> + return $self->{'_behavior'}{$name};
> }
>
> 1;
> diff --git a/tests/FTPTest.pm b/tests/FTPTest.pm
> index 98fc061..576ce05 100644
> --- a/tests/FTPTest.pm
> +++ b/tests/FTPTest.pm
> @@ -4,14 +4,13 @@ use strict;
> use warnings;
>
> use FTPServer;
> -use WgetTests;
> +use WgetTest;
>
> our @ISA = qw(WgetTest);
> my $VERSION = 0.01;
>
> -
> {
> - my %_attr_data = ( # DEFAULT
> + my %_attr_data = ( # DEFAULT
> );
>
> sub _default_for
> @@ -28,29 +27,32 @@ my $VERSION = 0.01;
> }
> }
>
> -
> -sub _setup_server {
> +sub _setup_server
> +{
> my $self = shift;
>
> - $self->{_server} = FTPServer->new (input => $self->{_input},
> - server_behavior =>
> - $self->{_server_behavior},
> - LocalAddr => 'localhost',
> - ReuseAddr => 1,
> - rootDir =>
> "$self->{_workdir}/$self->{_name}/input") or die "Cannot create server!!!";
> + $self->{_server} = FTPServer->new(
> + input => $self->{_input},
> + server_behavior => $self->{_server_behavior},
> + LocalAddr => 'localhost',
> + ReuseAddr => 1,
> + rootDir =>
> "$self->{_workdir}/$self->{_name}/input"
> + )
> + or die "Cannot create server!!!";
> }
>
> -
> -sub _launch_server {
> - my $self = shift;
> +sub _launch_server
> +{
> + my $self = shift;
> my $synch_func = shift;
>
> - $self->{_server}->run ($synch_func);
> + $self->{_server}->run($synch_func);
> }
>
> -sub _substitute_port {
> +sub _substitute_port
> +{
> my $self = shift;
> - my $ret = shift;
> + my $ret = shift;
> $ret =~ s/{{port}}/$self->{_server}->sockport/eg;
> return $ret;
> }
> diff --git a/tests/HTTPServer.pm b/tests/HTTPServer.pm
> index adadb45..aacc460 100644
> --- a/tests/HTTPServer.pm
> +++ b/tests/HTTPServer.pm
> @@ -8,47 +8,58 @@ use HTTP::Status;
> use HTTP::Headers;
> use HTTP::Response;
>
> -our @ISA=qw(HTTP::Daemon);
> +our @ISA = qw(HTTP::Daemon);
> my $VERSION = 0.01;
>
> -my $CRLF = "\015\012"; # "\r\n" is not portable
> -my $log = undef;
> +my $CRLF = "\015\012"; # "\r\n" is not portable
> +my $log = undef;
>
> -sub run {
> +sub run
> +{
> my ($self, $urls, $synch_callback) = @_;
> my $initialized = 0;
>
> - while (1) {
> - if (!$initialized) {
> + while (1)
> + {
> + if (!$initialized)
> + {
> $synch_callback->();
> $initialized = 1;
> }
> my $con = $self->accept();
> print STDERR "Accepted a new connection\n" if $log;
> - while (my $req = $con->get_request) {
> + while (my $req = $con->get_request)
> + {
> #my $url_path = $req->url->path;
> my $url_path = $req->url->as_string;
> - if ($url_path =~ m{/$}) { # append 'index.html'
> + if ($url_path =~ m{/$})
> + { # append 'index.html'
> $url_path .= 'index.html';
> }
> +
> #if ($url_path =~ m{^/}) { # remove trailing '/'
> # $url_path = substr ($url_path, 1);
> #}
> - if ($log) {
> + if ($log)
> + {
> print STDERR "Method: ", $req->method, "\n";
> print STDERR "Path: ", $url_path, "\n";
> print STDERR "Available URLs: ", "\n";
> - foreach my $key (keys %$urls) {
> + foreach my $key (keys %$urls)
> + {
> print STDERR $key, "\n";
> }
> }
> - if (exists($urls->{$url_path})) {
> + if (exists($urls->{$url_path}))
> + {
> print STDERR "Serving requested URL: ", $url_path, "\n"
> if $log;
> next unless ($req->method eq "HEAD" || $req->method eq
> "GET");
>
> my $url_rec = $urls->{$url_path};
> $self->send_response($req, $url_rec, $con);
> - } else {
> + }
> + else
> + {
> print STDERR "Requested wrong URL: ", $url_path, "\n" if
> $log;
> $con->send_error($HTTP::Status::RC_FORBIDDEN);
> last;
> @@ -59,73 +70,89 @@ sub run {
> }
> }
>
> -sub send_response {
> +sub send_response
> +{
> my ($self, $req, $url_rec, $con) = @_;
>
> # create response
> my ($code, $msg, $headers);
> my $send_content = ($req->method eq "GET");
> - if (exists $url_rec->{'auth_method'}) {
> + if (exists $url_rec->{'auth_method'})
> + {
> ($send_content, $code, $msg, $headers) =
> - $self->handle_auth($req, $url_rec);
> - } elsif (!$self->verify_request_headers ($req, $url_rec)) {
> + $self->handle_auth($req, $url_rec);
> + }
> + elsif (!$self->verify_request_headers($req, $url_rec))
> + {
> ($send_content, $code, $msg, $headers) =
> - ('', 400, 'Mismatch on expected headers', {});
> - } else {
> + ('', 400, 'Mismatch on expected headers', {});
> + }
> + else
> + {
> ($code, $msg) = @{$url_rec}{'code', 'msg'};
> $headers = $url_rec->{headers};
> }
> - my $resp = HTTP::Response->new ($code, $msg);
> + my $resp = HTTP::Response->new($code, $msg);
> print STDERR "HTTP::Response: \n", $resp->as_string if $log;
>
> - while (my ($name, $value) = each %{$headers}) {
> + while (my ($name, $value) = each %{$headers})
> + {
> # print STDERR "setting header: $name = $value\n";
> $resp->header($name => $value);
> }
> print STDERR "HTTP::Response with headers: \n", $resp->as_string if
> $log;
>
> - if ($send_content) {
> + if ($send_content)
> + {
> my $content = $url_rec->{content};
> - if (exists($url_rec->{headers}{"Content-Length"})) {
> + if (exists($url_rec->{headers}{"Content-Length"}))
> + {
> # Content-Length and length($content) don't match
> # manually prepare the HTTP response
> - $con->send_basic_header($url_rec->{code}, $resp->message,
> $resp->protocol);
> + $con->send_basic_header($url_rec->{code}, $resp->message,
> + $resp->protocol);
> print $con $resp->headers_as_string($CRLF);
> print $con $CRLF;
> print $con $content;
> next;
> }
> - if ($req->header("Range") && !$url_rec->{'force_code'}) {
> + if ($req->header("Range") && !$url_rec->{'force_code'})
> + {
> $req->header("Range") =~ m/bytes=(\d*)-(\d*)/;
> my $content_len = length($content);
> - my $start = $1 ? $1 : 0;
> - my $end = $2 ? $2 : ($content_len - 1);
> - my $len = $2 ? ($2 - $start) : ($content_len - $start);
> - if ($len > 0) {
> - $resp->header("Accept-Ranges" => "bytes");
> + my $start = $1 ? $1 : 0;
> + my $end = $2 ? $2 : ($content_len - 1);
> + my $len = $2 ? ($2 - $start) : ($content_len -
> $start);
> + if ($len > 0)
> + {
> + $resp->header("Accept-Ranges" => "bytes");
> $resp->header("Content-Length" => $len);
> - $resp->header("Content-Range"
> - => "bytes $start-$end/$content_len");
> + $resp->header(
> + "Content-Range" => "bytes
> $start-$end/$content_len");
> $resp->header("Keep-Alive" => "timeout=15, max=100");
> $resp->header("Connection" => "Keep-Alive");
> $con->send_basic_header(206,
> - "Partial Content", $resp->protocol);
> + "Partial Content",
> $resp->protocol);
> print $con $resp->headers_as_string($CRLF);
> print $con $CRLF;
> print $con substr($content, $start, $len);
> - } else {
> + }
> + else
> + {
> $con->send_basic_header(416, "Range Not Satisfiable",
> - $resp->protocol);
> + $resp->protocol);
> $resp->header("Keep-Alive" => "timeout=15, max=100");
> $resp->header("Connection" => "Keep-Alive");
> print $con $CRLF;
> }
> next;
> }
> +
> # fill in content
> $content = $self->_substitute_port($content) if defined $content;
> $resp->content($content);
> - print STDERR "HTTP::Response with content: \n", $resp->as_string
> if $log;
> + print STDERR "HTTP::Response with content: \n", $resp->as_string
> + if $log;
> }
>
> $con->send_response($resp);
> @@ -134,60 +161,81 @@ sub send_response {
>
> # Generates appropriate response content based on the authentication
> # status of the URL.
> -sub handle_auth {
> +sub handle_auth
> +{
> my ($self, $req, $url_rec) = @_;
> my ($send_content, $code, $msg, $headers);
> +
> # Catch failure to set code, msg:
> $code = 500;
> $msg = "Didn't set response code in handle_auth";
> +
> # Most cases, we don't want to send content.
> $send_content = 0;
> +
> # Initialize headers
> $headers = {};
> my $authhdr = $req->header('Authorization');
>
> # Have we sent the challenge yet?
> - unless ($url_rec->{auth_challenged} || $url_rec->{auth_no_challenge})
> {
> + unless ($url_rec->{auth_challenged} || $url_rec->{auth_no_challenge})
> + {
> # Since we haven't challenged yet, we'd better not
> # have received authentication (for our testing purposes).
> - if ($authhdr) {
> + if ($authhdr)
> + {
> $code = 400;
> $msg = "You sent auth before I sent challenge";
> - } else {
> + }
> + else
> + {
> # Send challenge
> $code = 401;
> $msg = "Authorization Required";
> - $headers->{'WWW-Authenticate'} = $url_rec->{'auth_method'}
> - . " realm=\"wget-test\"";
> + $headers->{'WWW-Authenticate'} =
> + $url_rec->{'auth_method'} . " realm=\"wget-test\"";
> $url_rec->{auth_challenged} = 1;
> }
> - } elsif (!defined($authhdr)) {
> + }
> + elsif (!defined($authhdr))
> + {
> # We've sent the challenge; we should have received valid
> # authentication with this one. A normal server would just
> # resend the challenge; but since this is a test, wget just
> # failed it.
> $code = 400;
> $msg = "You didn't send auth after I sent challenge";
> - if ($url_rec->{auth_no_challenge}) {
> - $msg = "--auth-no-challenge but no auth sent."
> + if ($url_rec->{auth_no_challenge})
> + {
> + $msg = "--auth-no-challenge but no auth sent.";
> }
> - } else {
> + }
> + else
> + {
> my ($sent_method) = ($authhdr =~ /^(\S+)/g);
> - unless ($sent_method eq $url_rec->{'auth_method'}) {
> + unless ($sent_method eq $url_rec->{'auth_method'})
> + {
> # Not the authorization type we were expecting.
> $code = 400;
> - $msg = "Expected auth type $url_rec->{'auth_method'} but got "
> - . "$sent_method";
> - } elsif (($sent_method eq 'Digest'
> - && &verify_auth_digest($authhdr, $url_rec, \$msg))
> - ||
> - ($sent_method eq 'Basic'
> - && &verify_auth_basic($authhdr, $url_rec, \$msg))) {
> + $msg = "Expected auth type $url_rec->{'auth_method'} but got
> "
> + . "$sent_method";
> + }
> + elsif (
> + (
> + $sent_method eq 'Digest'
> + && &verify_auth_digest($authhdr, $url_rec, \$msg)
> + )
> + || ( $sent_method eq 'Basic'
> + && &verify_auth_basic($authhdr, $url_rec, \$msg))
> + )
> + {
> # SUCCESSFUL AUTH: send expected message, headers, content.
> ($code, $msg) = @{$url_rec}{'code', 'msg'};
> - $headers = $url_rec->{headers};
> + $headers = $url_rec->{headers};
> $send_content = 1;
> - } else {
> + }
> + else
> + {
> $code = 400;
> }
> }
> @@ -195,43 +243,58 @@ sub handle_auth {
> return ($send_content, $code, $msg, $headers);
> }
>
> -sub verify_auth_digest {
> - return undef; # Not yet implemented.
> +sub verify_auth_digest
> +{
> + return undef; # Not yet implemented.
> }
>
> -sub verify_auth_basic {
> +sub verify_auth_basic
> +{
> require MIME::Base64;
> my ($authhdr, $url_rec, $msgref) = @_;
> - my $expected = MIME::Base64::encode_base64($url_rec->{'user'} . ':'
> - . $url_rec->{'passwd'}, '');
> + my $expected =
> + MIME::Base64::encode_base64(
> + $url_rec->{'user'} . ':' .
> $url_rec->{'passwd'},
> + '');
> my ($got) = $authhdr =~ /^Basic (.*)$/;
> - if ($got eq $expected) {
> + if ($got eq $expected)
> + {
> return 1;
> - } else {
> + }
> + else
> + {
> $$msgref = "Wanted ${expected} got ${got}";
> return undef;
> }
> }
>
> -sub verify_request_headers {
> +sub verify_request_headers
> +{
> my ($self, $req, $url_rec) = @_;
>
> return 1 unless exists $url_rec->{'request_headers'};
> - for my $hdrname (keys %{$url_rec->{'request_headers'}}) {
> + for my $hdrname (keys %{$url_rec->{'request_headers'}})
> + {
> my $must_not_match;
> my $ehdr = $url_rec->{'request_headers'}{$hdrname};
> - if ($must_not_match = ($hdrname =~ /^!(\w+)/)) {
> + if ($must_not_match = ($hdrname =~ /^!(\w+)/))
> + {
> $hdrname = $1;
> }
> - my $rhdr = $req->header ($hdrname);
> - if ($must_not_match) {
> - if (defined $rhdr && $rhdr =~ $ehdr) {
> + my $rhdr = $req->header($hdrname);
> + if ($must_not_match)
> + {
> + if (defined $rhdr && $rhdr =~ $ehdr)
> + {
> $rhdr = '' unless defined $rhdr;
> print STDERR "\n*** Match forbidden $hdrname: $rhdr =~
> $ehdr\n";
> return undef;
> }
> - } else {
> - unless (defined $rhdr && $rhdr =~ $ehdr) {
> + }
> + else
> + {
> + unless (defined $rhdr && $rhdr =~ $ehdr)
> + {
> $rhdr = '' unless defined $rhdr;
> print STDERR "\n*** Mismatch on $hdrname: $rhdr =~
> $ehdr\n";
> return undef;
> @@ -242,9 +305,10 @@ sub verify_request_headers {
> return 1;
> }
>
> -sub _substitute_port {
> +sub _substitute_port
> +{
> my $self = shift;
> - my $ret = shift;
> + my $ret = shift;
> $ret =~ s/{{port}}/$self->sockport/eg;
> return $ret;
> }
> diff --git a/tests/HTTPTest.pm b/tests/HTTPTest.pm
> index e0e436f..5c7f1e9 100644
> --- a/tests/HTTPTest.pm
> +++ b/tests/HTTPTest.pm
> @@ -4,14 +4,13 @@ use strict;
> use warnings;
>
> use HTTPServer;
> -use WgetTests;
> +use WgetTest;
>
> our @ISA = qw(WgetTest);
> my $VERSION = 0.01;
>
> -
> {
> - my %_attr_data = ( # DEFAULT
> + my %_attr_data = ( # DEFAULT
> );
>
> sub _default_for
> @@ -28,25 +27,26 @@ my $VERSION = 0.01;
> }
> }
>
> -
> -sub _setup_server {
> +sub _setup_server
> +{
> my $self = shift;
> - $self->{_server} = HTTPServer->new (LocalAddr => 'localhost',
> - ReuseAddr => 1)
> - or die "Cannot create server!!!";
> + $self->{_server} = HTTPServer->new(LocalAddr => 'localhost',
> + ReuseAddr => 1)
> + or die "Cannot create server!!!";
> }
>
> -
> -sub _launch_server {
> - my $self = shift;
> +sub _launch_server
> +{
> + my $self = shift;
> my $synch_func = shift;
>
> - $self->{_server}->run ($self->{_input}, $synch_func);
> + $self->{_server}->run($self->{_input}, $synch_func);
> }
>
> -sub _substitute_port {
> +sub _substitute_port
> +{
> my $self = shift;
> - my $ret = shift;
> + my $ret = shift;
> $ret =~ s/{{port}}/$self->{_server}->sockport/eg;
> return $ret;
> }
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index 58ef5b7..b8fe2fb 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -129,7 +129,7 @@ PX_TESTS = \
> Test-204.px
>
> EXTRA_DIST = FTPServer.pm FTPTest.pm HTTPServer.pm HTTPTest.pm \
> - WgetTests.pm WgetFeature.pm WgetFeature.cfg $(PX_TESTS) \
> + WgetTest.pm WgetFeature.pm WgetFeature.cfg $(PX_TESTS) \
> certs
>
> check_PROGRAMS = unit-tests
> diff --git a/tests/Test-proxied-https-auth.px
> b/tests/Test-proxied-https-auth.px
> index 272003f..97fb5f0 100755
> --- a/tests/Test-proxied-https-auth.px
> +++ b/tests/Test-proxied-https-auth.px
> @@ -4,7 +4,7 @@ use strict;
> use warnings;
>
> use WgetFeature qw(https);
> -use WgetTests; # For $WGETPATH.
> +use WgetTest; # For $WGETPATH.
>
> my $cert_path;
> my $key_path;
> diff --git a/tests/WgetFeature.pm b/tests/WgetFeature.pm
> index 118e79c..a829fad 100644
> --- a/tests/WgetFeature.pm
> +++ b/tests/WgetFeature.pm
> @@ -3,26 +3,41 @@ package WgetFeature;
> use strict;
> use warnings;
>
> -use WgetTests;
> +our $VERSION = 0.01;
>
> -our %skip_messages;
> -require 'WgetFeature.cfg';
> +use Carp;
> +use English qw(-no_match_vars);
> +use WgetTest;
> +
> +our %SKIP_MESSAGES;
> +{
> + open my $fh, '<', 'WgetFeature.cfg'
> + or croak "Cannot open 'WgetFeature.cfg': $ERRNO";
> + my @lines = <$fh>;
> + close $fh or carp "Cannot close 'WgetFeature.cfg': $ERRNO";
> + eval {
> + @lines;
> + 1;
> + } or carp "Cannot eval 'WgetFeature.cfg': $ERRNO";
> +}
>
> sub import
> {
> my ($class, $feature) = @_;
>
> my $output = `$WgetTest::WGETPATH --version`;
> - my ($list) = $output =~ /^([\+\-]\S+(?:\s+[\+\-]\S+)+)/m;
> - my %have_features = map {
> - my $feature = $_;
> - $feature =~ s/^.//;
> - ($feature, /^\+/ ? 1 : 0);
> - } split /\s+/, $list;
> -
> - unless ($have_features{$feature}) {
> - print $skip_messages{$feature}, "\n";
> - exit 77; # skip
> + my ($list) = $output =~ m/^([+-]\S+(?:\s+[+-]\S+)+)/msx;
> + my %have_features;
> + for my $f (split m/\s+/msx, $list)
> + {
> + my $feat = $f;
> + $feat =~ s/^.//msx;
> + $have_features{$feat} = $f =~ m/^[+]/msx ? 1 : 0;
> + }
> + if (!$have_features{$feature})
> + {
> + print "$SKIP_MESSAGES{$feature}\n";
> + exit 77; # skip
> }
> }
>
> diff --git a/tests/WgetTest.pm b/tests/WgetTest.pm
> new file mode 100644
> index 0000000..889a65b
> --- /dev/null
> +++ b/tests/WgetTest.pm
> @@ -0,0 +1,423 @@
> +package WgetTest;
> +
> +use strict;
> +use warnings;
> +
> +our $VERSION = 0.01;
> +
> +use Carp;
> +use Cwd;
> +use English qw(-no_match_vars);
> +use File::Path;
> +use IO::Handle;
> +use POSIX qw(locale_h);
> +use locale;
> +
> +our $WGETPATH = '../src/wget';
> +
> +my @unexpected_downloads = ();
> +
> +{
> + my %_attr_data = ( # DEFAULT
> + _cmdline => q{},
> + _workdir => Cwd::getcwd(),
> + _errcode => 0,
> + _existing => {},
> + _input => {},
> + _name => $PROGRAM_NAME,
> + _output => {},
> + _server_behavior => {},
> + );
> +
> + sub _default_for
> + {
> + my ($self, $attr) = @_;
> + return $_attr_data{$attr};
> + }
> +
> + sub _standard_keys
> + {
> + return keys %_attr_data;
> + }
> +}
> +
> +sub new
> +{
> + my ($caller, %args) = @_;
> + my $caller_is_obj = ref $caller;
> + my $class = $caller_is_obj || $caller;
> +
> + #print STDERR "class = ", $class, "\n";
> + #print STDERR "_attr_data {workdir} = ",
> $WgetTest::_attr_data{_workdir}, "\n";
> + my $self = bless {}, $class;
> + for my $attrname ($self->_standard_keys())
> + {
> +
> + #print STDERR "attrname = ", $attrname, " value = ";
> + my ($argname) = ($attrname =~ m/^_(.*)/msx);
> + if (exists $args{$argname})
> + {
> +
> + #printf STDERR "Setting up $attrname\n";
> + $self->{$attrname} = $args{$argname};
> + }
> + elsif ($caller_is_obj)
> + {
> +
> + #printf STDERR "Copying $attrname\n";
> + $self->{$attrname} = $caller->{$attrname};
> + }
> + else
> + {
> + #printf STDERR "Using default for $attrname\n";
> + $self->{$attrname} = $self->_default_for($attrname);
> + }
> +
> + #print STDERR $attrname, '=', $self->{$attrname}, "\n";
> + }
> +
> + #printf STDERR "_workdir default = ", $self->_default_for("_workdir");
> + return $self;
> +}
> +
> +sub run
> +{
> + my $self = shift;
> + my $result_message = "Test successful.\n";
> + my $errcode;
> +
> + $self->{_name} =~ s{.*/}{}msx; # remove path
> + $self->{_name} =~ s{[.][^.]+$}{}msx; # remove extension
> + printf "Running test $self->{_name}\n";
> +
> + # Setup
> + my $new_result = $self->_setup();
> + chdir "$self->{_workdir}/$self->{_name}/input"
> + or carp "Could not chdir to input directory: $ERRNO";
> + if (defined $new_result)
> + {
> + $result_message = $new_result;
> + $errcode = 1;
> + goto cleanup;
> + }
> +
> + # Launch server
> + my $pid = $self->_fork_and_launch_server();
> +
> + # Call wget
> + chdir "$self->{_workdir}/$self->{_name}/output"
> + or carp "Could not chdir to output directory: $ERRNO";
> +
> + my $cmdline = $self->{_cmdline};
> + $cmdline = $self->_substitute_port($cmdline);
> + $cmdline =
> + ($cmdline =~ m{^/.*}msx) ? $cmdline : "$self->{_workdir}/$cmdline";
> +
> + my $valgrind = $ENV{VALGRIND_TESTS};
> + if (!defined $valgrind || $valgrind eq q{} || $valgrind == 0)
> + {
> +
> + # Valgrind not requested - leave $cmdline as it is
> + }
> + elsif ($valgrind == 1)
> + {
> + $cmdline =
> + 'valgrind --error-exitcode=301 --leak-check=yes
> --track-origins=yes '
> + . $cmdline;
> + }
> + else
> + {
> + $cmdline = "$valgrind $cmdline";
> + }
> +
> + print "Calling $cmdline\n";
> + $errcode = system $cmdline;
> + $errcode >>= 8; # XXX: should handle abnormal error codes.
> +
> + # Shutdown server
> + # if we didn't explicitely kill the server, we would have to call
> + # waitpid ($pid, 0) here in order to wait for the child process to
> + # terminate
> + kill 'TERM', $pid;
> +
> + # Verify download
> + if ($errcode != $self->{_errcode})
> + {
> + $result_message =
> + "Test failed: wrong code returned (was: $errcode, expected:
> $self->{_errcode})\n";
> + goto CLEANUP;
> + }
> + my $error_str;
> + if ($error_str = $self->_verify_download())
> + {
> + $result_message = $error_str;
> + }
> +
> + CLEANUP:
> + $self->_cleanup();
> +
> + print $result_message;
> + return $errcode != $self->{_errcode} || ($error_str ? 1 : 0);
> +}
> +
> +sub _setup
> +{
> + my $self = shift;
> +
> + chdir $self->{_workdir}
> + or carp "Could not chdir into $self->{_workdir}: $ERRNO";
> +
> + # Create temporary directory
> + mkdir $self->{_name} or carp "Could not mkdir '$self->{_name}':
> $ERRNO";
> + chdir $self->{_name}
> + or carp "Could not chdir into '$self->{_name}': $ERRNO";
> + mkdir 'input' or carp "Could not mkdir 'input' $ERRNO";
> + mkdir 'output' or carp "Could not mkdir 'output': $ERRNO";
> +
> + # Setup existing files
> + chdir 'output' or carp "Could not chdir into 'output': $ERRNO";
> + for my $filename (keys %{$self->{_existing}})
> + {
> + open my $fh, '>', $filename
> + or return "Test failed: cannot open pre-existing file
> $filename\n";
> +
> + my $file = $self->{_existing}->{$filename};
> + print {$fh} $file->{content}
> + or return "Test failed: cannot write pre-existing file
> $filename\n";
> +
> + close $fh or carp $ERRNO;
> +
> + if (exists($file->{timestamp}))
> + {
> + utime $file->{timestamp}, $file->{timestamp}, $filename
> + or return
> + "Test failed: cannot set timestamp on pre-existing file
> $filename\n";
> + }
> + }
> +
> + chdir '../input' or carp "Cannot chdir into '../input': $ERRNO";
> + $self->_setup_server();
> +
> + chdir $self->{_workdir}
> + or carp "Cannot chdir into '$self->{_workdir}': $ERRNO";
> + return;
> +}
> +
> +sub _cleanup
> +{
> + my $self = shift;
> +
> + chdir $self->{_workdir}
> + or carp "Could not chdir into '$self->{_workdir}': $ERRNO";
> + if (!$ENV{WGET_TEST_NO_CLEANUP})
> + {
> + File::Path::rmtree($self->{_name});
> + }
> + return 1;
> +}
> +
> +# not a method
> +sub quotechar
> +{
> + my $c = ord shift;
> + if ($c >= 0x7 && $c <= 0xD)
> + {
> + return q{\\} . qw(a b t n v f r) [$c - 0x7];
> + }
> + else
> + {
> + return sprintf '\\x%02x', $c;
> + }
> +}
> +
> +# not a method
> +sub _show_diff
> +{
> + my ($expected, $actual) = @_;
> + my $SNIPPET_SIZE = 10;
> +
> + my $str = q{};
> + my $explen = length $expected;
> + my $actlen = length $actual;
> +
> + if ($explen != $actlen)
> + {
> + $str .= "Sizes don't match: expected = $explen, actual =
> $actlen\n";
> + }
> +
> + my $min = $explen <= $actlen ? $explen : $actlen;
> + my $line = 1;
> + my $col = 1;
> + my $i;
> +
> + # for ($i=0; $i != $min; ++$i) {
> + for my $i (0 .. $min - 1)
> + {
> + last if substr($expected, $i, 1) ne substr $actual, $i, 1;
> + if (substr($expected, $i, 1) eq q{\n})
> + {
> + $line++;
> + $col = 0;
> + }
> + else
> + {
> + $col++;
> + }
> + }
> + my $snip_start = $i - ($SNIPPET_SIZE / 2);
> + if ($snip_start < 0)
> + {
> + $SNIPPET_SIZE += $snip_start; # Take it from the end.
> + $snip_start = 0;
> + }
> + my $exp_snip = substr $expected, $snip_start, $SNIPPET_SIZE;
> + my $act_snip = substr $actual, $snip_start, $SNIPPET_SIZE;
> + $exp_snip =~ s/[^[:print:]]/ quotechar($&) /gemsx;
> + $act_snip =~ s/[^[:print:]]/ quotechar($&) /gemsx;
> + $str .= "Mismatch at line $line, col $col:\n";
> + $str .= " $exp_snip\n";
> + $str .= " $act_snip\n";
> +
> + return $str;
> +}
> +
> +sub _verify_download
> +{
> + my $self = shift;
> +
> + chdir "$self->{_workdir}/$self->{_name}/output"
> + or carp "Could not chdir into output directory: $ERRNO";
> +
> + # use slurp mode to read file content
> + my $old_input_record_separator = $INPUT_RECORD_SEPARATOR;
> + local $INPUT_RECORD_SEPARATOR = undef;
> +
> + while (my ($filename, $filedata) = each %{$self->{_output}})
> + {
> + open my $fh, '<', $filename
> + or return "Test failed: file $filename not downloaded\n";
> +
> + my $content = <$fh>;
> +
> + close $fh or carp $ERRNO;
> +
> + my $expected_content = $filedata->{'content'};
> + $expected_content = $self->_substitute_port($expected_content);
> + if ($content ne $expected_content)
> + {
> + return "Test failed: wrong content for file $filename\n"
> + . _show_diff($expected_content, $content);
> + }
> +
> + if (exists($filedata->{'timestamp'}))
> + {
> + my (
> + $dev, $ino, $mode, $nlink, $uid,
> + $gid, $rdev, $size, $atime, $mtime,
> + $ctime, $blksize, $blocks
> + )
> + = stat $filename;
> +
> + $mtime == $filedata->{'timestamp'}
> + or return "Test failed: wrong timestamp for file
> $filename\n";
> + }
> +
> + }
> +
> + local $INPUT_RECORD_SEPARATOR = $old_input_record_separator;
> +
> + # make sure no unexpected files were downloaded
> + chdir "$self->{_workdir}/$self->{_name}/output"
> + or carp "Could not change into output directory: $ERRNO";
> +
> + __dir_walk(
> + q{.},
> + sub {
> + if (!(exists $self->{_output}{$_[0]} ||
> $self->{_existing}{$_[0]}))
> + {
> + push @unexpected_downloads, $_[0];
> + }
> + },
> + sub { shift; return @_ }
> + );
> + if (@unexpected_downloads)
> + {
> + return 'Test failed: unexpected downloaded files [' . join ', ',
> + @unexpected_downloads . "]\n";
> + }
> +
> + return q{};
> +}
> +
> +sub __dir_walk
> +{
> + my ($top, $filefunc, $dirfunc) = @_;
> +
> + my $DIR;
> +
> + if (-d $top)
> + {
> + my $file;
> + if (!opendir $DIR, $top)
> + {
> + warn "Couldn't open directory $DIR: $ERRNO; skipping.\n";
> + return;
> + }
> +
> + my @results;
> + while ($file = readdir $DIR)
> + {
> + next if $file eq q{.} || $file eq q{..};
> + my $nextdir = $top eq q{.} ? $file : "$top/$file";
> + push @results, __dir_walk($nextdir, $filefunc, $dirfunc);
> + }
> +
> + return $dirfunc ? $dirfunc->($top, @results) : ();
> + }
> + else
> + {
> + return $filefunc ? $filefunc->($top) : ();
> + }
> +}
> +
> +sub _fork_and_launch_server
> +{
> + my $self = shift;
> +
> + pipe FROM_CHILD, TO_PARENT or croak 'Cannot create pipe!';
> + TO_PARENT->autoflush();
> +
> + my $pid = fork;
> + if ($pid < 0)
> + {
> + carp 'Cannot fork';
> + }
> + elsif ($pid == 0)
> + {
> +
> + # child
> + close FROM_CHILD or carp $ERRNO;
> +
> + # FTP Server has to start with english locale due to use of
> strftime month names in LIST command
> + setlocale(LC_ALL, 'C');
> + $self->_launch_server(
> + sub {
> + print {*TO_PARENT} "SYNC\n";
> + close TO_PARENT or carp $ERRNO;
> + }
> + );
> + }
> + else
> + {
> + # father
> + close TO_PARENT or carp $ERRNO;
> + chomp(my $line = <FROM_CHILD>);
> + close FROM_CHILD or carp $ERRNO;
> + }
> +
> + return $pid;
> +}
> +
> +1;
> +
> +# vim: et ts=4 sw=4
> diff --git a/tests/WgetTests.pm b/tests/WgetTests.pm
> deleted file mode 100644
> index b3d4bc6..0000000
> --- a/tests/WgetTests.pm
> +++ /dev/null
> @@ -1,334 +0,0 @@
> -package WgetTest;
> -$VERSION = 0.01;
> -
> -use strict;
> -use warnings;
> -
> -use Cwd;
> -use File::Path;
> -use POSIX qw(locale_h);
> -use locale;
> -
> -our $WGETPATH = "../src/wget";
> -
> -my @unexpected_downloads = ();
> -
> -{
> - my %_attr_data = ( # DEFAULT
> - _cmdline => "",
> - _workdir => Cwd::getcwd(),
> - _errcode => 0,
> - _existing => {},
> - _input => {},
> - _name => $0,
> - _output => {},
> - _server_behavior => {},
> - );
> -
> - sub _default_for
> - {
> - my ($self, $attr) = @_;
> - $_attr_data{$attr};
> - }
> -
> - sub _standard_keys
> - {
> - keys %_attr_data;
> - }
> -}
> -
> -
> -sub new {
> - my ($caller, %args) = @_;
> - my $caller_is_obj = ref($caller);
> - my $class = $caller_is_obj || $caller;
> - #print STDERR "class = ", $class, "\n";
> - #print STDERR "_attr_data {workdir} = ",
> $WgetTest::_attr_data{_workdir}, "\n";
> - my $self = bless {}, $class;
> - foreach my $attrname ($self->_standard_keys()) {
> - #print STDERR "attrname = ", $attrname, " value = ";
> - my ($argname) = ($attrname =~ /^_(.*)/);
> - if (exists $args{$argname}) {
> - #printf STDERR "Setting up $attrname\n";
> - $self->{$attrname} = $args{$argname};
> - } elsif ($caller_is_obj) {
> - #printf STDERR "Copying $attrname\n";
> - $self->{$attrname} = $caller->{$attrname};
> - } else {
> - #printf STDERR "Using default for $attrname\n";
> - $self->{$attrname} = $self->_default_for($attrname);
> - }
> - #print STDERR $attrname, '=', $self->{$attrname}, "\n";
> - }
> - #printf STDERR "_workdir default = ", $self->_default_for("_workdir");
> - return $self;
> -}
> -
> -
> -sub run {
> - my $self = shift;
> - my $result_message = "Test successful.\n";
> - my $errcode;
> -
> - $self->{_name} =~ s{.*/}{}; # remove path
> - $self->{_name} =~ s{\.[^.]+$}{}; # remove extension
> - printf "Running test $self->{_name}\n";
> -
> - # Setup
> - my $new_result = $self->_setup();
> - chdir ("$self->{_workdir}/$self->{_name}/input");
> - if (defined $new_result) {
> - $result_message = $new_result;
> - $errcode = 1;
> - goto cleanup;
> - }
> -
> - # Launch server
> - my $pid = $self->_fork_and_launch_server();
> -
> - # Call wget
> - chdir ("$self->{_workdir}/$self->{_name}/output");
> -
> - my $cmdline = $self->{_cmdline};
> - $cmdline = $self->_substitute_port($cmdline);
> - $cmdline = ($cmdline =~ m{^/.*}) ? $cmdline :
> "$self->{_workdir}/$cmdline";
> -
> - my $valgrind = $ENV{VALGRIND_TESTS};
> - if (!defined $valgrind || $valgrind == "" || $valgrind == "0") {
> - # Valgrind not requested - leave $cmdline as it is
> - } elsif ($valgrind == "1") {
> - $cmdline = "valgrind --error-exitcode=301 --leak-check=yes
> --track-origins=yes " . $cmdline;
> - } else {
> - $cmdline = $valgrind . " " . $cmdline;
> - }
> -
> - print "Calling $cmdline\n";
> - $errcode = system($cmdline);
> - $errcode >>= 8; # XXX: should handle abnormal error codes.
> -
> - # Shutdown server
> - # if we didn't explicitely kill the server, we would have to call
> - # waitpid ($pid, 0) here in order to wait for the child process to
> - # terminate
> - kill ('TERM', $pid);
> -
> - # Verify download
> - unless ($errcode == $self->{_errcode}) {
> - $result_message = "Test failed: wrong code returned (was:
> $errcode, expected: $self->{_errcode})\n";
> - goto cleanup;
> - }
> - my $error_str;
> - if ($error_str = $self->_verify_download()) {
> - $result_message = $error_str;
> - }
> -
> - cleanup:
> - $self->_cleanup();
> -
> - print $result_message;
> - return $errcode != $self->{_errcode} || ($error_str ? 1 : 0);
> -}
> -
> -
> -sub _setup {
> - my $self = shift;
> -
> - #print $self->{_name}, "\n";
> - chdir ($self->{_workdir});
> -
> - # Create temporary directory
> - mkdir ($self->{_name});
> - chdir ($self->{_name});
> - mkdir ("input");
> - mkdir ("output");
> -
> - # Setup existing files
> - chdir ("output");
> - foreach my $filename (keys %{$self->{_existing}}) {
> - open (FILE, ">$filename")
> - or return "Test failed: cannot open pre-existing file
> $filename\n";
> -
> - my $file = $self->{_existing}->{$filename};
> - print FILE $file->{content}
> - or return "Test failed: cannot write pre-existing file
> $filename\n";
> -
> - close (FILE);
> -
> - if (exists($file->{timestamp})) {
> - utime $file->{timestamp}, $file->{timestamp}, $filename
> - or return "Test failed: cannot set timestamp on
> pre-existing file $filename\n";
> - }
> - }
> -
> - chdir ("../input");
> - $self->_setup_server();
> -
> - chdir ($self->{_workdir});
> - return;
> -}
> -
> -
> -sub _cleanup {
> - my $self = shift;
> -
> - chdir ($self->{_workdir});
> - File::Path::rmtree ($self->{_name}) unless $ENV{WGET_TEST_NO_CLEANUP};
> -}
> -
> -# not a method
> -sub quotechar {
> - my $c = ord( shift );
> - if ($c >= 0x7 && $c <= 0xD) {
> - return '\\' . qw(a b t n v f r)[$c - 0x7];
> - } else {
> - return sprintf('\\x%02x', $c);
> - }
> -}
> -
> -# not a method
> -sub _show_diff {
> - my $SNIPPET_SIZE = 10;
> -
> - my ($expected, $actual) = @_;
> -
> - my $str = '';
> - my $explen = length $expected;
> - my $actlen = length $actual;
> -
> - if ($explen != $actlen) {
> - $str .= "Sizes don't match: expected = $explen, actual =
> $actlen\n";
> - }
> -
> - my $min = $explen <= $actlen? $explen : $actlen;
> - my $line = 1;
> - my $col = 1;
> - my $i;
> - for ($i=0; $i != $min; ++$i) {
> - last if substr($expected, $i, 1) ne substr($actual, $i, 1);
> - if (substr($expected, $i, 1) eq '\n') {
> - $line++;
> - $col = 0;
> - } else {
> - $col++;
> - }
> - }
> - my $snip_start = $i - ($SNIPPET_SIZE / 2);
> - if ($snip_start < 0) {
> - $SNIPPET_SIZE += $snip_start; # Take it from the end.
> - $snip_start = 0;
> - }
> - my $exp_snip = substr($expected, $snip_start, $SNIPPET_SIZE);
> - my $act_snip = substr($actual, $snip_start, $SNIPPET_SIZE);
> - $exp_snip =~s/[^[:print:]]/ quotechar($&) /ge;
> - $act_snip =~s/[^[:print:]]/ quotechar($&) /ge;
> - $str .= "Mismatch at line $line, col $col:\n";
> - $str .= " $exp_snip\n";
> - $str .= " $act_snip\n";
> -
> - return $str;
> -}
> -
> -sub _verify_download {
> - my $self = shift;
> -
> - chdir ("$self->{_workdir}/$self->{_name}/output");
> -
> - # use slurp mode to read file content
> - my $old_input_record_separator = $/;
> - undef $/;
> -
> - while (my ($filename, $filedata) = each %{$self->{_output}}) {
> - open (FILE, $filename)
> - or return "Test failed: file $filename not downloaded\n";
> -
> - my $content = <FILE>;
> - my $expected_content = $filedata->{'content'};
> - $expected_content = $self->_substitute_port($expected_content);
> - unless ($content eq $expected_content) {
> - return "Test failed: wrong content for file $filename\n"
> - . _show_diff($expected_content, $content);
> - }
> -
> - if (exists($filedata->{'timestamp'})) {
> - my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
> - $atime, $mtime, $ctime, $blksize, $blocks) = stat FILE;
> -
> - $mtime == $filedata->{'timestamp'}
> - or return "Test failed: wrong timestamp for file
> $filename\n";
> - }
> -
> - close (FILE);
> - }
> -
> - $/ = $old_input_record_separator;
> -
> - # make sure no unexpected files were downloaded
> - chdir ("$self->{_workdir}/$self->{_name}/output");
> -
> - __dir_walk('.',
> - sub { push @unexpected_downloads,
> - $_[0] unless (exists $self->{_output}{$_[0]} ||
> $self->{_existing}{$_[0]}) },
> - sub { shift; return @_ } );
> - if (@unexpected_downloads) {
> - return "Test failed: unexpected downloaded files [" . join(', ',
> @unexpected_downloads) . "]\n";
> - }
> -
> - return "";
> -}
> -
> -
> -sub __dir_walk {
> - my ($top, $filefunc, $dirfunc) = @_;
> -
> - my $DIR;
> -
> - if (-d $top) {
> - my $file;
> - unless (opendir $DIR, $top) {
> - warn "Couldn't open directory $DIR: $!; skipping.\n";
> - return;
> - }
> -
> - my @results;
> - while ($file = readdir $DIR) {
> - next if $file eq '.' || $file eq '..';
> - my $nextdir = $top eq '.' ? $file : "$top/$file";
> - push @results, __dir_walk($nextdir, $filefunc, $dirfunc);
> - }
> -
> - return $dirfunc ? $dirfunc->($top, @results) : () ;
> - } else {
> - return $filefunc ? $filefunc->($top) : () ;
> - }
> -}
> -
> -
> -sub _fork_and_launch_server
> -{
> - my $self = shift;
> -
> - pipe(FROM_CHILD, TO_PARENT) or die "Cannot create pipe!";
> - select((select(TO_PARENT), $| = 1)[0]);
> -
> - my $pid = fork();
> - if ($pid < 0) {
> - die "Cannot fork";
> - } elsif ($pid == 0) {
> - # child
> - close FROM_CHILD;
> - # FTP Server has to start with english locale due to use of
> strftime month names in LIST command
> - setlocale(LC_ALL,"C");
> - $self->_launch_server(sub { print TO_PARENT "SYNC\n"; close
> TO_PARENT });
> - } else {
> - # father
> - close TO_PARENT;
> - chomp(my $line = <FROM_CHILD>);
> - close FROM_CHILD;
> - }
> -
> - return $pid;
> -}
> -
> -1;
> -
> -# vim: et ts=4 sw=4
> --
> 2.0.4
>
>