From git at git.privoxy.org Sat Oct 10 09:01:28 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:28 +0200
Subject: [Privoxy-commits] [privoxy] 02/26: Add cts scenario "pcrs"
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070127.AB6D0101CD@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 007b5b75b2572823068af2dfa3932cbeef30c209
Author: Fabian Keil
AuthorDate: Sat Sep 5 12:23:50 2026 +0200
Add cts scenario "pcrs"
---
tests/cts/pcrs/data/DISABLED | 1 +
tests/cts/pcrs/data/test1 | 62 +++++++++++++++++++++++++++++++++++++++
tests/cts/pcrs/data/test2 | 61 ++++++++++++++++++++++++++++++++++++++
tests/cts/pcrs/data/test3 | 70 ++++++++++++++++++++++++++++++++++++++++++++
tests/cts/pcrs/data/test4 | 62 +++++++++++++++++++++++++++++++++++++++
tests/cts/pcrs/data/test5 | 62 +++++++++++++++++++++++++++++++++++++++
tests/cts/pcrs/data/test6 | 61 ++++++++++++++++++++++++++++++++++++++
tests/cts/pcrs/pcrs.action | 17 +++++++++++
tests/cts/pcrs/pcrs.filter | 21 +++++++++++++
tests/cts/pcrs/privoxy.conf | 17 +++++++++++
10 files changed, 434 insertions(+)
diff --git a/tests/cts/pcrs/data/DISABLED b/tests/cts/pcrs/data/DISABLED
new file mode 100644
index 00000000..da43e6a4
--- /dev/null
+++ b/tests/cts/pcrs/data/DISABLED
@@ -0,0 +1 @@
+# Don't disable any tests.
diff --git a/tests/cts/pcrs/data/test1 b/tests/cts/pcrs/data/test1
new file mode 100644
index 00000000..c835c54c
--- /dev/null
+++ b/tests/cts/pcrs/data/test1
@@ -0,0 +1,62 @@
+
+
+
+
+HTTP
+HTTP GET
+PCRS submatch limit reached
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+
+ab
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+Content-Length: 2
+
+b
+
+
+
+
+
+
+http
+
+
++filter{submatch-limit-not-reached}
+
+
+proxy
+
+
+http://%HOSTIP:%HTTPPORT/submatch-limit-not-reached/%TESTNUMBER
+
+
+
+
+
+GET /submatch-limit-not-reached/%TESTNUMBER HTTP/1.1%CR
+Host: %HOSTIP:%HTTPPORT%CR
+User-Agent: curl/%VERSION%CR
+Accept: */*%CR
+Connection: close%CR
+%CR
+
+
+
diff --git a/tests/cts/pcrs/data/test2 b/tests/cts/pcrs/data/test2
new file mode 100644
index 00000000..3f12b81e
--- /dev/null
+++ b/tests/cts/pcrs/data/test2
@@ -0,0 +1,61 @@
+
+
+
+
+HTTP
+HTTP GET
+PCRS submatch limit not reached
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+
+ab
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+
+ab
+
+
+
+
+
+
+http
+
+
++filter{submatch-limit-reached}
+
+
+proxy
+
+
+http://%HOSTIP:%HTTPPORT/submatch-limit-reached/%TESTNUMBER
+
+
+
+
+
+GET /submatch-limit-reached/%TESTNUMBER HTTP/1.1%CR
+Host: %HOSTIP:%HTTPPORT%CR
+User-Agent: curl/%VERSION%CR
+Accept: */*%CR
+Connection: close%CR
+%CR
+
+
+
diff --git a/tests/cts/pcrs/data/test3 b/tests/cts/pcrs/data/test3
new file mode 100644
index 00000000..ba13607e
--- /dev/null
+++ b/tests/cts/pcrs/data/test3
@@ -0,0 +1,70 @@
+
+
+
+
+HTTP
+HTTP GET
+Dynamic filter with variables
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+
+host variable:
+listen-address variable:
+origin variable:
+path variable:
+url variable:
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+Content-Length: 181
+
+host variable: 127.0.0.1
+listen-address variable: 127.0.0.1:9119
+origin variable: 127.0.0.1
+path variable: /embed-variables/%TESTNUMBER
+url variable: http://%HOSTIP:%HTTPPORT/embed-variables/%TESTNUMBER
+
+
+
+
+
+
+http
+
+
++filter{embed-variables}
+
+
+proxy
+
+
+http://%HOSTIP:%HTTPPORT/embed-variables/%TESTNUMBER
+
+
+
+
+
+GET /embed-variables/%TESTNUMBER HTTP/1.1%CR
+Host: %HOSTIP:%HTTPPORT%CR
+User-Agent: curl/%VERSION%CR
+Accept: */*%CR
+Connection: close%CR
+%CR
+
+
+
diff --git a/tests/cts/pcrs/data/test4 b/tests/cts/pcrs/data/test4
new file mode 100644
index 00000000..b91498a0
--- /dev/null
+++ b/tests/cts/pcrs/data/test4
@@ -0,0 +1,62 @@
+
+
+
+
+HTTP
+HTTP GET
+Filter with multiple submatches that are being referenced in the substitution text.
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+
+1 2 3 4 5 6 7 8 9
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+Content-Length: 18
+
+9 8 7 6 5 4 3 2 1
+
+
+
+
+
+
+http
+
+
++filter{submatches-used}
+
+
+proxy
+
+
+http://%HOSTIP:%HTTPPORT/submatches-used/%TESTNUMBER
+
+
+
+
+
+GET /submatches-used/%TESTNUMBER HTTP/1.1%CR
+Host: %HOSTIP:%HTTPPORT%CR
+User-Agent: curl/%VERSION%CR
+Accept: */*%CR
+Connection: close%CR
+%CR
+
+
+
diff --git a/tests/cts/pcrs/data/test5 b/tests/cts/pcrs/data/test5
new file mode 100644
index 00000000..6fcc2c6c
--- /dev/null
+++ b/tests/cts/pcrs/data/test5
@@ -0,0 +1,62 @@
+
+
+
+
+HTTP
+HTTP GET
+Filter with multiple submatches that are being referenced in the pattern
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+
+1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 31 31
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+Content-Length: 5
+
+Yay!
+
+
+
+
+
+
+http
+
+
++filter{submatches-referenced}
+
+
+proxy
+
+
+http://%HOSTIP:%HTTPPORT/submatches-referenced/%TESTNUMBER
+
+
+
+
+
+GET /submatches-referenced/%TESTNUMBER HTTP/1.1%CR
+Host: %HOSTIP:%HTTPPORT%CR
+User-Agent: curl/%VERSION%CR
+Accept: */*%CR
+Connection: close%CR
+%CR
+
+
+
diff --git a/tests/cts/pcrs/data/test6 b/tests/cts/pcrs/data/test6
new file mode 100644
index 00000000..baf1c899
--- /dev/null
+++ b/tests/cts/pcrs/data/test6
@@ -0,0 +1,61 @@
+
+
+
+
+HTTP
+HTTP GET
+Filter with multiple submatches that are being referenced in the pattern
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+
+Does not matter.
+
+
+
+
+
+HTTP/1.1 200 OK
+Date: Thu, 22 Jul 2010 11:22:33 GMT
+Connection: close
+Content-Type: text/html
+X-Control: swsclose
+
+Does not matter.
+
+
+
+
+
+
+http
+
+
++filter{lots-of-parentheses}
+
+
+proxy
+
+
+http://%HOSTIP:%HTTPPORT/lots-of-parentheses/%TESTNUMBER
+
+
+
+
+
+GET /lots-of-parentheses/%TESTNUMBER HTTP/1.1%CR
+Host: %HOSTIP:%HTTPPORT%CR
+User-Agent: curl/%VERSION%CR
+Accept: */*%CR
+Connection: close%CR
+%CR
+
+
+
diff --git a/tests/cts/pcrs/pcrs.action b/tests/cts/pcrs/pcrs.action
new file mode 100644
index 00000000..162f9492
--- /dev/null
+++ b/tests/cts/pcrs/pcrs.action
@@ -0,0 +1,17 @@
+{+filter{submatch-limit-not-reached}}
+/submatch-limit-not-reached/
+
+{+filter{submatch-limit-reached}}
+/submatch-limit-reached/
+
+{+filter{embed-variables}}
+/embed-variables/
+
+{+filter{submatches-used}}
+/submatches-used/
+
+{+filter{submatches-referenced}}
+/submatches-referenced/
+
+{+filter{lots-of-parentheses}}
+/lots-of-parentheses/
diff --git a/tests/cts/pcrs/pcrs.filter b/tests/cts/pcrs/pcrs.filter
new file mode 100644
index 00000000..15da4b95
--- /dev/null
+++ b/tests/cts/pcrs/pcrs.filter
@@ -0,0 +1,21 @@
+FILTER: submatch-limit-not-reached Filter with pcrs job that doesn't reach the submatch limit
+s@()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()(a)@@
+
+FILTER: submatch-limit-reached Filter with pcrs job that reaches the submatch limit
+s@()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()(a)@@
+
+FILTER: embed-variables Filter that uses dynamic variables.
+s@(host variable:)@$1 $host at D
+s@(listen-address variable:)@$1 $listen-address at D
+s@(origin variable:)@$1 $origin at D
+s@(path variable:)@$1 $path at D
+s@(url variable:)@$1 $url at D
+
+FILTER: submatches-used Filter that uses multiple submatches and references them in the substitution
+s@(1) (2) (3) (4) (5) (6) (7) (8) (9)@$9 $8 $7 $6 $5 $4 $3 $2 $1@
+
+FILTER: submatches-referenced Filter that uses multiple submatches and references on of them in the pattern
+s@(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) (23) (24) (25) (26) (27) (28) (29) (30) (31) \31 \31 at Yay!@
+
+FILTER: lots-of-parentheses Filter that would previously trigger OVE-20260829-0001 on some platforms
+s@()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()() [...]
diff --git a/tests/cts/pcrs/privoxy.conf b/tests/cts/pcrs/privoxy.conf
new file mode 100644
index 00000000..dd1a8c98
--- /dev/null
+++ b/tests/cts/pcrs/privoxy.conf
@@ -0,0 +1,17 @@
+listen-address 127.0.0.1:9119
+
+debug 1 # Log the destination for each request Privoxy let through. See also debug 1024.
+debug 2 # show each connection status
+debug 4 # show tagging-related messages
+debug 8 # show header parsing
+debug 32 # debug force feature
+debug 64 # debug regular expression filters
+debug 128 # debug redirects
+debug 256 # debug GIF de-animation
+debug 512 # Common Log Format
+debug 1024 # Log the destination for requests Privoxy didn't let through, and the reason why.
+debug 4096 # Startup banner and warnings.
+debug 8192 # Non-fatal errors
+
+filterfile ./pcrs.filter
+actionsfile ./pcrs.action
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:27 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:27 +0200
Subject: [Privoxy-commits] [privoxy] 01/26: pcrs: Properly deal with too
many submatches
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070127.5D438101CC@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit e8f6884f9750941d9af6f90ffff6f72158c6514e
Author: Fabian Keil
AuthorDate: Wed Sep 2 11:10:19 2026 +0200
pcrs: Properly deal with too many submatches
Previously on some platforms a pcrs job with lots of submatches
would result in crashes due to memory corruption.
On affected plaforms this could be remotely triggered after adding
and enabling a custom dynamic filter with a variable like $path in
the pattern part of the pcrs job and requesting an URL with lots
of '()' in the path.
While variables like $path that contain characters under the client's
control should not be used in the pattern part anyway, this is currently
not explicitly documented and should not result in memory corruption.
Reported by Eli Fulkerson. OVE-20260829-0001.
---
pcrs.c | 8 ++++++++
pcrs.h | 1 +
2 files changed, 9 insertions(+)
diff --git a/pcrs.c b/pcrs.c
index cfaf8571..5ff35f2a 100644
--- a/pcrs.c
+++ b/pcrs.c
@@ -110,6 +110,7 @@ const char *pcrs_strerror(const int error)
case PCRS_WARN_BADREF: return "(pcrs:) Backreference out of range";
case PCRS_WARN_TRUNCATION:
return "(pcrs:) At least one variable was too big and has been truncated before compilation";
+ case PCRS_TOO_MANY_SUBMATCHES: return "(pcrs:) Submatch limit reached";
default:
pcre2_get_error_message(error, (PCRE2_UCHAR8*)buf, sizeof(buf));
@@ -835,6 +836,13 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char
while ((submatches = pcre2_match(job->pattern, (const unsigned char *)subject,
subject_length, (size_t)offset, 0, pcre2_matches, NULL)) > 0)
{
+ if (submatches >= PCRS_MAX_SUBMATCHES)
+ {
+ free(matches);
+ pcre2_match_data_free(pcre2_matches);
+
+ return(PCRS_TOO_MANY_SUBMATCHES);
+ }
job->flags |= PCRS_SUCCESS;
matches[i].submatches = submatches;
diff --git a/pcrs.h b/pcrs.h
index 507d6970..7ebb7fc1 100644
--- a/pcrs.h
+++ b/pcrs.h
@@ -72,6 +72,7 @@
#define PCRS_WARN_BADREF -304 /* Backreference out of range */
#define PCRS_WARN_TRUNCATION -305 /* At least one pcrs variable was too big,
* only the first part was used. */
+#define PCRS_TOO_MANY_SUBMATCHES -306 /* PCRS_MAX_SUBMATCHES reached. */
/* Flags */
#define PCRS_GLOBAL 0x08000000u /* Job should be applied globally, as with perl's g option */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:26 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:26 +0200
Subject: [Privoxy-commits] [privoxy] branch master updated (314fc388 ->
08593d41)
Message-ID: <179161568668.32820.2707145156772435049@privoxy-git>
This is an automated email from the git hooks/post-receive script.
git pushed a change to branch master
in repository privoxy.
from 314fc388 privoxy-regression-test: In the perldoc synopsis, mark two options as optional
new e8f6884f pcrs: Properly deal with too many submatches
new 007b5b75 Add cts scenario "pcrs"
new 68369e3b pcrs_execute(): Plug unlikely memory leaks
new 81fbde2a chunked_body_is_complete(): Always initialize 'length'
new 5b06bd90 chunked_body_is_complete(): Pass valid buffer length to parse_chunk_size()
new df156ab1 Remove TODO item #189 as macOS packages have been available again for a while now
new 886e44b1 Clarify TODO item #136
new 234f97a8 Remove TODO item #12
new 26a973d6 default.filter: Fix typo in a comemnt
new 9001effc user-manual: Fix typo
new 92856faf default.filter: Document that variables shouldn't be used in the pattern part of pcrs commands
new 94d0df54 user-manual: Explicitly mention that variables shouldn't be used in the pattern part of pcrs commands
new 2d4d8f00 gen-skip-reasons.pl: Skip a couple of recently added upstream tests
new 5b86d796 Regenerate curl-test-manifest-for-privoxy
new 20b83f5f privoxy-runtests.pm: Overwrite citest_starttest() to skip a name length check
new 676f1119 tests: Modify test 15 from the chunked-transfer-encoding-https scenario
new 1b1dd355 tests/cts: Fix two acl-related tests
new 145ddf49 tests: Change two test names in connection-headers-with-keep-alive-timeout-set scenario
new 4a97f797 run-privoxy-tests.sh: Add an empty line before reporting the final result
new bd248a62 Unblock requests to files.pythonhosted.org/packages/
new d5230d6c rfc2553_connect_to(): Implement Happy Eyeballs (RFC 8305)
new 188845f1 p-config.sgml: Document the connect-attempt-delay directive
new 1c9941b7 Bump SMGL entities for 4.3.0 UNRELEASED (again)
new af37f38b Regenerate FAQ
new 1672f79e Regenerate user manual
new 08593d41 Regenerate config file
The 26 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
TODO | 9 +-
config | 60 ++
configure.in | 1 +
default.action.master | 2 +
default.filter | 4 +-
doc/source/faq.sgml | 8 +-
doc/source/p-config.sgml | 86 ++
doc/source/user-manual.sgml | 9 +-
doc/webserver/faq/index.html | 2 +-
doc/webserver/user-manual/appendix.html | 16 +-
doc/webserver/user-manual/config.html | 58 ++
doc/webserver/user-manual/filter-file.html | 15 +-
doc/webserver/user-manual/index.html | 1 +
errlog.c | 14 +-
errlog.h | 4 +-
jbsockets.c | 906 +++++++++++++++++----
jcc.c | 8 +-
loadcfg.c | 28 +
pcrs.c | 12 +
pcrs.h | 1 +
project.h | 8 +
.../data/test5 | 5 +-
.../acl-permit-access-with-exceptions/data/test5 | 3 +-
.../chunked-transfer-encoding-https/data/test15 | 8 +-
.../data/test11 | 2 +-
.../data/test12 | 2 +-
tests/cts/curl-test-manifest-for-privoxy | 9 +-
tests/cts/gen-skip-reasons.pl | 16 +-
.../data/DISABLED | 0
.../{forward-to-socks-proxy => pcrs}/data/test1 | 14 +-
.../{forward-to-socks-proxy => pcrs}/data/test2 | 13 +-
.../{forward-to-socks-proxy => pcrs}/data/test3 | 22 +-
.../data/test2 => pcrs/data/test4} | 14 +-
.../{forward-to-socks-proxy => pcrs}/data/test5 | 17 +-
.../data/test3 => pcrs/data/test6} | 13 +-
tests/cts/pcrs/pcrs.action | 17 +
tests/cts/pcrs/pcrs.filter | 21 +
.../privoxy.conf | 5 +-
tests/cts/privoxy-runtests.pm | 5 +
tests/cts/run-privoxy-tests.sh | 2 +
40 files changed, 1203 insertions(+), 237 deletions(-)
copy tests/cts/{acl-ip-address-permitted => pcrs}/data/DISABLED (100%)
copy tests/cts/{forward-to-socks-proxy => pcrs}/data/test1 (74%)
copy tests/cts/{forward-to-socks-proxy => pcrs}/data/test2 (76%)
copy tests/cts/{forward-to-socks-proxy => pcrs}/data/test3 (57%)
copy tests/cts/{forward-to-socks-proxy/data/test2 => pcrs/data/test4} (69%)
copy tests/cts/{forward-to-socks-proxy => pcrs}/data/test5 (65%)
copy tests/cts/{forward-to-socks-proxy/data/test3 => pcrs/data/test6} (71%)
create mode 100644 tests/cts/pcrs/pcrs.action
create mode 100644 tests/cts/pcrs/pcrs.filter
copy tests/cts/{acl-ip-address-permitted => pcrs}/privoxy.conf (92%)
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:29 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:29 +0200
Subject: [Privoxy-commits] [privoxy] 03/26: pcrs_execute(): Plug unlikely
memory leaks
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070127.D979310155@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 68369e3b90f00969434436e836de12469c8a5c85
Author: Fabian Keil
AuthorDate: Sun Sep 6 12:13:58 2026 +0200
pcrs_execute(): Plug unlikely memory leaks
---
pcrs.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/pcrs.c b/pcrs.c
index 5ff35f2a..509bdc2e 100644
--- a/pcrs.c
+++ b/pcrs.c
@@ -823,6 +823,8 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char
if (NULL == (matches = (pcrs_match *)malloc((size_t)max_matches * sizeof(pcrs_match))))
{
+ pcre2_match_data_free(pcre2_matches);
+
return(PCRS_ERR_NOMEM);
}
memset(matches, '\0', (size_t)max_matches * sizeof(pcrs_match));
@@ -876,6 +878,8 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char
if (NULL == (dummy = (pcrs_match *)realloc(matches, (size_t)max_matches * sizeof(pcrs_match))))
{
free(matches);
+ pcre2_match_data_free(pcre2_matches);
+
return(PCRS_ERR_NOMEM);
}
matches = dummy;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:30 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:30 +0200
Subject: [Privoxy-commits] [privoxy] 04/26: chunked_body_is_complete():
Always initialize 'length'
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070128.1A544101CF@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 81fbde2a6c7cbc383ab031f0273fc9d628b66e1c
Author: Fabian Keil
AuthorDate: Sun Sep 20 17:03:58 2026 +0200
chunked_body_is_complete(): Always initialize 'length'
... even in cases where callers aren't supposed to read it.
---
jcc.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/jcc.c b/jcc.c
index 8a595001..383eff55 100644
--- a/jcc.c
+++ b/jcc.c
@@ -1512,6 +1512,8 @@ static enum chunk_status chunked_body_is_complete(struct iob *iob, size_t *lengt
unsigned int chunksize;
char *p = iob->cur;
+ *length = 0;
+
do
{
/*
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:31 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:31 +0200
Subject: [Privoxy-commits] [privoxy] 05/26: chunked_body_is_complete(): Pass
valid buffer length to parse_chunk_size()
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070128.614E8101D1@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 5b06bd9062b002de4f8aca3ac712c3e42e76da23
Author: Fabian Keil
AuthorDate: Sun Sep 20 10:43:18 2026 +0200
chunked_body_is_complete(): Pass valid buffer length to parse_chunk_size()
Previously an unitialized variable was passed which could result in
"Conditional jump or move depends on uninitialised value(s)" warnings
from valgrind.
It remains unclear if the issue could also be used to cause reads
of unitialized memory or trigger crashes with ASAN or USAN.
OVE-20261004-0001.
---
jcc.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/jcc.c b/jcc.c
index 383eff55..9506047c 100644
--- a/jcc.c
+++ b/jcc.c
@@ -1516,15 +1516,17 @@ static enum chunk_status chunked_body_is_complete(struct iob *iob, size_t *lengt
do
{
+ size_t data_left = (size_t)(iob->eod - p);
/*
* We need at least a single digit, followed by "\r\n",
* followed by an unknown amount of data, followed by "\r\n".
*/
- if (p + 5 > iob->eod)
+ if (5 > data_left)
{
return CHUNK_STATUS_MISSING_DATA;
}
- if (JB_ERR_OK != parse_chunk_size(p, *length, &chunksize))
+
+ if (JB_ERR_OK != parse_chunk_size(p, data_left, &chunksize))
{
return CHUNK_STATUS_PARSE_ERROR;
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:32 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:32 +0200
Subject: [Privoxy-commits] [privoxy] 06/26: Remove TODO item #189 as macOS
packages have been available again for a while now
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070128.959F710157@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit df156ab1359788568693778dedd8395a92714056
Author: Fabian Keil
AuthorDate: Mon Sep 7 15:00:51 2026 +0200
Remove TODO item #189 as macOS packages have been available again for a while now
---
TODO | 5 -----
1 file changed, 5 deletions(-)
diff --git a/TODO b/TODO
index e9348bbd..33abc66c 100644
--- a/TODO
+++ b/TODO
@@ -475,11 +475,6 @@ https://www.privoxy.org/donate
# Copyright ...
#
-189) Bring back binary packages for macOS, preferably for both Intel and M1.
- The first step would be getting at least one build system, either
- donated or bought with donations earmarked for this.
- Interested donors: 0.
-
190) The socks5 authentication code should send user name an password
separately or we should increase the cbuf size to allow longer
user names and passwords.
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:34 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:34 +0200
Subject: [Privoxy-commits] [privoxy] 08/26: Remove TODO item #12
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070129.6DF7E101D6@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 234f97a857a57e8700aa451af3bb00992a600d3f
Author: Fabian Keil
AuthorDate: Mon Sep 7 15:14:41 2026 +0200
Remove TODO item #12
Pipelining doesn't work reliably and various clients removed
support for it.
---
TODO | 2 --
1 file changed, 2 deletions(-)
diff --git a/TODO b/TODO
index 8ff0466b..266a6270 100644
--- a/TODO
+++ b/TODO
@@ -44,8 +44,6 @@ https://www.privoxy.org/donate
Work in progress.
-12) Support pipelining for outgoing connections.
-
19) enable-forward-fallback. Syntax? Suggested by K.R.
21) User Manual delivery doesn't accept multiple slashes. Should it?
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:35 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:35 +0200
Subject: [Privoxy-commits] [privoxy] 09/26: default.filter: Fix typo in a
comemnt
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070129.9DA9B101D7@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 26a973d6c37627d9431ca8f42cb3039fc83f3f27
Author: Fabian Keil
AuthorDate: Thu Sep 17 10:04:41 2026 +0200
default.filter: Fix typo in a comemnt
---
default.filter | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/default.filter b/default.filter
index b0970e39..cd257425 100644
--- a/default.filter
+++ b/default.filter
@@ -61,7 +61,7 @@
# Note that '$' is a bad choice as delimiter for dynamic filters as you
# might end up with unintended variables if you use a variable name
# directly after the delimiter. Variables will be resolved without
-# escaping anything, therefore you also have to be careful not to chose
+# escaping anything, therefore you also have to be careful not to choose
# delimiters that appear in the replacement text. For example '<' should
# be save, while '?' will sooner or later cause conflicts with $url.
#
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:33 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:33 +0200
Subject: [Privoxy-commits] [privoxy] 07/26: Clarify TODO item #136
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070129.49DB7101D4@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 886e44b1aafd667c90a10755b72c673ca6cd5312
Author: Fabian Keil
AuthorDate: Mon Sep 7 15:08:06 2026 +0200
Clarify TODO item #136
---
TODO | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO b/TODO
index 33abc66c..8ff0466b 100644
--- a/TODO
+++ b/TODO
@@ -331,7 +331,7 @@ https://www.privoxy.org/donate
135) Add OpenBSM audit support.
-136) Make builds reproducible.
+136) Make binary packages reproducible.
138) Bring back the scripts to provide actions file feedback.
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:37 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:37 +0200
Subject: [Privoxy-commits] [privoxy] 11/26: default.filter: Document that
variables shouldn't be used in the pattern part of pcrs commands
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070130.51152101D8@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 92856faf436292440b39d13e7625d1c9eafa3d42
Author: Fabian Keil
AuthorDate: Thu Sep 17 10:13:47 2026 +0200
default.filter: Document that variables shouldn't be used in the pattern part of pcrs commands
---
default.filter | 2 ++
1 file changed, 2 insertions(+)
diff --git a/default.filter b/default.filter
index cd257425..14d0342e 100644
--- a/default.filter
+++ b/default.filter
@@ -64,6 +64,8 @@
# escaping anything, therefore you also have to be careful not to choose
# delimiters that appear in the replacement text. For example '<' should
# be save, while '?' will sooner or later cause conflicts with $url.
+# Using variables in the pattern part is not recommended, as special
+# characters are not escaped and may cause problems.
#
#################################################################################
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:38 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:38 +0200
Subject: [Privoxy-commits] [privoxy] 12/26: user-manual: Explicitly mention
that variables shouldn't be used in the pattern part of pcrs commands
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070130.8BCD3101D9@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 94d0df54c53d5e10d112dcbc61fe278cf87caac0
Author: Fabian Keil
AuthorDate: Thu Sep 17 10:15:11 2026 +0200
user-manual: Explicitly mention that variables shouldn't be used in the pattern part of pcrs commands
---
doc/source/user-manual.sgml | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/doc/source/user-manual.sgml b/doc/source/user-manual.sgml
index 9b9e8905..e2137e1b 100644
--- a/doc/source/user-manual.sgml
+++ b/doc/source/user-manual.sgml
@@ -7308,6 +7308,13 @@ webmail.example.com
be save, while '?' will sooner or later cause conflicts with $url.
+
+
+ Using variables in the pattern part is not recommended, as special
+ characters are not escaped and may cause problems.
+
+
+
The non-standard option letter T (trivial) prevents
parsing for backreferences in the substitute. Use it if you want to include
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:36 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:36 +0200
Subject: [Privoxy-commits] [privoxy] 10/26: user-manual: Fix typo
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070129.F1F1F1015A@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 9001effc2d4decbb466d8b0b9a83447c3720acd4
Author: Fabian Keil
AuthorDate: Thu Sep 17 10:06:09 2026 +0200
user-manual: Fix typo
---
doc/source/user-manual.sgml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/source/user-manual.sgml b/doc/source/user-manual.sgml
index ba565a90..9b9e8905 100644
--- a/doc/source/user-manual.sgml
+++ b/doc/source/user-manual.sgml
@@ -7303,7 +7303,7 @@ webmail.example.com
Note that '$' is a bad choice for a delimiter in a dynamic filter as you
might end up with unintended variables if you use a variable name
directly after the delimiter. Variables will be resolved without
- escaping anything, therefore you also have to be careful not to chose
+ escaping anything, therefore you also have to be careful not to choose
delimiters that appear in the replacement text. For example '<' should
be save, while '?' will sooner or later cause conflicts with $url.
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:39 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:39 +0200
Subject: [Privoxy-commits] [privoxy] 13/26: gen-skip-reasons.pl: Skip a
couple of recently added upstream tests
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070130.DF05F1015E@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 2d4d8f003427b81caacf56fa270e6532c7aab6f8
Author: Fabian Keil
AuthorDate: Thu Sep 17 10:54:25 2026 +0200
gen-skip-reasons.pl: Skip a couple of recently added upstream tests
... that aren't expected to work when using Privoxy.
---
tests/cts/gen-skip-reasons.pl | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/tests/cts/gen-skip-reasons.pl b/tests/cts/gen-skip-reasons.pl
index 9918ed87..651d9a02 100755
--- a/tests/cts/gen-skip-reasons.pl
+++ b/tests/cts/gen-skip-reasons.pl
@@ -30,7 +30,7 @@ sub main() {
for my $testnum (1..3500) {
my $why;
- if ($testnum == 1) {
+ if ($testnum == 1 or $testnum == 320) {
$why = "Expected to fail. Multiple values in Connection header that get removed by Privoxy.";
} elsif ($testnum == 2) {
$why = "Expected to fail. Missing space after status code that gets added by Privoxy.";
@@ -57,6 +57,8 @@ sub main() {
$testnum == 1417 or
$testnum == 1493) {
$why = "Expected to fail with Privoxy. Test contains non-standard 'Connection: mooo' header that Privoxy replaces with 'Connection: close'.";
+ } elsif ($testnum == 36) {
+ $why = "Expected to fail due to 'Connection: mooo' header.";
} elsif ($testnum == 46) {
$why = "Invalid URL and use of --resolv.";
} elsif ($testnum == 58) {
@@ -81,6 +83,8 @@ sub main() {
$why = "Chunked transfer with trailers which Privoxy does not understand. Needs investigating.";
} elsif ($testnum == 389) {
$why = "Known to fail depending on the DNS resolver on the system as Privoxy does not implement RFC6761 internally.";
+ } elsif ($testnum == 394) {
+ $why = "Known to fail. Privoxy removed an invalid Content-Length header which causes curl to accept the response.";
} elsif ($testnum == 1052) {
$why = "Expected to fail. Connection header expected in one response but not in the other. Not yet covered by runtests.pl's proxy mode.";
} elsif ($testnum == 1118) {
@@ -157,6 +161,8 @@ sub main() {
$why = "Expected to fail. Privoxy does not support chunked trailers.";
} elsif ($testnum == 1533) {
$why = "Sends an invalid method. Needs investigating.";
+ } elsif ($testnum == 1515) {
+ $why = "Depends on DNS and isn't relevant for Privoxy.";
} elsif ($testnum == 1542) {
$why = "Expected to fail. Expects HTTPPORT in logs which gets replaced by Privoxy's listening port.";
} elsif ($testnum == 1543) {
@@ -171,6 +177,10 @@ sub main() {
$why = "Known to fail as curl adds a Proxy-Connection header to the JSON output which the test doesn't expect.";
} elsif ($testnum == 1685) {
$why = "Known to fail as Privoxy converts a tab in a Cookie header to space.";
+ } elsif ($testnum == 1689) {
+ $why = "Known to fail as curl adds a Proxy-Connection header when using Privoxy.";
+ } elsif ($testnum == 1721) {
+ $why = "Known to fail. Looks like a curl bug that should be reported upstream.";
} elsif ($testnum == 1915) {
$why = "Known to fail. Uses tool that doesn't expect a proxy.";
} elsif ($testnum == 1933) {
@@ -189,6 +199,8 @@ sub main() {
$why = "Known to fail. Test does not expect proxy request.";
} elsif ($testnum == 2100) {
$why = "Known to fail. Use DNS-over-HTTP.";
+ } elsif ($testnum == 2105) {
+ $why = "Known to fail. Contains invalid header which Privoxy currently passes on truncated.";
} elsif ($testnum == 3014 or $testnum == 3015) {
$why = "Known to fail. Curl adds a Proxy-Connection header while test expect a certain number of headers.";
}
@@ -217,7 +229,7 @@ sub main() {
printf("keyword:%s: Protocol %s is supported by Privoxy but the tests need additional magic before they can be used.\n", $protocol, $protocol);
}
- foreach my $misc ('proxy', '--resolve', '--libcurl', 'CURLOPT_RESOLVE') {
+ foreach my $misc ('--connect-to', 'proxy', '--resolve', '--libcurl', 'CURLOPT_RESOLVE') {
printf("keyword:%s: Tests with keyword '%s' currently don't work with Privoxy as they need additional runtests.pl changes.\n", $misc, $misc);
}
printf("keyword:%s: Tests with keyword '%s' aren't expected to work with Privoxy running in a jail without IPv6 connectivity.\n", 'IPv6', 'IPv6');
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:40 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:40 +0200
Subject: [Privoxy-commits] [privoxy] 14/26: Regenerate
curl-test-manifest-for-privoxy
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070131.5D1551015F@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 5b86d796620d3c753d35a3ce3f593d11899ddea5
Author: Fabian Keil
AuthorDate: Thu Sep 17 11:38:50 2026 +0200
Regenerate curl-test-manifest-for-privoxy
---
tests/cts/curl-test-manifest-for-privoxy | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/tests/cts/curl-test-manifest-for-privoxy b/tests/cts/curl-test-manifest-for-privoxy
index b4bba271..7e7f5d37 100644
--- a/tests/cts/curl-test-manifest-for-privoxy
+++ b/tests/cts/curl-test-manifest-for-privoxy
@@ -1,3 +1,4 @@
+keyword:--connect-to: Tests with keyword '--connect-to' currently don't work with Privoxy as they need additional runtests.pl changes.
keyword:--libcurl: Tests with keyword '--libcurl' currently don't work with Privoxy as they need additional runtests.pl changes.
keyword:--request-target: Tests with keyword '--request-target' don't work with Privoxy as they use the OPTIONS method which is currently not properly supported (TODO #186).
keyword:--resolve: Tests with keyword '--resolve' currently don't work with Privoxy as they need additional runtests.pl changes.
@@ -19,7 +20,7 @@ keyword:SOCKS4: Protocol SOCKS4 is supported by Privoxy but the tests need addit
keyword:SOCKS5: Protocol SOCKS5 is supported by Privoxy but the tests need additional magic before they can be used.
keyword:TELNET: Protocol TELNET is not supported by Privoxy.
keyword:unsupported: Tests with keyword 'unsupported' do not reach the proxy. Or do they?
-test:1: Expected to fail. Multiple values in Connection header that get removed by Privoxy.
+test:1, 320: Expected to fail. Multiple values in Connection header that get removed by Privoxy.
test:1052: Expected to fail. Connection header expected in one response but not in the other. Not yet covered by runtests.pl's proxy mode.
test:1074: Expected to fail. Privoxy doesn't downgrade the forwarded request and doesn't have to as long as the client is treated like a HTTP/1.0 client. Needs double-checking.
test:1118: Expected to fail. Looks like a curl bug although Privoxy's behaviour seems subobtimal as well.
@@ -38,6 +39,7 @@ test:1433: Expected to fail. Privoxy will enforce a valid HTTP version number
test:1479: Expected to fail. Uses HTTP/0.9 response.
test:1480: Expected to fail. Uses HTTP Continue response but no final response.
test:1506, 1510: Expected to fail when using a proxy. Hardcoded addresses in expected output.
+test:1515: Depends on DNS and isn't relevant for Privoxy.
test:1533: Sends an invalid method. Needs investigating.
test:1542: Expected to fail. Expects HTTPPORT in logs which gets replaced by Privoxy's listening port.
test:1543: Expected to fail as the URL contains spaces. XXX: Looks like a curl bug that should be investigated.
@@ -49,7 +51,9 @@ test:16, 45, 63: Not supposed to work with Privoxy. Expected forwarding failure.
test:1665: Expected to fail. Trigger Privoxy's MS IIS 5 hack which the test does not expect.
test:1671: Known to fail as curl adds a Proxy-Connection header to the JSON output which the test doesn't expect.
test:1685: Known to fail as Privoxy converts a tab in a Cookie header to space.
+test:1689: Known to fail as curl adds a Proxy-Connection header when using Privoxy.
test:17: Not supposed to work with Privoxy. Invalid METHODs get rejected.
+test:1721: Known to fail. Looks like a curl bug that should be reported upstream.
test:187: Expected to fail. Test doesn't deal with Privoxy's error message in case of invalid URLs.
test:19, 20: Not supposed to work with Privoxy. Tests behaviour with non-existing server and doesn't deal with error messages coming from a proxy.
test:1901, 1902, 1903: Known to fail due to different response orders.
@@ -62,6 +66,7 @@ test:2049, 2052, 2053, 2054: Uses --connect-to. Need investigating.
test:207: Expected to fail. Test doesn't handle Privoxy's error message. Privoxy doesn't behave correctly, though.
test:2082, 2084, 2085: Known to fail. Uses %%HTTPPORT and does not expect Privoxy's port but the remote one.
test:2100: Known to fail. Use DNS-over-HTTP.
+test:2105: Known to fail. Contains invalid header which Privoxy currently passes on truncated.
test:260: Known to fail. Looks like a curl bug. The URL passed to Privoxy is invalid but the test expect a valid one when not using a proxy
test:262: Not supposed to work with Privoxy. Privoxy doesn't support nul bytes in headers and neither does the spec.
test:266, 1116, 1540: Known to fail. Uses chunk trailers which Privoxy currently doesn't support.
@@ -71,7 +76,9 @@ test:309: Known to fail. Uses https and test does not expect the 'Connection est
test:31, 1105, 1160: Expected to fail. Privoxy normalizes white-space in a cookie.
test:339, 347, 1482, 1483, 1591: Chunked transfer with trailers which Privoxy does not understand. Needs investigating.
test:34, 457, 1417, 1493: Expected to fail with Privoxy. Test contains non-standard 'Connection: mooo' header that Privoxy replaces with 'Connection: close'.
+test:36: Expected to fail due to 'Connection: mooo' header.
test:389: Known to fail depending on the DNS resolver on the system as Privoxy does not implement RFC6761 internally.
+test:394: Known to fail. Privoxy removed an invalid Content-Length header which causes curl to accept the response.
test:412, 413: Known to fail as curl is tunneling the request even though it's vanilla HTTP.
test:415: Known to fail. Control code in Content-Length header.
test:435: Expected to fail. Uses %%{remote_port} and expects the port of the server and not the one from Privoxy.
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:41 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:41 +0200
Subject: [Privoxy-commits] [privoxy] 15/26: privoxy-runtests.pm: Overwrite
citest_starttest() to skip a name length check
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070131.97E2A101DB@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 20b83f5fcf7a767a174fcd941073bb661cd6b7d4
Author: Fabian Keil
AuthorDate: Sun Sep 20 17:21:12 2026 +0200
privoxy-runtests.pm: Overwrite citest_starttest() to skip a name length check
---
tests/cts/privoxy-runtests.pm | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tests/cts/privoxy-runtests.pm b/tests/cts/privoxy-runtests.pm
index 9f731a44..93ddc16c 100644
--- a/tests/cts/privoxy-runtests.pm
+++ b/tests/cts/privoxy-runtests.pm
@@ -210,6 +210,11 @@ sub startnew {
return &$real_startnew($cmd, $pidfile, $timeout, $fake);
}
+# Overwritten to allow test names longer than 70 characters.
+sub citest_starttest {
+ return 0;
+}
+
sub main() {
# Look but don't touch, @ARGV is still needed elsewhere
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:42 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:42 +0200
Subject: [Privoxy-commits] [privoxy] 16/26: tests: Modify test 15 from the
chunked-transfer-encoding-https scenario
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070131.EF487101DD@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 676f1119d0080674954ccc373121aa0f3e5f2d8d
Author: Fabian Keil
AuthorDate: Sun Sep 20 19:12:55 2026 +0200
tests: Modify test 15 from the chunked-transfer-encoding-https scenario
Previously it was basically the same as test 14.
---
tests/cts/chunked-transfer-encoding-https/data/test15 | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/tests/cts/chunked-transfer-encoding-https/data/test15 b/tests/cts/chunked-transfer-encoding-https/data/test15
index c2c9bc77..d250030d 100644
--- a/tests/cts/chunked-transfer-encoding-https/data/test15
+++ b/tests/cts/chunked-transfer-encoding-https/data/test15
@@ -29,6 +29,9 @@ X-Control: swsclose%CR
100%CR
%repeat[255 x %hex[%00]hex%]%
%CR
+100%CR
+%repeat[255 x D]%
+%CR
0%CR
%CR
@@ -48,6 +51,7 @@ X-Control: swsclose%CR
%repeat[255 x B]%
%repeat[255 x C]%
%repeat[255 x %hex[%00]hex%]%
+%repeat[255 x D]%
@@ -56,13 +60,13 @@ X-Control: swsclose%CR
https
-Chunked transfer encoding - Multiple chunks, chunk at the end contains binary zeroes and is valid.
+Chunked transfer encoding - Multiple chunks, chunk in the middle contains binary zeroes and is valid.
proxy
---insecure --raw https://%HOSTIP:%HTTPSPORT/chunked-transfer-encoding/%TESTNUMBER
+--insecure https://%HOSTIP:%HTTPSPORT/chunked-transfer-encoding/%TESTNUMBER
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:43 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:43 +0200
Subject: [Privoxy-commits] [privoxy] 17/26: tests/cts: Fix two acl-related
tests
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070133.100DC10162@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 1b1dd355397fde313ac22cb8f2aaffab9ef0f723
Author: Fabian Keil
AuthorDate: Sun Sep 20 19:19:04 2026 +0200
tests/cts: Fix two acl-related tests
... that previously contained proxy-reply sections that were
ineffective due to a duplicated '<'.
---
.../acl-multiple-ip-addresses-specified-with-destination/data/test5 | 5 ++---
tests/cts/acl-permit-access-with-exceptions/data/test5 | 3 +--
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/tests/cts/acl-multiple-ip-addresses-specified-with-destination/data/test5 b/tests/cts/acl-multiple-ip-addresses-specified-with-destination/data/test5
index d7c9b092..f21bfd8e 100644
--- a/tests/cts/acl-multiple-ip-addresses-specified-with-destination/data/test5
+++ b/tests/cts/acl-multiple-ip-addresses-specified-with-destination/data/test5
@@ -7,7 +7,7 @@ HTTP GET
-<
+
HTTP/1.1 503 Connect failed
Content-Length: 44
@@ -19,13 +19,12 @@ Last-Modified: Wed, 08 Jun 1955 12:00:00 GMT
Expires: Sat, 17 Jun 2000 12:00:00 GMT
Pragma: no-cache
-Could not connect to destination 127.0.0.1.
-Request from client address from denied network range
+HEAD request from client address from denied network range
--head --interface 127.0.1.3 http://127.0.0.1/%TESTNUMBER
diff --git a/tests/cts/acl-permit-access-with-exceptions/data/test5 b/tests/cts/acl-permit-access-with-exceptions/data/test5
index d7c9b092..f5eeb54d 100644
--- a/tests/cts/acl-permit-access-with-exceptions/data/test5
+++ b/tests/cts/acl-permit-access-with-exceptions/data/test5
@@ -7,7 +7,7 @@ HTTP GET
-<
+
HTTP/1.1 503 Connect failed
Content-Length: 44
@@ -19,7 +19,6 @@ Last-Modified: Wed, 08 Jun 1955 12:00:00 GMT
Expires: Sat, 17 Jun 2000 12:00:00 GMT
Pragma: no-cache
-Could not connect to destination 127.0.0.1.
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:44 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:44 +0200
Subject: [Privoxy-commits] [privoxy] 18/26: tests: Change two test names in
connection-headers-with-keep-alive-timeout-set scenario
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070133.56CE8101DE@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 145ddf49b7deaeb60b2fe024affebfc0e0a8f4a1
Author: Fabian Keil
AuthorDate: Sun Sep 20 19:23:17 2026 +0200
tests: Change two test names in connection-headers-with-keep-alive-timeout-set scenario
... which previously were the same which is no longer allowed when
using the test framework from a more recent curl checkout.
---
tests/cts/connection-headers-with-keep-alive-timeout-set/data/test11 | 2 +-
tests/cts/connection-headers-with-keep-alive-timeout-set/data/test12 | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/cts/connection-headers-with-keep-alive-timeout-set/data/test11 b/tests/cts/connection-headers-with-keep-alive-timeout-set/data/test11
index 467cf82a..ebd0c54c 100644
--- a/tests/cts/connection-headers-with-keep-alive-timeout-set/data/test11
+++ b/tests/cts/connection-headers-with-keep-alive-timeout-set/data/test11
@@ -37,7 +37,7 @@ Blafasel.
http
-Multiple conflicting "Connection:" headers.
+Multiple conflicting "Connection:" headers. "Connection: keep-alive" wins.
http://%HOSTIP:%HTTPPORT/%TESTNUMBER
diff --git a/tests/cts/connection-headers-with-keep-alive-timeout-set/data/test12 b/tests/cts/connection-headers-with-keep-alive-timeout-set/data/test12
index 94f4cefa..9c6b3e5e 100644
--- a/tests/cts/connection-headers-with-keep-alive-timeout-set/data/test12
+++ b/tests/cts/connection-headers-with-keep-alive-timeout-set/data/test12
@@ -36,7 +36,7 @@ Blafasel.
http
-Multiple conflicting "Connection:" headers.
+Multiple conflicting "Connection:" headers. "Connection: close" wins.
http://%HOSTIP:%HTTPPORT/%TESTNUMBER
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:45 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:45 +0200
Subject: [Privoxy-commits] [privoxy] 19/26: run-privoxy-tests.sh: Add an
empty line before reporting the final result
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070133.DD929101DF@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 4a97f797e7159f0578dc985dc5c44cf2873d2404
Author: Fabian Keil
AuthorDate: Sun Oct 4 10:53:13 2026 +0200
run-privoxy-tests.sh: Add an empty line before reporting the final result
---
tests/cts/run-privoxy-tests.sh | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tests/cts/run-privoxy-tests.sh b/tests/cts/run-privoxy-tests.sh
index 3781ee61..78133844 100755
--- a/tests/cts/run-privoxy-tests.sh
+++ b/tests/cts/run-privoxy-tests.sh
@@ -190,6 +190,8 @@ main() {
fi
done
+ echo
+
if [ -n "${scenarios_with_errors}" ]; then
echo "The following test scenarios had at least one error:${scenarios_with_errors}"
exit 1
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:46 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:46 +0200
Subject: [Privoxy-commits] [privoxy] 20/26: Unblock requests to
files.pythonhosted.org/packages/
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070134.373B6101E1@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit bd248a62af7563989f61519a129ecad03b66cf15
Author: Fabian Keil
AuthorDate: Sun Oct 4 21:09:12 2026 +0200
Unblock requests to files.pythonhosted.org/packages/
---
default.action.master | 2 ++
1 file changed, 2 insertions(+)
diff --git a/default.action.master b/default.action.master
index a65de1c7..3d66bccf 100644
--- a/default.action.master
+++ b/default.action.master
@@ -816,6 +816,8 @@ support./(.*/)?track
/.*download
# URL = https://gitlab.torproject.org/search/count?group_id=268&project_id=571&scope=users&search=src%2Ftest%2Ftest_util.c
gitlab./search/count\?
+# URL = https://files.pythonhosted.org/packages/23/ad/28ecd7cb894d172f3c9c80a075eeeb2017ac62e3632cee05a5f9493547eb/lxml-6.1.3.tar.gz
+files.pythonhosted.org/packages/
#----------------------------------------------------------------------------
# Misc Web-bugs, JS and just plain Junk. Images here aren't normal images.
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:47 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:47 +0200
Subject: [Privoxy-commits] [privoxy] 21/26: rfc2553_connect_to(): Implement
Happy Eyeballs (RFC 8305)
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070134.9891C101E3@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit d5230d6c73db58ba1de49fc86b8930ec9d1a9588
Author: Rustam Abdullaev
AuthorDate: Sat Sep 19 12:35:34 2026 +0200
rfc2553_connect_to(): Implement Happy Eyeballs (RFC 8305)
If a host resolves to multiple addresses, sort them so that address
families alternate and start connection attempts in parallel: the first
attempt is started right away, additional ones are started as soon as
a previous attempt failed or the new connect-attempt-delay directive
(default: 250 milliseconds) expired while previous attempts are still
pending. The first attempt to succeed wins, the other ones are aborted.
This limits the delay caused by unreachable addresses, for example
when a host has an IPv6 address but only IPv4 connectivity is available,
to the connect-attempt-delay instead of the 30 second connection
timeout.
Setting connect-attempt-delay to 0 restores the previous behaviour
of trying the addresses one after the other.
The first attempt is made to the first address returned by
getaddrinfo(), whichever family it belongs to, followed by an
address of the other family (RFC 8305 section 4).
The timeouts are measured with clock_gettime(CLOCK_MONOTONIC) where
available so they aren't affected by changes of the system time.
As getaddrinfo() is synchronous, the "Resolution Delay" part of
RFC 8305 isn't implemented.
On Windows the socket is made non-blocking to be able to run concurrent
connect attempts. Handle the select's exception set as that's where the
non-blocking Winsock connect() signals errors. Use the Winsock error
translation from errlog.c for the log messages as strerror() knows
nothing about Winsock error codes.
Also update the logging to more consistently log the host, IP and port
for each connect attempt (previously only the last attempt logged the
host).
Note, Happy Eyeballs is currently implemented for POSIX with getaddrinfo
support and Windows; other targets remain a to-do, should the need
arise.
SF patch #151.
---
configure.in | 1 +
errlog.c | 14 +-
errlog.h | 4 +-
jbsockets.c | 906 +++++++++++++++++++++++++++++++++++++++++++++++++----------
loadcfg.c | 28 ++
project.h | 8 +
6 files changed, 804 insertions(+), 157 deletions(-)
diff --git a/configure.in b/configure.in
index ef1e5347..715973aa 100644
--- a/configure.in
+++ b/configure.in
@@ -782,6 +782,7 @@ AC_CHECK_FUNCS([ \
gethostbyaddr_r \
gethostbyname \
gethostbyname_r \
+ clock_gettime \
gettimeofday \
inet_ntoa \
memchr \
diff --git a/errlog.c b/errlog.c
index a3fb3781..c38646c5 100644
--- a/errlog.c
+++ b/errlog.c
@@ -87,9 +87,6 @@ static int debug = (LOG_LEVEL_FATAL | LOG_LEVEL_ERROR);
/* static functions */
static void fatal_error(const char *error_message);
-#ifdef _WIN32
-static char *w32_socket_strerr(int errcode, char *tmp_buf);
-#endif
#ifdef MUTEX_LOCKS_AVAILABLE
static void lock_logfile(void)
@@ -837,7 +834,7 @@ void log_error(int loglevel, const char *fmt, ...)
/* Non-standard: Print error code from errno */
#ifdef _WIN32
ival = WSAGetLastError();
- format_string = w32_socket_strerr(ival, tempbuf);
+ format_string = w32_socket_strerr(ival, tempbuf, sizeof(tempbuf));
#else /* ifndef _WIN32 */
ival = errno;
#ifdef HAVE_STRERROR
@@ -982,13 +979,14 @@ const char *jb_err_to_string(jb_err jb_error)
* 1 : errcode = The return value from WSAGetLastError().
* 2 : tmp_buf = A temporary buffer that might be used to
* store the string.
+ * 3 : buffer_size = Size of tmp_buf in bytes.
*
* Returns : String representing the error code. This may be
* a global string constant or a string stored in
* tmp_buf.
*
*********************************************************************/
-static char *w32_socket_strerr(int errcode, char *tmp_buf)
+char *w32_socket_strerr(int errcode, char *tmp_buf, size_t buffer_size)
{
#define TEXT_FOR_ERROR(code,text) \
if (errcode == code) \
@@ -1054,7 +1052,11 @@ static char *w32_socket_strerr(int errcode, char *tmp_buf)
* TEXT_FOR_ERROR(WSA_OPERATION_ABORTED, "Overlapped operation aborted.");
*/
- sprintf(tmp_buf, "(error number %d)", errcode);
+ if (buffer_size == 0)
+ {
+ return "";
+ }
+ snprintf(tmp_buf, buffer_size, "(error number %d)", errcode);
return tmp_buf;
}
#endif /* def _WIN32 */
diff --git a/errlog.h b/errlog.h
index af1e675e..671f40dd 100644
--- a/errlog.h
+++ b/errlog.h
@@ -75,6 +75,9 @@ extern void init_log_module(void);
extern void show_version(const char *prog_name);
extern void log_error(int loglevel, const char *fmt, ...);
extern const char *jb_err_to_string(jb_err jb_error);
+#ifdef _WIN32
+extern char *w32_socket_strerr(int errcode, char *tmp_buf, size_t buffer_size);
+#endif
#endif /* ndef ERRLOG_H_INCLUDED */
@@ -83,4 +86,3 @@ extern const char *jb_err_to_string(jb_err jb_error);
tab-width: 3
end:
*/
-
diff --git a/jbsockets.c b/jbsockets.c
index 47ac67a2..ba85714e 100644
--- a/jbsockets.c
+++ b/jbsockets.c
@@ -72,6 +72,10 @@
#endif
+/* For clock_gettime() and gettimeofday() */
+#include
+#include
+
#ifdef HAVE_POLL
#ifdef __GLIBC__
#include
@@ -189,23 +193,580 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
}
#ifdef HAVE_RFC2553
-/* Getaddrinfo implementation */
-static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client_state *csp)
+
+/*
+ * Number of milliseconds after which a single connection
+ * attempt is considered to have failed.
+ */
+#define CONNECT_TIMEOUT_MSECS 30000
+
+#ifndef HAVE_POLL
+/* Only used as opaque pointer type if poll() isn't available. */
+struct pollfd;
+#endif
+
+/*
+ * Possible results of start_connection_attempt().
+ */
+enum connect_attempt_result
{
- struct addrinfo hints, *result, *rp;
- char service[6];
- int retval;
+ CONNECT_ATTEMPT_FAILED,
+ CONNECT_ATTEMPT_PENDING,
+ CONNECT_ATTEMPT_CONNECTED
+};
+
+/*
+ * State of a connection attempt to a single address.
+ *
+ * Used by rfc2553_connect_to() which may have several
+ * attempts in flight at the same time (RFC 8305).
+ */
+struct connect_attempt
+{
+ /** The address to connect to. */
+ const struct addrinfo *address;
+
+ /** The socket used for the attempt or JB_INVALID_SOCKET. */
+ jb_socket fd;
+
+ /** Whether or not the attempt has been started but not completed yet. */
+ int pending;
+
+ /** Set by wait_for_connection_attempts() if the attempt completed. */
+ int ready;
+
+ /** The time at which the attempt was started. */
+ struct timeval start_time;
+
+#if !defined(_WIN32) && !defined(__BEOS__)
+ /** The file status flags of the socket before it was made non-blocking. */
+ int flags;
+#endif
+
+ /** Textual representation of the address. */
+ char ip_addr_str[NI_MAXHOST];
+};
+
+
+/*********************************************************************
+ *
+ * Function : get_monotonic_time
+ *
+ * Description : Gets the current time for the purpose of measuring
+ * time intervals. Uses a monotonic clock if available
+ * so that the intervals aren't affected by changes
+ * of the system time.
+ *
+ * Parameters :
+ * 1 : now = Receives the current time.
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+static void get_monotonic_time(struct timeval *now)
+{
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+ {
+ now->tv_sec = ts.tv_sec;
+ now->tv_usec = (suseconds_t)(ts.tv_nsec / 1000);
+ return;
+ }
+#endif
+ gettimeofday(now, NULL);
+}
+
+
+/*********************************************************************
+ *
+ * Function : msecs_since
+ *
+ * Description : Returns the number of milliseconds that have
+ * passed since the given point in time.
+ *
+ * Parameters :
+ * 1 : start = The point in time to compare against.
+ * Has to come from get_monotonic_time().
+ *
+ * Returns : Number of milliseconds that passed since start.
+ *
+ *********************************************************************/
+static long msecs_since(const struct timeval *start)
+{
+ struct timeval now;
+
+ get_monotonic_time(&now);
+
+ return (now.tv_sec - start->tv_sec) * 1000
+ + (now.tv_usec - start->tv_usec) / 1000;
+}
+
+
+/*********************************************************************
+ *
+ * Function : get_socket_error
+ *
+ * Description : Returns the error code of the socket call that
+ * just failed. On Windows the socket functions don't
+ * set errno.
+ *
+ * Parameters : None
+ *
+ * Returns : The error code.
+ *
+ *********************************************************************/
+static int get_socket_error(void)
+{
+#ifdef _WIN32
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+
+/*********************************************************************
+ *
+ * Function : socket_strerror
+ *
+ * Description : Returns a textual representation of an error
+ * code returned by get_socket_error().
+ *
+ * Parameters :
+ * 1 : error = The error code.
+ * 2 : buffer = Scratch space that may be used for the result.
+ * 3 : buffer_size = Size of buffer in bytes.
+ *
+ * Returns : The error text, possibly stored in buffer.
+ *
+ *********************************************************************/
+#define SOCKET_STRERROR_BUFFER_SIZE 128
+static const char *socket_strerror(int error, char *buffer, size_t buffer_size)
+{
+#ifdef _WIN32
+ const char *text;
+ size_t length;
+
+ if (buffer_size == 0)
+ {
+ return "";
+ }
+ text = w32_socket_strerr(error, buffer, buffer_size);
+ if (text != buffer)
+ {
+ strlcpy(buffer, text, buffer_size);
+ }
+ /* Remove the trailing period so the text can be embedded in a sentence. */
+ length = strlen(buffer);
+ if ((length > 0) && (buffer[length - 1] == '.'))
+ {
+ buffer[length - 1] = '\0';
+ }
+ return buffer;
+#else
+ (void)buffer;
+ (void)buffer_size;
+ return strerror(error);
+#endif
+}
+
+
+/*********************************************************************
+ *
+ * Function : set_socket_blocking_mode
+ *
+ * Description : Switches a socket between blocking and
+ * non-blocking mode.
+ *
+ * Parameters :
+ * 1 : attempt = The connection attempt whose socket
+ * to modify. Its flags member is used
+ * to remember the original mode.
+ * 2 : blocking = TRUE to make the socket blocking,
+ * FALSE to make it non-blocking.
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+static void set_socket_blocking_mode(struct connect_attempt *attempt,
+ int blocking)
+{
+#if defined(_WIN32)
+ u_long non_blocking = !blocking;
+
+ ioctlsocket(attempt->fd, FIONBIO, &non_blocking);
+#elif !defined(__BEOS__)
+ if (!blocking)
+ {
+ attempt->flags = fcntl(attempt->fd, F_GETFL, 0);
+ if (attempt->flags != -1)
+ {
+ fcntl(attempt->fd, F_SETFL, attempt->flags | O_NDELAY);
+ }
+ }
+ else if (attempt->flags != -1)
+ {
+ fcntl(attempt->fd, F_SETFL, attempt->flags);
+ }
+#else
+ (void)attempt;
+ (void)blocking;
+#endif
+}
+
+
+/*********************************************************************
+ *
+ * Function : order_addresses
+ *
+ * Description : Distributes the addresses returned by getaddrinfo()
+ * to the connection attempts in the order the attempts
+ * should be made.
+ *
+ * As described in RFC 8305 section 4 the addresses
+ * are sorted by alternating between address families,
+ * starting with the family of the first address, which
+ * is the family preferred by the resolver (RFC 6724).
+ * The order of the addresses within a family is
+ * preserved.
+ *
+ * Parameters :
+ * 1 : result = The list returned by getaddrinfo().
+ * 2 : attempts = Array of connection attempts with
+ * room for attempt_count entries.
+ * 3 : attempt_count = Maximum number of addresses to use.
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+static void order_addresses(const struct addrinfo *result,
+ struct connect_attempt *attempts, int attempt_count)
+{
+ const struct addrinfo *first_family_address = result;
+ const struct addrinfo *other_family_address = result;
+ const int first_family = result->ai_family;
+ int count = 0;
+
+ while ((count < attempt_count)
+ && ((first_family_address != NULL) || (other_family_address != NULL)))
+ {
+ /* Skip the addresses that belong to the other family */
+ while ((first_family_address != NULL)
+ && (first_family_address->ai_family != first_family))
+ {
+ first_family_address = first_family_address->ai_next;
+ }
+ if (first_family_address != NULL)
+ {
+ attempts[count++].address = first_family_address;
+ first_family_address = first_family_address->ai_next;
+ }
+
+ /* Skip the addresses that belong to the first family */
+ while ((other_family_address != NULL)
+ && (other_family_address->ai_family == first_family))
+ {
+ other_family_address = other_family_address->ai_next;
+ }
+ if ((count < attempt_count) && (other_family_address != NULL))
+ {
+ attempts[count++].address = other_family_address;
+ other_family_address = other_family_address->ai_next;
+ }
+ }
+}
+
+
+/*********************************************************************
+ *
+ * Function : start_connection_attempt
+ *
+ * Description : Creates a socket and starts a non-blocking
+ * connection attempt to the attempt's address.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : attempt = The connection attempt to start.
+ * 3 : socket_error = Receives the errno of the failure
+ * in case the attempt fails.
+ *
+ * Returns : CONNECT_ATTEMPT_CONNECTED if the connection was
+ * established right away, CONNECT_ATTEMPT_PENDING
+ * if the attempt is in progress or
+ * CONNECT_ATTEMPT_FAILED if it failed.
+ *
+ *********************************************************************/
+static enum connect_attempt_result start_connection_attempt(
+ struct client_state *csp, struct connect_attempt *attempt,
+ int *socket_error)
+{
+ const struct addrinfo *rp = attempt->address;
jb_socket fd;
+ int retval;
+#ifdef FEATURE_ACL
+ struct access_control_addr dst[1];
+#endif /* def FEATURE_ACL */
+
+ retval = getnameinfo(rp->ai_addr, rp->ai_addrlen, attempt->ip_addr_str,
+ sizeof(attempt->ip_addr_str), NULL, 0, NI_NUMERICHOST);
+ if (retval)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to get the host name from the socket structure: %s",
+ gai_strerror(retval));
+ *socket_error = errno = EINVAL;
+ return CONNECT_ATTEMPT_FAILED;
+ }
+
+#ifdef FEATURE_ACL
+ memcpy(&dst->addr, rp->ai_addr, rp->ai_addrlen);
+#ifdef ACL_DEBUG
+ dst->addr_length = rp->ai_addrlen;
+#endif
+
+ if (block_acl(csp, dst))
+ {
+ *socket_error = errno = EPERM;
+ return CONNECT_ATTEMPT_FAILED;
+ }
+#endif /* def FEATURE_ACL */
+
+ fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+#ifdef _WIN32
+ if (fd == JB_INVALID_SOCKET)
+#else
+ if (fd < 0)
+#endif
+ {
+ *socket_error = get_socket_error();
+ return CONNECT_ATTEMPT_FAILED;
+ }
+
+#ifndef HAVE_POLL
+#ifndef _WIN32
+ if (fd >= FD_SETSIZE)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Server socket number too high to use select(): %d >= %d",
+ fd, FD_SETSIZE);
+ close_socket(fd);
+ *socket_error = EMFILE;
+ return CONNECT_ATTEMPT_FAILED;
+ }
+#endif
+#endif
+
+#ifdef FEATURE_EXTERNAL_FILTERS
+ mark_socket_for_close_on_execute(fd);
+#endif
+
+ set_no_delay_flag(fd);
+
+ attempt->fd = fd;
+ set_socket_blocking_mode(attempt, FALSE);
+ get_monotonic_time(&attempt->start_time);
+
+ while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET)
+ {
+ int error = get_socket_error();
+
+#ifdef _WIN32
+ if (error == WSAEWOULDBLOCK)
+#else /* ifndef _WIN32 */
+ if (error == EINPROGRESS)
+#endif /* ndef _WIN32 */
+ {
+ return CONNECT_ATTEMPT_PENDING;
+ }
+
+ if (error != EINTR)
+ {
+ *socket_error = error;
+ close_socket(fd);
+ attempt->fd = JB_INVALID_SOCKET;
+ return CONNECT_ATTEMPT_FAILED;
+ }
+ }
+
+ /*
+ * connect() succeeded right away. This is expected on platforms
+ * where the socket couldn't be made non-blocking and may also
+ * happen for local addresses.
+ */
+ return CONNECT_ATTEMPT_CONNECTED;
+}
+
+
+/*********************************************************************
+ *
+ * Function : wait_for_connection_attempts
+ *
+ * Description : Waits until at least one of the pending connection
+ * attempts completes (successfully or not) or the
+ * timeout expires. Completed attempts are marked as
+ * ready.
+ *
+ * Parameters :
+ * 1 : attempts = Array of connection attempts.
+ * 2 : attempt_count = Number of entries in the array.
+ * 3 : timeout_msecs = Maximum number of milliseconds to wait.
+ * 4 : poll_fds = Scratch space for poll() with room for
+ * attempt_count entries. Unused if poll()
+ * isn't available.
+ *
+ * Returns : Number of attempts that are ready, 0 in case
+ * of a timeout or -1 on error with errno set.
+ *
+ *********************************************************************/
+static int wait_for_connection_attempts(struct connect_attempt *attempts,
+ int attempt_count, int timeout_msecs, struct pollfd *poll_fds)
+{
+ int i;
+ int ready_count = 0;
+ int retval;
#ifdef HAVE_POLL
- struct pollfd poll_fd[1];
+ int poll_fd_count = 0;
+
+ for (i = 0; i < attempt_count; i++)
+ {
+ attempts[i].ready = 0;
+ if (attempts[i].pending)
+ {
+ poll_fds[poll_fd_count].fd = attempts[i].fd;
+ poll_fds[poll_fd_count].events = POLLOUT;
+ poll_fd_count++;
+ }
+ }
+
+ retval = poll(poll_fds, (nfds_t)poll_fd_count, timeout_msecs);
+ if (retval > 0)
+ {
+ poll_fd_count = 0;
+ for (i = 0; i < attempt_count; i++)
+ {
+ if (attempts[i].pending)
+ {
+ /*
+ * Any event means the attempt completed, whether or not
+ * it succeeded is determined through SO_ERROR by the caller.
+ */
+ if (poll_fds[poll_fd_count].revents != 0)
+ {
+ attempts[i].ready = 1;
+ ready_count++;
+ }
+ poll_fd_count++;
+ }
+ }
+ }
#else
fd_set wfds;
+ fd_set efds;
struct timeval timeout;
-#endif
-#if !defined(_WIN32) && !defined(__BEOS__)
- int flags;
-#endif
- int connect_failed;
+ jb_socket max_fd = 0;
+
+ /*
+ * A completed attempt makes the socket writable, except on
+ * Windows where a failed attempt is reported through the
+ * exception set instead.
+ */
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+ for (i = 0; i < attempt_count; i++)
+ {
+ attempts[i].ready = 0;
+ if (attempts[i].pending)
+ {
+ FD_SET(attempts[i].fd, &wfds);
+ FD_SET(attempts[i].fd, &efds);
+ if (attempts[i].fd > max_fd)
+ {
+ max_fd = attempts[i].fd;
+ }
+ }
+ }
+
+ timeout.tv_sec = timeout_msecs / 1000;
+ timeout.tv_usec = (timeout_msecs % 1000) * 1000;
+
+ /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Weird! */
+ retval = select((int)max_fd + 1, NULL, &wfds, &efds, &timeout);
+ if (retval > 0)
+ {
+ for (i = 0; i < attempt_count; i++)
+ {
+ if (attempts[i].pending
+ && (FD_ISSET(attempts[i].fd, &wfds) || FD_ISSET(attempts[i].fd, &efds)))
+ {
+ attempts[i].ready = 1;
+ ready_count++;
+ }
+ }
+ }
+#endif /* def HAVE_POLL */
+
+ if (retval < 0)
+ {
+ return -1;
+ }
+
+ return ready_count;
+}
+
+
+/*********************************************************************
+ *
+ * Function : rfc2553_connect_to
+ *
+ * Description : Resolves the host and connects to one of its
+ * addresses using getaddrinfo().
+ *
+ * Implements the connection part of Happy Eyeballs
+ * (RFC 8305): the first connection attempt is started
+ * right away, additional attempts to the remaining
+ * addresses are started as soon as a previous attempt
+ * failed or the connect-attempt-delay expired while
+ * previous attempts are still pending. The first
+ * attempt to succeed wins and the others are aborted.
+ *
+ * As getaddrinfo() is synchronous and returns the
+ * addresses of all families at once, the "Resolution
+ * Delay" part of RFC 8305 doesn't apply.
+ *
+ * Parameters :
+ * 1 : host = hostname to connect to
+ * 2 : portnum = port to connect to
+ * 3 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : JB_INVALID_SOCKET => failure, else it is the socket
+ * file descriptor.
+ *
+ *********************************************************************/
+static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client_state *csp)
+{
+ struct addrinfo hints;
+ struct addrinfo *result;
+ const struct addrinfo *rp;
+ struct connect_attempt *attempts;
+ struct connect_attempt *attempt;
+ const struct connect_attempt *last_attempt = NULL;
+ const struct connect_attempt *failed_attempt = NULL;
+ struct connect_attempt *winner = NULL;
+ struct pollfd *poll_fds = NULL;
+ const int connect_attempt_delay = csp->config->connect_attempt_delay;
+ char service[6];
+ char error_buffer[SOCKET_STRERROR_BUFFER_SIZE];
+ int retval;
+ jb_socket fd = JB_INVALID_SOCKET;
+ int address_count = 0;
+ int attempt_count = 0;
+ int pending_count = 0;
+ int start_next_attempt = 1;
+ long timeout_msecs;
+ long remaining_msecs;
+ int i;
/*
* XXX: Initializing it here is only necessary
* because not all situations are properly
@@ -213,10 +774,6 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
*/
int socket_error = 0;
-#ifdef FEATURE_ACL
- struct access_control_addr dst[1];
-#endif /* def FEATURE_ACL */
-
/* Don't leak memory when retrying. */
freez(csp->error_message);
freez(csp->http->host_ip_addr_str);
@@ -252,181 +809,230 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
csp->http->host_ip_addr_str = zalloc_or_die(NI_MAXHOST);
- for (rp = result; rp != NULL; rp = rp->ai_next)
+ /*
+ * Cap the number of addresses to the capacity of select()'s fd_sets
+ * for the unlikely event we get more addresses than the capacity
+ * (64 on Windows, typically 1024 or more on POSIX).
+ */
+ for (rp = result; (rp != NULL) && (address_count < FD_SETSIZE);
+ rp = rp->ai_next)
{
-
-#ifdef FEATURE_ACL
- memcpy(&dst->addr, rp->ai_addr, rp->ai_addrlen);
-#ifdef ACL_DEBUG
- dst->addr_length = rp->ai_addrlen;
+ address_count++;
+ }
+ attempts = zalloc_or_die((size_t)address_count * sizeof(*attempts));
+#ifdef HAVE_POLL
+ poll_fds = zalloc_or_die((size_t)address_count * sizeof(*poll_fds));
#endif
+ order_addresses(result, attempts, address_count);
+ for (i = 0; i < address_count; i++)
+ {
+ attempts[i].fd = JB_INVALID_SOCKET;
+ }
- if (block_acl(csp, dst))
- {
- socket_error = errno = EPERM;
- continue;
- }
-#endif /* def FEATURE_ACL */
-
- retval = getnameinfo(rp->ai_addr, rp->ai_addrlen,
- csp->http->host_ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
- if (retval)
+ while ((fd == JB_INVALID_SOCKET)
+ && ((pending_count > 0) || (attempt_count < address_count)))
+ {
+ /*
+ * Start the next attempt if there's nothing else to wait for,
+ * a previous attempt just failed or the connect-attempt-delay
+ * expired since the last attempt was started.
+ */
+ if ((attempt_count < address_count)
+ && (start_next_attempt || (pending_count == 0)
+ || ((connect_attempt_delay > 0)
+ && (msecs_since(&last_attempt->start_time)
+ >= connect_attempt_delay))))
{
- log_error(LOG_LEVEL_ERROR,
- "Failed to get the host name from the socket structure: %s",
- gai_strerror(retval));
- continue;
- }
+ attempt = &attempts[attempt_count++];
+ last_attempt = attempt;
+ start_next_attempt = 0;
- fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
-#ifdef _WIN32
- if (fd == JB_INVALID_SOCKET)
-#else
- if (fd < 0)
-#endif
- {
+ switch (start_connection_attempt(csp, attempt, &socket_error))
+ {
+ case CONNECT_ATTEMPT_CONNECTED:
+ fd = attempt->fd;
+ winner = attempt;
+ break;
+ case CONNECT_ATTEMPT_PENDING:
+ if (pending_count > 0)
+ {
+ log_error(LOG_LEVEL_CONNECT,
+ "Connecting to %s[%s]:%s while %d earlier "
+ "connection attempt(s) are still pending.",
+ host, attempt->ip_addr_str, service, pending_count);
+ }
+ attempt->pending = 1;
+ pending_count++;
+ break;
+ case CONNECT_ATTEMPT_FAILED:
+ default:
+ failed_attempt = attempt;
+ if ((pending_count > 0) || (attempt_count < address_count))
+ {
+ /*
+ * Log this now as we'll try another address next.
+ * If the last address fails, too, it will get logged
+ * outside the loop body.
+ */
+ log_error(LOG_LEVEL_CONNECT,
+ "Could not connect to %s[%s]:%s: %s.",
+ host, attempt->ip_addr_str, service,
+ socket_strerror(socket_error,
+ error_buffer, sizeof(error_buffer)));
+ }
+ start_next_attempt = 1;
+ break;
+ }
continue;
}
-#ifndef HAVE_POLL
-#ifndef _WIN32
- if (fd >= FD_SETSIZE)
- {
- log_error(LOG_LEVEL_ERROR,
- "Server socket number too high to use select(): %d >= %d",
- fd, FD_SETSIZE);
- close_socket(fd);
- freeaddrinfo(result);
- return JB_INVALID_SOCKET;
- }
-#endif
-#endif
-
-#ifdef FEATURE_EXTERNAL_FILTERS
- mark_socket_for_close_on_execute(fd);
-#endif
-
- set_no_delay_flag(fd);
-
-#if !defined(_WIN32) && !defined(__BEOS__)
- if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
- {
- flags |= O_NDELAY;
- fcntl(fd, F_SETFL, flags);
- }
-#endif /* !defined(_WIN32) && !defined(__BEOS__) */
-
- connect_failed = 0;
- while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET)
+ /*
+ * Wait for the pending attempts until one of them completes,
+ * the oldest one times out or it's time to start another one.
+ */
+ timeout_msecs = CONNECT_TIMEOUT_MSECS;
+ for (i = 0; i < attempt_count; i++)
{
-#ifdef _WIN32
- if (errno == WSAEINPROGRESS)
-#else /* ifndef _WIN32 */
- if (errno == EINPROGRESS)
-#endif /* ndef _WIN32 */
+ if (attempts[i].pending)
{
- break;
+ remaining_msecs = CONNECT_TIMEOUT_MSECS
+ - msecs_since(&attempts[i].start_time);
+ if (remaining_msecs < timeout_msecs)
+ {
+ timeout_msecs = remaining_msecs;
+ }
}
-
- if (errno != EINTR)
+ }
+ if ((connect_attempt_delay > 0) && (attempt_count < address_count))
+ {
+ remaining_msecs = connect_attempt_delay
+ - msecs_since(&last_attempt->start_time);
+ if (remaining_msecs < timeout_msecs)
{
- socket_error = errno;
- close_socket(fd);
- connect_failed = 1;
- break;
+ timeout_msecs = remaining_msecs;
}
}
- if (connect_failed)
+ if (timeout_msecs < 0)
{
- continue;
+ timeout_msecs = 0;
}
-#if !defined(_WIN32) && !defined(__BEOS__)
- if (flags != -1)
+ retval = wait_for_connection_attempts(attempts, attempt_count,
+ (int)timeout_msecs, poll_fds);
+ if (retval < 0)
{
- flags &= ~O_NDELAY;
- fcntl(fd, F_SETFL, flags);
+ socket_error = get_socket_error();
+ if (socket_error == EINTR)
+ {
+ continue;
+ }
+ log_error(LOG_LEVEL_ERROR, "Waiting for the connection "
+ "attempts to %s to complete failed: %E", host);
+ break;
}
-#endif /* !defined(_WIN32) && !defined(__BEOS__) */
-
-#ifdef HAVE_POLL
- poll_fd[0].fd = fd;
- poll_fd[0].events = POLLOUT;
- retval = poll(poll_fd, 1, 30000);
- if (retval == 0)
+ /* Check which of the pending attempts completed or timed out */
+ for (i = 0; i < attempt_count; i++)
{
- if (rp->ai_next != NULL)
- {
- /* Log this now as we'll try another address next */
- log_error(LOG_LEVEL_CONNECT,
- "Could not connect to [%s]:%s: Operation timed out.",
- csp->http->host_ip_addr_str, service);
- }
- else
+ attempt = &attempts[i];
+ if (!attempt->pending)
{
- /*
- * This is the last address, don't log this now
- * as it would result in a duplicated log message.
- */
- socket_error = ETIMEDOUT;
+ continue;
}
- }
- else if (retval > 0)
-#else
- /* wait for connection to complete */
- FD_ZERO(&wfds);
- FD_SET(fd, &wfds);
-
- memset(&timeout, 0, sizeof(timeout));
- timeout.tv_sec = 30;
- /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Weird! */
- if ((select((int)fd + 1, NULL, &wfds, NULL, &timeout) > 0)
- && FD_ISSET(fd, &wfds))
-#endif
- {
- socklen_t optlen = sizeof(socket_error);
- if (!getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error, &optlen))
+ if (attempt->ready)
{
- if (!socket_error)
+ int connection_error = 0;
+ socklen_t optlen = sizeof(connection_error);
+
+ if (getsockopt(attempt->fd, SOL_SOCKET, SO_ERROR,
+ (char *)&connection_error, &optlen))
{
- /* Connection established, no need to try other addresses. */
- break;
+ connection_error = get_socket_error();
+ log_error(LOG_LEVEL_ERROR, "Could not get the state of "
+ "the connection to %s[%s]:%s: %s; dropping connection.",
+ host, attempt->ip_addr_str, service,
+ socket_strerror(connection_error,
+ error_buffer, sizeof(error_buffer)));
}
- if (rp->ai_next != NULL)
+ if (!connection_error)
{
- /*
- * There's another address we can try, so log that this
- * one didn't work out. If the last one fails, too,
- * it will get logged outside the loop body so we don't
- * have to mention it here.
- */
- log_error(LOG_LEVEL_CONNECT, "Could not connect to [%s]:%s: %s.",
- csp->http->host_ip_addr_str, service, strerror(socket_error));
+ /* Connection established, no need to wait for the others. */
+ fd = attempt->fd;
+ winner = attempt;
+ break;
}
+ socket_error = connection_error;
+ }
+ else if (msecs_since(&attempt->start_time) >= CONNECT_TIMEOUT_MSECS)
+ {
+#ifdef _WIN32
+ socket_error = WSAETIMEDOUT;
+#else
+ socket_error = ETIMEDOUT;
+#endif
}
else
{
- socket_error = errno;
- log_error(LOG_LEVEL_ERROR, "Could not get the state of "
- "the connection to [%s]:%s: %s; dropping connection.",
- csp->http->host_ip_addr_str, service, strerror(errno));
+ /* Still pending */
+ continue;
}
- }
+ failed_attempt = attempt;
- /* Connection failed, try next address */
- close_socket(fd);
+ if ((pending_count > 1) || (attempt_count < address_count))
+ {
+ /*
+ * There's another address we can try, so log that this
+ * one didn't work out. If the last one fails, too,
+ * it will get logged outside the loop body so we don't
+ * have to mention it here.
+ */
+ log_error(LOG_LEVEL_CONNECT, "Could not connect to %s[%s]:%s: %s.",
+ host, attempt->ip_addr_str, service,
+ socket_strerror(socket_error, error_buffer, sizeof(error_buffer)));
+ }
+ close_socket(attempt->fd);
+ attempt->fd = JB_INVALID_SOCKET;
+ attempt->pending = 0;
+ pending_count--;
+ start_next_attempt = 1;
+ }
}
+ /* Abort the attempts that didn't win. */
+ for (i = 0; i < attempt_count; i++)
+ {
+ if ((attempts[i].fd != JB_INVALID_SOCKET) && (attempts[i].fd != fd))
+ {
+ log_error(LOG_LEVEL_CONNECT,
+ "Aborting the connection attempt to %s[%s]:%s.",
+ host, attempts[i].ip_addr_str, service);
+ close_socket(attempts[i].fd);
+ }
+ }
freeaddrinfo(result);
- if (!rp)
+ freez(poll_fds);
+
+ if (winner == NULL)
{
- log_error(LOG_LEVEL_CONNECT, "Could not connect to [%s]:%s: %s.",
- host, service, strerror(socket_error));
- csp->error_message = strdup(strerror(socket_error));
+ if (failed_attempt != NULL)
+ {
+ strlcpy(csp->http->host_ip_addr_str,
+ failed_attempt->ip_addr_str, NI_MAXHOST);
+ }
+ freez(attempts);
+ log_error(LOG_LEVEL_CONNECT, "Could not connect to %s[%s]:%s: %s.",
+ host, csp->http->host_ip_addr_str, service,
+ socket_strerror(socket_error, error_buffer, sizeof(error_buffer)));
+ csp->error_message = strdup(socket_strerror(socket_error,
+ error_buffer, sizeof(error_buffer)));
return(JB_INVALID_SOCKET);
}
+
+ set_socket_blocking_mode(winner, TRUE);
+ strlcpy(csp->http->host_ip_addr_str, winner->ip_addr_str, NI_MAXHOST);
+ freez(attempts);
+
log_error(LOG_LEVEL_CONNECT, "Connected to %s[%s]:%s.",
host, csp->http->host_ip_addr_str, service);
diff --git a/loadcfg.c b/loadcfg.c
index 6b86854f..791f9259 100644
--- a/loadcfg.c
+++ b/loadcfg.c
@@ -98,6 +98,14 @@
*/
#define DEFAULT_LISTEN_BACKLOG 128
+/*
+ * Default number of milliseconds to wait before starting
+ * a connection attempt to the next address of a host while
+ * previous attempts are still pending. The value is the one
+ * recommended by RFC 8305 (Happy Eyeballs Version 2).
+ */
+#define DEFAULT_CONNECT_ATTEMPT_DELAY 250
+
#ifdef FEATURE_TOGGLE
/* Privoxy is enabled by default. */
int global_toggle_state = 1;
@@ -143,6 +151,7 @@ static struct file_list *current_configfile = NULL;
#define hash_client_tag_lifetime 3239141416U /* "client-tag-lifetime" */
#define hash_compression_level 2464423563U /* "compression-level" */
#define hash_confdir 1978389U /* "confdir" */
+#define hash_connect_attempt_delay 2712638590U /* "connect-attempt-delay" */
#define hash_connection_sharing 1348841265U /* "connection-sharing" */
#define hash_cors_allowed_origin 2769345637U /* "cors-allowed-origin" */
#define hash_debug 78263U /* "debug" */
@@ -759,6 +768,7 @@ struct configuration_spec * load_config(void)
*/
config->max_client_connections = 128;
config->socket_timeout = 300; /* XXX: Should be a macro. */
+ config->connect_attempt_delay = DEFAULT_CONNECT_ATTEMPT_DELAY;
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
config->default_server_timeout = 0;
config->keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
@@ -1000,6 +1010,24 @@ struct configuration_spec * load_config(void)
}
#endif
+/* *************************************************************************
+ * connect-attempt-delay number_of_milliseconds
+ * *************************************************************************/
+ case hash_connect_attempt_delay :
+ {
+ int connect_attempt_delay = parse_numeric_value(cmd, arg);
+ if (0 <= connect_attempt_delay)
+ {
+ config->connect_attempt_delay = connect_attempt_delay;
+ }
+ else
+ {
+ log_error(LOG_LEVEL_FATAL,
+ "Invalid connect-attempt-delay: '%s'", arg);
+ }
+ break;
+ }
+
/* *************************************************************************
* connection-sharing (0|1)
* *************************************************************************/
diff --git a/project.h b/project.h
index 53209caf..ea12e486 100644
--- a/project.h
+++ b/project.h
@@ -1582,6 +1582,14 @@ struct configuration_spec
/* Timeout when waiting on sockets for data to become available. */
int socket_timeout;
+ /*
+ * Number of milliseconds to wait before starting a connection
+ * attempt to the next address of a host while previous attempts
+ * are still pending (Happy Eyeballs, RFC 8305). 0 disables
+ * parallel connection attempts.
+ */
+ int connect_attempt_delay;
+
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
/* Maximum number of seconds after which an open connection will no longer be reused. */
unsigned int keep_alive_timeout;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:48 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:48 +0200
Subject: [Privoxy-commits] [privoxy] 22/26: p-config.sgml: Document the
connect-attempt-delay directive
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070135.8BE97101E4@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 188845f1a06cc42d88b63a8cd7247080ed68f741
Author: Rustam Abdullaev
AuthorDate: Sat Sep 19 12:35:46 2026 +0200
p-config.sgml: Document the connect-attempt-delay directive
SF patch #151.
---
doc/source/p-config.sgml | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/doc/source/p-config.sgml b/doc/source/p-config.sgml
index 366cfefa..16963025 100644
--- a/doc/source/p-config.sgml
+++ b/doc/source/p-config.sgml
@@ -3910,6 +3910,92 @@ compression-level 0
+connect-attempt-delay
+
+
+ Specifies:
+
+
+ Number of milliseconds to wait before starting a connection attempt
+ to the next address of a host while previous attempts are still
+ pending.
+
+
+
+
+ Type of value:
+
+
+ Time in milliseconds.
+
+
+
+
+ Default value:
+
+ 250
+
+
+
+ Effect if unset:
+
+
+ A default value of 250 milliseconds is used.
+
+
+
+
+ Notes:
+
+
+ If a host resolves to multiple addresses, Privoxy
+ tries to connect to them following the Happy Eyeballs
+ algorithm described in RFC 8305: the addresses are sorted so that
+ address families alternate, the first connection attempt is started
+ right away and additional attempts are started in parallel whenever
+ a previous attempt fails or the connect-attempt-delay
+ expires. The first attempt to succeed wins, the other ones are aborted.
+
+
+ This limits the delay caused by unreachable addresses, for example
+ when a host has an IPv6 address but the system only has working
+ IPv4 connectivity, to the configured value instead of the connection
+ timeout.
+
+
+ RFC 8305 recommends a value between 100 and 2000 milliseconds.
+ Setting the value to 0 disables parallel connection attempts, so that
+ the addresses are tried one after the other with the next attempt
+ only being started after the previous one failed.
+
+
+ Note that the addresses are resolved with a single synchronous
+ lookup, the Resolution Delay
described in RFC 8305
+ doesn't apply. The first attempt is made to the first address
+ returned by the resolver, whichever family it belongs to, followed
+ by an address of the other family.
+
+
+ This directive has no effect if Privoxy
+ has been compiled without getaddrinfo() support. On platforms where
+ the connection attempts can't be made non-blocking the addresses are
+ tried one after the other regardless of this setting.
+
+
+
+
+ Example:
+
+
+ # Give the first address a full second before trying the next one
+ connect-attempt-delay 1000
+
+
+
+
+@@connect-attempt-delay 250]]>
+
+
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:49 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:49 +0200
Subject: [Privoxy-commits] [privoxy] 23/26: Bump SMGL entities for 4.3.0
UNRELEASED (again)
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070135.CA54210166@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 1c9941b7ea0845aeccad98d8b7104ce20739b04d
Author: Fabian Keil
AuthorDate: Sat Oct 10 07:56:07 2026 +0200
Bump SMGL entities for 4.3.0 UNRELEASED (again)
---
doc/source/faq.sgml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/doc/source/faq.sgml b/doc/source/faq.sgml
index 106af3dc..3beb407a 100644
--- a/doc/source/faq.sgml
+++ b/doc/source/faq.sgml
@@ -9,10 +9,10 @@
-
-
-
-
+
+
+
+
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:50 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:50 +0200
Subject: [Privoxy-commits] [privoxy] 24/26: Regenerate FAQ
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070136.2E578101E6@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit af37f38b6250e256bb309d3924aed867e6f532ef
Author: Fabian Keil
AuthorDate: Sat Oct 10 07:57:17 2026 +0200
Regenerate FAQ
---
doc/webserver/faq/index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/webserver/faq/index.html b/doc/webserver/faq/index.html
index 710d1360..d8c26c23 100644
--- a/doc/webserver/faq/index.html
+++ b/doc/webserver/faq/index.html
@@ -38,7 +38,7 @@
Please note that this document is a work in progress. This copy represents the state at the release of
- version 4.2.0. You can find the latest version of the document at https://www.privoxy.org/faq/. Please see the Contact section if
you want to contact the developers.
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:52 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:52 +0200
Subject: [Privoxy-commits] [privoxy] 26/26: Regenerate config file
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070136.D5BE1101E8@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 08593d415b661a676ce95c05934f8929f426e957
Author: Fabian Keil
AuthorDate: Sat Oct 10 08:28:22 2026 +0200
Regenerate config file
... with the recently added connect-attempt-delay section.
---
config | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/config b/config
index 034a4cc6..a90ff280 100644
--- a/config
+++ b/config
@@ -2444,6 +2444,66 @@ socket-timeout 300
# receive-buffer-size 32768
#
#
+# 6.20. connect-attempt-delay
+# ============================
+#
+# Specifies:
+#
+# Number of milliseconds to wait before starting a connection
+# attempt to the next address of a host while previous attempts
+# are still pending.
+#
+# Type of value:
+#
+# Time in milliseconds.
+#
+# Default value:
+#
+# 250
+#
+# Effect if unset:
+#
+# A default value of 250 milliseconds is used.
+#
+# Notes:
+#
+# If a host resolves to multiple addresses, Privoxy tries to
+# connect to them following the "Happy Eyeballs" algorithm
+# described in RFC 8305: the addresses are sorted so that
+# address families alternate, the first connection attempt is
+# started right away and additional attempts are started in
+# parallel whenever a previous attempt fails or the
+# connect-attempt-delay expires. The first attempt to succeed
+# wins, the other ones are aborted.
+#
+# This limits the delay caused by unreachable addresses, for
+# example when a host has an IPv6 address but the system only
+# has working IPv4 connectivity, to the configured value instead
+# of the connection timeout.
+#
+# RFC 8305 recommends a value between 100 and 2000 milliseconds.
+# Setting the value to 0 disables parallel connection attempts,
+# so that the addresses are tried one after the other with the
+# next attempt only being started after the previous one failed.
+#
+# Note that the addresses are resolved with a single synchronous
+# lookup, the "Resolution Delay" described in RFC 8305 doesn't
+# apply. The first attempt is made to the first address returned
+# by the resolver, whichever family it belongs to, followed by
+# an address of the other family.
+#
+# This directive has no effect if Privoxy has been compiled
+# without getaddrinfo() support. On platforms where the
+# connection attempts can't be made non-blocking the addresses
+# are tried one after the other regardless of this setting.
+#
+# Example:
+#
+# # Give the first address a full second before trying the next one
+# connect-attempt-delay 1000
+#
+connect-attempt-delay 250
+#
# 7. HTTPS INSPECTION
# ====================
#
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
From git at git.privoxy.org Sat Oct 10 09:01:51 2026
From: git at git.privoxy.org (User Git)
Date: Sat, 10 Oct 2026 09:01:51 +0200
Subject: [Privoxy-commits] [privoxy] 25/26: Regenerate user manual
In-Reply-To: <179161568668.32820.2707145156772435049@privoxy-git>
References: <179161568668.32820.2707145156772435049@privoxy-git>
Message-ID: <20261010070136.976AE101E7@git.privoxy.org>
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 1672f79e6fc22a52c50acd13b55899581646bd07
Author: Fabian Keil
AuthorDate: Sat Oct 10 07:57:27 2026 +0200
Regenerate user manual
---
doc/webserver/user-manual/appendix.html | 16 ++++-----
doc/webserver/user-manual/config.html | 58 ++++++++++++++++++++++++++++++
doc/webserver/user-manual/filter-file.html | 15 +++++++-
doc/webserver/user-manual/index.html | 1 +
4 files changed, 81 insertions(+), 9 deletions(-)
diff --git a/doc/webserver/user-manual/appendix.html b/doc/webserver/user-manual/appendix.html
index a6768127..f21d908c 100644
--- a/doc/webserver/user-manual/appendix.html
+++ b/doc/webserver/user-manual/appendix.html
@@ -202,7 +202,7 @@
these. If not, you will get a friendly error message. Internet access is not necessary either.
-
-
Privoxy main page:
+ Privoxy main page:
http://config.privoxy.org/
@@ -211,7 +211,7 @@
"APPLICATION">Privoxy)
-
-
View and toggle client tags:
+ View and toggle client tags:
http://config.privoxy.org/client-tags
@@ -219,21 +219,21 @@
-
Show information about the current configuration, including viewing and editing of actions
- files:
+ files:
http://config.privoxy.org/show-status
-
-
Show the browser's request headers:
+ Show the browser's request headers:
http://config.privoxy.org/show-request
-
-
Show which actions apply to a URL and why:
+ Show which actions apply to a URL and why:
http://config.privoxy.org/show-url-info
@@ -242,15 +242,15 @@
-
Toggle Privoxy on or off. This feature can be turned off/on in the main config
file. When toggled "off", "Privoxy" continues to run,
- but only as a pass-through proxy, with no actions taking place:
+ but only as a pass-through proxy, with no actions taking place:
http://config.privoxy.org/toggle
- Short cuts. Turn off, then on:
+ Short cuts. Turn off, then on:
http://config.privoxy.org/toggle?set=disable
-
+
http://config.privoxy.org/toggle?set=enable
diff --git a/doc/webserver/user-manual/config.html b/doc/webserver/user-manual/config.html
index 5f142e8b..1ecd8a1e 100644
--- a/doc/webserver/user-manual/config.html
+++ b/doc/webserver/user-manual/config.html
@@ -2392,6 +2392,64 @@
+
+
+
+
+ - Specifies:
+ -
+
Number of milliseconds to wait before starting a connection attempt to the next address of a host
+ while previous attempts are still pending.
+
+ - Type of value:
+ -
+
Time in milliseconds.
+
+ - Default value:
+ -
+
250
+
+ - Effect if unset:
+ -
+
A default value of 250 milliseconds is used.
+
+ - Notes:
+ -
+
If a host resolves to multiple addresses, Privoxy tries to connect to
+ them following the "Happy Eyeballs" algorithm described in RFC 8305: the
+ addresses are sorted so that address families alternate, the first connection attempt is started right
+ away and additional attempts are started in parallel whenever a previous attempt fails or the connect-attempt-delay expires. The first attempt to succeed wins, the other ones are
+ aborted.
+ This limits the delay caused by unreachable addresses, for example when a host has an IPv6 address but
+ the system only has working IPv4 connectivity, to the configured value instead of the connection
+ timeout.
+ RFC 8305 recommends a value between 100 and 2000 milliseconds. Setting the value to 0 disables
+ parallel connection attempts, so that the addresses are tried one after the other with the next attempt
+ only being started after the previous one failed.
+ Note that the addresses are resolved with a single synchronous lookup, the "Resolution Delay" described in RFC 8305 doesn't apply. The first attempt is made to the
+ first address returned by the resolver, whichever family it belongs to, followed by an address of the
+ other family.
+ This directive has no effect if Privoxy has been compiled without
+ getaddrinfo() support. On platforms where the connection attempts can't be made non-blocking the
+ addresses are tried one after the other regardless of this setting.
+
+ - Example:
+ -
+
+
+
+ # Give the first address a full second before trying the next one
+ connect-attempt-delay 1000
+ |
+
+
+
+
+
+