privoxy-regression-test: Bump copyright
[privoxy.git] / tools / privoxy-regression-test.pl
index 4288e46..c2c8f85 100755 (executable)
@@ -17,7 +17,7 @@
 # - Document magic Expect Header values
 # - Internal fuzz support?
 #
-# Copyright (c) 2007-2020 Fabian Keil <fk@fabiankeil.de>
+# Copyright (c) 2007-2021 Fabian Keil <fk@fabiankeil.de>
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -38,7 +38,7 @@ use strict;
 use Getopt::Long;
 
 use constant {
-    PRT_VERSION => 'Privoxy-Regression-Test 0.7.1',
+    PRT_VERSION => 'Privoxy-Regression-Test 0.7.2',
  
     CURL => 'curl',
 
@@ -47,11 +47,13 @@ use constant {
     CLI_LOOPS     => 1,
     CLI_MAX_TIME  => 5,
     CLI_MIN_LEVEL => 0,
-    # XXX: why limit at all?
+    # The reason for a maximum test level is explained in the
+    # perldoc section TEST LEVELS near the end of this file.
     CLI_MAX_LEVEL => 100,
     CLI_FORKS     => 0,
     CLI_SLEEP_TIME => 0,
 
+    PRIVOXY_ADDRESS  => 'http://127.0.0.1:8118/',
     PRIVOXY_CGI_URL  => 'http://p.p/',
     FELLATIO_URL     => 'http://127.0.0.1:8080/',
     LEADING_LOG_DATE => 1,
@@ -89,6 +91,7 @@ sub init_our_variables() {
     our $leading_log_date = LEADING_LOG_DATE;
     our $privoxy_cgi_url  = PRIVOXY_CGI_URL;
     our $log_level = get_default_log_level();
+    our $proxy = defined $ENV{'http_proxy'} ? $ENV{'http_proxy'} : PRIVOXY_ADDRESS;
 }
 
 sub get_default_log_level() {
@@ -132,7 +135,7 @@ sub parse_tag($) {
 sub check_for_forbidden_characters($) {
 
     my $string = shift;
-    my $allowed = '[-=\dA-Za-z~{}\[\]:./();\t ,+@"_%?&*^]';
+    my $allowed = '[-=\dA-Za-z~{}\[\]:./();\t ,+@"_%?&*^|]';
 
     unless ($string =~ m/^$allowed*$/o) {
         my $forbidden = $string;
@@ -1299,10 +1302,20 @@ sub get_server_header($$) {
 sub get_status_code($) {
 
     my $buffer_ref = shift;
+    our $privoxy_cgi_url;
+
+    my $skip_connection_established_response = $privoxy_cgi_url =~ m@^https://@;
     my @buffer = @{$buffer_ref}; 
 
     foreach (@buffer) {
 
+        if ($skip_connection_established_response) {
+
+            next if (m@^HTTP/1\.1 200 Connection established@);
+            next if (m@^\r\n$@);
+            $skip_connection_established_response = 0;
+        }
+
         if (/^HTTP\/\d\.\d (\d{3})/) {
 
             return $1;
@@ -1370,7 +1383,7 @@ sub get_cgi_page_or_else($) {
 
     if (200 != $status_code) {
 
-        my $log_message = "Failed to fetch Privoxy CGI Page. " .
+        my $log_message = "Failed to fetch Privoxy CGI page '$cgi_url'. " .
                           "Received status code ". $status_code .
                           " while only 200 is acceptable.";
 
@@ -1403,8 +1416,13 @@ sub get_show_request_with_curl($) {
 
     # Enable the action to test
     $curl_parameters .= '-H \'X-Privoxy-Control: ' . $test->{'tag'} . '\' ';
-    # The header to filter
-    $curl_parameters .= '-H \'' . $header . '\' ';
+
+    # Add the header to filter
+    if ($privoxy_cgi_url =~ m@^https://@ and $header =~ m@^Host:@) {
+        $curl_parameters .= '--proxy-header \'' . $header . '\' ';
+    } else {
+        $curl_parameters .= '-H \'' . $header . '\' ';
+    }
 
     $curl_parameters .= ' ';
     $curl_parameters .= $privoxy_cgi_url;
@@ -1668,6 +1686,7 @@ sub list_test_types() {
 sub help() {
 
     our %cli_options;
+    our $privoxy_cgi_url;
 
     print_version();
 
@@ -1686,7 +1705,8 @@ Options and their default values if they have any:
     [--max-level $cli_options{'max-level'}]
     [--max-time $cli_options{'max-time'}]
     [--min-level $cli_options{'min-level'}]
-    [--privoxy-address]
+    [--privoxy-address $cli_options{'privoxy-address'}]
+    [--privoxy-cgi-prefix $privoxy_cgi_url]
     [--retries $cli_options{'retries'}]
     [--show-skipped-tests]
     [--shuffle-tests]
@@ -1712,6 +1732,7 @@ sub init_cli_options() {
 
     our %cli_options;
     our $log_level;
+    our $proxy;
 
     $cli_options{'debug'}     = $log_level;
     $cli_options{'forks'}     = CLI_FORKS;
@@ -1721,16 +1742,19 @@ sub init_cli_options() {
     $cli_options{'min-level'} = CLI_MIN_LEVEL;
     $cli_options{'sleep-time'}= CLI_SLEEP_TIME;
     $cli_options{'retries'}   = CLI_RETRIES;
+    $cli_options{'privoxy-address'} = $proxy;
 }
 
 sub parse_cli_options() {
 
     our %cli_options;
     our $log_level;
+    our $privoxy_cgi_url;
 
     init_cli_options();
 
     GetOptions (
+        'check-bad-ssl'      => \$cli_options{'check-bad-ssl'},
         'debug=i'            => \$cli_options{'debug'},
         'forks=i'            => \$cli_options{'forks'},
         'fuzzer-address=s'   => \$cli_options{'fuzzer-address'},
@@ -1744,6 +1768,7 @@ sub parse_cli_options() {
         'max-time=i'         => \$cli_options{'max-time'},
         'min-level=i'        => \$cli_options{'min-level'},
         'privoxy-address=s'  => \$cli_options{'privoxy-address'},
+        'privoxy-cgi-prefix=s' => \$privoxy_cgi_url, # XXX: Should use cli_options()
         'retries=i'          => \$cli_options{'retries'},
         'shuffle-tests'      => \$cli_options{'shuffle-tests'},
         'show-skipped-tests' => \$cli_options{'show-skipped-tests'},
@@ -1804,11 +1829,55 @@ sub start_forks($) {
     }
 }
 
+sub check_bad_ssl() {
+    my $failures = 0;
+    my @bad_ssl_urls_to_check = (
+        "https://expired.badssl.com/",
+        "https://wrong.host.badssl.com/",
+        "https://self-signed.badssl.com/",
+        "https://untrusted-root.badssl.com/",
+        "https://no-common-name.badssl.com/", # XXX: Certificate has expired ...
+        "https://no-subject.badssl.com/", # XXX: Certificate has expired ...
+        "https://incomplete-chain.badssl.com/",
+        );
+    # This is needed for get_status_code() to skip the
+    # status code from the "HTTP/1.1 200 Connection established"
+    # reply.
+    our $privoxy_cgi_url = "https://p.p/";
+
+    log_message("Requesting pages from badssl.com with various " .
+        "certificate problems. This will only work if Privoxy " .
+        "has been configured properly and can reach the Internet.");
+
+    foreach my $url_to_check (@bad_ssl_urls_to_check) {
+        my ($buffer_ref, $status_code);
+        log_message("Requesting $url_to_check");
+
+        $buffer_ref = get_page_with_curl($url_to_check);
+        $status_code = get_status_code($buffer_ref);
+
+        if (!check_status_code_result($status_code, "403")) {
+            $failures++;
+        }
+
+    }
+    if ($failures == 0) {
+        log_message("All requests resulted in status code 403 as expected.");
+    } else {
+        log_message("There were $failures requests that did not result in status code 403!");
+    }
+
+    return $failures;
+}
+
 sub main() {
 
     init_our_variables();
     parse_cli_options();
     init_proxy_settings('vanilla-proxy');
+    if (cli_option_is_set('check-bad-ssl')) {
+        exit check_bad_ssl();
+    }
     load_regression_tests();
     init_proxy_settings('fuzz-proxy');
     start_forks(get_cli_option('forks')) if cli_option_is_set('forks');
@@ -1823,11 +1892,11 @@ B<privoxy-regression-test> - A regression test "framework" for Privoxy.
 
 =head1 SYNOPSIS
 
-B<privoxy-regression-test> [B<--debug bitmask>] [B<--forks> forks]
+B<privoxy-regression-test> [B<--check-bad-ssl>] [B<--debug bitmask>] [B<--forks> forks]
 [B<--fuzzer-feeding>] [B<--fuzzer-feeding>] [B<--help>] [B<--level level>]
 [B<--local-test-file testfile>] [B<--loops count>] [B<--max-level max-level>]
 [B<--max-time max-time>] [B<--min-level min-level>] B<--privoxy-address proxy-address>
-[B<--retries retries>] [B<--test-number test-number>]
+B<--privoxy-cgi-prefix cgi-prefix> [B<--retries retries>] [B<--test-number test-number>]
 [B<--show-skipped-tests>] [B<--sleep-time> seconds] [B<--verbose>]
 [B<--version>]
 
@@ -1973,6 +2042,13 @@ a given file without having to remove or disable the tests completely.
 
 =head1 OPTIONS
 
+B<--check-bad-ssl> Instead of running the regression tests
+as described above, request pages from badssl.com with bad
+certificates to verify that Privoxy is detecting the
+certificate issues. Only works if Privoxy has been compiled
+with FEATURE_HTTPS_INSPECTION, has been configured properly
+and can reach the Internet.
+
 B<--debug bitmask> Add the bitmask provided as integer
 to the debug settings.
 
@@ -2023,8 +2099,23 @@ above or equal to the numerical B<min-level>.
 
 B<--privoxy-address proxy-address> Privoxy's listening address.
 If it's not set, the value of the environment variable http_proxy
-will be used. B<proxy-address> has to be specified in http_proxy
-syntax.
+will be used unless the variable isn't set in which case
+http://127.0.0.1:8118/ will be used. B<proxy-address> has to
+be specified in http_proxy syntax.
+
+B<--privoxy-cgi-prefix privoxy-cgi-prefix> The prefix to use when
+building URLs that are supposed to reach Privoxy's CGI interface.
+If it's not set, B<http://p.p/> is used, which is supposed to work
+with the default Privoxy configuration.
+If Privoxy has been built with B<FEATURE_HTTPS_INSPECTION> enabled,
+and if https inspection is activated with the B<+https-inspection>
+action, this option can be used with
+B<https://p.p/> provided the system running Privoxy-Regression-Test
+has been configured to trust the certificate used by Privoxy.
+Note that there are currently two tests in the official
+B<regression-tests.action> file that are expected to fail when
+using a B<privoxy-cgi-prefix> with B<https://> and aren't automatically
+skipped.
 
 B<--retries retries> Retry B<retries> times.
 
@@ -2096,7 +2187,7 @@ Privoxy-Regression-Test in a meaningful way.
 
 =head1 SEE ALSO
 
-privoxy(1) curl(1)
+privoxy(8) curl(1)
 
 =head1 AUTHOR