urlmatch.@OBJEXT@: urlmatch.c urlmatch.h config.h $(PROJECT_H_DEPS) errlog.h miscutil.h ssplit.h
client-tags.@OBJEXT@: client-tags.c client-tags.h config.h $(PROJECT_H_DEPS) errlog.h miscutil.h ssplit.h
fuzz.@OBJEXT@: fuzz.c config.h $(PROJECT_H_DEPS) errlog.h miscutil.h ssplit.h
+ssl.@OBJEXT@: ssl.c ssl.h config.h $(PROJECT_H_DEPS) encode.h errlog.h jcc.h miscutil.h
# GNU regex
gnu_regex.@OBJEXT@: gnu_regex.c gnu_regex.h config.h
#elif defined(MUTEX_LOCKS_AVAILABLE)
privoxy_mutex_lock(&localtime_mutex);
timeptr = localtime(¤t_time);
- privoxy_mutex_unlock(&localtime_mutex);
#else
timeptr = localtime(¤t_time);
#endif
strftime(buf, buffer_size, "%a %b %d %X %Z %Y", timeptr);
+#if !defined(HAVE_LOCALTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_unlock(&localtime_mutex);
+#endif
}
go.idmnet.bbelements.com/please/showit/
# Blocked URL = http://gm-link.com/tm_image.asp?c=12345&x=0&u=email@address.tld&orc.gif
gm-link.com/
+# Blocked URL = https://collector.githubapp.com/github/page_view?dimensions[page]=https%3A%2F%2Fgithub.com%2Fopenbsd%2Fsrc%2Fblob%2F5ecdd0566b441ae0b99e73f410875e05dc0fa5b7%2Flib%2Flibc%2Finclude%2Fthread_private.h&dimensions[title]=src%2Fthread_private.h%20at%205ecdd0566b441ae0b99e73f410875e05dc0fa5b7%20%C2%B7%20openbsd%2Fsrc%20%C2%B7%20GitHub&dimensions[referrer]=https%3A%2F%2Fgithub.com%2Fopenbsd%2Fsrc%2Fsearch%3Fq%3D_MUTEX_LOCK%26unscoped_q%3D_MUTEX_LOCK&dimensions[user_agent]=Mozilla%2F5.0%20(X11%3B%20ElectroBSD%20amd64%3B%20rv%3A68.0)%20Gecko%2F20100101%20Firefox%2F68.0&dimensions[screen_resolution]=1366x768&dimensions[pixel_ratio]=1&dimensions[browser_resolution]=1362x636&dimensions[tz_seconds]=7200&dimensions[timestamp]=1591515169218&dimensions[referrer]=&dimensions[request_id]=22CA%3AE6F6%3A271ED2A%3A3839C5D%3A5EDB8295&dimensions[visitor_id]=5184934927058829974&dimensions[region_edge]=ams&dimensions[region_render]=ams&dimensions[user_id]=929183&dimensions[user_login]=openbsd&dimensions[repository_id]=66966208&dimensions[repository_nwo]=openbsd%2Fsrc&dimensions[repository_public]=true&dimensions[repository_is_fork]=false&dimensions[repository_network_root_id]=66966208&dimensions[repository_network_root_nwo]=openbsd%2Fsrc&dimensions[repository_explore_github_marketplace_ci_cta_shown]=false&&measures[performance_timing]=1-172-172-13996-12735-12426-12394-3858-172-172-172--13996-0---172-3853-3412-0--&&&dimensions[cid]=268614077.1591515169
+collector.githubapp.com/
+
#############################################################################
# Site-specific block patterns;
oss-fuzz.com/
# URL = https://sourcepoint.vice.com/mms/choice_select?choice_id=523912&requestUUID=a98ca09e-5c1f-4aa4-b28e-ab5b26150859-1591162630861&href=https%3A%2F%2Fwww.vice.com%2Fen_us%2Farticle%2F7kpb9a%2Fhow-to-protest-racist-violence-instead-of-posting-blackout-tuesday-square
sourcepoint.vice.com/
+# URL = https://collector.githubapp.com/github/page_view?dimensions[page]=https%3A%2F%2Fgithub.com%2Fopenbsd%2Fsrc%2Fblob%2F5ecdd0566b441ae0b99e73f410875e05dc0fa5b7%2Flib%2Flibc%2Finclude%2Fthread_private.h&dimensions[title]=src%2Fthread_private.h%20at%205ecdd0566b441ae0b99e73f410875e05dc0fa5b7%20%C2%B7%20openbsd%2Fsrc%20%C2%B7%20GitHub&dimensions[referrer]=https%3A%2F%2Fgithub.com%2Fopenbsd%2Fsrc%2Fsearch%3Fq%3D_MUTEX_LOCK%26unscoped_q%3D_MUTEX_LOCK&dimensions[user_agent]=Mozilla%2F5.0%20(X11%3B%20ElectroBSD%20amd64%3B%20rv%3A68.0)%20Gecko%2F20100101%20Firefox%2F68.0&dimensions[screen_resolution]=1366x768&dimensions[pixel_ratio]=1&dimensions[browser_resolution]=1362x636&dimensions[tz_seconds]=7200&dimensions[timestamp]=1591515169218&dimensions[referrer]=&dimensions[request_id]=22CA%3AE6F6%3A271ED2A%3A3839C5D%3A5EDB8295&dimensions[visitor_id]=5184934927058829974&dimensions[region_edge]=ams&dimensions[region_render]=ams&dimensions[user_id]=929183&dimensions[user_login]=openbsd&dimensions[repository_id]=66966208&dimensions[repository_nwo]=openbsd%2Fsrc&dimensions[repository_public]=true&dimensions[repository_is_fork]=false&dimensions[repository_network_root_id]=66966208&dimensions[repository_network_root_nwo]=openbsd%2Fsrc&dimensions[repository_explore_github_marketplace_ci_cta_shown]=false&&measures[performance_timing]=1-172-172-13996-12735-12426-12394-3858-172-172-172--13996-0---172-3853-3412-0--&&&dimensions[cid]=268614077.1591515169
+collector.githubapp.com/
{+redirect{s@.*url=@http://@} -block}
# Sticky Actions = +redirect -block
Purpose : FAQ
- Copyright (C) 2001-2018 Privoxy Developers https://www.privoxy.org/
+ Copyright (C) 2001-2020 Privoxy Developers https://www.privoxy.org/
See LICENSE.
Based partially on the Internet Junkbuster FAQ originally written by and
<subscript>
<!-- Completely the wrong markup, but very little is allowed -->
<!-- in this part of an article. FIXME -->
- <link linkend="copyright">Copyright</link> &my-copy; 2001-2018 by
+ <link linkend="copyright">Copyright</link> &my-copy; 2001-2020 by
<ulink url="https://www.privoxy.org/">Privoxy Developers</ulink>
</subscript>
</pubdate>
<ulink url="https://www.privoxy.org/">Privoxy</ulink>.
It is not a substitute for the
<ulink url="../user-manual/index.html"><citetitle>Privoxy User Manual</citetitle></ulink>.
-<!--
- This works, at least in some situations:
- Test: <ulink url="privoxy-user-manual.pdf"><citetitle>User Manual</citetitle></ulink>.
--->
</para>
<!-- Include privoxy.sgml boilerplate: -->
</para>
<variablelist>
<varlistentry>
- <term>Gold (10000 EUR/year)</term>
+ <term>Gold (12000 USD/year)</term>
<listitem>
<para>
Logo shown at the bottom of the
</listitem>
</varlistentry>
<varlistentry>
- <term>Silver (1000 EUR/year)</term>
+ <term>Silver (1200 USD/year)</term>
<listitem>
<para>
Logo shown randomly at the bottom of the
</listitem>
</varlistentry>
<varlistentry>
- <term>Bronze (500 EUR/year)</term>
+ <term>Bronze (600 USD/year)</term>
<listitem>
<para>
Logo and link on the <ulink url="https://www.privoxy.org/sponsors/">sponsor page</ulink>.
amount of guesswork. It is not realistic to catch all of these short of
disabling Javascript, which would break many sites. And lastly, if the
cookies are embedded in a HTTPS/SSL secure session via Javascript, they are beyond
- <application>Privoxy's</application> reach.
+ <application>Privoxy's</application> reach unless you enable
+ <ulink url="../user-manual/actions-file.html#HTTPS-INSPECTION">https-inspection</ulink>.
</para>
<para>
All in all, &my-app; can help manage cookies in general, can help minimize
<sect2 renderas="sect3" id="ssl">
<title>How can Privoxy filter Secure (HTTPS) URLs?</title>
<para>
- Since secure HTTP connections are encrypted SSL sessions between your browser
- and the secure site, and are meant to be reliably <emphasis>secure</emphasis>,
- there is little that <application>Privoxy</application> can do but hand the raw
+ If you enable
+ <ulink url="../user-manual/actions-file.html#HTTPS-INSPECTION">https-inspection</ulink>
+ <application>Privoxy</application> will impersonate the destination
+ server and can thus filter encrypted requests and responses as well.
+</para>
+<para>
+ Without
+ <ulink url="../user-manual/actions-file.html#HTTPS-INSPECTION">https-inspection</ulink>
+ secure HTTP connections are encrypted SSL sessions between your
+ browser and the secure site, and there is little
+ that <application>Privoxy</application> can do but hand the raw
gibberish data though from one end to the other unprocessed.
</para>
<para>
for HTTPS.
</para>
<para>
- Adding HTTP/2 support is on the TODO list but currently
- nobody is known to work on it.
+ Adding HTTP/2 support is on the
+ <ulink url="https://www.privoxy.org/gitweb/?p=privoxy.git;a=blob_plain;f=TODO;hb=HEAD">TODO</ulink>
+ list but currently nobody is known to work on it.
</para>
</sect2>
trickier because the syntax can vary widely, and thus requires a certain amount of guesswork. It is not realistic
to catch all of these short of disabling Javascript, which would break many sites. And lastly, if the cookies are
embedded in a HTTPS/SSL secure session via Javascript, they are beyond <span class="APPLICATION">Privoxy's</span>
- reach.</p>
+ reach unless you enable <a href="../user-manual/actions-file.html#HTTPS-INSPECTION" target=
+ "_top">https-inspection</a>.</p>
<p>All in all, <span class="APPLICATION">Privoxy</span> can help manage cookies in general, can help minimize the
loss of privacy posed by cookies, but can't realistically stop all cookies.</p>
</div>
"APPLICATION">Junkbuster</span> (tm) FAQ, and modified as appropriate for <span class=
"APPLICATION">Privoxy</span>.</p>
<div class="SECT2">
- <h2 class="SECT2"><a name="AEN1499" id="AEN1499">7.1. License</a></h2>
+ <h2 class="SECT2"><a name="AEN1504" id="AEN1504">7.1. License</a></h2>
<p><span class="APPLICATION">Privoxy</span> is free software; you can redistribute it and/or modify it under the
terms of the <i class="CITETITLE">GNU General Public License</i>, version 2, as published by the Free Software
Foundation.</p>
"CITETITLE">license</i></a> for details.</p>
</div>
<div class="SECT2">
- <h2 class="SECT2"><a name="AEN1508" id="AEN1508">7.2. History</a></h2>
+ <h2 class="SECT2"><a name="AEN1513" id="AEN1513">7.2. History</a></h2>
<p>A long time ago, there was the <span class="APPLICATION">Internet Junkbuster</span>, by Anonymous Coders and
Junkbusters Corporation. This saved many users a lot of pain in the early days of web advertising and user
tracking.</p>
<p>We are currently offering the following sponsor levels as an experiment:</p>
<div class="VARIABLELIST">
<dl>
- <dt>Gold (10000 EUR/year)</dt>
+ <dt>Gold (12000 USD/year)</dt>
<dd>
<p>Logo shown at the bottom of the <a href="https://www.privoxy.org/" target="_top">Privoxy homepage</a>.
Logo, link and self description on the <a href="https://www.privoxy.org/sponsors/" target="_top">sponsor
page</a>.</p>
</dd>
- <dt>Silver (1000 EUR/year)</dt>
+ <dt>Silver (1200 USD/year)</dt>
<dd>
<p>Logo shown randomly at the bottom of the <a href="https://www.privoxy.org/" target="_top">Privoxy
homepage</a>. Logo, link and self description on the <a href="https://www.privoxy.org/sponsors/" target=
"_top">sponsor page</a>.</p>
</dd>
- <dt>Bronze (500 EUR/year)</dt>
+ <dt>Bronze (600 USD/year)</dt>
<dd>
<p>Logo and link on the <a href="https://www.privoxy.org/sponsors/" target="_top">sponsor page</a>.</p>
</dd>
<div class="ARTICLE">
<div class="TITLEPAGE">
<h1 class="TITLE"><a name="AEN2" id="AEN2">Privoxy Frequently Asked Questions</a></h1>
- <p class="PUBDATE"><sub><a href="copyright.html">Copyright</a> © 2001-2018 by <a href=
+ <p class="PUBDATE"><sub><a href="copyright.html">Copyright</a> © 2001-2020 by <a href=
"https://www.privoxy.org/" target="_top">Privoxy Developers</a></sub><br></p>
<div>
<div class="ABSTRACT">
<dt>7. <a href="copyright.html">Privoxy Copyright, License and History</a></dt>
<dd>
<dl>
- <dt>7.1. <a href="copyright.html#AEN1499">License</a></dt>
- <dt>7.2. <a href="copyright.html#AEN1508">History</a></dt>
+ <dt>7.1. <a href="copyright.html#AEN1504">License</a></dt>
+ <dt>7.2. <a href="copyright.html#AEN1513">History</a></dt>
</dl>
</dd>
</dl>
</div>
<div class="SECT2">
<h3 class="SECT2"><a name="SSL" id="SSL">4.15. How can Privoxy filter Secure (HTTPS) URLs?</a></h3>
- <p>Since secure HTTP connections are encrypted SSL sessions between your browser and the secure site, and are
- meant to be reliably <span class="emphasis"><i class="EMPHASIS">secure</i></span>, there is little that
+ <p>If you enable <a href="../user-manual/actions-file.html#HTTPS-INSPECTION" target="_top">https-inspection</a>
+ <span class="APPLICATION">Privoxy</span> will impersonate the destination server and can thus filter encrypted
+ requests and responses as well.</p>
+ <p>Without <a href="../user-manual/actions-file.html#HTTPS-INSPECTION" target="_top">https-inspection</a> secure
+ HTTP connections are encrypted SSL sessions between your browser and the secure site, and there is little that
<span class="APPLICATION">Privoxy</span> can do but hand the raw gibberish data though from one end to the other
unprocessed.</p>
<p>The only exception to this is blocking by host patterns, as the client needs to tell <span class=
<h3 class="SECT2"><a name="HTTP2" id="HTTP2">4.16. Does Privoxy support HTTP/2?</a></h3>
<p>Privoxy currently doesn't parse HTTP/2 but applications can tunnel HTTP/2 through Privoxy if Privoxy is
configured to allow CONNECT requests (default) which are also used for HTTPS.</p>
- <p>Adding HTTP/2 support is on the TODO list but currently nobody is known to work on it.</p>
+ <p>Adding HTTP/2 support is on the <a href=
+ "https://www.privoxy.org/gitweb/?p=privoxy.git;a=blob_plain;f=TODO;hb=HEAD" target="_top">TODO</a> list but
+ currently nobody is known to work on it.</p>
</div>
<div class="SECT2">
<h3 class="SECT2"><a name="SECURE" id="SECURE">4.17. Privoxy runs as a <span class="QUOTE">"server"</span>. How
int tz_length = 0;
time (&now);
-#ifdef HAVE_GMTIME_R
- gmt = *gmtime_r(&now, &gmt);
-#elif defined(MUTEX_LOCKS_AVAILABLE)
- privoxy_mutex_lock(&gmtime_mutex);
- gmt = *gmtime(&now);
- privoxy_mutex_unlock(&gmtime_mutex);
-#else
- gmt = *gmtime(&now);
-#endif
+ gmt = *privoxy_gmtime_r(&now, &gmt);
#ifdef HAVE_LOCALTIME_R
tm_now = localtime_r(&now, &dummy);
#elif defined(MUTEX_LOCKS_AVAILABLE)
privoxy_mutex_lock(&localtime_mutex);
tm_now = localtime(&now);
- privoxy_mutex_unlock(&localtime_mutex);
#else
tm_now = localtime(&now);
#endif
mins = hrs * 60 + tm_now->tm_min - gmt.tm_min;
length = strftime(buffer, buffer_size, "%d/%b/%Y:%H:%M:%S ", tm_now);
+#if !defined(HAVE_LOCALTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_unlock(&localtime_mutex);
+#endif
if (length > (size_t)0)
{
{
return;
}
-#ifdef FEATURE_HTTPS_INSPECTION
- /*
- * Log the request unless we're https inspecting
- * in which case we don't have the path yet and
- * will log the request later.
- */
- if (!client_use_ssl(csp))
-#endif
- {
- log_error(LOG_LEVEL_REQUEST, "%s%s", http->hostport, http->path);
- }
/* decide how to route the HTTP request */
fwd = forward_url(csp, http);
}
#endif
+#ifdef FEATURE_HTTPS_INSPECTION
+ /*
+ * Log the request unless we're https inspecting
+ * in which case we don't have the path yet and
+ * will log the request later.
+ */
+ if (!client_use_ssl(csp))
+#endif
+ {
+ log_error(LOG_LEVEL_REQUEST, "%s%s", http->hostport, http->path);
+ }
+
if (http->ssl && connect_port_is_forbidden(csp))
{
const char *acceptable_connect_ports =
{
log_error(LOG_LEVEL_CONNECT,
"Closing server socket %d connected to %s. "
- "Keep-alive %u. Tainted: %u. Socket alive %u. Timeout: %u.",
+ "Keep-alive: %u. Tainted: %u. Socket alive: %u. Timeout: %u.",
csp->server_connection.sfd, csp->server_connection.host,
0 != (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE),
0 != (csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED),
* to deserve their own file but don't really fit in
* any other file.
*
- * Copyright : Written by and Copyright (C) 2001-2018 the
+ * Copyright : Written by and Copyright (C) 2001-2020 the
* Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
#include "project.h"
#include "miscutil.h"
+#include "jcc.h"
#include "errlog.h"
/*********************************************************************
* Exits if the file can't be opened
*
* Parameters :
- * 1 : pidfile = Path of the pidfile that gets created.
+ * 1 : pid_file = Path of the pid file that gets created.
*
* Returns : N/A
*
*********************************************************************/
-void write_pid_file(const char *pidfile)
+void write_pid_file(const char *pid_file)
{
FILE *fp;
- if ((fp = fopen(pidfile, "w")) == NULL)
+ if ((fp = fopen(pid_file, "w")) == NULL)
{
- log_error(LOG_LEVEL_FATAL, "can't open pidfile '%s': %E", pidfile);
+ log_error(LOG_LEVEL_FATAL, "can't open pid file '%s': %E", pid_file);
}
else
{
}
+/*********************************************************************
+ *
+ * Function : privoxy_gmtime_r
+ *
+ * Description : Behave like gmtime_r() and convert a
+ * time_t to a struct tm.
+ *
+ * Parameters :
+ * 1 : time_spec: The time to convert
+ * 2 : result: The struct tm to use as storage
+ *
+ * Returns : Pointer to the result or NULL on error.
+ *
+ *********************************************************************/
+struct tm *privoxy_gmtime_r(const time_t *time_spec, struct tm *result)
+{
+ struct tm *timeptr;
+
+#ifdef HAVE_GMTIME_R
+ timeptr = gmtime_r(time_spec, result);
+#elif defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_lock(&gmtime_mutex);
+ timeptr = gmtime(time_spec);
+#else
+#warning Using unlocked gmtime()
+ timeptr = gmtime(time_spec);
+#endif
+
+ if (timeptr == NULL)
+ {
+#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_unlock(&gmtime_mutex);
+#endif
+ return NULL;
+ }
+
+#if !defined(HAVE_GMTIME_R)
+ *result = *timeptr;
+ timeptr = result;
+#ifdef MUTEX_LOCKS_AVAILABLE
+ privoxy_mutex_unlock(&gmtime_mutex);
+#endif
+#endif
+
+ return timeptr;
+}
+
#if !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV)
/*********************************************************************
*
extern void *malloc_or_die(size_t buffer_size);
#if defined(unix)
-extern void write_pid_file(const char *pidfile);
+extern void write_pid_file(const char *pid_file);
#endif /* unix */
extern unsigned int hash_string(const char* s);
#endif /* ndef HAVE_STRLCAT */
extern int privoxy_millisleep(unsigned milliseconds);
+extern struct tm *privoxy_gmtime_r(const time_t *time_spec, struct tm *result);
#if defined(__cplusplus)
}
time_t now;
struct tm *timeptr = NULL;
long int rtime;
-#ifdef HAVE_GMTIME_R
struct tm gmt;
-#endif
+
now = time(NULL);
rtime = (long int)difftime(now, last_modified);
if (rtime)
rtime *= -1;
}
last_modified += rtime;
-#ifdef HAVE_GMTIME_R
- timeptr = gmtime_r(&last_modified, &gmt);
-#elif defined(MUTEX_LOCKS_AVAILABLE)
- privoxy_mutex_lock(&gmtime_mutex);
- timeptr = gmtime(&last_modified);
- privoxy_mutex_unlock(&gmtime_mutex);
-#else
- timeptr = gmtime(&last_modified);
-#endif
+ timeptr = privoxy_gmtime_r(&last_modified, &gmt);
if ((NULL == timeptr) || !strftime(newheader,
sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr))
{
freez(*header);
return JB_ERR_OK;
}
-
freez(*header);
*header = strdup("Last-Modified: ");
string_append(header, newheader);
static jb_err client_if_modified_since(struct client_state *csp, char **header)
{
char newheader[50];
-#ifdef HAVE_GMTIME_R
struct tm gmt;
-#endif
struct tm *timeptr = NULL;
time_t tm = 0;
const char *newval;
*header);
}
tm += rtime * (negative_range ? -1 : 1);
-#ifdef HAVE_GMTIME_R
- timeptr = gmtime_r(&tm, &gmt);
-#elif defined(MUTEX_LOCKS_AVAILABLE)
- privoxy_mutex_lock(&gmtime_mutex);
- timeptr = gmtime(&tm);
- privoxy_mutex_unlock(&gmtime_mutex);
-#else
- timeptr = gmtime(&tm);
-#endif
+ timeptr = privoxy_gmtime_r(&tm, &gmt);
if ((NULL == timeptr) || !strftime(newheader,
sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr))
{
freez(*header);
return JB_ERR_OK;
}
-
freez(*header);
*header = strdup("If-Modified-Since: ");
string_append(header, newheader);
char tmp[50];
struct tm *timeptr = NULL;
time_t expiry_date = time(NULL) + lifetime;
-#ifdef HAVE_GMTIME_R
struct tm gmt;
- timeptr = gmtime_r(&expiry_date, &gmt);
-#elif defined(MUTEX_LOCKS_AVAILABLE)
- privoxy_mutex_lock(&gmtime_mutex);
- timeptr = gmtime(&expiry_date);
- privoxy_mutex_unlock(&gmtime_mutex);
-#else
- timeptr = gmtime(&expiry_date);
-#endif
-
+ timeptr = privoxy_gmtime_r(&expiry_date, &gmt);
if (NULL == timeptr)
{
log_error(LOG_LEVEL_FATAL,
{
char recreated_date[100];
struct tm *tm;
+ struct tm storage;
time_t result2;
- tm = gmtime(result);
+ tm = privoxy_gmtime_r(result, &storage);
if (!strftime(recreated_date, sizeof(recreated_date),
time_formats[i], tm))
{
# Expect Header = Referer: http://config.privoxy.org/foo/baaz.html
TAG:^client-header-filter\{hide-tor-exit-notation\}$
+#######################################################
+# Test client-header-filter{no-brotli-accepted}.
+#######################################################
+
+{+client-header-filter{no-brotli-accepted}}
+# Set Header = Accept-Encoding: gzip, deflate, br
+# Expect Header = Accept-Encoding: gzip, deflate
+#
+# Set Header = Accept-Encoding: gzip, br, deflate
+# Expect Header = Accept-Encoding: gzip, deflate
+#
+# Set Header = Accept-Encoding: br, gzip, deflate
+# Expect Header = Accept-Encoding: gzip, deflate
+#
+# Set Header = Accept-Encoding: br
+# Expect Header = Accept-Encoding:
+#
+# Set Header = Accept-Encoding: gzip, deflate
+# Expect Header = NO CHANGE
+#
+TAG:^client-header-filter\{no-brotli-accepted\}$
+
#######################################################
# Test crunch-client-header{}.
#######################################################
size_t buffer_size)
{
struct tm valid_date;
+ struct tm *timeptr;
size_t ret;
-#ifndef HAVE_GMTIME_R
-#error HTTP inspection currently requires gmtime_r() which seems to be missing
-#endif
- if (NULL == gmtime_r(&time_spec, &valid_date))
+ timeptr = privoxy_gmtime_r(&time_spec, &valid_date);
+ if (NULL == timeptr)
{
return 1;
}
- ret = strftime(buffer, buffer_size, "%Y%m%d%H%M%S", &valid_date);
+ ret = strftime(buffer, buffer_size, "%Y%m%d%H%M%S", timeptr);
if (ret != 14)
{
return 1;
return '';
}
- $c =~ s@(?<=\(size )(\d+)\)(?= with)@$h{'Number'}$1$h{'Standard'}@;
+ $c =~ s@(?<=\(size )(\d+)@$h{'Number'}$1$h{'Standard'}@;
$c =~ s@(?<=\(new size )(\d+)@$h{'Number'}$1$h{'Standard'}@;
$c =~ s@(?<=produced )(\d+)(?= hits)@$h{'Number'}$1$h{'Standard'}@;
# Forwarded the last 1954 bytes
$c =~ s@(?<=the last )(\d+)@$h{'Number'}$1$h{'Standard'}@;
+ } elsif ($c =~ m/^Waiting for the next client connection. Currently active threads:/) {
+
+ # Waiting for the next client connection. Currently active threads: 30
+ $c =~ s@(?<=threads: )(\d+)@$h{'Number'}$1$h{'Standard'}@;
+
} elsif ($c =~ m/^Looks like we / or
$c =~ m/^Unsetting keep-alive flag/ or
$c =~ m/^No connections to wait/ or
our %cli_options;
# +0200] "GET https://www.youtube.com/watch?v=JmcA9LIIXWw HTTP/1.1" 200 68004
- $content =~ m/^[+-]\d{4}\] "(\w+) (.+) (HTTP\/\d\.\d)" (\d+) (\d+)/;
+ # +0200] "VERSION-CONTROL http://p.p/ HTTP/1.1" 200 2787
+ $content =~ m/^[+-]\d{4}\] "([^ ]+) (.+) (HTTP\/\d\.\d)" (\d+) (\d+)/;
$method = $1;
$resource = $2;
$http_version = $3;
$status_code = $4;
$size = $5;
+ $stats{requests_clf}++;
+
unless (defined $method) {
+ # +0200] "Invalid request" 400 0
+ return if ($content =~ m/^[+-]\d{4}\] "Invalid request"/);
print("Failed to parse: $content\n");
return;
}
$stats{'http-version'}{$http_version}++;
if ($cli_options{'host-statistics-threshold'} != 0) {
- $resource =~ m@(?:http[s]://)([^/]+)/?@;
+ $resource =~ m@(?:https?://)?([^/]+)/?@;
$stats{'hosts'}{$1}++;
}
$stats{'content-size-total'} += $size;
$stats{'status-code'}{$status_code}++;
- $stats{requests_clf}++;
}
sub gather_loglevel_request_stats($$) {
# - Document magic Expect Header values
# - Internal fuzz support?
#
-# Copyright (c) 2007-2016 Fabian Keil <fk@fabiankeil.de>
+# Copyright (c) 2007-2020 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
use Getopt::Long;
use constant {
- PRT_VERSION => 'Privoxy-Regression-Test 0.7',
+ PRT_VERSION => 'Privoxy-Regression-Test 0.7.1',
CURL => 'curl',
REDIRECT_TEST =>108,
};
-sub init_our_variables () {
+sub init_our_variables() {
our $leading_log_time = LEADING_LOG_TIME;
our $leading_log_date = LEADING_LOG_DATE;
our $log_level = get_default_log_level();
}
-sub get_default_log_level () {
+sub get_default_log_level() {
my $log_level = 0;
#
############################################################################
-sub parse_tag ($) {
+sub parse_tag($) {
my $tag = shift;
return $tag;
}
-sub check_for_forbidden_characters ($) {
+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;
# XXX: Contains a lot of code duplicated from load_action_files()
# that should be factored out.
-sub load_regression_tests_from_file ($) {
+sub load_regression_tests_from_file($) {
my $action_file = shift;
# initialized here
l(LL_FILE_LOADING, "Sticky actions: " . $sticky_actions);
$regression_tests[$si][$ri]{'sticky-actions'} = $sticky_actions;
} else {
- log_and_die("Sticky URL without Sticky Actions: $value");
+ log_and_die("Sticky URL without Sticky Actions in $action_file: $value");
}
} else {
}
-sub load_regression_tests_through_privoxy () {
+sub load_regression_tests_through_privoxy() {
our $privoxy_cgi_url;
our @privoxy_config;
load_action_files(\@actionfiles);
}
-sub token_starts_new_test ($) {
+sub token_starts_new_test($) {
my $token = shift;
my @new_test_directives = ('set header', 'fetch test',
return 0;
}
-sub tokenize ($) {
+sub tokenize($) {
my ($token, $value) = (undef, undef);
return ($token, $value);
}
-sub enlist_new_test ($$$$$$) {
+sub enlist_new_test($$$$$$) {
my ($regression_tests, $token, $value, $si, $ri, $number) = @_;
my $type;
# XXX: Shares a lot of code with load_regression_tests_from_file()
# that should be factored out.
-sub load_action_files ($) {
+sub load_action_files($) {
# initialized here
our %actions;
l(LL_FILE_LOADING, "Sticky actions: " . $sticky_actions);
$regression_tests[$si][$ri]{'sticky-actions'} = $sticky_actions;
} else {
- log_and_die("Sticky URL without Sticky Actions: $value");
+ log_and_die("Sticky URL without Sticky Actions in $actionfile: $value");
}
} else {
############################################################################
# Fisher Yates shuffle from Perl's "How do I shuffle an array randomly?" FAQ
-sub fisher_yates_shuffle ($) {
+sub fisher_yates_shuffle($) {
my $deck = shift;
my $i = @$deck;
while ($i--) {
}
}
-sub execute_regression_tests () {
+sub execute_regression_tests() {
our @regression_tests;
my $loops = get_cli_option('loops');
}
}
-sub get_skip_reason ($) {
+sub get_skip_reason($) {
my $test = shift;
my $skip_reason = undef;
return $skip_reason;
}
-sub level_is_unacceptable ($) {
+sub level_is_unacceptable($) {
my $level = shift;
my $min_level = get_cli_option('min-level');
my $max_level = get_cli_option('max-level');
return $reason;
}
-sub dependency_unsatisfied ($) {
+sub dependency_unsatisfied($) {
my $level = shift;
our %dependencies;
return $dependency_problem;
}
-sub register_dependency ($$) {
+sub register_dependency($$) {
my $level = shift;
my $dependency = shift;
}
}
-sub execute_method_test ($) {
+sub execute_method_test($) {
my $test = shift;
my $buffer_ref;
return check_status_code_result($status_code, $expected_status_code);
}
-sub execute_redirect_test ($) {
+sub execute_redirect_test($) {
my $test = shift;
my $buffer_ref;
return $success;
}
-sub execute_dumb_fetch_test ($) {
+sub execute_dumb_fetch_test($) {
my $test = shift;
my $buffer_ref;
return check_status_code_result($status_code, $expected_status_code);
}
-sub execute_block_test ($) {
+sub execute_block_test($) {
my $test = shift;
my $url = $test->{'data'};
return defined $final_results->{'+block'};
}
-sub execute_sticky_actions_test ($) {
+sub execute_sticky_actions_test($) {
my $test = shift;
my $url = $test->{'data'};
return $verified_actions == @sticky_actions;
}
-sub get_final_results ($) {
+sub get_final_results($) {
my $url = shift;
my $curl_parameters = '';
return \%final_results;
}
-sub check_status_code_result ($$) {
+sub check_status_code_result($$) {
my $status_code = shift;
my $expected_status_code = shift;
return $result;
}
-sub execute_client_header_regression_test ($) {
+sub execute_client_header_regression_test($) {
my $test = shift;
my $buffer_ref;
return check_header_result($test, $header);
}
-sub execute_server_header_regression_test ($) {
+sub execute_server_header_regression_test($) {
my $test = shift;
my $buffer_ref;
return check_header_result($test, $header);
}
-sub interpret_result ($) {
+sub interpret_result($) {
my $success = shift;
return $success ? "Success" : "Failure";
}
-sub check_header_result ($$) {
+sub check_header_result($$) {
my $test = shift;
my $header = shift;
return $success;
}
-sub get_header_name ($) {
+sub get_header_name($) {
my $header = shift;
return $header;
}
-sub get_header ($$) {
+sub get_header($$) {
our $filtered_request = '';
return $header;
}
-sub get_server_header ($$) {
+sub get_server_header($$) {
my $buffer_ref = shift;
my $test = shift;
return $header;
}
-sub get_status_code ($) {
+sub get_status_code($) {
my $buffer_ref = shift;
my @buffer = @{$buffer_ref};
}
}
-sub get_test_keys () {
+sub get_test_keys() {
return ('tag', 'data', 'expect-header', 'ignore');
}
# XXX: incomplete
-sub test_content_as_string ($) {
+sub test_content_as_string($) {
my $test = shift;
#
############################################################################
-sub get_cgi_page_or_else ($) {
+sub get_cgi_page_or_else($) {
my $cgi_url = shift;
my $content_ref = get_page_with_curl($cgi_url);
}
# XXX: misleading name
-sub get_show_request_with_curl ($) {
+sub get_show_request_with_curl($) {
our $privoxy_cgi_url;
my $test = shift;
return get_cgi_page_or_else($curl_parameters);
}
-sub get_head_with_curl ($) {
+sub get_head_with_curl($) {
our $fellatio_url = FELLATIO_URL;
my $test = shift;
return get_page_with_curl($curl_parameters);
}
-sub get_page_with_curl ($) {
+sub get_page_with_curl($) {
our $proxy;
$curl_line .= " --user-agent '" . PRT_VERSION . "' ";
# We aren't too patient
$curl_line .= " --max-time '" . get_cli_option('max-time') . "' ";
+ # We don't want curl to treat "[]", "{}" etc. special
+ $curl_line .= " --globoff ";
$curl_line .= $parameters;
# XXX: still necessary?
#
############################################################################
-sub array_as_string ($) {
+sub array_as_string($) {
my $array_ref = shift;
my $string = '';
return $string;
}
-sub show_test ($) {
+sub show_test($) {
my $test = shift;
log_message('Test is:' . test_content_as_string($test));
}
# Conditional log
-sub l ($$) {
+sub l($$) {
our $log_level;
my $this_level = shift;
my $message = shift;
log_message($message) if ($log_level & $this_level);
}
-sub log_and_die ($) {
+sub log_and_die($) {
my $message = shift;
log_message('Oh noes. ' . $message . ' Fatal error. Exiting.');
exit;
}
-sub log_message ($) {
+sub log_message($) {
my $message = shift;
printf("%s\n", $message);
}
-sub log_result ($$) {
+sub log_result($$) {
our $filtered_request;
log_message($message) if (!$result or cli_option_is_set('verbose'));
}
-sub quote ($) {
+sub quote($) {
my $s = shift;
return '\'' . $s . '\'';
}
-sub print_version () {
+sub print_version() {
printf PRT_VERSION . "\n";
}
-sub list_test_types () {
+sub list_test_types() {
my %test_types = (
'Client header test' => CLIENT_HEADER_TEST,
'Server header test' => 2,
}
}
-sub help () {
+sub help() {
our %cli_options;
exit(0);
}
-sub init_cli_options () {
+sub init_cli_options() {
our %cli_options;
our $log_level;
$cli_options{'retries'} = CLI_RETRIES;
}
-sub parse_cli_options () {
+sub parse_cli_options() {
our %cli_options;
our $log_level;
$log_level |= $cli_options{'debug'};
}
-sub cli_option_is_set ($) {
+sub cli_option_is_set($) {
our %cli_options;
my $cli_option = shift;
return defined $cli_options{$cli_option};
}
-sub get_cli_option ($) {
+sub get_cli_option($) {
our %cli_options;
my $cli_option = shift;
}
}
-sub main () {
+sub main() {
init_our_variables();
parse_cli_options();