From 65f07bce7c5c11d3239d6d7b27fad94b622f746c Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sun, 15 Jun 2014 18:28:51 +0200 Subject: [PATCH] Add privoxy-runtests.pm Overwrites some of the functions used by curl's runtests.pl to let it properly deal with Privoxy being used as proxy. Sponsored by: Privoxy project funds collected at SPI --- tests/cts/privoxy-runtests.pm | 223 ++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 tests/cts/privoxy-runtests.pm diff --git a/tests/cts/privoxy-runtests.pm b/tests/cts/privoxy-runtests.pm new file mode 100644 index 00000000..b04b027d --- /dev/null +++ b/tests/cts/privoxy-runtests.pm @@ -0,0 +1,223 @@ +################################################################################ +# privoxy-runtests.pm +# +# Code that has to be loaded by curl's runtests.pl with the -L option +# to deal with modifications required when using the tests with Privoxy. +# +# Copyright (c) 2014-2022 Fabian Keil +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +################################################################################ + +use strict; +use warnings; +no warnings "redefine"; + +my $verbose = 0; +my $use_external_proxy = 0; + +BEGIN { + # Keep a couple of functions from getpart.pm accessible so + # our redefinitions don't have to reimplement them. + our $real_showdiff = \&showdiff; + our $real_getpart = \&getpart; + our $real_getpartattr = \&getpartattr; + our $real_compareparts = \&compareparts; + our $real_startnew = \&startnew; +} + +sub print_skipped_header($) { + my $skipped_header = shift; + $skipped_header =~ s@\r?\n$@@; + print "Skipping '$skipped_header'\n"; +} + +# Process headers to ignore differences that are to be expected +# when Privoxy is being used. +# +# - Filter out "Proxy-Connection:" headers when checking for +# test success. +# - Filter out a header that is specified with a "X-Ignore-Header" header. +# - Deal with tests that don't expect CRLF header endings as +# long as the test uses it consistently. +# - Reduce spaces in server headers with a too-simplistic heuristic +# that happens to work for the existing tests. +sub process_headers($$) { + my ($head1_ref, $head2_ref) = @_; + my @head1; + my @head2; + my $crlf_expected = 0; + my $connection_header_expected = 0; + my $proxy_connection_header_expected = 0; + my $parsing_server_headers = 0; + my $ignore_header; + my $ignored_header; + + foreach (@$head2_ref) { + if (/^HTTP/) { + # If it starts like a response line, assume we are + # looking at server headers. + $parsing_server_headers = 1; + } + if (/^\r?\n$/) { + $parsing_server_headers = 0; + } + if (/\r\n$/) { + $crlf_expected = 1; # XXX: assume the expectancy is consistent. + } + + if (/^Connection:/) { + $connection_header_expected = 1; + } + if (/^Proxy-Connection:/) { + $proxy_connection_header_expected = 1; + } + if (/^X-Ignore-Header: (.*)/) { + $ignore_header = $1; + print "Ignoring header '$ignore_header'\n" if $verbose; + } + if (defined $ignore_header and /^$ignore_header: .*/) { + $ignored_header = $_; + } + + if ($parsing_server_headers and not /"/) { + # Normalize spaces in server headers similar to the way Privoxy + # does. This is required for curl tests 29, 40, 42 and 54. + s@ +@ @g; + } + } + + if ($verbose) { + print "Expecting " . ($crlf_expected ? "" : "no ") . "crlf\n"; + print "Expecting " . ($connection_header_expected ? "a" : "no") . " Connection: header\n"; + print "Expecting " . ($proxy_connection_header_expected ? "a" : "no") . " Proxy-Connection: header\n"; + } + + foreach (@$head1_ref) { + + s@\r\n$@\n@ unless ($crlf_expected); + + if ((m/^Connection:/ and not $connection_header_expected) or + (m/^Proxy-Connection:/ and not $proxy_connection_header_expected)) { + print_skipped_header($_) if ($verbose); + next; + } + if (defined $ignore_header) { + if (m/^$ignore_header:/) { + push @head1, "X-Ignore-Header: $ignore_header\n"; + $_ = $ignored_header; + } + } + push @head1, $_; + } + $head1_ref = \@head1; + + return ($head1_ref, $head2_ref); +} + +# Behaves like the real compareparts(), but if a proxy is being used, +# headers are run through process_headers() before checking them for +# differences. +sub compareparts { + my ($head1_ref, $head2_ref) = @_; + our $real_compareparts; + + if ($use_external_proxy) { + ($head1_ref, $head2_ref) = process_headers($head1_ref, $head2_ref); + } + + return &$real_compareparts($head1_ref, $head2_ref); +} + +# Behaves like the real getpart() but if a proxy is being used +# and a proxy-reply section exists, it is returned instead of +# a common reply section. +sub getpart { + my ($section, $part) = @_; + our $real_getpart; + + if ($use_external_proxy and + $section eq 'reply' and + partexists("proxy-reply", $part)) { + $section = "proxy-reply"; + } + + return &$real_getpart($section, $part); +} + +# Behaves like the real getpartattr() but if a proxy is being used +# and a proxy-reply section exists, it is being used instead of +# a common reply section. +sub getpartattr { + my ($section, $part)=@_; + our $real_getpartattr; + + if ($use_external_proxy and + $section eq 'reply' and + partexists("proxy-reply", $part)) { + $section = "proxy-reply"; + } + + return &$real_getpartattr($section, $part); +} + +# Behaves like the real logmsg but suppresses warnings +# about unknown tests +sub logmsg { + for (@_) { + next if /^Warning: test\d+ not present in/; + print "$_"; + } +} + +# Behaves like the real showdiff() but diffs twice, +# the second time after processing the headers. +sub showdiff { + my ($logdir, $head1_ref, $head2_ref) = @_; + our $real_showdiff; + + print "Unprocessed headers:\n"; + print &$real_showdiff($logdir, $head1_ref, $head2_ref); + + print "Processed headers:\n"; + ($head1_ref, $head2_ref) = process_headers($head1_ref, $head2_ref); + return &$real_showdiff($logdir, $head1_ref, $head2_ref); +} + +# Behaves like the real startnew() but sets a static port if +# the started server is httpserver.pl. +sub startnew { + my ($cmd, $pidfile, $timeout, $fake) = @_; + our $real_startnew; + + if ($cmd =~ /httpserver\.pl/) { + $cmd =~ s@--port 0@--port 20000@; + } elsif ($cmd =~ m@server/socksd@) { + $cmd =~ s@--port 0@--port 20001@; + } + + return &$real_startnew($cmd, $pidfile, $timeout, $fake); +} + +sub main() { + + # Look but don't touch, @ARGV is still needed elsewhere + foreach my $arg (@ARGV) { + $use_external_proxy = 1 if ($arg eq "-P"); + $verbose = 1 if ($arg eq "-v"); + } + + return 1; +} + +main(); -- 2.39.2