diff -u -r -N squid-4.0.13/cfgaux/ltmain.sh squid-4.0.14/cfgaux/ltmain.sh --- squid-4.0.13/cfgaux/ltmain.sh 2016-08-06 00:53:58.000000000 +1200 +++ squid-4.0.14/cfgaux/ltmain.sh 2016-09-09 02:13:25.000000000 +1200 @@ -31,7 +31,7 @@ PROGRAM=libtool PACKAGE=libtool -VERSION="2.4.6 Debian-2.4.6-1" +VERSION="2.4.6 Debian-2.4.6-2" package_revision=2.4.6 @@ -1977,7 +1977,7 @@ # End: # Set a version string. -scriptversion='(GNU libtool) 2.4.6 Debian-2.4.6-1' +scriptversion='(GNU libtool) 2.4.6' # func_echo ARG... @@ -2068,7 +2068,7 @@ compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) - version: $progname $scriptversion + version: $progname $scriptversion Debian-2.4.6-2 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` diff -u -r -N squid-4.0.13/ChangeLog squid-4.0.14/ChangeLog --- squid-4.0.13/ChangeLog 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/ChangeLog 2016-09-09 02:12:03.000000000 +1200 @@ -1,3 +1,20 @@ +Changes to squid-4.0.14 (08 Sep 2016): + + - Regression Bug 4570: crash after rev.14755 + - Regression Bug 4561: Replace use of default move operators with explicit implementation + - Bug 4503: Do not access-log SslBump-faked CONNECTs with _ABORTED suffixes + - Bug 4404: Do not access-log chunked non-persistent responses with _ABORTED suffix + - Fix crashes on shutdown while cleaning up idle ICAP connections + - Fix logformat unable to configure codes with /-escape + - HTTP: MUST respond with 414 (URI Too Long) when request-target exceeds limits + - HTTP: validate Content-Length header values + - Make Squid death due to overloaded helpers optional + - Better support for unknown URL schemes + - Do not log error:transaction-end-before-headers after invalid requests + - ... and many portability and build fixes + - ... and some documentation updates + - ... and all fixes from 3.5.20 + Changes to squid-4.0.13 (05 Aug 2016): - Regression Bug 4540: revert r14720 buffer update @@ -206,6 +223,19 @@ - ... and many documentation changes - ... and much code cleanup and polishing +Changes to squid-3.5.21 (08 Sep 2016): + + - Bug 4563: duplicate code in httpMakeVaryMark + - Bug 4542: authentication credentials IP TTL updated incorrectly + - Bug 4534: assertion failure in xcalloc when using many cache_dir + - Bug 4428: mal-formed Cache-Control:stale-if-error header + - Bug 3025: Proxy-Authenticate problem using ICAP server + - Fix segfault via Ftp::Client::readControlReply() + - Fix SSL-Bump failure results in SEGFAULT + - HTTP/1.1: MUST always revalidate Cache-Control:no-cache responses + - HTTP/1.1: do not allow Proxy-Connection to override Connection header + - SSL: CN wildcard must only match a single domain component [fragment] + Changes to squid-3.5.20 (01 Jul 2016): - Bug 4523: smblib compile fails on NetBSD diff -u -r -N squid-4.0.13/configure squid-4.0.14/configure --- squid-4.0.13/configure 2016-08-06 00:55:28.000000000 +1200 +++ squid-4.0.14/configure 2016-09-09 02:15:20.000000000 +1200 @@ -1,7 +1,7 @@ #! /bin/sh # From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.0.13. +# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.0.14. # # Report bugs to . # @@ -595,8 +595,8 @@ # Identity of this package. PACKAGE_NAME='Squid Web Proxy' PACKAGE_TARNAME='squid' -PACKAGE_VERSION='4.0.13' -PACKAGE_STRING='Squid Web Proxy 4.0.13' +PACKAGE_VERSION='4.0.14' +PACKAGE_STRING='Squid Web Proxy 4.0.14' PACKAGE_BUGREPORT='http://bugs.squid-cache.org/' PACKAGE_URL='' @@ -1648,7 +1648,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures Squid Web Proxy 4.0.13 to adapt to many kinds of systems. +\`configure' configures Squid Web Proxy 4.0.14 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1719,7 +1719,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Squid Web Proxy 4.0.13:";; + short | recursive ) echo "Configuration of Squid Web Proxy 4.0.14:";; esac cat <<\_ACEOF @@ -2148,7 +2148,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Squid Web Proxy configure 4.0.13 +Squid Web Proxy configure 4.0.14 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -3252,7 +3252,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Squid Web Proxy $as_me 4.0.13, which was +It was created by Squid Web Proxy $as_me 4.0.14, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4119,7 +4119,7 @@ # Define the identity of the package. PACKAGE='squid' - VERSION='4.0.13' + VERSION='4.0.14' cat >>confdefs.h <<_ACEOF @@ -42599,7 +42599,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by Squid Web Proxy $as_me 4.0.13, which was +This file was extended by Squid Web Proxy $as_me 4.0.14, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -42665,7 +42665,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -Squid Web Proxy config.status 4.0.13 +Squid Web Proxy config.status 4.0.14 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -u -r -N squid-4.0.13/configure.ac squid-4.0.14/configure.ac --- squid-4.0.13/configure.ac 2016-08-06 00:55:28.000000000 +1200 +++ squid-4.0.14/configure.ac 2016-09-09 02:15:20.000000000 +1200 @@ -5,7 +5,7 @@ ## Please see the COPYING and CONTRIBUTORS files for details. ## -AC_INIT([Squid Web Proxy],[4.0.13],[http://bugs.squid-cache.org/],[squid]) +AC_INIT([Squid Web Proxy],[4.0.14],[http://bugs.squid-cache.org/],[squid]) AC_PREREQ(2.61) AC_CONFIG_HEADERS([include/autoconf.h]) AC_CONFIG_AUX_DIR(cfgaux) diff -u -r -N squid-4.0.13/doc/debug-sections.txt squid-4.0.14/doc/debug-sections.txt --- squid-4.0.13/doc/debug-sections.txt 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/doc/debug-sections.txt 2016-09-09 02:12:03.000000000 +1200 @@ -140,6 +140,7 @@ section 83 SSL accelerator support section 83 SSL-Bump Server/Peer negotiation section 83 TLS Server/Peer negotiation +section 83 TLS session management section 84 Helper process maintenance section 85 Client-side Request Routines section 86 ESI Expressions diff -u -r -N squid-4.0.13/doc/release-notes/release-4.html squid-4.0.14/doc/release-notes/release-4.html --- squid-4.0.13/doc/release-notes/release-4.html 2016-08-06 02:24:35.000000000 +1200 +++ squid-4.0.14/doc/release-notes/release-4.html 2016-09-09 03:30:00.000000000 +1200 @@ -2,10 +2,10 @@ - Squid 4.0.13 release notes + Squid 4.0.14 release notes -

Squid 4.0.13 release notes

+

Squid 4.0.14 release notes

Squid Developers


@@ -61,7 +61,7 @@

1. Notice

-

The Squid Team are pleased to announce the release of Squid-4.0.13 for testing.

+

The Squid Team are pleased to announce the release of Squid-4.0.14 for testing.

This new release is available for download from http://www.squid-cache.org/Versions/v4/ or the mirrors.

@@ -313,10 +313,15 @@
acl

New -m flag for note ACL to match substrings.

+

New connections_encrypted type for matching transactions +where all HTTP messages were received over TLS transport connections, +including messages received from ICAP servers.

auth_param

New parameter queue-size= to set the maximum number of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

cache_peer

New option auth-no-keytab to let GSSAPI implementation determine @@ -336,19 +341,20 @@

external_acl_type

New parameter queue-size= to set the maximum number of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

Format field updated to accept any logformat %macro code.

http_port

New option tls-min-version=1.N to set minimum TLS version allowed.

-

New option tls-default-ca replaces sslflags=NO_DEFAULT_CA

+

New option tls-default-ca replaces sslflags=NO_DEFAULT_CA, +the default is also changed to OFF.

New option tls-no-npn to disable sending TLS NPN extension.

All option= values for SSLv2 configuration or disabling have been removed.

Removed version= option. Use tls-options= instead.

Manual squid.conf update may be required on upgrade.

Replaced cafile= with tls-cafile= which takes multiple entries.

-

New option tls-default-ca replaces sslflags=NO_DEFAULT_CA, -the default is also changed to OFF.

https_port

New option tls-min-version=1.N to set minimum TLS version allowed.

@@ -413,14 +419,26 @@
sslcrtd_children

New parameter queue-size= to set the maximum number of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

sslcrtvalidator_children

New parameter queue-size= to set the maximum number of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

+ +
store_id_children
+

New parameter queue-size= to set the maximum number +of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

url_rewrite_children

New parameter queue-size= to set the maximum number of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

diff -u -r -N squid-4.0.13/include/version.h squid-4.0.14/include/version.h --- squid-4.0.13/include/version.h 2016-08-06 00:55:28.000000000 +1200 +++ squid-4.0.14/include/version.h 2016-09-09 02:15:21.000000000 +1200 @@ -7,7 +7,7 @@ */ #ifndef SQUID_RELEASE_TIME -#define SQUID_RELEASE_TIME 1470401568 +#define SQUID_RELEASE_TIME 1473343915 #endif /* diff -u -r -N squid-4.0.13/RELEASENOTES.html squid-4.0.14/RELEASENOTES.html --- squid-4.0.13/RELEASENOTES.html 2016-08-06 02:24:35.000000000 +1200 +++ squid-4.0.14/RELEASENOTES.html 2016-09-09 03:30:00.000000000 +1200 @@ -2,10 +2,10 @@ - Squid 4.0.13 release notes + Squid 4.0.14 release notes -

Squid 4.0.13 release notes

+

Squid 4.0.14 release notes

Squid Developers


@@ -61,7 +61,7 @@

1. Notice

-

The Squid Team are pleased to announce the release of Squid-4.0.13 for testing.

+

The Squid Team are pleased to announce the release of Squid-4.0.14 for testing.

This new release is available for download from http://www.squid-cache.org/Versions/v4/ or the mirrors.

@@ -313,10 +313,15 @@
acl

New -m flag for note ACL to match substrings.

+

New connections_encrypted type for matching transactions +where all HTTP messages were received over TLS transport connections, +including messages received from ICAP servers.

auth_param

New parameter queue-size= to set the maximum number of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

cache_peer

New option auth-no-keytab to let GSSAPI implementation determine @@ -336,19 +341,20 @@

external_acl_type

New parameter queue-size= to set the maximum number of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

Format field updated to accept any logformat %macro code.

http_port

New option tls-min-version=1.N to set minimum TLS version allowed.

-

New option tls-default-ca replaces sslflags=NO_DEFAULT_CA

+

New option tls-default-ca replaces sslflags=NO_DEFAULT_CA, +the default is also changed to OFF.

New option tls-no-npn to disable sending TLS NPN extension.

All option= values for SSLv2 configuration or disabling have been removed.

Removed version= option. Use tls-options= instead.

Manual squid.conf update may be required on upgrade.

Replaced cafile= with tls-cafile= which takes multiple entries.

-

New option tls-default-ca replaces sslflags=NO_DEFAULT_CA, -the default is also changed to OFF.

https_port

New option tls-min-version=1.N to set minimum TLS version allowed.

@@ -413,14 +419,26 @@
sslcrtd_children

New parameter queue-size= to set the maximum number of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

sslcrtvalidator_children

New parameter queue-size= to set the maximum number of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

+ +
store_id_children
+

New parameter queue-size= to set the maximum number +of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

url_rewrite_children

New parameter queue-size= to set the maximum number of queued requests.

+

New parameter on-persistent-overload= to set the action taken +when the helper queue is overloaded.

diff -u -r -N squid-4.0.13/src/acl/CertificateData.cc squid-4.0.14/src/acl/CertificateData.cc --- squid-4.0.13/src/acl/CertificateData.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/acl/CertificateData.cc 2016-09-09 02:12:03.000000000 +1200 @@ -96,11 +96,11 @@ char *newAttribute = ConfigParser::strtokFile(); if (!newAttribute) { - if (attributeIsOptional) - return; - - debugs(28, DBG_CRITICAL, "FATAL: required attribute argument missing"); - self_destruct(); + if (!attributeIsOptional) { + debugs(28, DBG_CRITICAL, "FATAL: required attribute argument missing"); + self_destruct(); + } + return; } // Handle the cases where we have optional -x type attributes @@ -119,6 +119,7 @@ if (!valid) { debugs(28, DBG_CRITICAL, "FATAL: Unknown option. Supported option(s) are: " << validAttributesStr); self_destruct(); + return; } /* an acl must use consistent attributes in all config lines */ @@ -126,6 +127,7 @@ if (strcasecmp(newAttribute, attribute) != 0) { debugs(28, DBG_CRITICAL, "FATAL: An acl must use consistent attributes in all config lines (" << newAttribute << "!=" << attribute << ")."); self_destruct(); + return; } } else { if (strcasecmp(newAttribute, "DN") != 0) { @@ -146,6 +148,7 @@ if (nid == 0) { debugs(28, DBG_CRITICAL, "FATAL: Not valid SSL certificate attribute name or numerical OID: " << newAttribute); self_destruct(); + return; } } attribute = xstrdup(newAttribute); diff -u -r -N squid-4.0.13/src/acl/external/delayer/ext_delayer_acl.8 squid-4.0.14/src/acl/external/delayer/ext_delayer_acl.8 --- squid-4.0.13/src/acl/external/delayer/ext_delayer_acl.8 2016-08-06 02:26:06.000000000 +1200 +++ squid-4.0.14/src/acl/external/delayer/ext_delayer_acl.8 2016-09-09 03:30:51.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "EXT_DELAYER_ACL 8" -.TH EXT_DELAYER_ACL 8 "2016-08-05" "perl v5.22.2" "User Contributed Perl Documentation" +.TH EXT_DELAYER_ACL 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.0.13/src/acl/external/SQL_session/ext_sql_session_acl.8 squid-4.0.14/src/acl/external/SQL_session/ext_sql_session_acl.8 --- squid-4.0.13/src/acl/external/SQL_session/ext_sql_session_acl.8 2016-08-06 02:26:22.000000000 +1200 +++ squid-4.0.14/src/acl/external/SQL_session/ext_sql_session_acl.8 2016-09-09 03:31:02.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "EXT_SQL_SESSION_ACL 8" -.TH EXT_SQL_SESSION_ACL 8 "2016-08-05" "perl v5.22.2" "User Contributed Perl Documentation" +.TH EXT_SQL_SESSION_ACL 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.0.13/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 squid-4.0.14/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 --- squid-4.0.13/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 2016-08-06 02:26:28.000000000 +1200 +++ squid-4.0.14/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 2016-09-09 03:31:06.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "EXT_WBINFO_GROUP_ACL 8" -.TH EXT_WBINFO_GROUP_ACL 8 "2016-08-05" "perl v5.22.2" "User Contributed Perl Documentation" +.TH EXT_WBINFO_GROUP_ACL 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.0.13/src/acl/Ip.cc squid-4.0.14/src/acl/Ip.cc --- squid-4.0.13/src/acl/Ip.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/acl/Ip.cc 2016-09-09 02:12:03.000000000 +1200 @@ -373,9 +373,9 @@ int errcode = getaddrinfo(addr1,NULL,&hints,&hp); if (hp == NULL) { + delete q; if (strcmp(addr1, "::1") == 0) { debugs(28, DBG_IMPORTANT, "aclIpParseIpData: IPv6 has not been enabled in host DNS resolver."); - delete q; } else { debugs(28, DBG_CRITICAL, "aclIpParseIpData: Bad host/IP: '" << addr1 << "' in '" << t << "', flags=" << hints.ai_flags << @@ -413,14 +413,14 @@ debugs(28, 3, "" << addr1 << " --> " << r->addr1 ); } + freeaddrinfo(hp); + if (*Q != NULL) { debugs(28, DBG_CRITICAL, "aclIpParseIpData: Bad host/IP: '" << t << "'"); self_destruct(); return NULL; } - freeaddrinfo(hp); - return q; } diff -u -r -N squid-4.0.13/src/acl/ServerName.cc squid-4.0.14/src/acl/ServerName.cc --- squid-4.0.13/src/acl/ServerName.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/acl/ServerName.cc 2016-09-09 02:12:03.000000000 +1200 @@ -31,7 +31,7 @@ const char *h = static_cast(a); const char *d = static_cast(b); debugs(28, 7, "Match:" << h << " <> " << d); - return matchDomainName(h, d, true); + return matchDomainName(h, d, mdnHonorWildcards); } bool diff -u -r -N squid-4.0.13/src/adaptation/ecap/XactionRep.cc squid-4.0.14/src/adaptation/ecap/XactionRep.cc --- squid-4.0.13/src/adaptation/ecap/XactionRep.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/adaptation/ecap/XactionRep.cc 2016-09-09 02:12:03.000000000 +1200 @@ -727,7 +727,7 @@ buf.append(" A?", 3); } - buf.appendf(" %s%u]", id.Prefix, id.value); + buf.appendf(" %s%u]", id.prefix(), id.value); buf.terminate(); diff -u -r -N squid-4.0.13/src/adaptation/icap/ServiceRep.cc squid-4.0.14/src/adaptation/icap/ServiceRep.cc --- squid-4.0.13/src/adaptation/icap/ServiceRep.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/adaptation/icap/ServiceRep.cc 2016-09-09 02:12:03.000000000 +1200 @@ -34,9 +34,6 @@ Adaptation::Icap::ServiceRep::ServiceRep(const ServiceConfigPointer &svcCfg): AsyncJob("Adaptation::Icap::ServiceRep"), Adaptation::Service(svcCfg), sslContext(NULL), -#if USE_OPENSSL - sslSession(NULL), -#endif theOptions(NULL), theOptionsFetcher(0), theLastUpdate(0), theBusyConns(0), theAllWaiters(0), diff -u -r -N squid-4.0.13/src/adaptation/icap/ServiceRep.h squid-4.0.14/src/adaptation/icap/ServiceRep.h --- squid-4.0.13/src/adaptation/icap/ServiceRep.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/adaptation/icap/ServiceRep.h 2016-09-09 02:12:03.000000000 +1200 @@ -111,9 +111,7 @@ virtual void noteAdaptationAnswer(const Answer &answer); Security::ContextPtr sslContext; -#if USE_OPENSSL - SSL_SESSION *sslSession; -#endif + Security::SessionStatePointer sslSession; private: // stores Prepare() callback info diff -u -r -N squid-4.0.13/src/adaptation/icap/Xaction.cc squid-4.0.14/src/adaptation/icap/Xaction.cc --- squid-4.0.13/src/adaptation/icap/Xaction.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/adaptation/icap/Xaction.cc 2016-09-09 02:12:03.000000000 +1200 @@ -59,10 +59,10 @@ AccessLogEntry::Pointer const &alp, const time_t timeout = 0): AsyncJob("Ssl::IcapPeerConnector"), - PeerConnector(aServerConn, aCallback, alp, timeout), icapService(service) {} + Security::PeerConnector(aServerConn, aCallback, alp, timeout), icapService(service) {} /* Security::PeerConnector API */ - virtual bool initializeTls(Security::SessionPointer &); + virtual bool initialize(Security::SessionPointer &); virtual void noteNegotiationDone(ErrorState *error); virtual Security::ContextPtr getSslContext() {return icapService->sslContext;} @@ -301,8 +301,8 @@ CloseDialer(this,&Adaptation::Icap::Xaction::noteCommClosed)); comm_add_close_handler(io.conn->fd, closer); - // If it is a reused connection and the SSL object is build - // we should not negotiate new SSL session + // If it is a reused connection and the TLS object is built + // we should not negotiate new TLS session const auto &ssl = fd_table[io.conn->fd].ssl; if (!ssl && service().cfg().secure.encryptTransport) { CbcPointer me(this); @@ -669,7 +669,7 @@ fillPendingStatus(buf); buf.append("/", 1); fillDoneStatus(buf); - buf.appendf(" %s%u]", id.Prefix, id.value); + buf.appendf(" %s%u]", id.prefix(), id.value); buf.terminate(); return buf.content(); @@ -705,27 +705,23 @@ } bool -Ssl::IcapPeerConnector::initializeTls(Security::SessionPointer &serverSession) +Ssl::IcapPeerConnector::initialize(Security::SessionPointer &serverSession) { - if (!Security::PeerConnector::initializeTls(serverSession)) + if (!Security::PeerConnector::initialize(serverSession)) return false; -#if USE_OPENSSL assert(!icapService->cfg().secure.sslDomain.isEmpty()); +#if USE_OPENSSL SBuf *host = new SBuf(icapService->cfg().secure.sslDomain); SSL_set_ex_data(serverSession.get(), ssl_ex_index_server, host); ACLFilledChecklist *check = static_cast(SSL_get_ex_data(serverSession.get(), ssl_ex_index_cert_error_check)); if (check) check->dst_peer_name = *host; +#endif - if (icapService->sslSession) - SSL_set_session(serverSession.get(), icapService->sslSession); - + Security::SetSessionResumeData(serverSession, icapService->sslSession); return true; -#else - return false; -#endif } void @@ -734,16 +730,8 @@ if (error) return; -#if USE_OPENSSL const int fd = serverConnection()->fd; - auto ssl = fd_table[fd].ssl.get(); - assert(ssl); - if (!SSL_session_reused(ssl)) { - if (icapService->sslSession) - SSL_SESSION_free(icapService->sslSession); - icapService->sslSession = SSL_get1_session(ssl); - } -#endif + Security::MaybeGetSessionResumeData(fd_table[fd].ssl, icapService->sslSession); } void @@ -764,13 +752,13 @@ if (answer.conn != NULL) answer.conn->close(); debugs(93, 2, typeName << - " SSL negotiation to " << service().cfg().uri << " failed"); + " TLS negotiation to " << service().cfg().uri << " failed"); service().noteConnectionFailed("failure"); detailError(ERR_DETAIL_ICAP_XACT_SSL_START); - throw TexcHere("cannot connect to the SSL ICAP service"); + throw TexcHere("cannot connect to the TLS ICAP service"); } - debugs(93, 5, "SSL negotiation to " << service().cfg().uri << " complete"); + debugs(93, 5, "TLS negotiation to " << service().cfg().uri << " complete"); service().noteConnectionUse(answer.conn); diff -u -r -N squid-4.0.13/src/anyp/UriScheme.cc squid-4.0.14/src/anyp/UriScheme.cc --- squid-4.0.13/src/anyp/UriScheme.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/anyp/UriScheme.cc 2016-09-09 02:12:03.000000000 +1200 @@ -11,22 +11,24 @@ #include "squid.h" #include "anyp/UriScheme.h" -char const * -AnyP::UriScheme::c_str() const +AnyP::UriScheme::UriScheme(AnyP::ProtocolType const aScheme, const char *img) : + theScheme_(aScheme) { - if (theScheme_ == AnyP::PROTO_UNKNOWN) - return "(unknown)"; + if (img) + // image could be provided explicitly (case-sensitive) + image_ = img; - static char out[BUFSIZ]; - int p = 0; + else if (theScheme_ == AnyP::PROTO_UNKNOWN) + // image could be actually unknown and not provided + image_ = "(unknown)"; - if (theScheme_ > AnyP::PROTO_NONE && theScheme_ < AnyP::PROTO_MAX) { - const char *in = AnyP::ProtocolType_str[theScheme_]; - for (; p < (BUFSIZ-1) && in[p] != '\0'; ++p) - out[p] = xtolower(in[p]); + else if (theScheme_ > AnyP::PROTO_NONE && theScheme_ < AnyP::PROTO_MAX) { + // image could be implied by a registered transfer protocol + // which use upper-case labels, so down-case for scheme image + image_ = AnyP::ProtocolType_str[theScheme_]; + image_.toLower(); } - out[p] = '\0'; - return out; + // else, image is an empty string ("://example.com/") } unsigned short diff -u -r -N squid-4.0.13/src/anyp/UriScheme.h squid-4.0.14/src/anyp/UriScheme.h --- squid-4.0.13/src/anyp/UriScheme.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/anyp/UriScheme.h 2016-09-09 02:12:03.000000000 +1200 @@ -10,6 +10,7 @@ #define SQUID_ANYP_URISCHEME_H #include "anyp/ProtocolType.h" +#include "sbuf/SBuf.h" #include @@ -23,27 +24,35 @@ { public: UriScheme() : theScheme_(AnyP::PROTO_NONE) {} - UriScheme(AnyP::ProtocolType const aScheme) : theScheme_(aScheme) {} + UriScheme(AnyP::ProtocolType const aScheme, const char *img = nullptr); + UriScheme(const AnyP::UriScheme &o) : theScheme_(o.theScheme_), image_(o.image_) {} + UriScheme(AnyP::UriScheme &&) = default; ~UriScheme() {} - operator AnyP::ProtocolType() const { return theScheme_; } + AnyP::UriScheme& operator=(const AnyP::UriScheme &o) { + theScheme_ = o.theScheme_; + image_ = o.image_; + return *this; + } + AnyP::UriScheme& operator=(AnyP::UriScheme &&) = default; + operator AnyP::ProtocolType() const { return theScheme_; } + // XXX: does not account for comparison of unknown schemes (by image) bool operator != (AnyP::ProtocolType const & aProtocol) const { return theScheme_ != aProtocol; } /** Get a char string representation of the scheme. - * Does not include the ':' or '://" terminators. - * - * An upper bound length of BUFSIZ bytes converted. Remainder will be truncated. - * The result of this call will remain usable only until any subsequest call - * and must be copied if persistence is needed. + * Does not include the ':' or "://" terminators. */ - char const *c_str() const; + SBuf image() const {return image_;} unsigned short defaultPort() const; private: /// This is a typecode pointer into the enum/registry of protocols handled. AnyP::ProtocolType theScheme_; + + /// the string representation + SBuf image_; }; } // namespace AnyP @@ -51,7 +60,7 @@ inline std::ostream & operator << (std::ostream &os, AnyP::UriScheme const &scheme) { - os << scheme.c_str(); + os << scheme.image(); return os; } diff -u -r -N squid-4.0.13/src/auth/basic/DB/basic_db_auth.8 squid-4.0.14/src/auth/basic/DB/basic_db_auth.8 --- squid-4.0.13/src/auth/basic/DB/basic_db_auth.8 2016-08-06 02:27:20.000000000 +1200 +++ squid-4.0.14/src/auth/basic/DB/basic_db_auth.8 2016-09-09 03:31:37.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_DB_AUTH 8" -.TH BASIC_DB_AUTH 8 "2016-08-05" "perl v5.22.2" "User Contributed Perl Documentation" +.TH BASIC_DB_AUTH 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.0.13/src/auth/basic/POP3/basic_pop3_auth.8 squid-4.0.14/src/auth/basic/POP3/basic_pop3_auth.8 --- squid-4.0.13/src/auth/basic/POP3/basic_pop3_auth.8 2016-08-06 02:27:35.000000000 +1200 +++ squid-4.0.14/src/auth/basic/POP3/basic_pop3_auth.8 2016-09-09 03:31:47.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_POP3_AUTH 8" -.TH BASIC_POP3_AUTH 8 "2016-08-05" "perl v5.22.2" "User Contributed Perl Documentation" +.TH BASIC_POP3_AUTH 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.0.13/src/base/AsyncJob.cc squid-4.0.14/src/base/AsyncJob.cc --- squid-4.0.13/src/base/AsyncJob.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/base/AsyncJob.cc 2016-09-09 02:12:03.000000000 +1200 @@ -165,7 +165,7 @@ if (stopReason != NULL) { buf.appendf("Stopped, reason:%s", stopReason); } - buf.appendf(" %s%u]", id.Prefix, id.value); + buf.appendf(" %s%u]", id.prefix(), id.value); buf.terminate(); return buf.content(); diff -u -r -N squid-4.0.13/src/base/CbcPointer.h squid-4.0.14/src/base/CbcPointer.h --- squid-4.0.13/src/base/CbcPointer.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/base/CbcPointer.h 2016-09-09 02:12:03.000000000 +1200 @@ -28,6 +28,7 @@ CbcPointer(); // a nil pointer CbcPointer(Cbc *aCbc); CbcPointer(const CbcPointer &p); + CbcPointer(CbcPointer &&); ~CbcPointer(); Cbc *raw() const; ///< a temporary raw Cbc pointer; may be invalid @@ -42,6 +43,7 @@ bool operator ==(const CbcPointer &o) const { return lock == o.lock; } CbcPointer &operator =(const CbcPointer &p); + CbcPointer &operator =(CbcPointer &&); /// support converting a child cbc pointer into a parent cbc pointer template @@ -100,6 +102,13 @@ } template +CbcPointer::CbcPointer(CbcPointer &&d): cbc(d.cbc), lock(d.lock) +{ + d.cbc = nullptr; + d.lock = nullptr; +} + +template CbcPointer::~CbcPointer() { clear(); @@ -116,6 +125,19 @@ } return *this; } + +template +CbcPointer &CbcPointer::operator =(CbcPointer &&d) +{ + if (this != &d) { // assignment to self + clear(); + cbc = d.cbc; + d.cbc = nullptr; + lock = d.lock; + d.lock = nullptr; + } + return *this; +} template void diff -u -r -N squid-4.0.13/src/base/InstanceId.h squid-4.0.14/src/base/InstanceId.h --- squid-4.0.13/src/base/InstanceId.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/base/InstanceId.h 2016-09-09 02:12:03.000000000 +1200 @@ -25,35 +25,41 @@ public: typedef unsigned int Value; ///< id storage type; \todo: parameterize? - InstanceId(): value(++Last ? Last : ++Last) {} + InstanceId(): value(0) {change();} operator Value() const { return value; } bool operator ==(const InstanceId &o) const { return value == o.value; } bool operator !=(const InstanceId &o) const { return !(*this == o); } - void change() {value = ++Last ? Last : ++Last;} + void change(); - /// prints Prefix followed by ID value; \todo: use HEX for value printing? + /// prints class-pecific prefix followed by ID value; \todo: use HEX for value printing? std::ostream &print(std::ostream &os) const; + /// returns the class-pecific prefix + const char * const prefix() const; + public: - static const char *Prefix; ///< Class shorthand string for debugging Value value; ///< instance identifier private: InstanceId(const InstanceId& right); ///< not implemented; IDs are unique InstanceId& operator=(const InstanceId &right); ///< not implemented - -private: - static Value Last; ///< the last used ID value }; /// convenience macro to instantiate Class-specific stuff in .cc files -#define InstanceIdDefinitions(Class, prefix) \ - template<> const char *InstanceId::Prefix = prefix; \ - template<> InstanceId::Value InstanceId::Last = 0; \ +#define InstanceIdDefinitions(Class, pfx) \ + template<> const char * const \ + InstanceId::prefix() const { \ + return pfx; \ + } \ template<> std::ostream & \ InstanceId::print(std::ostream &os) const { \ - return os << Prefix << value; \ + return os << pfx << value; \ + } \ + template<> void \ + InstanceId::change() { \ + static InstanceId::Value Last = 0; \ + value = ++Last ? Last : ++Last; \ } /// print the id diff -u -r -N squid-4.0.13/src/base/RegexPattern.cc squid-4.0.14/src/base/RegexPattern.cc --- squid-4.0.13/src/base/RegexPattern.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/base/RegexPattern.cc 2016-09-09 02:12:03.000000000 +1200 @@ -8,6 +8,7 @@ #include "squid.h" #include "base/RegexPattern.h" +#include RegexPattern::RegexPattern(int aFlags, const char *aPattern) : flags(aFlags), @@ -16,9 +17,29 @@ memset(®ex, 0, sizeof(regex)); } +RegexPattern::RegexPattern(RegexPattern &&o) : + flags(std::move(o.flags)), + regex(std::move(o.regex)), + pattern(std::move(o.pattern)) +{ + memset(&o.regex, 0, sizeof(o.regex)); + o.pattern = nullptr; +} + RegexPattern::~RegexPattern() { xfree(pattern); regfree(®ex); } +RegexPattern & +RegexPattern::operator =(RegexPattern &&o) +{ + flags = std::move(o.flags); + regex = std::move(o.regex); + memset(&o.regex, 0, sizeof(o.regex)); + pattern = std::move(o.pattern); + o.pattern = nullptr; + return *this; +} + diff -u -r -N squid-4.0.13/src/base/RegexPattern.h squid-4.0.14/src/base/RegexPattern.h --- squid-4.0.13/src/base/RegexPattern.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/base/RegexPattern.h 2016-09-09 02:12:03.000000000 +1200 @@ -23,10 +23,15 @@ public: RegexPattern() = delete; RegexPattern(int aFlags, const char *aPattern); - RegexPattern(const RegexPattern &) = delete; - RegexPattern(RegexPattern &&) = default; ~RegexPattern(); + // regex type varies by library, usually not safe to copy + RegexPattern(const RegexPattern &) = delete; + RegexPattern &operator =(const RegexPattern &) = delete; + + RegexPattern(RegexPattern &&); + RegexPattern &operator =(RegexPattern &&); + const char * c_str() const {return pattern;} bool match(const char *str) const {return regexec(®ex,str,0,NULL,0)==0;} diff -u -r -N squid-4.0.13/src/base/RunnersRegistry.cc squid-4.0.14/src/base/RunnersRegistry.cc --- squid-4.0.13/src/base/RunnersRegistry.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/base/RunnersRegistry.cc 2016-09-09 02:12:03.000000000 +1200 @@ -14,44 +14,78 @@ typedef std::set Runners; /// all known runners static Runners *TheRunners = NULL; +/// used to avoid re-creating deleted TheRunners after shutdown finished. +static bool RunnersGone = false; -/// safely returns registered runners, initializing structures as needed -static Runners & -GetRunners() +/// creates the registered runners container if needed +/// \return either registered runners (if they should exist) or nil (otherwise) +static Runners * +FindRunners() { - if (!TheRunners) + if (!TheRunners && !RunnersGone) TheRunners = new Runners; - return *TheRunners; + return TheRunners; } -int -RegisterRunner(RegisteredRunner *rr) +static inline void +GetRidOfRunner(RegisteredRunner *rr) { - Runners &runners = GetRunners(); - runners.insert(rr); - return runners.size(); + if (!dynamic_cast(rr)) + delete rr; + // else ignore; IndependentRunner } -int -DeregisterRunner(RegisteredRunner *rr) +bool +RegisterRunner(RegisteredRunner *rr) { - Runners &runners = GetRunners(); - runners.erase(rr); - return runners.size(); + if (Runners *runners = FindRunners()) { + runners->insert(rr); + return true; + } + + // past finishShutdown + GetRidOfRunner(rr); + return false; } void -RunRegistered(const RegisteredRunner::Method &m) +RunRegistered(const RegisteredRunner::Method &event) { - Runners &runners = GetRunners(); - typedef Runners::iterator RRI; - for (RRI i = runners.begin(); i != runners.end(); ++i) - ((*i)->*m)(); - - if (m == &RegisteredRunner::finishShutdown) { - delete TheRunners; - TheRunners = NULL; + if (Runners *runners = FindRunners()) { + // Many things may happen during the loop below. We copy to withstand + // runner removal/addition and avoid surprises due to registrations from + // parent constructors (with a half-baked "this"!). This copy also + // simplifies overall RR logic as it guarantees that registering a + // runner during event X loop does not execute runner::X(). + Runners oldRunners(*runners); + for (auto runner: oldRunners) { + if (runners->find(runner) != runners->end()) // still registered + (runner->*event)(); + } } + + if (event != &RegisteredRunner::finishShutdown) + return; + + // this is the last event; delete registry-dependent runners (and only them) + if (Runners *runners = FindRunners()) { + RunnersGone = true; + TheRunners = nullptr; + // from now on, no runners can be registered or unregistered + for (auto runner: *runners) + GetRidOfRunner(runner); // leaves a dangling pointer in runners + delete runners; + } +} + +/* IndependentRunner */ + +void +IndependentRunner::unregisterRunner() +{ + if (Runners *runners = FindRunners()) + runners->erase(this); + // else it is too late, finishShutdown() has been called } bool diff -u -r -N squid-4.0.13/src/base/RunnersRegistry.h squid-4.0.14/src/base/RunnersRegistry.h --- squid-4.0.13/src/base/RunnersRegistry.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/base/RunnersRegistry.h 2016-09-09 02:12:03.000000000 +1200 @@ -77,24 +77,33 @@ /// Called after stopping the main loop and before releasing memory. /// Meant for quick/basic cleanup that does not require any other modules. virtual ~RegisteredRunner() {} - /// exists to simplify caller interface; override the destructor instead - void finishShutdown() { delete this; } + + /// Meant for cleanup of services needed by the already destroyed objects. + virtual void finishShutdown() {} /// a pointer to one of the above notification methods typedef void (RegisteredRunner::*Method)(); }; -/// registers a given runner with the given registry and returns registry count -int RegisterRunner(RegisteredRunner *rr); - -/// de-registers a given runner with the given registry and returns registry count -int DeregisterRunner(RegisteredRunner *rr); +/// registers a given runner with the given registry and returns true on success +bool RegisterRunner(RegisteredRunner *rr); /// Calls a given method of all runners. /// All runners are destroyed after the finishShutdown() call. void RunRegistered(const RegisteredRunner::Method &m); +/// A RegisteredRunner with lifetime determined by forces outside the Registry. +class IndependentRunner: public RegisteredRunner +{ +public: + virtual ~IndependentRunner() { unregisterRunner(); } + +protected: + void registerRunner() {RegisterRunner(this);} + void unregisterRunner(); ///< unregisters self; safe to call multiple times +}; + /// convenience macro to describe/debug the caller and the method being called #define RunRegisteredHere(m) \ debugs(1, 2, "running " # m); \ diff -u -r -N squid-4.0.13/src/cache_cf.cc squid-4.0.14/src/cache_cf.cc --- squid-4.0.13/src/cache_cf.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/cache_cf.cc 2016-09-09 02:12:03.000000000 +1200 @@ -230,8 +230,6 @@ static void parse_b_size_t(size_t * var); static void parse_b_int64_t(int64_t * var); -static bool parseNamedIntList(const char *data, const String &name, std::vector &list); - static void parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap); static void dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap); static void free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap); @@ -898,6 +896,7 @@ if (!p->sslContext) { debugs(3, DBG_CRITICAL, "ERROR: Could not initialize cache_peer " << p->name << " TLS context"); self_destruct(); + return; } } } @@ -965,11 +964,15 @@ Config.redirectChildren.concurrency = cval; } - if (!strcmp(name, "log_access")) + if (!strcmp(name, "log_access")) { self_destruct(); + return; + } - if (!strcmp(name, "log_icap")) + if (!strcmp(name, "log_icap")) { self_destruct(); + return; + } if (!strcmp(name, "ignore_ims_on_miss")) { // the replacement directive cache_revalidate_on_miss has opposite meanings for ON/OFF value @@ -1001,6 +1004,7 @@ else { debugs(3, DBG_CRITICAL, "ERROR: unknown directive: " << name); self_destruct(); + return; } // add the value as unquoted-string because the old values did not support whitespace @@ -1015,13 +1019,17 @@ static void parseTimeLine(time_msec_t * tptr, const char *units, bool allowMsec, bool expectMoreArguments = false) { - time_msec_t u; - if ((u = parseTimeUnits(units, allowMsec)) == 0) + time_msec_t u = parseTimeUnits(units, allowMsec); + if (u == 0) { self_destruct(); + return; + } - char *token; - if ((token = ConfigParser::NextToken()) == NULL) + char *token = ConfigParser::NextToken();; + if (!token) { self_destruct(); + return; + } double d = xatof(token); @@ -1033,6 +1041,7 @@ } else if (!expectMoreArguments) { self_destruct(); + return; } else { token = NULL; // show default units if dying below @@ -1761,14 +1770,17 @@ static void parse_authparam(Auth::ConfigVector * config) { - char *type_str; - char *param_str; - - if ((type_str = ConfigParser::NextToken()) == NULL) + char *type_str = ConfigParser::NextToken(); + if (!type_str) { self_destruct(); + return; + } - if ((param_str = ConfigParser::NextToken()) == NULL) + char *param_str = ConfigParser::NextToken(); + if (!param_str) { self_destruct(); + return; + } /* find a configuration for the scheme in the currently parsed configs... */ Auth::Config *schemeCfg = Auth::Config::Find(type_str); @@ -1780,6 +1792,7 @@ if (theScheme == NULL) { debugs(3, DBG_CRITICAL, "Parsing Config File: Unknown authentication scheme '" << type_str << "'."); self_destruct(); + return; } config->push_back(theScheme->createConfig()); @@ -1787,6 +1800,7 @@ if (schemeCfg == NULL) { debugs(3, DBG_CRITICAL, "Parsing Config File: Corruption configuring authentication scheme '" << type_str << "'."); self_destruct(); + return; } } @@ -1827,20 +1841,19 @@ static void parse_cachedir(Store::DiskConfig *swap) { - char *type_str; - char *path_str; - RefCount sd; - int i; - int fs; - - if ((type_str = ConfigParser::NextToken()) == NULL) + char *type_str = ConfigParser::NextToken(); + if (!type_str) { self_destruct(); + return; + } - if ((path_str = ConfigParser::NextToken()) == NULL) + char *path_str = ConfigParser::NextToken(); + if (!path_str) { self_destruct(); + return; + } - fs = find_fstype(type_str); - + int fs = find_fstype(type_str); if (fs < 0) { debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: This proxy does not support the '" << type_str << "' cache type. Ignoring."); return; @@ -1848,7 +1861,8 @@ /* reconfigure existing dir */ - for (i = 0; i < swap->n_configured; ++i) { + RefCount sd; + for (int i = 0; i < swap->n_configured; ++i) { assert (swap->swapDirs[i].getRaw()); if ((strcasecmp(path_str, dynamic_cast(swap->swapDirs[i].getRaw())->path)) == 0) { @@ -2015,19 +2029,21 @@ static void parse_peer(CachePeer ** head) { - char *token = NULL; - CachePeer *p = new CachePeer; - - if ((token = ConfigParser::NextToken()) == NULL) + char *host_str = ConfigParser::NextToken(); + if (!host_str) { self_destruct(); + return; + } - p->host = xstrdup(token); - - p->name = xstrdup(token); - - if ((token = ConfigParser::NextToken()) == NULL) + char *token = ConfigParser::NextToken(); + if (!token) { self_destruct(); + return; + } + CachePeer *p = new CachePeer; + p->host = xstrdup(host_str); + p->name = xstrdup(host_str); p->type = parseNeighborType(token); if (p->type == PEER_MULTICAST) { @@ -2037,8 +2053,11 @@ p->http_port = GetTcpService(); - if (!p->http_port) + if (!p->http_port) { + delete p; self_destruct(); + return; + } p->icp.port = GetUdpService(); @@ -2390,13 +2409,14 @@ static void parse_peer_access(void) { - char *host = NULL; - CachePeer *p; - - if (!(host = ConfigParser::NextToken())) + char *host = ConfigParser::NextToken(); + if (!host) { self_destruct(); + return; + } - if ((p = peerFindByName(host)) == NULL) { + CachePeer *p = peerFindByName(host); + if (!p) { debugs(15, DBG_CRITICAL, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'"); return; } @@ -2409,30 +2429,31 @@ static void parse_hostdomaintype(void) { - char *host = NULL; - char *type = NULL; - char *domain = NULL; - - if (!(host = ConfigParser::NextToken())) + char *host = ConfigParser::NextToken(); + if (!host) { self_destruct(); + return; + } - if (!(type = ConfigParser::NextToken())) + char *type = ConfigParser::NextToken(); + if (!type) { self_destruct(); + return; + } + char *domain = nullptr; while ((domain = ConfigParser::NextToken())) { - NeighborTypeDomainList *l = NULL; - NeighborTypeDomainList **L = NULL; - CachePeer *p; - - if ((p = peerFindByName(host)) == NULL) { + CachePeer *p = peerFindByName(host); + if (!p) { debugs(15, DBG_CRITICAL, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'"); return; } - l = static_cast(xcalloc(1, sizeof(NeighborTypeDomainList))); + auto *l = static_cast(xcalloc(1, sizeof(NeighborTypeDomainList))); l->type = parseNeighborType(type); l->domain = xstrdup(domain); + NeighborTypeDomainList **L = nullptr; for (L = &(p->typelist); *L; L = &((*L)->next)); *L = l; } @@ -2488,9 +2509,10 @@ parse_onoff(int *var) { char *token = ConfigParser::NextToken(); - - if (token == NULL) + if (!token) { self_destruct(); + return; + } if (!strcmp(token, "on")) { *var = 1; @@ -2529,9 +2551,10 @@ parse_tristate(int *var) { char *token = ConfigParser::NextToken(); - - if (token == NULL) + if (!token) { self_destruct(); + return; + } if (!strcmp(token, "on")) { *var = 1; @@ -2557,9 +2580,10 @@ parse_pipelinePrefetch(int *var) { char *token = ConfigParser::PeekAtToken(); - - if (token == NULL) + if (!token) { self_destruct(); + return; + } if (!strcmp(token, "on")) { debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'pipeline_prefetch on' is deprecated. Please update to use 1 (or a higher number)."); @@ -2820,11 +2844,13 @@ static void parse_string(char **var) { - char *token = ConfigParser::NextToken(); safe_free(*var); - if (token == NULL) + char *token = ConfigParser::NextToken(); + if (!token) { self_destruct(); + return; + } *var = xstrdup(token); } @@ -2868,11 +2894,13 @@ static void parse_TokenOrQuotedString(char **var) { - char *token = ConfigParser::NextQuotedToken(); safe_free(*var); - if (token == NULL) + char *token = ConfigParser::NextQuotedToken(); + if (!token) { self_destruct(); + return; + } *var = xstrdup(token); } @@ -3110,9 +3138,10 @@ parse_uri_whitespace(int *var) { char *token = ConfigParser::NextToken(); - - if (token == NULL) + if (!token) { self_destruct(); + return; + } if (!strcmp(token, "strip")) *var = URI_WHITESPACE_STRIP; @@ -3219,8 +3248,10 @@ parse_memcachemode(SquidConfig *) { char *token = ConfigParser::NextToken(); - if (!token) + if (!token) { self_destruct(); + return; + } if (strcmp(token, "always") == 0) { Config.onoff.memory_cache_first = 1; @@ -3298,8 +3329,10 @@ s->s = ipa; *head = s; - } else + } else { self_destruct(); + return; + } } } @@ -3348,7 +3381,7 @@ s->name = xstrdup(token); s->connection_auth_disabled = false; - const char *portType = AnyP::UriScheme(s->transport.protocol).c_str(); + const SBuf &portType = AnyP::UriScheme(s->transport.protocol).image(); if (*token == '[') { /* [ipv6]:port */ @@ -3357,16 +3390,19 @@ if (!t) { debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing ']' on IPv6 address: " << token); self_destruct(); + return; } *t = '\0'; ++t; if (*t != ':') { debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing Port in: " << token); self_destruct(); + return; } if (!Ip::EnableIpv6) { debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: IPv6 is not available."); self_destruct(); + return; } port = xatos(t + 1); } else if ((t = strchr(token, ':'))) { @@ -3382,11 +3418,13 @@ } else { debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing Port: " << token); self_destruct(); + return; } if (port == 0 && host != NULL) { debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: Port cannot be 0: " << token); self_destruct(); + return; } if (NULL == host) { @@ -3443,6 +3481,7 @@ if (s->flags.isIntercepted()) { debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": Accelerator mode requires its own port. It cannot be shared with other modes."); self_destruct(); + return; } s->flags.accelSurrogate = true; s->vhost = true; @@ -3450,6 +3489,7 @@ if (s->flags.accelSurrogate || s->flags.tproxyIntercept) { debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": Intercept mode requires its own interception port. It cannot be shared with other modes."); self_destruct(); + return; } s->flags.natIntercept = true; Ip::Interceptor.StartInterception(); @@ -3460,6 +3500,7 @@ if (s->flags.natIntercept || s->flags.accelSurrogate) { debugs(3,DBG_CRITICAL, "FATAL: " << cfg_directive << ": TPROXY option requires its own interception port. It cannot be shared with other modes."); self_destruct(); + return; } s->flags.tproxyIntercept = true; Ip::Interceptor.StartTransparency(); @@ -3473,6 +3514,7 @@ if (!Ip::Interceptor.ProbeForTproxy(s->s)) { debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": TPROXY support in the system does not work."); self_destruct(); + return; } } else if (strcmp(token, "require-proxy-header") == 0) { @@ -3487,6 +3529,7 @@ if (!s->flags.accelSurrogate) { debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": defaultsite option requires Acceleration mode flag."); self_destruct(); + return; } safe_free(s->defaultsite); s->defaultsite = xstrdup(token + 12); @@ -3505,24 +3548,28 @@ if (!s->flags.accelSurrogate) { debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": vport option requires Acceleration mode flag."); self_destruct(); + return; } s->vport = -1; } else if (strncmp(token, "vport=", 6) == 0) { if (!s->flags.accelSurrogate) { debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": vport option requires Acceleration mode flag."); self_destruct(); + return; } s->vport = xatos(token + 6); } else if (strncmp(token, "protocol=", 9) == 0) { if (!s->flags.accelSurrogate) { debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": protocol option requires Acceleration mode flag."); self_destruct(); + return; } s->transport = parsePortProtocol(ToUpper(SBuf(token + 9))); } else if (strcmp(token, "allow-direct") == 0) { if (!s->flags.accelSurrogate) { debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": allow-direct option requires Acceleration mode flag."); self_destruct(); + return; } s->allow_direct = true; } else if (strcmp(token, "act-as-origin") == 0) { @@ -3535,6 +3582,7 @@ if (!s->flags.accelSurrogate) { debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": ignore-cc option requires Acceleration mode flag."); self_destruct(); + return; } #endif s->ignore_cc = true; @@ -3556,12 +3604,15 @@ s->disable_pmtu_discovery = DISABLE_PMTU_TRANSPARENT; else if (!strcmp(token + 23, "always")) s->disable_pmtu_discovery = DISABLE_PMTU_ALWAYS; - else + else { self_destruct(); + return; + } } else if (strcmp(token, "ipv4") == 0) { if ( !s->s.setIPv4() ) { debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": IPv6 addresses cannot be used as IPv4-Only. " << s->s ); self_destruct(); + return; } } else if (strcmp(token, "tcpkeepalive") == 0) { s->tcp_keepalive.enabled = true; @@ -3697,26 +3748,31 @@ if (s->flags.tunnelSslBumping && !hijacked) { debugs(3, DBG_CRITICAL, "FATAL: ssl-bump on https_port requires tproxy/intercept which is missing."); self_destruct(); + return; } if (hijacked && !s->flags.tunnelSslBumping) { debugs(3, DBG_CRITICAL, "FATAL: tproxy/intercept on https_port requires ssl-bump which is missing."); self_destruct(); + return; } #endif if (s->flags.proxySurrogate) { debugs(3,DBG_CRITICAL, "FATAL: https_port: require-proxy-header option is not supported on HTTPS ports."); self_destruct(); + return; } } else if (protoName.cmp("FTP") == 0) { /* ftp_port does not support ssl-bump */ if (s->flags.tunnelSslBumping) { debugs(3, DBG_CRITICAL, "FATAL: ssl-bump is not supported for ftp_port."); self_destruct(); + return; } if (s->flags.proxySurrogate) { // Passive FTP data channel does not work without deep protocol inspection in the frontend. debugs(3,DBG_CRITICAL, "FATAL: require-proxy-header option is not supported on ftp_port."); self_destruct(); + return; } } @@ -3724,7 +3780,7 @@ // clone the port options from *s to *(s->next) s->next = s->clone(); s->next->s.setIPv4(); - debugs(3, 3, AnyP::UriScheme(s->transport.protocol).c_str() << "_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s); + debugs(3, 3, AnyP::UriScheme(s->transport.protocol).image() << "_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s); } while (*head != NULL) @@ -3768,7 +3824,7 @@ // TODO: compare against prefix of 'n' instead of assuming http_port if (s->transport.protocol != AnyP::PROTO_HTTP) - storeAppendPrintf(e, " protocol=%s", AnyP::UriScheme(s->transport.protocol).c_str()); + storeAppendPrintf(e, " protocol=%s", AnyP::ProtocolType_str[s->transport.protocol]); if (s->allow_direct) storeAppendPrintf(e, " allow-direct"); @@ -3903,20 +3959,19 @@ static void parse_access_log(CustomLog ** logs) { - CustomLog *cl = (CustomLog *)xcalloc(1, sizeof(*cl)); - - // default buffer size and fatal settings - cl->bufferSize = 8*MAX_URL; - cl->fatal = true; - - /* determine configuration style */ - const char *filename = ConfigParser::NextToken(); if (!filename) { self_destruct(); return; } + CustomLog *cl = (CustomLog *)xcalloc(1, sizeof(*cl)); + + cl->filename = xstrdup(filename); + // default buffer size and fatal settings + cl->bufferSize = 8*MAX_URL; + cl->fatal = true; + if (strcmp(filename, "none") == 0) { cl->type = Log::Format::CLF_NONE; aclParseAclList(LegacyParser, &cl->aclList, filename); @@ -3926,7 +3981,6 @@ return; } - cl->filename = xstrdup(filename); cl->type = Log::Format::CLF_UNKNOWN; cl->rotateCount = -1; // default: use global logfile_rotate setting. @@ -3948,7 +4002,10 @@ } else { debugs(3, DBG_CRITICAL, "Unknown value for on-error '" << token << "' expected 'drop' or 'die'"); + xfree(cl->filename); + xfree(cl); self_destruct(); + return; } } else if (strncasecmp(token, "buffer-size=", 12) == 0) { parseBytesOptionValue(&cl->bufferSize, B_BYTES_STR, token+12); @@ -3961,7 +4018,10 @@ break; // done with name=value options, now to ACLs } else { debugs(3, DBG_CRITICAL, "Unknown access_log option " << token); + xfree(cl->filename); + xfree(cl); self_destruct(); + return; } // Pop the token, it was a valid "name=value" option (void)ConfigParser::NextToken(); @@ -4131,6 +4191,7 @@ } } +#if HAVE_CPU_AFFINITY /* until somebody else needs this general code */ /// parses list of integers form name=N1,N2,N3,... static bool parseNamedIntList(const char *data, const String &name, std::vector &list) @@ -4151,6 +4212,7 @@ } return data && *data == '\0'; } +#endif static void parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap) @@ -4159,8 +4221,8 @@ debugs(3, DBG_CRITICAL, "FATAL: Squid built with no CPU affinity " << "support, do not set 'cpu_affinity_map'"); self_destruct(); -#endif /* HAVE_CPU_AFFINITY */ +#else /* HAVE_CPU_AFFINITY */ if (!*cpuAffinityMap) *cpuAffinityMap = new CpuAffinityMap; @@ -4181,6 +4243,7 @@ "contain numbers <= 0"); self_destruct(); } +#endif } static void @@ -4303,10 +4366,12 @@ if (strcmp(token,"in") != 0) { debugs(3, DBG_CRITICAL, "expecting 'in' on'" << config_input_line << "'"); self_destruct(); + return; } if ((token = ConfigParser::NextToken()) == NULL) { self_destruct(); + return; } d = static_cast (xatoi(token)); @@ -4318,8 +4383,11 @@ else if ((token = ConfigParser::NextToken()) == NULL) { debugs(3, DBG_CRITICAL, "No time-units on '" << config_input_line << "'"); self_destruct(); - } else if ((m = parseTimeUnits(token, false)) == 0) + return; + } else if ((m = parseTimeUnits(token, false)) == 0) { self_destruct(); + return; + } cfg->oldest_service_failure = (m * d); } @@ -4346,6 +4414,7 @@ char *al; sslproxy_cert_adapt *ca = (sslproxy_cert_adapt *) xcalloc(1, sizeof(sslproxy_cert_adapt)); if ((al = ConfigParser::NextToken()) == NULL) { + xfree(ca); self_destruct(); return; } @@ -4357,6 +4426,7 @@ param = s; s = strchr(s, '}'); if (!s) { + xfree(ca); self_destruct(); return; } @@ -4375,6 +4445,7 @@ if (param) { if (strlen(param) > 64) { debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: setCommonName{" <alg = Ssl::algSignSelf; else { debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_sign: unknown cert signing algorithm: " << al); + xfree(cs); self_destruct(); return; } @@ -4721,6 +4795,7 @@ (ftpEpsvIsDeprecatedRule && !FtpEspvDeprecated && *ftp_epsv != NULL)) { debugs(3, DBG_CRITICAL, "FATAL: do not mix \"ftp_epsv on|off\" cfg lines with \"ftp_epsv allow|deny ...\" cfg lines. Update your ftp_epsv rules."); self_destruct(); + return; } if (ftpEpsvIsDeprecatedRule) { @@ -4731,6 +4806,7 @@ ftpEpsvRule->context("(ftp_epsv rule)", config_input_line); ACL *a = ACL::FindByName("all"); if (!a) { + delete ftpEpsvRule; self_destruct(); return; } @@ -4779,12 +4855,14 @@ } else { debugs(3, DBG_CRITICAL, "FATAL: unsuported \"on_timeout\" action:" << value); self_destruct(); + return; } } else if (strcasecmp(key, "response") == 0) { config->response = xstrdup(value); } else { debugs(3, DBG_CRITICAL, "FATAL: unsuported option " << key); self_destruct(); + return; } } diff -u -r -N squid-4.0.13/src/CachePeer.cc squid-4.0.14/src/CachePeer.cc --- squid-4.0.13/src/CachePeer.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/CachePeer.cc 2016-09-09 02:12:03.000000000 +1200 @@ -42,7 +42,6 @@ domain(NULL), #if USE_OPENSSL sslContext(NULL), - sslSession(NULL), #endif front_end_https(0), connection_auth(2 /* auto */) @@ -102,9 +101,6 @@ #if USE_OPENSSL if (sslContext) SSL_CTX_free(sslContext); - - if (sslSession) - SSL_SESSION_free(sslSession); #endif } diff -u -r -N squid-4.0.13/src/CachePeer.h squid-4.0.14/src/CachePeer.h --- squid-4.0.13/src/CachePeer.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/CachePeer.h 2016-09-09 02:12:03.000000000 +1200 @@ -184,9 +184,7 @@ /// security settings for peer connection Security::PeerOptions secure; Security::ContextPtr sslContext; -#if USE_OPENSSL - SSL_SESSION *sslSession; -#endif + Security::SessionStatePointer sslSession; int front_end_https; int connection_auth; diff -u -r -N squid-4.0.13/src/carp.cc squid-4.0.14/src/carp.cc --- squid-4.0.13/src/carp.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/carp.cc 2016-09-09 02:12:03.000000000 +1200 @@ -167,7 +167,7 @@ // this code follows URI syntax pattern. // corner cases should use the full effective request URI if (tp->options.carp_key.scheme) { - key.append(request->url.getScheme().c_str()); + key.append(request->url.getScheme().image()); if (key.length()) //if the scheme is not empty key.append("://"); } diff -u -r -N squid-4.0.13/src/cf.data.pre squid-4.0.14/src/cf.data.pre --- squid-4.0.13/src/cf.data.pre 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/cf.data.pre 2016-09-09 02:12:03.000000000 +1200 @@ -566,7 +566,8 @@ For Digest there is no default, this parameter is mandatory. For NTLM and Negotiate this parameter is ignored. - "children" numberofchildren [startup=N] [idle=N] [concurrency=N] [queue-size=N] + "children" numberofchildren [startup=N] [idle=N] [concurrency=N] + [queue-size=N] [on-persistent-overload=action] The maximum number of authenticator processes to spawn. If you start too few Squid will have to wait for them to process @@ -591,10 +592,27 @@ Concurrency must not be set unless it's known the helper supports the input format with channel-ID fields. - The queue-size= option sets the maximum number of queued - requests. If the queued requests exceed queue size for more - than 3 minutes then squid aborts its operation. - The default value is set to 2*numberofchildren/ + The queue-size=N option sets the maximum number of queued + requests to N. The default maximum is 2*numberofchildren. Squid + is allowed to temporarily exceed the configured maximum, marking + the affected helper as "overloaded". If the helper overload + lasts more than 3 minutes, the action prescribed by the + on-persistent-overload option applies. + + The on-persistent-overload=action option specifies Squid + reaction to a new helper request arriving when the helper + has been overloaded for more that 3 minutes already. The number + of queued requests determines whether the helper is overloaded + (see the queue-size option). + + Two actions are supported: + + die Squid worker quits. This is the default behavior. + + ERR Squid treats the helper request as if it was + immediately submitted, and the helper immediately + replied with an ERR response. This action has no effect + on the already queued and in-progress helper requests. NOTE: NTLM and Negotiate schemes do not support concurrency in the Squid code module even though some helpers can. @@ -5125,11 +5143,29 @@ queue-size=N - Sets the maximum number of queued requests. - If the queued requests exceed queue size and redirector_bypass - configuration option is set, then redirector is bypassed. Otherwise, if - overloading persists squid may abort its operation. - The default value is set to 2*numberofchildren. + Sets the maximum number of queued requests to N. The default maximum + is 2*numberofchildren. If the queued requests exceed queue size and + redirector_bypass configuration option is set, then redirector is bypassed. + Otherwise, Squid is allowed to temporarily exceed the configured maximum, + marking the affected helper as "overloaded". If the helper overload lasts + more than 3 minutes, the action prescribed by the on-persistent-overload + option applies. + + on-persistent-overload=action + + Specifies Squid reaction to a new helper request arriving when the helper + has been overloaded for more that 3 minutes already. The number of queued + requests determines whether the helper is overloaded (see the queue-size + option). + + Two actions are supported: + + die Squid worker quits. This is the default behavior. + + ERR Squid treats the helper request as if it was + immediately submitted, and the helper immediately + replied with an ERR response. This action has no effect + on the already queued and in-progress helper requests. DOC_END NAME: url_rewrite_host_header redirect_rewrites_host_header @@ -5172,11 +5208,10 @@ DEFAULT: off DOC_START When this is 'on', a request will not go through the - redirector if all the helpers are busy. If this is 'off' - and the redirector queue grows too large, Squid will exit - with a FATAL error and ask you to increase the number of - redirectors. You should only enable this if the redirectors - are not critical to your caching system. If you use + redirector if all the helpers are busy. If this is 'off' and the + redirector queue grows too large, the action is prescribed by the + on-persistent-overload option. You should only enable this if the + redirectors are not critical to your caching system. If you use redirectors for access control, and you enable this option, users may have access to pages they should not be allowed to request. @@ -5332,11 +5367,29 @@ queue-size=N - Sets the maximum number of queued requests. - If the queued requests exceed queue size and store_id_bypass - configuration option is set, then storeID helper is bypassed. Otherwise, - if overloading persists squid may abort its operation. - The default value is set to 2*numberofchildren. + Sets the maximum number of queued requests to N. The default maximum + is 2*numberofchildren. If the queued requests exceed queue size and + redirector_bypass configuration option is set, then redirector is bypassed. + Otherwise, Squid is allowed to temporarily exceed the configured maximum, + marking the affected helper as "overloaded". If the helper overload lasts + more than 3 minutes, the action prescribed by the on-persistent-overload + option applies. + + on-persistent-overload=action + + Specifies Squid reaction to a new helper request arriving when the helper + has been overloaded for more that 3 minutes already. The number of queued + requests determines whether the helper is overloaded (see the queue-size + option). + + Two actions are supported: + + die Squid worker quits. This is the default behavior. + + ERR Squid treats the helper request as if it was + immediately submitted, and the helper immediately + replied with an ERR response. This action has no effect + on the already queued and in-progress helper requests. DOC_END NAME: store_id_access storeurl_rewrite_access @@ -5359,11 +5412,10 @@ DEFAULT: on DOC_START When this is 'on', a request will not go through the - helper if all helpers are busy. If this is 'off' - and the helper queue grows too large, Squid will exit - with a FATAL error and ask you to increase the number of - helpers. You should only enable this if the helperss - are not critical to your caching system. If you use + helper if all helpers are busy. If this is 'off' and the helper + queue grows too large, the action is prescribed by the + on-persistent-overload option. You should only enable this if the + helpers are not critical to your caching system. If you use helpers for critical caching components, and you enable this option, users may not get objects from cache. This options sets default queue-size option of the store_id_children diff -u -r -N squid-4.0.13/src/client_side.cc squid-4.0.14/src/client_side.cc --- squid-4.0.13/src/client_side.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/client_side.cc 2016-09-09 02:12:03.000000000 +1200 @@ -587,7 +587,6 @@ checkLogging(); flags.readMore = false; - DeregisterRunner(this); clientdbEstablished(clientConnection->remote, -1); /* decrement */ pipeline.terminateAll(0); @@ -1043,10 +1042,6 @@ // swanSong() in the close handler will cleanup. if (Comm::IsConnOpen(clientConnection)) clientConnection->close(); - - // deregister now to ensure finalShutdown() does not kill us prematurely. - // fd_table purge will cleanup if close handler was not fast enough. - DeregisterRunner(this); } char * @@ -1221,7 +1216,8 @@ } // else nothing to alter port-wise. const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen + strlen(host); http->uri = (char *)xcalloc(url_sz, 1); - snprintf(http->uri, url_sz, "%s://%s" SQUIDSBUFPH, AnyP::UriScheme(conn->transferProtocol.protocol).c_str(), host, SQUIDSBUFPRINT(url)); + const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image(); + snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH, SQUIDSBUFPRINT(scheme), host, SQUIDSBUFPRINT(url)); debugs(33, 5, "ACCEL VHOST REWRITE: " << http->uri); } else if (conn->port->defaultsite /* && !vhost */) { debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport); @@ -1233,8 +1229,9 @@ if (vport > 0) { snprintf(vportStr, sizeof(vportStr),":%d",vport); } - snprintf(http->uri, url_sz, "%s://%s%s" SQUIDSBUFPH, - AnyP::UriScheme(conn->transferProtocol.protocol).c_str(), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url)); + const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image(); + snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s%s" SQUIDSBUFPH, + SQUIDSBUFPRINT(scheme), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url)); debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << http->uri); } else if (vport > 0 /* && (!vhost || no Host:) */) { debugs(33, 5, "ACCEL VPORT REWRITE: *_port IP + vport=" << vport); @@ -1242,9 +1239,9 @@ const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen; http->uri = (char *)xcalloc(url_sz, 1); http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN); - snprintf(http->uri, url_sz, "%s://%s:%d" SQUIDSBUFPH, - AnyP::UriScheme(conn->transferProtocol.protocol).c_str(), - ipbuf, vport, SQUIDSBUFPRINT(url)); + const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image(); + snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH, + SQUIDSBUFPRINT(scheme), ipbuf, vport, SQUIDSBUFPRINT(url)); debugs(33, 5, "ACCEL VPORT REWRITE: " << http->uri); } } @@ -1262,8 +1259,9 @@ const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen + strlen(host); http->uri = (char *)xcalloc(url_sz, 1); - snprintf(http->uri, url_sz, "%s://%s" SQUIDSBUFPH, - AnyP::UriScheme(conn->transferProtocol.protocol).c_str(), host, SQUIDSBUFPRINT(hp->requestUri())); + const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image(); + snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH, + SQUIDSBUFPRINT(scheme), host, SQUIDSBUFPRINT(hp->requestUri())); debugs(33, 5, "TRANSPARENT HOST REWRITE: " << http->uri); } else { /* Put the local socket IP address as the hostname. */ @@ -1271,8 +1269,9 @@ http->uri = (char *)xcalloc(url_sz, 1); static char ipbuf[MAX_IPSTRLEN]; http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN); - snprintf(http->uri, url_sz, "%s://%s:%d" SQUIDSBUFPH, - AnyP::UriScheme(http->getConn()->transferProtocol.protocol).c_str(), + const SBuf &scheme = AnyP::UriScheme(http->getConn()->transferProtocol.protocol).image(); + snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH, + SQUIDSBUFPRINT(scheme), ipbuf, http->getConn()->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri())); debugs(33, 5, "TRANSPARENT REWRITE: " << http->uri); } @@ -1309,10 +1308,14 @@ } if (!parsedOk) { - if (hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge || hp->parseStatusCode == Http::scUriTooLong) - return csd->abortRequestParsing("error:request-too-large"); - - return csd->abortRequestParsing("error:invalid-request"); + const bool tooBig = + hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge || + hp->parseStatusCode == Http::scUriTooLong; + auto result = csd->abortRequestParsing( + tooBig ? "error:request-too-large" : "error:invalid-request"); + // assume that remaining leftovers belong to this bad request + csd->consumeInput(csd->inBuf.length()); + return result; } } @@ -1679,7 +1682,7 @@ http->flags.internal = true; } else if (Config.onoff.global_internal_static && internalStaticCheck(request->url.path())) { debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (global_internal_static on)"); - request->url.setScheme(AnyP::PROTO_HTTP); + request->url.setScheme(AnyP::PROTO_HTTP, "http"); request->url.host(internalHostname()); request->url.port(getMyPort()); http->flags.internal = true; @@ -2655,7 +2658,7 @@ return; } - if (SSL_session_reused(ssl)) { + if (Security::SessionIsResumed(fd_table[fd].ssl)) { debugs(83, 2, "clientNegotiateSSL: Session " << SSL_get_session(ssl) << " reused on FD " << fd << " (" << fd_table[fd].ipaddr << ":" << (int)fd_table[fd].remote_port << ")"); } else { @@ -2977,10 +2980,14 @@ void ConnStateData::getSslContextStart() { - // XXX starting SSL with a pipeline of requests still waiting for non-SSL replies? - assert(pipeline.count() < 2); // the CONNECT is okay for now. Anything else is a bug. - pipeline.terminateAll(0); - /* careful: terminateAll(0) above frees request, host, etc. */ + // If we are called, then CONNECT has succeeded. Finalize it. + if (auto xact = pipeline.front()) { + if (xact->http && xact->http->request && xact->http->request->method == Http::METHOD_CONNECT) + xact->finished(); + // cannot proceed with encryption if requests wait for plain responses + Must(pipeline.empty()); + } + /* careful: finished() above frees request, host, etc. */ if (port->generateHostCertificates) { Ssl::CertificateProperties certProperties; @@ -3445,7 +3452,7 @@ clientHttpConnectionsOpen(void) { for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) { - const char *scheme = AnyP::UriScheme(s->transport.protocol).c_str(); + const SBuf &scheme = AnyP::UriScheme(s->transport.protocol).image(); if (MAXTCPLISTENPORTS == NHttpSockets) { debugs(1, DBG_IMPORTANT, "WARNING: You have too many '" << scheme << "_port' lines."); diff -u -r -N squid-4.0.13/src/client_side.h squid-4.0.14/src/client_side.h --- squid-4.0.13/src/client_side.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/client_side.h 2016-09-09 02:12:03.000000000 +1200 @@ -62,7 +62,7 @@ * managing, or for graceful half-close use the stopReceiving() or * stopSending() methods. */ -class ConnStateData : public Server, public HttpControlMsgSink, public RegisteredRunner +class ConnStateData : public Server, public HttpControlMsgSink, private IndependentRunner { public: diff -u -r -N squid-4.0.13/src/client_side_reply.cc squid-4.0.14/src/client_side_reply.cc --- squid-4.0.13/src/client_side_reply.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/client_side_reply.cc 2016-09-09 02:12:03.000000000 +1200 @@ -1262,13 +1262,6 @@ debugs(88, 5, "clientReplyStatus: transfer is DONE: " << done << flags.complete); /* Ok we're finished, but how? */ - const int64_t expectedBodySize = - http->storeEntry()->getReply()->bodySize(http->request->method); - if (!http->request->flags.proxyKeepalive && expectedBodySize < 0) { - debugs(88, 5, "clientReplyStatus: closing, content_length < 0"); - return STREAM_FAILED; - } - if (EBIT_TEST(http->storeEntry()->flags, ENTRY_BAD_LENGTH)) { debugs(88, 5, "clientReplyStatus: truncated response body"); return STREAM_UNPLANNED_COMPLETE; @@ -1279,6 +1272,8 @@ return STREAM_FAILED; } + const int64_t expectedBodySize = + http->storeEntry()->getReply()->bodySize(http->request->method); if (expectedBodySize >= 0 && !http->gotEnough()) { debugs(88, 5, "clientReplyStatus: client didn't get all it expected"); return STREAM_UNPLANNED_COMPLETE; @@ -1359,8 +1354,14 @@ // if there is not configured a peer proxy with login=PASS or login=PASSTHRU option enabled // remove the Proxy-Authenticate header - if ( !request->peer_login || (strcmp(request->peer_login,"PASS") != 0 && strcmp(request->peer_login,"PASSTHRU") != 0)) - reply->header.delById(Http::HdrType::PROXY_AUTHENTICATE); + if ( !request->peer_login || (strcmp(request->peer_login,"PASS") != 0 && strcmp(request->peer_login,"PASSTHRU") != 0)) { +#if USE_ADAPTATION + // but allow adaptation services to authenticate clients + // via request satisfaction + if (!http->requestSatisfactionMode()) +#endif + reply->header.delById(Http::HdrType::PROXY_AUTHENTICATE); + } reply->header.removeHopByHopEntries(); @@ -2253,7 +2254,7 @@ */ if (http->request == NULL) { - http->request = new HttpRequest(m, AnyP::PROTO_NONE, null_string); + http->request = new HttpRequest(m, AnyP::PROTO_NONE, "http", null_string); HTTPMSGLOCK(http->request); } diff -u -r -N squid-4.0.13/src/client_side_request.cc squid-4.0.14/src/client_side_request.cc --- squid-4.0.13/src/client_side_request.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/client_side_request.cc 2016-09-09 02:12:03.000000000 +1200 @@ -1809,7 +1809,7 @@ repContext->setReplyToStoreEntry(e, "immediate SslBump error"); errorAppendEntry(e, calloutContext->error); calloutContext->error = NULL; - if (calloutContext->readNextRequest) + if (calloutContext->readNextRequest && getConn()) getConn()->flags.readMore = true; // resume any pipeline reads. node = (clientStreamNode *)client_stream.tail->data; clientStreamRead(node, this, node->readBuffer); diff -u -r -N squid-4.0.13/src/client_side_request.h squid-4.0.14/src/client_side_request.h --- squid-4.0.13/src/client_side_request.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/client_side_request.h 2016-09-09 02:12:03.000000000 +1200 @@ -148,6 +148,7 @@ public: void startAdaptation(const Adaptation::ServiceGroupPointer &g); + bool requestSatisfactionMode() const { return request_satisfaction_mode; } private: /// Handles an adaptation client request failure. diff -u -r -N squid-4.0.13/src/comm.cc squid-4.0.14/src/comm.cc --- squid-4.0.13/src/comm.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/comm.cc 2016-09-09 02:12:03.000000000 +1200 @@ -838,7 +838,7 @@ comm_close_complete(const FdeCbParams ¶ms) { fde *F = &fd_table[params.fd]; - F->ssl.resetWithoutLocking(nullptr); + F->ssl.reset(); #if USE_OPENSSL if (F->dynamicSslContext) { diff -u -r -N squid-4.0.13/src/DelaySpec.cc squid-4.0.14/src/DelaySpec.cc --- squid-4.0.13/src/DelaySpec.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/DelaySpec.cc 2016-09-09 02:12:03.000000000 +1200 @@ -43,8 +43,10 @@ { // get the token. char *token = ConfigParser::NextToken(); - if (token == NULL) + if (!token) { self_destruct(); + return; + } // no-limit value if (strcmp(token, "none") == 0 || token[0] == '-') { diff -u -r -N squid-4.0.13/src/enums.h squid-4.0.14/src/enums.h --- squid-4.0.13/src/enums.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/enums.h 2016-09-09 02:12:03.000000000 +1200 @@ -67,11 +67,11 @@ */ enum { ENTRY_SPECIAL, - ENTRY_REVALIDATE, + ENTRY_REVALIDATE_ALWAYS, DELAY_SENDING, RELEASE_REQUEST, REFRESH_REQUEST, - ENTRY_CACHABLE_RESERVED_FOR_FUTURE_USE, + ENTRY_REVALIDATE_STALE, ENTRY_DISPATCHED, KEY_PRIVATE, ENTRY_FWD_HDR_WAIT, diff -u -r -N squid-4.0.13/src/errorpage.cc squid-4.0.14/src/errorpage.cc --- squid-4.0.13/src/errorpage.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/errorpage.cc 2016-09-09 02:12:03.000000000 +1200 @@ -946,7 +946,8 @@ case 'P': if (request) { - p = request->url.getScheme().c_str(); + const SBuf &m = request->url.getScheme().image(); + mb.append(m.rawContent(), m.length()); } else if (!building_deny_info_url) { p = "[unknown protocol]"; } diff -u -r -N squid-4.0.13/src/external_acl.cc squid-4.0.14/src/external_acl.cc --- squid-4.0.13/src/external_acl.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/external_acl.cc 2016-09-09 02:12:03.000000000 +1200 @@ -178,12 +178,14 @@ void parse_externalAclHelper(external_acl ** list) { - external_acl *a = new external_acl; char *token = ConfigParser::NextToken(); - if (!token) + if (!token) { self_destruct(); + return; + } + external_acl *a = new external_acl; a->name = xstrdup(token); // Allow supported %macros inside quoted tokens @@ -319,8 +321,11 @@ } /* There must be at least one format token */ - if (!a->format.format) + if (!a->format.format) { + delete a; self_destruct(); + return; + } // format has implicit %DATA on the end if not used explicitly if (!data_used) { @@ -330,8 +335,11 @@ } /* helper */ - if (!token) + if (!token) { + delete a; self_destruct(); + return; + } wordlistAdd(&a->cmdline, token); @@ -466,18 +474,25 @@ void ACLExternal::parse() { - if (data) + if (data) { self_destruct(); + return; + } char *token = ConfigParser::strtokFile(); - if (!token) + if (!token) { self_destruct(); + return; + } data = new external_acl_data(find_externalAclHelper(token)); - if (!data->def) + if (!data->def) { + delete data; self_destruct(); + return; + } // def->name is the name of the external_acl_type. // this is the name of the 'acl' directive being tested @@ -613,7 +628,8 @@ if (!entry) { debugs(82, 2, HERE << acl->def->name << "(\"" << key << "\") = lookup needed"); - if (!acl->def->theHelper->queueFull()) { + // TODO: All other helpers allow temporary overload. Should not we? + if (!acl->def->theHelper->willOverload()) { debugs(82, 2, HERE << "\"" << key << "\": queueing a call."); if (!ch->goAsync(ExternalACLLookup::Instance())) debugs(82, 2, "\"" << key << "\": no async support!"); @@ -622,12 +638,12 @@ } else { if (!staleEntry) { debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name << - "' queue overload. Request rejected '" << key << "'."); + "' queue full. Request rejected '" << key << "'."); external_acl_message = "SYSTEM TOO BUSY, TRY AGAIN LATER"; return ACCESS_DUNNO; } else { debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name << - "' queue overload. Using stale result. '" << key << "'."); + "' queue full. Using stale result. '" << key << "'."); entry = staleEntry; /* Fall thru to processing below */ } diff -u -r -N squid-4.0.13/src/fde.h squid-4.0.14/src/fde.h --- squid-4.0.13/src/fde.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/fde.h 2016-09-09 02:12:03.000000000 +1200 @@ -167,7 +167,7 @@ halfClosedReader = NULL; read_method = NULL; write_method = NULL; - ssl.resetWithoutLocking(nullptr); + ssl.reset(); dynamicSslContext = NULL; #if _SQUID_WINDOWS_ win32.handle = (long)NULL; diff -u -r -N squid-4.0.13/src/format/Format.cc squid-4.0.14/src/format/Format.cc --- squid-4.0.13/src/format/Format.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/format/Format.cc 2016-09-09 02:12:03.000000000 +1200 @@ -996,7 +996,9 @@ case LFT_CLIENT_REQ_URLSCHEME: if (al->request) { - out = al->request->url.getScheme().c_str(); + const SBuf s(al->request->url.getScheme().image()); + sb.append(s.rawContent(), s.length()); + out = sb.termedBuf(); quote = 1; } break; @@ -1075,7 +1077,9 @@ case LFT_SERVER_REQ_URLSCHEME: if (al->adapted_request) { - out = al->adapted_request->url.getScheme().c_str(); + const SBuf s(al->adapted_request->url.getScheme().image()); + sb.append(s.rawContent(), s.length()); + out = sb.termedBuf(); quote = 1; } break; diff -u -r -N squid-4.0.13/src/format/Token.cc squid-4.0.14/src/format/Token.cc --- squid-4.0.13/src/format/Token.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/format/Token.cc 2016-09-09 02:12:03.000000000 +1200 @@ -343,6 +343,11 @@ ++cur; break; + case '/': + quote = LOG_QUOTE_SHELL; + ++cur; + break; + default: quote = *quoting; break; diff -u -r -N squid-4.0.13/src/FwdState.cc squid-4.0.14/src/FwdState.cc --- squid-4.0.13/src/FwdState.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/FwdState.cc 2016-09-09 02:12:03.000000000 +1200 @@ -847,27 +847,29 @@ ConnStateData *pinned_connection = request->pinnedConnection(); debugs(17,7, "pinned peer connection: " << pinned_connection); // pinned_connection may become nil after a pconn race - if (pinned_connection) + if (pinned_connection) { serverConn = pinned_connection->borrowPinnedConnection(request, serverDestinations[0]->getPeer()); - else - serverConn = NULL; - if (Comm::IsConnOpen(serverConn)) { - pinned_connection->stopPinnedConnectionMonitoring(); - flags.connected_okay = true; - ++n_tries; - request->flags.pinned = true; - if (pinned_connection->pinnedAuth()) - request->flags.auth = true; + if (Comm::IsConnOpen(serverConn)) { + pinned_connection->stopPinnedConnectionMonitoring(); + flags.connected_okay = true; + ++n_tries; + request->flags.pinned = true; + if (pinned_connection->pinnedAuth()) + request->flags.auth = true; - closeHandler = comm_add_close_handler(serverConn->fd, fwdServerClosedWrapper, this); + closeHandler = comm_add_close_handler(serverConn->fd, fwdServerClosedWrapper, this); - syncWithServerConn(pinned_connection->pinning.host); + syncWithServerConn(pinned_connection->pinning.host); + + // the server may close the pinned connection before this request + pconnRace = racePossible; + dispatch(); + return; + } + + } else + serverConn = nullptr; - // the server may close the pinned connection before this request - pconnRace = racePossible; - dispatch(); - return; - } // Pinned connection failure. debugs(17,2,HERE << "Pinned connection failed: " << pinned_connection); ErrorState *anErr = new ErrorState(ERR_ZERO_SIZE_OBJECT, Http::scServiceUnavailable, request); diff -u -r -N squid-4.0.13/src/helper/ChildConfig.cc squid-4.0.14/src/helper/ChildConfig.cc --- squid-4.0.13/src/helper/ChildConfig.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/helper/ChildConfig.cc 2016-09-09 02:12:03.000000000 +1200 @@ -24,6 +24,7 @@ n_running(0), n_active(0), queue_size(0), + onPersistentOverload(actDie), defaultQueueSize(true) {} @@ -35,6 +36,7 @@ n_running(0), n_active(0), queue_size(2 * m), + onPersistentOverload(actDie), defaultQueueSize(true) {} @@ -48,6 +50,7 @@ n_idle = rhs.n_idle; concurrency = rhs.concurrency; queue_size = rhs.queue_size; + onPersistentOverload = rhs.onPersistentOverload; defaultQueueSize = rhs.defaultQueueSize; return *this; } @@ -96,6 +99,16 @@ } else if (strncmp(token, "queue-size=", 11) == 0) { queue_size = xatoui(token + 11); defaultQueueSize = false; + } else if (strncmp(token, "on-persistent-overload=", 23) == 0) { + const SBuf action(token + 23); + if (action.cmp("ERR") == 0) + onPersistentOverload = actErr; + else if (action.cmp("die") == 0) + onPersistentOverload = actDie; + else { + debugs(0, DBG_CRITICAL, "ERROR: Unsupported on-persistent-overloaded action: " << action); + self_destruct(); + } } else { debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Undefined option: " << token << "."); self_destruct(); diff -u -r -N squid-4.0.13/src/helper/ChildConfig.h squid-4.0.14/src/helper/ChildConfig.h --- squid-4.0.13/src/helper/ChildConfig.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/helper/ChildConfig.h 2016-09-09 02:12:03.000000000 +1200 @@ -90,6 +90,14 @@ */ unsigned int queue_size; + /// how to handle a serious problem with a helper request submission + enum SubmissionErrorHandlingAction { + actDie, ///< kill the caller process (i.e., Squid worker) + actErr ///< drop the request and send an error to the caller + }; + /// how to handle a new request for helper that was overloaded for too long + SubmissionErrorHandlingAction onPersistentOverload; + /** * True if the default queue size is used. * Needed in the cases where we need to adjust default queue_size in diff -u -r -N squid-4.0.13/src/helper.cc squid-4.0.14/src/helper.cc --- squid-4.0.13/src/helper.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/helper.cc 2016-09-09 02:12:03.000000000 +1200 @@ -45,8 +45,8 @@ static void helperServerFree(helper_server *srv); static void helperStatefulServerFree(helper_stateful_server *srv); static void Enqueue(helper * hlp, Helper::Xaction *); -static helper_server *GetFirstAvailable(helper * hlp); -static helper_stateful_server *StatefulGetFirstAvailable(statefulhelper * hlp); +static helper_server *GetFirstAvailable(const helper * hlp); +static helper_stateful_server *StatefulGetFirstAvailable(const statefulhelper * hlp); static void helperDispatch(helper_server * srv, Helper::Xaction * r); static void helperStatefulDispatch(helper_stateful_server * srv, Helper::Xaction * r); static void helperKickQueue(helper * hlp); @@ -379,54 +379,101 @@ else Enqueue(this, r); - if (!queueFull()) { - full_time = 0; - } else if (!full_time) { - debugs(84, 3, id_name << " queue became full"); - full_time = squid_curtime; + syncQueueStats(); +} + +/// handles helperSubmit() and helperStatefulSubmit() failures +static void +SubmissionFailure(helper *hlp, HLPCB *callback, void *data) +{ + auto result = Helper::Error; + if (!hlp) { + debugs(84, 3, "no helper"); + result = Helper::Unknown; } + // else pretend the helper has responded with ERR + + callback(data, Helper::Reply(result)); } void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data) { - if (hlp == NULL) { - debugs(84, 3, "helperSubmit: hlp == NULL"); - Helper::Reply const nilReply(Helper::Unknown); - callback(data, nilReply); - return; - } - hlp->prepSubmit(); - hlp->submit(buf, callback, data); + if (!hlp || !hlp->trySubmit(buf, callback, data)) + SubmissionFailure(hlp, callback, data); } +/// whether queuing an additional request would overload the helper bool helper::queueFull() const { + return stats.queue_size >= static_cast(childs.queue_size); +} + +bool +helper::overloaded() const { return stats.queue_size > static_cast(childs.queue_size); } -/// prepares the helper for request submission via trySubmit() or helperSubmit() -/// currently maintains full_time and kills Squid if the helper remains full for too long +/// synchronizes queue-dependent measurements with the current queue state void +helper::syncQueueStats() +{ + if (overloaded()) { + if (overloadStart) { + debugs(84, 5, id_name << " still overloaded; dropped " << droppedRequests); + } else { + overloadStart = squid_curtime; + debugs(84, 3, id_name << " became overloaded"); + } + } else { + if (overloadStart) { + debugs(84, 5, id_name << " is no longer overloaded"); + if (droppedRequests) { + debugs(84, DBG_IMPORTANT, "helper " << id_name << + " is no longer overloaded after dropping " << droppedRequests << + " requests in " << (squid_curtime - overloadStart) << " seconds"); + droppedRequests = 0; + } + overloadStart = 0; + } + } +} + +/// prepares the helper for request submission +/// returns true if and only if the submission should proceed +/// may kill Squid if the helper remains overloaded for too long +bool helper::prepSubmit() { - if (!queueFull()) - full_time = 0; - else if (!full_time) // may happen here if reconfigure decreases capacity - full_time = squid_curtime; - else if (squid_curtime - full_time > 180) - fatalf("Too many queued %s requests", id_name); + // re-sync for the configuration may have changed since the last submission + syncQueueStats(); + + // Nothing special to do if the new request does not overload (i.e., the + // queue is not even full yet) or only _starts_ overloading this helper + // (i.e., the queue is currently at its limit). + if (!overloaded()) + return true; + + if (squid_curtime - overloadStart <= 180) + return true; // also OK: overload has not persisted long enough to panic + + if (childs.onPersistentOverload == Helper::ChildConfig::actDie) + fatalf("Too many queued %s requests; see on-persistent-overload.", id_name); + + if (!droppedRequests) { + debugs(84, DBG_IMPORTANT, "WARNING: dropping requests to overloaded " << + id_name << " helper configured with on-persistent-overload=err"); + } + ++droppedRequests; + debugs(84, 3, "failed to send " << droppedRequests << " helper requests to " << id_name); + return false; } bool helper::trySubmit(const char *buf, HLPCB * callback, void *data) { - prepSubmit(); - - if (queueFull()) { - debugs(84, DBG_IMPORTANT, id_name << " drops request due to a full queue"); - return false; // request was ignored - } + if (!prepSubmit()) + return false; // request was dropped submit(buf, callback, data); // will send or queue return true; // request submitted or queued @@ -445,14 +492,19 @@ void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPCB * callback, void *data, helper_stateful_server * lastserver) { - if (hlp == NULL) { - debugs(84, 3, "helperStatefulSubmit: hlp == NULL"); - Helper::Reply const nilReply(Helper::Unknown); - callback(data, nilReply); - return; - } - hlp->prepSubmit(); - hlp->submit(buf, callback, data, lastserver); + if (!hlp || !hlp->trySubmit(buf, callback, data, lastserver)) + SubmissionFailure(hlp, callback, data); +} + +/// If possible, submit request. Otherwise, either kill Squid or return false. +bool +statefulhelper::trySubmit(const char *buf, HLPCB * callback, void *data, helper_stateful_server *lastserver) +{ + if (!prepSubmit()) + return false; // request was dropped + + submit(buf, callback, data, lastserver); // will send or queue + return true; // request submitted or queued } void statefulhelper::submit(const char *buf, HLPCB * callback, void *data, helper_stateful_server * lastserver) @@ -477,12 +529,7 @@ debugs(84, DBG_DATA, "placeholder: '" << r->request.placeholder << "', " << Raw("buf", buf, (!buf?0:strlen(buf)))); - if (!queueFull()) { - full_time = 0; - } else if (!full_time) { - debugs(84, 3, id_name << " queue became full"); - full_time = squid_curtime; - } + syncQueueStats(); } /** @@ -570,6 +617,11 @@ " P\tPLACEHOLDER\n", 101); } +bool +helper::willOverload() const { + return queueFull() && !(childs.needNew() || GetFirstAvailable(this)); +} + void helperShutdown(helper * hlp) { @@ -1186,7 +1238,7 @@ } static helper_server * -GetFirstAvailable(helper * hlp) +GetFirstAvailable(const helper * hlp) { dlink_node *n; helper_server *srv; @@ -1217,14 +1269,13 @@ selected = srv; } - /* Check for overload */ if (!selected) { debugs(84, 5, "GetFirstAvailable: None available."); return NULL; } if (selected->stats.pending >= (hlp->childs.concurrency ? hlp->childs.concurrency : 1)) { - debugs(84, 3, "GetFirstAvailable: Least-loaded helper is overloaded!"); + debugs(84, 3, "GetFirstAvailable: Least-loaded helper is fully loaded!"); return NULL; } @@ -1233,7 +1284,7 @@ } static helper_stateful_server * -StatefulGetFirstAvailable(statefulhelper * hlp) +StatefulGetFirstAvailable(const statefulhelper * hlp) { dlink_node *n; helper_stateful_server *srv = NULL; diff -u -r -N squid-4.0.13/src/helper.h squid-4.0.14/src/helper.h --- squid-4.0.13/src/helper.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/helper.h 2016-09-09 02:12:03.000000000 +1200 @@ -49,13 +49,13 @@ * idle: no processes are working on requests (and no requests are queued); * normal: some, but not all processes are working (and no requests are queued); * busy: all processes are working (and some requests are possibly queued); - * full: all processes are working and at least 2*#processes requests are queued. + * overloaded: a busy helper with more than queue-size requests in the queue. * - * A "busy" helper queues new requests and issues a WARNING every 10 minutes or so. - * A "full" helper either drops new requests or keeps queuing them, depending on + * A busy helper queues new requests and issues a WARNING every 10 minutes or so. + * An overloaded helper either drops new requests or keeps queuing them, depending on * whether the caller can handle dropped requests (trySubmit vs helperSubmit APIs). - * An attempt to use a "full" helper that has been "full" for 3+ minutes kills worker. - * Given enough load, all helpers except for external ACL will make such attempts. + * If an overloaded helper has been overloaded for 3+ minutes, an attempt to use + * it results in on-persistent-overload action, which may kill worker. */ class helper { @@ -66,7 +66,8 @@ cmdline(NULL), id_name(name), ipc_type(0), - full_time(0), + droppedRequests(0), + overloadStart(0), last_queue_warn(0), last_restart(0), timeout(0), @@ -77,13 +78,10 @@ } ~helper(); - /// whether at least one more request can be successfully submitted - bool queueFull() const; - /// \returns next request in the queue, or nil. Helper::Xaction *nextRequest(); - ///< If not full, submit request. Otherwise, either kill Squid or return false. + /// If possible, submit request. Otherwise, either kill Squid or return false. bool trySubmit(const char *buf, HLPCB * callback, void *data); /// Submits a request to the helper or add it to the queue if none of @@ -92,6 +90,9 @@ /// Dump some stats about the helper state to a Packable object void packStatsInto(Packable *p, const char *label = NULL) const; + /// whether the helper will be in "overloaded" state after one more request + /// already overloaded helpers return true + bool willOverload() const; public: wordlist *cmdline; @@ -101,7 +102,8 @@ Helper::ChildConfig childs; ///< Configuration settings for number running. int ipc_type; Ip::Address addr; - time_t full_time; ///< when a full helper became full (zero for non-full helpers) + unsigned int droppedRequests; ///< requests not sent during helper overload + time_t overloadStart; ///< when the helper became overloaded (zero if it is not) time_t last_queue_warn; time_t last_restart; time_t timeout; ///< Requests timeout @@ -120,7 +122,10 @@ protected: friend void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data); - void prepSubmit(); + bool queueFull() const; + bool overloaded() const; + void syncQueueStats(); + bool prepSubmit(); void submit(const char *buf, HLPCB * callback, void *data); }; @@ -138,6 +143,7 @@ private: friend void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPCB * callback, void *data, helper_stateful_server * lastserver); void submit(const char *buf, HLPCB * callback, void *data, helper_stateful_server *lastserver); + bool trySubmit(const char *buf, HLPCB * callback, void *data, helper_stateful_server *lastserver); }; /** diff -u -r -N squid-4.0.13/src/http/ContentLengthInterpreter.cc squid-4.0.14/src/http/ContentLengthInterpreter.cc --- squid-4.0.13/src/http/ContentLengthInterpreter.cc 1970-01-01 12:00:00.000000000 +1200 +++ squid-4.0.14/src/http/ContentLengthInterpreter.cc 2016-09-09 02:12:03.000000000 +1200 @@ -0,0 +1,134 @@ +/* + * Copyright (C) 1996-2016 The Squid Software Foundation and contributors + * + * Squid software is distributed under GPLv2+ license and includes + * contributions from numerous individuals and organizations. + * Please see the COPYING and CONTRIBUTORS files for details. + */ + +/* DEBUG: section 55 HTTP Header */ + +#include "squid.h" +#include "base/CharacterSet.h" +#include "Debug.h" +#include "http/ContentLengthInterpreter.h" +#include "http/one/Parser.h" +#include "HttpHeaderTools.h" +#include "SquidConfig.h" +#include "SquidString.h" +#include "StrList.h" + +Http::ContentLengthInterpreter::ContentLengthInterpreter(const int aDebugLevel): + value(-1), + headerWideProblem(nullptr), + debugLevel(aDebugLevel), + sawBad(false), + needsSanitizing(false), + sawGood(false) +{ +} + +/// checks whether all characters after the Content-Length are allowed +bool +Http::ContentLengthInterpreter::goodSuffix(const char *suffix, const char * const end) const +{ + // optimize for the common case that does not need delimiters + if (suffix == end) + return true; + + for (const CharacterSet &delimiters = Http::One::Parser::DelimiterCharacters(); + suffix < end; ++suffix) { + if (!delimiters[*suffix]) + return false; + } + // needsSanitizing = true; // TODO: Always remove trailing whitespace? + return true; // including empty suffix +} + +/// handles a single-token Content-Length value +/// rawValue null-termination requirements are those of httpHeaderParseOffset() +bool +Http::ContentLengthInterpreter::checkValue(const char *rawValue, const int valueSize) +{ + Must(!sawBad); + + int64_t latestValue = -1; + char *suffix = nullptr; + // TODO: Handle malformed values with leading signs (e.g., "-0" or "+1"). + if (!httpHeaderParseOffset(rawValue, &latestValue, &suffix)) { + debugs(55, DBG_IMPORTANT, "WARNING: Malformed" << Raw("Content-Length", rawValue, valueSize)); + sawBad = true; + return false; + } + + if (latestValue < 0) { + debugs(55, debugLevel, "WARNING: Negative" << Raw("Content-Length", rawValue, valueSize)); + sawBad = true; + return false; + } + + // check for garbage after the number + if (!goodSuffix(suffix, rawValue + valueSize)) { + debugs(55, debugLevel, "WARNING: Trailing garbage in" << Raw("Content-Length", rawValue, valueSize)); + sawBad = true; + return false; + } + + if (sawGood) { + /* we have found at least two, possibly identical values */ + + needsSanitizing = true; // replace identical values with a single value + + const bool conflicting = value != latestValue; + if (conflicting) + headerWideProblem = "Conflicting"; // overwrite any lesser problem + else if (!headerWideProblem) // preserve a possibly worse problem + headerWideProblem = "Duplicate"; + + // with relaxed_header_parser, identical values are permitted + sawBad = !Config.onoff.relaxed_header_parser || conflicting; + return false; // conflicting or duplicate + } + + sawGood = true; + value = latestValue; + return true; +} + +/// handles Content-Length: a, b, c +bool +Http::ContentLengthInterpreter::checkList(const String &list) +{ + Must(!sawBad); + + if (!Config.onoff.relaxed_header_parser) { + debugs(55, debugLevel, "WARNING: List-like" << Raw("Content-Length", list.rawBuf(), list.size())); + sawBad = true; + return false; + } + + needsSanitizing = true; // remove extra commas (at least) + + const char *pos = nullptr; + const char *item = nullptr;; + int ilen = -1; + while (strListGetItem(&list, ',', &item, &ilen, &pos)) { + if (!checkValue(item, ilen) && sawBad) + break; + // keep going after a duplicate value to find conflicting ones + } + return false; // no need to keep this list field; it will be sanitized away +} + +bool +Http::ContentLengthInterpreter::checkField(const String &rawValue) +{ + if (sawBad) + return false; // one rotten apple is enough to spoil all of them + + // TODO: Optimize by always parsing the first integer first. + return rawValue.pos(',') ? + checkList(rawValue) : + checkValue(rawValue.rawBuf(), rawValue.size()); +} + diff -u -r -N squid-4.0.13/src/http/ContentLengthInterpreter.h squid-4.0.14/src/http/ContentLengthInterpreter.h --- squid-4.0.13/src/http/ContentLengthInterpreter.h 1970-01-01 12:00:00.000000000 +1200 +++ squid-4.0.14/src/http/ContentLengthInterpreter.h 2016-09-09 02:12:03.000000000 +1200 @@ -0,0 +1,57 @@ +/* + * Copyright (C) 1996-2016 The Squid Software Foundation and contributors + * + * Squid software is distributed under GPLv2+ license and includes + * contributions from numerous individuals and organizations. + * Please see the COPYING and CONTRIBUTORS files for details. + */ + +#ifndef SQUID_SRC_HTTP_CONTENTLENGTH_INTERPRETER_H +#define SQUID_SRC_HTTP_CONTENTLENGTH_INTERPRETER_H + +class String; + +namespace Http +{ + +/// Finds the intended Content-Length value while parsing message-header fields. +/// Deals with complications such as value lists and/or repeated fields. +class ContentLengthInterpreter +{ +public: + explicit ContentLengthInterpreter(const int aDebugLevel); + + /// updates history based on the given message-header field + /// \return true iff the field should be added/remembered for future use + bool checkField(const String &field); + + /// intended Content-Length value if sawGood is set and sawBad is not set + /// meaningless otherwise + int64_t value; + + /* for debugging (declared here to minimize padding) */ + const char *headerWideProblem; ///< worst header-wide problem found (or nil) + const int debugLevel; ///< debugging level for certain warnings + + /// whether a malformed Content-Length value was present + bool sawBad; + + /// whether all remembered fields should be removed + /// removed fields ought to be replaced with the intended value (if known) + /// irrelevant if sawBad is set + bool needsSanitizing; + + /// whether a valid field value was present, possibly among problematic ones + /// irrelevant if sawBad is set + bool sawGood; + +protected: + bool goodSuffix(const char *suffix, const char * const end) const; + bool checkValue(const char *start, const int size); + bool checkList(const String &list); +}; + +} // namespace Http + +#endif /* SQUID_SRC_HTTP_CONTENTLENGTH_INTERPRETER_H */ + diff -u -r -N squid-4.0.13/src/http/Makefile.am squid-4.0.14/src/http/Makefile.am --- squid-4.0.13/src/http/Makefile.am 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/http/Makefile.am 2016-09-09 02:12:03.000000000 +1200 @@ -14,6 +14,8 @@ noinst_LTLIBRARIES = libhttp.la libhttp_la_SOURCES = \ + ContentLengthInterpreter.cc \ + ContentLengthInterpreter.h \ forward.h \ MethodType.cc \ MethodType.h \ diff -u -r -N squid-4.0.13/src/http/Makefile.in squid-4.0.14/src/http/Makefile.in --- squid-4.0.13/src/http/Makefile.in 2016-08-06 00:55:04.000000000 +1200 +++ squid-4.0.14/src/http/Makefile.in 2016-09-09 02:14:50.000000000 +1200 @@ -163,8 +163,9 @@ CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libhttp_la_DEPENDENCIES = one/libhttp1.la -am_libhttp_la_OBJECTS = MethodType.lo RegisteredHeaders.lo \ - RequestMethod.lo StatusCode.lo StatusLine.lo Stream.lo +am_libhttp_la_OBJECTS = ContentLengthInterpreter.lo MethodType.lo \ + RegisteredHeaders.lo RequestMethod.lo StatusCode.lo \ + StatusLine.lo Stream.lo libhttp_la_OBJECTS = $(am_libhttp_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -757,6 +758,8 @@ DIST_SUBDIRS = one url_rewriters noinst_LTLIBRARIES = libhttp.la libhttp_la_SOURCES = \ + ContentLengthInterpreter.cc \ + ContentLengthInterpreter.h \ forward.h \ MethodType.cc \ MethodType.h \ @@ -839,6 +842,7 @@ distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ContentLengthInterpreter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MethodType.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RegisteredHeaders.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestMethod.Plo@am__quote@ diff -u -r -N squid-4.0.13/src/http/one/Parser.h squid-4.0.14/src/http/one/Parser.h --- squid-4.0.13/src/http/one/Parser.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/http/one/Parser.h 2016-09-09 02:12:03.000000000 +1200 @@ -106,6 +106,10 @@ */ Http::StatusCode parseStatusCode; + /// the characters which are to be considered valid whitespace + /// (WSP / BSP / OWS) + static const CharacterSet &DelimiterCharacters(); + protected: /** * detect and skip the CRLF or (if tolerant) LF line terminator @@ -117,10 +121,6 @@ */ bool skipLineTerminator(Http1::Tokenizer &tok) const; - /// the characters which are to be considered valid whitespace - /// (WSP / BSP / OWS) - static const CharacterSet &DelimiterCharacters(); - /** * Scan to find the mime headers block for current message. * diff -u -r -N squid-4.0.13/src/http/one/RequestParser.cc squid-4.0.14/src/http/one/RequestParser.cc --- squid-4.0.13/src/http/one/RequestParser.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/http/one/RequestParser.cc 2016-09-09 02:12:03.000000000 +1200 @@ -85,6 +85,10 @@ return false; } method_ = HttpRequestMethod(methodFound); + + if (!skipDelimiter(tok.skipAll(DelimiterCharacters()), "after method")) + return false; + return true; } @@ -212,17 +216,17 @@ * we just check how many character the caller has skipped. */ bool -Http::One::RequestParser::skipDelimiter(const size_t count) +Http::One::RequestParser::skipDelimiter(const size_t count, const char *where) { if (count <= 0) { - debugs(33, ErrorLevel(), "invalid request-line: missing delimiter"); + debugs(33, ErrorLevel(), "invalid request-line: missing delimiter " << where); parseStatusCode = Http::scBadRequest; return false; } // tolerant parser allows multiple whitespace characters between request-line fields if (count > 1 && !Config.onoff.relaxed_header_parser) { - debugs(33, ErrorLevel(), "invalid request-line: too many delimiters"); + debugs(33, ErrorLevel(), "invalid request-line: too many delimiters " << where); parseStatusCode = Http::scBadRequest; return false; } @@ -270,19 +274,28 @@ static const CharacterSet lineChars = CharacterSet::LF.complement("notLF"); ::Parser::Tokenizer lineTok(buf_); if (!lineTok.prefix(line, lineChars) || !lineTok.skip('\n')) { + if (buf_.length() >= Config.maxRequestHeaderSize) { + /* who should we blame for our failure to parse this line? */ + + Http1::Tokenizer methodTok(buf_); + if (!parseMethodField(methodTok)) + return -1; // blame a bad method (or its delimiter) + + // assume it is the URI + debugs(74, ErrorLevel(), "invalid request-line: URI exceeds " << + Config.maxRequestHeaderSize << "-byte limit"); + parseStatusCode = Http::scUriTooLong; + return -1; + } debugs(74, 5, "Parser needs more data"); return 0; } Http1::Tokenizer tok(line); - const CharacterSet &delimiters = DelimiterCharacters(); if (!parseMethodField(tok)) return -1; - if (!skipDelimiter(tok.skipAll(delimiters))) - return -1; - /* now parse backwards, to leave just the URI */ if (!skipTrailingCrs(tok)) return -1; @@ -290,7 +303,7 @@ if (!parseHttpVersionField(tok)) return -1; - if (!http0() && !skipDelimiter(tok.skipAllTrailing(delimiters))) + if (!http0() && !skipDelimiter(tok.skipAllTrailing(DelimiterCharacters()), "before protocol version")) return -1; /* parsed everything before and after the URI */ diff -u -r -N squid-4.0.13/src/http/one/RequestParser.h squid-4.0.14/src/http/one/RequestParser.h --- squid-4.0.13/src/http/one/RequestParser.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/http/one/RequestParser.h 2016-09-09 02:12:03.000000000 +1200 @@ -52,7 +52,7 @@ bool parseMethodField(Http1::Tokenizer &); bool parseUriField(Http1::Tokenizer &); bool parseHttpVersionField(Http1::Tokenizer &); - bool skipDelimiter(const size_t count); + bool skipDelimiter(const size_t count, const char *where); bool skipTrailingCrs(Http1::Tokenizer &tok); bool http0() const {return !msgProtocol_.major;} diff -u -r -N squid-4.0.13/src/http/url_rewriters/LFS/url_lfs_rewrite.8 squid-4.0.14/src/http/url_rewriters/LFS/url_lfs_rewrite.8 --- squid-4.0.13/src/http/url_rewriters/LFS/url_lfs_rewrite.8 2016-08-06 02:28:23.000000000 +1200 +++ squid-4.0.14/src/http/url_rewriters/LFS/url_lfs_rewrite.8 2016-09-09 03:32:18.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "URL_LFS_REWRITE 8" -.TH URL_LFS_REWRITE 8 "2016-08-05" "perl v5.22.2" "User Contributed Perl Documentation" +.TH URL_LFS_REWRITE 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.0.13/src/http.cc squid-4.0.14/src/http.cc --- squid-4.0.13/src/http.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/http.cc 2016-09-09 02:12:03.000000000 +1200 @@ -571,23 +571,14 @@ /* NOTREACHED */ } -/* - * For Vary, store the relevant request headers as - * virtual headers in the reply - * Returns an empty SBuf if the variance cannot be stored - */ -SBuf -httpMakeVaryMark(HttpRequest * request, HttpReply const * reply) +/// assemble a variant key (vary-mark) from the given Vary header and HTTP request +static void +assembleVaryKey(String &vary, SBuf &vstr, const HttpRequest &request) { - String vary, hdr; - const char *pos = NULL; - const char *item; - const char *value; - int ilen; - SBuf vstr; static const SBuf asterisk("*"); - - vary = reply->header.getList(Http::HdrType::VARY); + const char *pos = nullptr; + const char *item = nullptr; + int ilen = 0; while (strListGetItem(&vary, ',', &item, &ilen, &pos)) { SBuf name(item, ilen); @@ -599,8 +590,8 @@ if (!vstr.isEmpty()) vstr.append(", ", 2); vstr.append(name); - hdr = request->header.getByName(name); - value = hdr.termedBuf(); + String hdr(request.header.getByName(name)); + const char *value = hdr.termedBuf(); if (value) { value = rfc1738_escape_part(value); vstr.append("=\"", 2); @@ -610,37 +601,26 @@ hdr.clean(); } +} - vary.clean(); -#if X_ACCELERATOR_VARY - - pos = NULL; - vary = reply->header.getList(Http::HdrType::HDR_X_ACCELERATOR_VARY); - - while (strListGetItem(&vary, ',', &item, &ilen, &pos)) { - SBuf name(item, ilen); - if (name == asterisk) { - vstr.clear(); - break; - } - name.toLower(); - if (!vstr.isEmpty()) - vstr.append(", ", 2); - vstr.append(name); - hdr = request->header.getByName(name); - value = hdr.termedBuf(); - - if (value) { - value = rfc1738_escape_part(value); - vstr.append("=\"", 2); - vstr.append(value); - vstr.append("\"", 1); - } +/* + * For Vary, store the relevant request headers as + * virtual headers in the reply + * Returns an empty SBuf if the variance cannot be stored + */ +SBuf +httpMakeVaryMark(HttpRequest * request, HttpReply const * reply) +{ + SBuf vstr; + String vary; - hdr.clean(); - } + vary = reply->header.getList(Http::HdrType::VARY); + assembleVaryKey(vary, vstr, *request); +#if X_ACCELERATOR_VARY vary.clean(); + vary = reply->header.getList(Http::HdrType::HDR_X_ACCELERATOR_VARY); + assembleVaryKey(vary, vstr, *request); #endif debugs(11, 3, vstr); @@ -1008,8 +988,10 @@ // CC:private (yes, these can sometimes be stored) const bool ccPrivate = rep->cache_control->hasPrivate(); - if (ccMustRevalidate || ccNoCacheNoParams || ccSMaxAge || ccPrivate) - EBIT_SET(entry->flags, ENTRY_REVALIDATE); + if (ccNoCacheNoParams || ccPrivate) + EBIT_SET(entry->flags, ENTRY_REVALIDATE_ALWAYS); + else if (ccMustRevalidate || ccSMaxAge) + EBIT_SET(entry->flags, ENTRY_REVALIDATE_STALE); } #if USE_HTTP_VIOLATIONS // response header Pragma::no-cache is undefined in HTTP else { @@ -1019,7 +1001,7 @@ * but servers like "Active Imaging Webcast/2.0" sure do use it */ if (rep->header.has(Http::HdrType::PRAGMA) && rep->header.hasListMember(Http::HdrType::PRAGMA,"no-cache",',')) - EBIT_SET(entry->flags, ENTRY_REVALIDATE); + EBIT_SET(entry->flags, ENTRY_REVALIDATE_ALWAYS); } #endif } diff -u -r -N squid-4.0.13/src/HttpHdrCc.cc squid-4.0.14/src/HttpHdrCc.cc --- squid-4.0.13/src/HttpHdrCc.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/HttpHdrCc.cc 2016-09-09 02:12:03.000000000 +1200 @@ -238,6 +238,25 @@ /* for all options having values, "=value" after the name */ switch (flag) { + case HttpHdrCcType::CC_PUBLIC: + break; + case HttpHdrCcType::CC_PRIVATE: + if (Private().size()) + p->appendf("=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(Private())); + break; + + case HttpHdrCcType::CC_NO_CACHE: + if (noCache().size()) + p->appendf("=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(noCache())); + break; + case HttpHdrCcType::CC_NO_STORE: + break; + case HttpHdrCcType::CC_NO_TRANSFORM: + break; + case HttpHdrCcType::CC_MUST_REVALIDATE: + break; + case HttpHdrCcType::CC_PROXY_REVALIDATE: + break; case HttpHdrCcType::CC_MAX_AGE: p->appendf("=%d", maxAge()); break; @@ -253,8 +272,14 @@ case HttpHdrCcType::CC_MIN_FRESH: p->appendf("=%d", minFresh()); break; - default: - /* do nothing, directive was already printed */ + case HttpHdrCcType::CC_ONLY_IF_CACHED: + break; + case HttpHdrCcType::CC_STALE_IF_ERROR: + p->appendf("=%d", staleIfError()); + break; + case HttpHdrCcType::CC_OTHER: + case HttpHdrCcType::CC_ENUM_END: + // done below after the loop break; } diff -u -r -N squid-4.0.13/src/HttpHeader.cc squid-4.0.14/src/HttpHeader.cc --- squid-4.0.13/src/HttpHeader.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/HttpHeader.cc 2016-09-09 02:12:03.000000000 +1200 @@ -12,6 +12,7 @@ #include "base/EnumIterator.h" #include "base64.h" #include "globals.h" +#include "http/ContentLengthInterpreter.h" #include "HttpHdrCc.h" #include "HttpHdrContRange.h" #include "HttpHdrScTarget.h" // also includes HttpHdrSc.h @@ -242,7 +243,7 @@ HttpHeader::needUpdate(HttpHeader const *fresh) const { for (const auto e: fresh->entries) { - if (skipUpdateHeader(e->id)) + if (!e || skipUpdateHeader(e->id)) continue; String value; const char *name = e->name.termedBuf(); @@ -320,7 +321,6 @@ { const char *field_ptr = header_start; const char *header_end = header_start + hdrLen; // XXX: remove - HttpHeaderEntry *e, *e2; int warnOnError = (Config.onoff.relaxed_header_parser <= 0 ? DBG_IMPORTANT : 2); PROF_start(HttpHeaderParse); @@ -338,6 +338,7 @@ return 0; } + Http::ContentLengthInterpreter clen(warnOnError); /* common format headers are ":[ws]" lines delimited by . * continuation lines start with a (single) space or tab */ while (field_ptr < header_end) { @@ -419,6 +420,7 @@ break; /* terminating blank line */ } + HttpHeaderEntry *e; if ((e = HttpHeaderEntry::parse(field_start, field_end)) == NULL) { debugs(55, warnOnError, "WARNING: unparseable HTTP header field {" << getStringPrefix(field_start, field_end-field_start) << "}"); @@ -432,45 +434,15 @@ return 0; } - // XXX: RFC 7230 Section 3.3.3 item #4 requires sending a 502 error in - // several cases that we do not yet cover. TODO: Rewrite to cover more. - if (e->id == Http::HdrType::CONTENT_LENGTH && (e2 = findEntry(e->id)) != nullptr) { - if (e->value != e2->value) { - int64_t l1, l2; - debugs(55, warnOnError, "WARNING: found two conflicting content-length headers in {" << - getStringPrefix(header_start, hdrLen) << "}"); - - if (!Config.onoff.relaxed_header_parser) { - delete e; - PROF_stop(HttpHeaderParse); - clean(); - return 0; - } - - if (!httpHeaderParseOffset(e->value.termedBuf(), &l1)) { - debugs(55, DBG_IMPORTANT, "WARNING: Unparseable content-length '" << e->value << "'"); - delete e; - continue; - } else if (!httpHeaderParseOffset(e2->value.termedBuf(), &l2)) { - debugs(55, DBG_IMPORTANT, "WARNING: Unparseable content-length '" << e2->value << "'"); - delById(e2->id); - } else { - if (l1 != l2) - conflictingContentLength_ = true; - delete e; - continue; - } - } else { - debugs(55, warnOnError, "NOTICE: found double content-length header"); - delete e; + if (e->id == Http::HdrType::CONTENT_LENGTH && !clen.checkField(e->value)) { + delete e; - if (Config.onoff.relaxed_header_parser) - continue; + if (Config.onoff.relaxed_header_parser) + continue; // clen has printed any necessary warnings - PROF_stop(HttpHeaderParse); - clean(); - return 0; - } + PROF_stop(HttpHeaderParse); + clean(); + return 0; } if (e->id == Http::HdrType::OTHER && stringHasWhitespace(e->name.termedBuf())) { @@ -488,14 +460,29 @@ addEntry(e); } + if (clen.headerWideProblem) { + debugs(55, warnOnError, "WARNING: " << clen.headerWideProblem << + " Content-Length field values in" << + Raw("header", header_start, hdrLen)); + } + if (chunked()) { // RFC 2616 section 4.4: ignore Content-Length with Transfer-Encoding + // RFC 7230 section 3.3.3 #3: Transfer-Encoding overwrites Content-Length delById(Http::HdrType::CONTENT_LENGTH); - // RFC 7230 section 3.3.3 #4: ignore Content-Length conflicts with Transfer-Encoding - conflictingContentLength_ = false; - } else if (conflictingContentLength_) { - // ensure our callers do not see the conflicting Content-Length value + // and clen state becomes irrelevant + } else if (clen.sawBad) { + // ensure our callers do not accidentally see bad Content-Length values delById(Http::HdrType::CONTENT_LENGTH); + conflictingContentLength_ = true; // TODO: Rename to badContentLength_. + } else if (clen.needsSanitizing) { + // RFC 7230 section 3.3.2: MUST either reject or ... [sanitize]; + // ensure our callers see a clean Content-Length value or none at all + delById(Http::HdrType::CONTENT_LENGTH); + if (clen.sawGood) { + putInt64(Http::HdrType::CONTENT_LENGTH, clen.value); + debugs(55, 5, "sanitized Content-Length to be " << clen.value); + } } PROF_stop(HttpHeaderParse); @@ -1479,12 +1466,9 @@ HttpHeaderEntry::getInt64() const { int64_t val = -1; - int ok = httpHeaderParseOffset(value.termedBuf(), &val); - httpHeaderNoteParsedEntry(id, value, ok == 0); - /* XXX: Should we check ok - ie - * return ok ? -1 : value; - */ - return val; + const bool ok = httpHeaderParseOffset(value.termedBuf(), &val); + httpHeaderNoteParsedEntry(id, value, ok); + return val; // remains -1 if !ok (XXX: bad method API) } static void diff -u -r -N squid-4.0.13/src/HttpHeaderTools.cc squid-4.0.14/src/HttpHeaderTools.cc --- squid-4.0.13/src/HttpHeaderTools.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/HttpHeaderTools.cc 2016-09-09 02:12:03.000000000 +1200 @@ -82,32 +82,26 @@ } /** - * return true if a given directive is found in at least one of - * the "connection" header-fields note: if Http::HdrType::PROXY_CONNECTION is - * present we ignore Http::HdrType::CONNECTION. + * \return true if a given directive is found in the Connection header field-value. + * + * \note if no Connection header exists we may check the Proxy-Connection header */ -int +bool httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive) { String list; - int res; + /* what type of header do we have? */ + if (hdr->getList(Http::HdrType::CONNECTION, &list)) + return strListIsMember(&list, directive, ',') != 0; #if USE_HTTP_VIOLATIONS - if (hdr->has(Http::HdrType::PROXY_CONNECTION)) - list = hdr->getList(Http::HdrType::PROXY_CONNECTION); - else + if (hdr->getList(Http::HdrType::PROXY_CONNECTION, &list)) + return strListIsMember(&list, directive, ',') != 0; #endif - if (hdr->has(Http::HdrType::CONNECTION)) - list = hdr->getList(Http::HdrType::CONNECTION); - else - return 0; - - res = strListIsMember(&list, directive, ','); - list.clean(); - - return res; + // else, no connection header for it to exist in + return false; } /** handy to printf prefixes of potentially very long buffers */ @@ -138,18 +132,29 @@ return 1; } -int -httpHeaderParseOffset(const char *start, int64_t * value) +bool +httpHeaderParseOffset(const char *start, int64_t *value, char **endPtr) { + char *end = nullptr; errno = 0; - int64_t res = strtoll(start, NULL, 10); - if (!res && EINVAL == errno) { /* maybe not portable? */ - debugs(66, 7, "failed to parse offset in " << start); - return 0; + const int64_t res = strtoll(start, &end, 10); + if (errno && !res) { + debugs(66, 7, "failed to parse malformed offset in " << start); + return false; + } + if (errno == ERANGE && (res == LLONG_MIN || res == LLONG_MAX)) { // no overflow + debugs(66, 7, "failed to parse huge offset in " << start); + return false; + } + if (start == end) { + debugs(66, 7, "failed to parse empty offset"); + return false; } *value = res; + if (endPtr) + *endPtr = end; debugs(66, 7, "offset " << start << " parsed as " << res); - return 1; + return true; } /** diff -u -r -N squid-4.0.13/src/HttpHeaderTools.h squid-4.0.14/src/HttpHeaderTools.h --- squid-4.0.13/src/HttpHeaderTools.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/HttpHeaderTools.h 2016-09-09 02:12:03.000000000 +1200 @@ -117,9 +117,15 @@ bool quoted; }; -int httpHeaderParseOffset(const char *start, int64_t * off); +/// A strtoll(10) wrapper that checks for strtoll() failures and other problems. +/// XXX: This function is not fully compatible with some HTTP syntax rules. +/// Just like strtoll(), allows whitespace prefix, a sign, and _any_ suffix. +/// Requires at least one digit to be present. +/// Sets "off" and "end" arguments if and only if no problems were found. +/// \return true if and only if no problems were found. +bool httpHeaderParseOffset(const char *start, int64_t *offPtr, char **endPtr = nullptr); -int httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive); +bool httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive); int httpHeaderParseInt(const char *start, int *val); void httpHeaderPutStrf(HttpHeader * hdr, Http::HdrType id, const char *fmt,...) PRINTF_FORMAT_ARG3; diff -u -r -N squid-4.0.13/src/HttpRequest.cc squid-4.0.14/src/HttpRequest.cc --- squid-4.0.13/src/HttpRequest.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/HttpRequest.cc 2016-09-09 02:12:03.000000000 +1200 @@ -44,13 +44,13 @@ init(); } -HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) : +HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aSchemeImg, const char *aUrlpath) : HttpMsg(hoRequest) { static unsigned int id = 1; debugs(93,7, HERE << "constructed, this=" << this << " id=" << ++id); init(); - initHTTP(aMethod, aProtocol, aUrlpath); + initHTTP(aMethod, aProtocol, aSchemeImg, aUrlpath); } HttpRequest::~HttpRequest() @@ -60,10 +60,10 @@ } void -HttpRequest::initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) +HttpRequest::initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aSchemeImg, const char *aUrlpath) { method = aMethod; - url.setScheme(aProtocol); + url.setScheme(aProtocol, aSchemeImg); url.path(aUrlpath); } @@ -180,11 +180,7 @@ copy->pstate = pstate; // TODO: should we assert a specific state here? copy->body_pipe = body_pipe; - copy->url.setScheme(url.getScheme()); - copy->url.userInfo(url.userInfo()); - copy->url.host(url.host()); - copy->url.port(url.port()); - copy->url.path(url.path()); + copy->url = url; // range handled in hdrCacheInit() copy->ims = ims; diff -u -r -N squid-4.0.13/src/HttpRequest.h squid-4.0.14/src/HttpRequest.h --- squid-4.0.13/src/HttpRequest.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/HttpRequest.h 2016-09-09 02:12:03.000000000 +1200 @@ -49,11 +49,11 @@ typedef RefCount Pointer; HttpRequest(); - HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath); + HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *schemeImage, const char *aUrlpath); ~HttpRequest(); virtual void reset(); - void initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath); + void initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *schemeImage, const char *aUrlpath); virtual HttpRequest *clone() const; diff -u -r -N squid-4.0.13/src/ipc/MemMap.h squid-4.0.14/src/ipc/MemMap.h --- squid-4.0.13/src/ipc/MemMap.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/ipc/MemMap.h 2016-09-09 02:12:03.000000000 +1200 @@ -124,7 +124,6 @@ const SBuf path; ///< cache_dir path, used for logging Mem::Pointer shared; - int ttl; private: int slotIndexByKey(const cache_key *const key) const; diff -u -r -N squid-4.0.13/src/log/Config.cc squid-4.0.14/src/log/Config.cc --- squid-4.0.13/src/log/Config.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/log/Config.cc 2016-09-09 02:12:03.000000000 +1200 @@ -19,13 +19,15 @@ { char *name, *def; - if ((name = ConfigParser::NextToken()) == NULL) + if (!(name = ConfigParser::NextToken())) { self_destruct(); + } ::Format::Format *nlf = new ::Format::Format(name); ConfigParser::EnableMacros(); - if ((def = ConfigParser::NextQuotedOrToEol()) == NULL) { + if (!(def = ConfigParser::NextQuotedOrToEol())) { + delete nlf; self_destruct(); return; } @@ -34,6 +36,7 @@ debugs(3, 2, "Log Format for '" << name << "' is '" << def << "'"); if (!nlf->parse(def)) { + delete nlf; self_destruct(); return; } diff -u -r -N squid-4.0.13/src/log/DB/log_db_daemon.8 squid-4.0.14/src/log/DB/log_db_daemon.8 --- squid-4.0.13/src/log/DB/log_db_daemon.8 2016-08-06 02:28:37.000000000 +1200 +++ squid-4.0.14/src/log/DB/log_db_daemon.8 2016-09-09 03:32:27.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "LOG_DB_DAEMON 8" -.TH LOG_DB_DAEMON 8 "2016-08-05" "perl v5.22.2" "User Contributed Perl Documentation" +.TH LOG_DB_DAEMON 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.0.13/src/Makefile.am squid-4.0.14/src/Makefile.am --- squid-4.0.13/src/Makefile.am 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/Makefile.am 2016-09-09 02:12:03.000000000 +1200 @@ -546,12 +546,12 @@ ip/libip.la \ fs/libfs.la \ DiskIO/libdiskio.la \ + comm/libcomm.la \ + security/libsecurity.la \ $(SSL_LIBS) \ ipc/libipc.la \ mgr/libmgr.la \ anyp/libanyp.la \ - comm/libcomm.la \ - security/libsecurity.la \ parser/libparser.la \ eui/libeui.la \ icmp/libicmp.la \ diff -u -r -N squid-4.0.13/src/Makefile.in squid-4.0.14/src/Makefile.in --- squid-4.0.13/src/Makefile.in 2016-08-06 00:54:37.000000000 +1200 +++ squid-4.0.14/src/Makefile.in 2016-09-09 02:14:18.000000000 +1200 @@ -416,8 +416,8 @@ clients/libclients.la servers/libservers.la ftp/libftp.la \ helper/libhelper.la http/libhttp.la dns/libdns.la \ base/libbase.la libsquid.la ip/libip.la fs/libfs.la \ - DiskIO/libdiskio.la $(SSL_LIBS) ipc/libipc.la mgr/libmgr.la \ - anyp/libanyp.la comm/libcomm.la security/libsecurity.la \ + DiskIO/libdiskio.la comm/libcomm.la security/libsecurity.la \ + $(SSL_LIBS) ipc/libipc.la mgr/libmgr.la anyp/libanyp.la \ parser/libparser.la eui/libeui.la icmp/libicmp.la \ log/liblog.la format/libformat.la sbuf/libsbuf.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @@ -2947,8 +2947,8 @@ clients/libclients.la servers/libservers.la ftp/libftp.la \ helper/libhelper.la http/libhttp.la dns/libdns.la \ base/libbase.la libsquid.la ip/libip.la fs/libfs.la \ - DiskIO/libdiskio.la $(SSL_LIBS) ipc/libipc.la mgr/libmgr.la \ - anyp/libanyp.la comm/libcomm.la security/libsecurity.la \ + DiskIO/libdiskio.la comm/libcomm.la security/libsecurity.la \ + $(SSL_LIBS) ipc/libipc.la mgr/libmgr.la anyp/libanyp.la \ parser/libparser.la eui/libeui.la icmp/libicmp.la \ log/liblog.la format/libformat.la sbuf/libsbuf.la $(XTRA_OBJS) \ $(REPL_OBJS) $(NETTLELIB) $(CRYPTLIB) $(REGEXLIB) \ diff -u -r -N squid-4.0.13/src/Parsing.cc squid-4.0.14/src/Parsing.cc --- squid-4.0.13/src/Parsing.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/Parsing.cc 2016-09-09 02:12:03.000000000 +1200 @@ -126,9 +126,10 @@ GetInteger64(void) { char *token = ConfigParser::NextToken(); - - if (token == NULL) + if (!token) { self_destruct(); + return -1; // not reachable + } return xatoll(token, 10); } @@ -143,8 +144,10 @@ char *token = ConfigParser::NextToken(); int i; - if (token == NULL) + if (!token) { self_destruct(); + return -1; // not reachable + } // The conversion must honor 0 and 0x prefixes, which are important for things like umask int64_t ret = xatoll(token, 0); @@ -173,6 +176,7 @@ if (!token) { debugs(3, DBG_CRITICAL, "FATAL: A percentage value is missing."); self_destruct(); + return 0.0; // not reachable } //if there is a % in the end of the digits, we remove it and go on. @@ -195,9 +199,10 @@ GetShort(void) { char *token = ConfigParser::NextToken(); - - if (token == NULL) + if (!token) { self_destruct(); + return 0; // not reachable + } return xatos(token); } diff -u -r -N squid-4.0.13/src/pconn.cc squid-4.0.14/src/pconn.cc --- squid-4.0.13/src/pconn.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/pconn.cc 2016-09-09 02:12:03.000000000 +1200 @@ -31,14 +31,19 @@ /* ========== IdleConnList ============================================ */ -IdleConnList::IdleConnList(const char *key, PconnPool *thePool) : +IdleConnList::IdleConnList(const char *aKey, PconnPool *thePool) : capacity_(PCONN_FDS_SZ), size_(0), parent_(thePool) { - hash.key = xstrdup(key); - hash.next = NULL; + //Initialize hash_link members + key = xstrdup(aKey); + next = NULL; + theList_ = new Comm::ConnectionPointer[capacity_]; + + RegisterRunner(this); + // TODO: re-attach to MemPools. WAS: theList = (?? *)pconn_fds_pool->alloc(); } @@ -54,7 +59,7 @@ delete[] theList_; - xfree(hash.key); + xfree(key); } /** Search the list. Matches by FD socket number. @@ -95,7 +100,7 @@ if (parent_) { parent_->noteConnectionRemoved(); if (size_ == 0) { - debugs(48, 3, HERE << "deleting " << hashKeyStr(&hash)); + debugs(48, 3, "deleting " << hashKeyStr(this)); delete this; } } @@ -146,7 +151,7 @@ } if (parent_ && size_ == 0) { - debugs(48, 3, HERE << "deleting " << hashKeyStr(&hash)); + debugs(48, 3, "deleting " << hashKeyStr(this)); delete this; } } @@ -237,13 +242,13 @@ * quite a bit of CPU. Just keep it in mind. */ Comm::ConnectionPointer -IdleConnList::findUseable(const Comm::ConnectionPointer &key) +IdleConnList::findUseable(const Comm::ConnectionPointer &aKey) { assert(size_); // small optimization: do the constant bool tests only once. - const bool keyCheckAddr = !key->local.isAnyAddr(); - const bool keyCheckPort = key->local.port() > 0; + const bool keyCheckAddr = !aKey->local.isAnyAddr(); + const bool keyCheckPort = aKey->local.port() > 0; for (int i=size_-1; i>=0; --i) { @@ -251,11 +256,11 @@ continue; // local end port is required, but dont match. - if (keyCheckPort && key->local.port() != theList_[i]->local.port()) + if (keyCheckPort && aKey->local.port() != theList_[i]->local.port()) continue; // local address is required, but does not match. - if (keyCheckAddr && key->local.matchIPAddr(theList_[i]->local) != 0) + if (keyCheckAddr && aKey->local.matchIPAddr(theList_[i]->local) != 0) continue; // our connection timeout handler is scheduled to run already. unsafe for now. @@ -314,6 +319,12 @@ list->findAndClose(io.conn); } +void +IdleConnList::endingShutdown() +{ + closeN(size_); +} + /* ========== PconnPool PRIVATE FUNCTIONS ============================================ */ const char * @@ -381,7 +392,7 @@ static void DeleteIdleConnList(void *hashItem) { - delete reinterpret_cast(hashItem); + delete static_cast(hashItem); } PconnPool::~PconnPool() @@ -411,10 +422,10 @@ if (list == NULL) { list = new IdleConnList(aKey, this); - debugs(48, 3, HERE << "new IdleConnList for {" << hashKeyStr(&list->hash) << "}" ); - hash_join(table, &list->hash); + debugs(48, 3, "new IdleConnList for {" << hashKeyStr(list) << "}" ); + hash_join(table, list); } else { - debugs(48, 3, HERE << "found IdleConnList for {" << hashKeyStr(&list->hash) << "}" ); + debugs(48, 3, "found IdleConnList for {" << hashKeyStr(list) << "}" ); } list->push(conn); @@ -442,7 +453,7 @@ notifyManager("pop failure"); return Comm::ConnectionPointer(); } else { - debugs(48, 3, HERE << "found " << hashKeyStr(&list->hash) << + debugs(48, 3, "found " << hashKeyStr(list) << (keepOpen ? " to use" : " to kill")); } @@ -480,7 +491,7 @@ } // may delete current - reinterpret_cast(current)->closeN(1); + static_cast(current)->closeN(1); } } @@ -489,7 +500,7 @@ { theCount -= list->count(); assert(theCount >= 0); - hash_remove_link(table, &list->hash); + hash_remove_link(table, list); } void diff -u -r -N squid-4.0.13/src/pconn.h squid-4.0.14/src/pconn.h --- squid-4.0.13/src/pconn.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/pconn.h 2016-09-09 02:12:03.000000000 +1200 @@ -10,6 +10,7 @@ #define SQUID_PCONN_H #include "base/CbcPointer.h" +#include "base/RunnersRegistry.h" #include "mgr/forward.h" #include @@ -35,7 +36,7 @@ /** \ingroup PConnAPI * A list of connections currently open to a particular destination end-point. */ -class IdleConnList +class IdleConnList: public hash_link, private IndependentRunner { CBDATA_CLASS(IdleConnList); @@ -62,6 +63,8 @@ int count() const { return size_; } void closeN(size_t count); + // IndependentRunner API + virtual void endingShutdown(); private: bool isAvailable(int i) const; bool removeAt(int index); @@ -70,9 +73,6 @@ static IOCB Read; static CTCB Timeout; -public: - hash_link hash; /** must be first */ - private: /** List of connections we are holding. * Sorted as FIFO list for most efficient speeds on pop() and findUsable() diff -u -r -N squid-4.0.13/src/PeerPoolMgr.cc squid-4.0.14/src/PeerPoolMgr.cc --- squid-4.0.13/src/PeerPoolMgr.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/PeerPoolMgr.cc 2016-09-09 02:12:03.000000000 +1200 @@ -61,7 +61,7 @@ // ErrorState, getOutgoingAddress(), and other APIs may require a request. // We fake one. TODO: Optionally send this request to peers? - request = new HttpRequest(Http::METHOD_OPTIONS, AnyP::PROTO_HTTP, "*"); + request = new HttpRequest(Http::METHOD_OPTIONS, AnyP::PROTO_HTTP, "http", "*"); request->url.host(peer->host); checkpoint("peer initialized"); diff -u -r -N squid-4.0.13/src/redirect.cc squid-4.0.14/src/redirect.cc --- squid-4.0.13/src/redirect.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/redirect.cc 2016-09-09 02:12:03.000000000 +1200 @@ -295,7 +295,9 @@ assert(handler); debugs(61, 5, "redirectStart: '" << http->uri << "'"); - if (Config.onoff.redirector_bypass && redirectors->queueFull()) { + // TODO: Deprecate Config.onoff.redirector_bypass in favor of either + // onPersistentOverload or a new onOverload option that applies to all helpers. + if (Config.onoff.redirector_bypass && redirectors->willOverload()) { /* Skip redirector if the queue is full */ ++redirectorBypassed; Helper::Reply bypassReply; @@ -319,7 +321,7 @@ assert(handler); debugs(61, 5, "storeIdStart: '" << http->uri << "'"); - if (Config.onoff.store_id_bypass && storeIds->queueFull()) { + if (Config.onoff.store_id_bypass && storeIds->willOverload()) { /* Skip StoreID Helper if the queue is full */ ++storeIdBypassed; Helper::Reply bypassReply; diff -u -r -N squid-4.0.13/src/refresh.cc squid-4.0.14/src/refresh.cc --- squid-4.0.13/src/refresh.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/refresh.cc 2016-09-09 02:12:03.000000000 +1200 @@ -346,8 +346,12 @@ * Cache-Control: proxy-revalidate * the spec says the response must always be revalidated if stale. */ - if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1) { - debugs(22, 3, "YES: Must revalidate stale object (origin set must-revalidate, proxy-revalidate, no-cache, s-maxage, or private)"); + const bool revalidateAlways = EBIT_TEST(entry->flags, ENTRY_REVALIDATE_ALWAYS); + if (revalidateAlways || (staleness > -1 && + EBIT_TEST(entry->flags, ENTRY_REVALIDATE_STALE))) { + debugs(22, 3, "YES: Must revalidate stale object (origin set " << + (revalidateAlways ? "no-cache or private" : + "must-revalidate, proxy-revalidate or s-maxage") << ")"); if (request) request->flags.failOnValidationError = true; return STALE_MUST_REVALIDATE; diff -u -r -N squid-4.0.13/src/security/BlindPeerConnector.cc squid-4.0.14/src/security/BlindPeerConnector.cc --- squid-4.0.13/src/security/BlindPeerConnector.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/security/BlindPeerConnector.cc 2016-09-09 02:12:03.000000000 +1200 @@ -9,6 +9,7 @@ #include "squid.h" #include "CachePeer.h" #include "comm/Connection.h" +#include "errorpage.h" #include "fde.h" #include "HttpRequest.h" #include "neighbors.h" @@ -30,9 +31,9 @@ } bool -Security::BlindPeerConnector::initializeTls(Security::SessionPointer &serverSession) +Security::BlindPeerConnector::initialize(Security::SessionPointer &serverSession) { - if (!Security::PeerConnector::initializeTls(serverSession)) + if (!Security::PeerConnector::initialize(serverSession)) return false; if (const CachePeer *peer = serverConnection()->getPeer()) { @@ -46,8 +47,7 @@ SBuf *host = new SBuf(peer->secure.sslDomain); SSL_set_ex_data(serverSession.get(), ssl_ex_index_server, host); - if (peer->sslSession) - SSL_set_session(serverSession.get(), peer->sslSession); + Security::SetSessionResumeData(serverSession, peer->sslSession); } else { SBuf *hostName = new SBuf(request->url.host()); SSL_set_ex_data(serverSession.get(), ssl_ex_index_server, (void*)hostName); @@ -70,15 +70,9 @@ return; } -#if USE_OPENSSL - const int fd = serverConnection()->fd; - Security::SessionPtr ssl = fd_table[fd].ssl.get(); - if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) { - if (serverConnection()->getPeer()->sslSession) - SSL_SESSION_free(serverConnection()->getPeer()->sslSession); - - serverConnection()->getPeer()->sslSession = SSL_get1_session(ssl); + if (auto *peer = serverConnection()->getPeer()) { + const int fd = serverConnection()->fd; + Security::MaybeGetSessionResumeData(fd_table[fd].ssl, peer->sslSession); } -#endif } diff -u -r -N squid-4.0.13/src/security/BlindPeerConnector.h squid-4.0.14/src/security/BlindPeerConnector.h --- squid-4.0.13/src/security/BlindPeerConnector.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/security/BlindPeerConnector.h 2016-09-09 02:12:03.000000000 +1200 @@ -6,11 +6,13 @@ * Please see the COPYING and CONTRIBUTORS files for details. */ -#ifndef SQUID_SRC_SSL_BLINDPEERCONNECTOR_H -#define SQUID_SRC_SSL_BLINDPEERCONNECTOR_H +#ifndef SQUID_SRC_SECURITY_BLINDPEERCONNECTOR_H +#define SQUID_SRC_SECURITY_BLINDPEERCONNECTOR_H #include "security/PeerConnector.h" +class ErrorState; + namespace Security { @@ -31,20 +33,21 @@ /* Security::PeerConnector API */ - /// Calls parent initializeTls(), configure the created TLS session object to - /// try reuse TLS session and sets the hostname to use for certificates validation + /// Calls parent initialize(), configures the created TLS session object + /// to try and reuse a TLS session and sets the hostname to use for + /// certificate validation /// \returns true on successful initialization - virtual bool initializeTls(Security::SessionPointer &); + virtual bool initialize(Security::SessionPointer &); /// Return the configured Security::ContextPtr object virtual Security::ContextPtr getSslContext(); - /// On error calls peerConnectFailed function, on success store the used SSL session - /// for later use - virtual void noteNegotiationDone(ErrorState *error); + /// On error calls peerConnectFailed(). + /// On success store the used TLS session for later use. + virtual void noteNegotiationDone(ErrorState *); }; } // namespace Security -#endif /* SQUID_SRC_SSL_BLINDPEERCONNECTOR_H */ +#endif /* SQUID_SRC_SECURITY_BLINDPEERCONNECTOR_H */ diff -u -r -N squid-4.0.13/src/security/cert_generators/file/security_file_certgen.cc squid-4.0.14/src/security/cert_generators/file/security_file_certgen.cc --- squid-4.0.13/src/security/cert_generators/file/security_file_certgen.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/security/cert_generators/file/security_file_certgen.cc 2016-09-09 02:12:03.000000000 +1200 @@ -204,8 +204,8 @@ if (!Ssl::certificateMatchesProperties(cert.get(), certProperties)) { // The certificate changed (renewed or other reason). // Generete a new one with the updated fields. - cert.resetWithoutLocking(nullptr); - pkey.resetWithoutLocking(nullptr); + cert.reset(); + pkey.reset(); db.purgeCert(cert_subject); } } diff -u -r -N squid-4.0.13/src/security/cert_validators/fake/security_fake_certverify.8 squid-4.0.14/src/security/cert_validators/fake/security_fake_certverify.8 --- squid-4.0.13/src/security/cert_validators/fake/security_fake_certverify.8 2016-08-06 02:29:07.000000000 +1200 +++ squid-4.0.14/src/security/cert_validators/fake/security_fake_certverify.8 2016-09-09 03:32:45.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "SECURITY_FAKE_CERTVERIFY 8" -.TH SECURITY_FAKE_CERTVERIFY 8 "2016-08-05" "perl v5.22.2" "User Contributed Perl Documentation" +.TH SECURITY_FAKE_CERTVERIFY 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.0.13/src/security/Handshake.cc squid-4.0.14/src/security/Handshake.cc --- squid-4.0.13/src/security/Handshake.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/security/Handshake.cc 2016-09-09 02:12:03.000000000 +1200 @@ -337,7 +337,7 @@ return; } debugs(83, 5, "ignoring " << message.msg_body.length() << "-byte type-" << - message.msg_type << " handshake message"); + static_cast(message.msg_type) << " handshake message"); } void diff -u -r -N squid-4.0.13/src/security/LockingPointer.h squid-4.0.14/src/security/LockingPointer.h --- squid-4.0.13/src/security/LockingPointer.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/security/LockingPointer.h 2016-09-09 02:12:03.000000000 +1200 @@ -74,8 +74,9 @@ return *this; } - // move semantics are definitely okay, when possible - explicit LockingPointer(SelfType &&) = default; + LockingPointer(SelfType &&o) : raw(nullptr) { + resetWithoutLocking(o.release()); + } SelfType &operator =(SelfType &&o) { if (o.get() != raw) resetWithoutLocking(o.release()); diff -u -r -N squid-4.0.13/src/security/PeerConnector.cc squid-4.0.14/src/security/PeerConnector.cc --- squid-4.0.13/src/security/PeerConnector.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/security/PeerConnector.cc 2016-09-09 02:12:03.000000000 +1200 @@ -60,8 +60,8 @@ AsyncJob::start(); Security::SessionPointer tmp; - if (prepareSocket() && initializeTls(tmp)) - negotiateSsl(); + if (prepareSocket() && initialize(tmp)) + negotiate(); else mustStop("Security::PeerConnector TLS socket initialize failed"); } @@ -97,7 +97,7 @@ } bool -Security::PeerConnector::initializeTls(Security::SessionPointer &serverSession) +Security::PeerConnector::initialize(Security::SessionPointer &serverSession) { #if USE_OPENSSL Security::ContextPtr sslContext(getSslContext()); @@ -106,7 +106,7 @@ if (!Ssl::CreateClient(sslContext, serverConnection(), "server https start")) { ErrorState *anErr = new ErrorState(ERR_SOCKET_FAILURE, Http::scInternalServerError, request.getRaw()); anErr->xerrno = errno; - debugs(83, DBG_IMPORTANT, "Error allocating SSL handle: " << ERR_error_string(ERR_get_error(), NULL)); + debugs(83, DBG_IMPORTANT, "Error allocating TLS handle: " << ERR_error_string(ERR_get_error(), NULL)); noteNegotiationDone(anErr); bail(anErr); return false; @@ -166,15 +166,17 @@ } void -Security::PeerConnector::negotiateSsl() +Security::PeerConnector::negotiate() { - if (!Comm::IsConnOpen(serverConnection()) || fd_table[serverConnection()->fd].closing()) + if (!Comm::IsConnOpen(serverConnection())) return; -#if USE_OPENSSL const int fd = serverConnection()->fd; - Security::SessionPtr ssl = fd_table[fd].ssl.get(); - const int result = SSL_connect(ssl); + if (fd_table[fd].closing()) + return; + +#if USE_OPENSSL + const int result = SSL_connect(fd_table[fd].ssl.get()); #else const int result = -1; #endif @@ -345,9 +347,9 @@ void Security::PeerConnector::NegotiateSsl(int, void *data) { - PeerConnector *pc = static_cast(data); + PeerConnector *pc = static_cast(data); // Use job calls to add done() checks and other job logic/protections. - CallJobHere(83, 7, pc, Security::PeerConnector, negotiateSsl); + CallJobHere(83, 7, pc, Security::PeerConnector, negotiate); } void @@ -380,7 +382,7 @@ // Log connection details, if any recordNegotiationDetails(); - noteSslNegotiationError(ret, ssl_error, ssl_lib_error); + noteNegotiationError(ret, ssl_error, ssl_lib_error); #endif } @@ -423,7 +425,7 @@ } void -Security::PeerConnector::noteSslNegotiationError(const int ret, const int ssl_error, const int ssl_lib_error) +Security::PeerConnector::noteNegotiationError(const int ret, const int ssl_error, const int ssl_lib_error) { #if USE_OPENSSL // not used unless OpenSSL enabled. #if defined(EPROTO) @@ -449,7 +451,7 @@ anErr->xerrno = sysErrNo; Security::SessionPtr ssl = fd_table[fd].ssl.get(); - Ssl::ErrorDetail *errFromFailure = (Ssl::ErrorDetail *)SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail); + Ssl::ErrorDetail *errFromFailure = static_cast(SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail)); if (errFromFailure != NULL) { // The errFromFailure is attached to the ssl object // and will be released when ssl object destroyed. @@ -534,7 +536,7 @@ } if (serverConn != NULL) buf.appendf(" FD %d", serverConn->fd); - buf.appendf(" %s%u]", id.Prefix, id.value); + buf.appendf(" %s%u]", id.prefix(), id.value); buf.terminate(); return buf.content(); diff -u -r -N squid-4.0.13/src/security/PeerConnector.h squid-4.0.14/src/security/PeerConnector.h --- squid-4.0.13/src/security/PeerConnector.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/security/PeerConnector.h 2016-09-09 02:12:03.000000000 +1200 @@ -6,13 +6,14 @@ * Please see the COPYING and CONTRIBUTORS files for details. */ -#ifndef SQUID_SRC_SSL_PEERCONNECTOR_H -#define SQUID_SRC_SSL_PEERCONNECTOR_H +#ifndef SQUID_SRC_SECURITY_PEERCONNECTOR_H +#define SQUID_SRC_SECURITY_PEERCONNECTOR_H #include "acl/Acl.h" #include "base/AsyncCbdataCalls.h" #include "base/AsyncJob.h" #include "CommCalls.h" +#include "http/forward.h" #include "security/EncryptorAnswer.h" #include "security/forward.h" #if USE_OPENSSL @@ -22,7 +23,6 @@ #include #include -class HttpRequest; class ErrorState; class AccessLogEntry; typedef RefCount AccessLogEntryPointer; @@ -31,26 +31,28 @@ { /** - * Connects Squid to SSL/TLS-capable peers or services. - * Contains common code and interfaces of various specialized PeerConnectors, + * Initiates encryption on a connection to peers or servers. + * Despite its name does not perform any connect(2) operations. + * + * Contains common code and interfaces of various specialized PeerConnector's, * including peer certificate validation code. \par * The caller receives a call back with Security::EncryptorAnswer. If answer.error - * is not nil, then there was an error and the SSL connection to the SSL peer + * is not nil, then there was an error and the encryption to the peer or server * was not fully established. The error object is suitable for error response * generation. \par * The caller must monitor the connection for closure because this * job will not inform the caller about such events. \par - * PeerConnector class curently supports a form of SSL negotiation timeout, - * which accounted only when sets the read timeout from SSL peer. + * PeerConnector class currently supports a form of TLS negotiation timeout, + * which is accounted only when sets the read timeout from encrypted peers/servers. * For a complete solution, the caller must monitor the overall connection * establishment timeout and close the connection on timeouts. This is probably * better than having dedicated (or none at all!) timeouts for peer selection, * DNS lookup, TCP handshake, SSL handshake, etc. Some steps may have their * own timeout, but not all steps should be forced to have theirs. - * XXX: tunnel.cc and probably other subsystems does not have an "overall + * XXX: tunnel.cc and probably other subsystems do not have an "overall * connection establishment" timeout. We need to change their code so that they * start monitoring earlier and close on timeouts. This change may need to be * discussed on squid-dev. @@ -63,7 +65,7 @@ CBDATA_CLASS(PeerConnector); public: - /// Callback dialier API to allow PeerConnector to set the answer. + /// Callback dialer API to allow PeerConnector to set the answer. class CbDialer { public: @@ -72,8 +74,6 @@ virtual Security::EncryptorAnswer &answer() = 0; }; - typedef RefCount HttpRequestPointer; - public: PeerConnector(const Comm::ConnectionPointer &aServerConn, AsyncCall::Pointer &aCallback, @@ -104,19 +104,19 @@ void setReadTimeout(); /// \returns true on successful TLS session initialization - virtual bool initializeTls(Security::SessionPointer &); + virtual bool initialize(Security::SessionPointer &); /// Performs a single secure connection negotiation step. - /// It is called multiple times untill the negotiation finish or aborted. - void negotiateSsl(); + /// It is called multiple times untill the negotiation finishes or aborts. + void negotiate(); - /// Called after SSL negotiations have finished. Cleans up SSL state. + /// Called after negotiation has finished. Cleans up TLS/SSL state. /// Returns false if we are now waiting for the certs validation job. /// Otherwise, returns true, regardless of negotiation success/failure. bool sslFinalized(); - /// Called when the SSL negotiation step aborted because data needs to - /// be transferred to/from SSL server or on error. In the first case + /// Called when the negotiation step aborted because data needs to + /// be transferred to/from server or on error. In the first case /// setups the appropriate Comm::SetSelect handler. In second case /// fill an error and report to the PeerConnector caller. void handleNegotiateError(const int result); @@ -148,7 +148,7 @@ /// \param result the SSL_connect return code /// \param ssl_error the error code returned from the SSL_get_error function /// \param ssl_lib_error the error returned from the ERR_Get_Error function - virtual void noteSslNegotiationError(const int result, const int ssl_error, const int ssl_lib_error); + virtual void noteNegotiationError(const int result, const int ssl_error, const int ssl_lib_error); /// Called when the SSL negotiation to the server completed and the certificates /// validated using the cert validator. @@ -156,7 +156,7 @@ virtual void noteNegotiationDone(ErrorState *error) {} /// Must implemented by the kid classes to return the Security::ContextPtr object to use - /// for building the SSL objects. + /// for building the encryption context objects. virtual Security::ContextPtr getSslContext() = 0; /// mimics FwdState to minimize changes to FwdState::initiate/negotiateSsl @@ -210,5 +210,5 @@ } // namespace Security -#endif /* SQUID_SRC_SSL_PEERCONNECTOR_H */ +#endif /* SQUID_SRC_SECURITY_PEERCONNECTOR_H */ diff -u -r -N squid-4.0.13/src/security/Session.cc squid-4.0.14/src/security/Session.cc --- squid-4.0.13/src/security/Session.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/security/Session.cc 2016-09-09 02:12:03.000000000 +1200 @@ -6,9 +6,12 @@ * Please see the COPYING and CONTRIBUTORS files for details. */ +/* DEBUG: section 83 TLS session management */ + #include "squid.h" #include "anyp/PortCfg.h" #include "base/RunnersRegistry.h" +#include "Debug.h" #include "ipc/MemMap.h" #include "security/Session.h" #include "SquidConfig.h" @@ -16,6 +19,66 @@ #define SSL_SESSION_ID_SIZE 32 #define SSL_SESSION_MAX_SIZE 10*1024 +bool +Security::SessionIsResumed(const Security::SessionPointer &s) +{ + bool result = false; +#if USE_OPENSSL + result = SSL_session_reused(s.get()) == 1; +#elif USE_GNUTLS + result = gnutls_session_is_resumed(s.get()) != 0; +#endif + debugs(83, 7, "session=" << (void*)s.get() << ", query? answer: " << (result ? 'T' : 'F') ); + return result; +} + +void +Security::MaybeGetSessionResumeData(const Security::SessionPointer &s, Security::SessionStatePointer &data) +{ + if (!SessionIsResumed(s)) { +#if USE_OPENSSL + // nil is valid for SSL_get1_session(), it cannot fail. + data.reset(SSL_get1_session(s.get())); +#elif USE_GNUTLS + gnutls_datum_t *tmp = nullptr; + const auto x = gnutls_session_get_data2(s.get(), tmp); + if (x != GNUTLS_E_SUCCESS) { + debugs(83, 3, "session=" << (void*)s.get() << " error: " << gnutls_strerror(x)); + } + data.reset(tmp); +#endif + debugs(83, 5, "session=" << (void*)s.get() << " data=" << (void*)data.get()); + } else { + debugs(83, 5, "session=" << (void*)s.get() << " data=" << (void*)data.get() << ", do nothing."); + } +} + +void +Security::SetSessionResumeData(const Security::SessionPointer &s, const Security::SessionStatePointer &data) +{ + if (data) { +#if USE_OPENSSL + if (!SSL_set_session(s.get(), data.get())) { + const auto ssl_error = ERR_get_error(); + debugs(83, 3, "session=" << (void*)s.get() << " data=" << (void*)data.get() << + " resume error: " << ERR_error_string(ssl_error, nullptr)); + } +#elif USE_GNUTLS + const auto x = gnutls_session_set_data(s.get(), data->data, data->size); + if (x != GNUTLS_E_SUCCESS) { + debugs(83, 3, "session=" << (void*)s.get() << " data=" << (void*)data.get() << + " resume error: " << gnutls_strerror(x)); + } +#else + // critical because, how did it get here? + debugs(83, DBG_CRITICAL, "no TLS library. session=" << (void*)s.get() << " data=" << (void*)data.get()); +#endif + debugs(83, 5, "session=" << (void*)s.get() << " data=" << (void*)data.get()); + } else { + debugs(83, 5, "session=" << (void*)s.get() << " no resume data"); + } +} + static bool isTlsServer() { diff -u -r -N squid-4.0.13/src/security/Session.h squid-4.0.14/src/security/Session.h --- squid-4.0.13/src/security/Session.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/security/Session.h 2016-09-09 02:12:03.000000000 +1200 @@ -9,6 +9,7 @@ #ifndef SQUID_SRC_SECURITY_SESSION_H #define SQUID_SRC_SECURITY_SESSION_H +#include "base/HardFun.h" #include "security/LockingPointer.h" #include @@ -32,6 +33,8 @@ CtoCpp1(SSL_free, SSL *); typedef LockingPointer SessionPointer; +typedef std::unique_ptr> SessionStatePointer; + #elif USE_GNUTLS typedef gnutls_session_t SessionPtr; // Locks can be implemented attaching locks counter to gnutls_session_t @@ -40,14 +43,38 @@ CtoCpp1(gnutls_deinit, gnutls_session_t); typedef LockingPointer SessionPointer; +// wrapper function to get around gnutls_free being a typedef +inline void squid_gnutls_free(void *d) {gnutls_free(d);} +typedef std::unique_ptr> SessionStatePointer; + #else // use void* so we can check against NULL typedef void* SessionPtr; CtoCpp1(xfree, SessionPtr); typedef LockingPointer SessionPointer; +typedef std::unique_ptr SessionStatePointer; + #endif +/// whether the session is a resumed one +bool SessionIsResumed(const Security::SessionPointer &); + +/** + * When the session is not a resumed session, retrieve the details needed to + * resume a later connection and store them in 'data'. This may result in 'data' + * becoming a nil Pointer if no details exist or an error occurs. + * + * When the session is already a resumed session, do nothing and leave 'data' + * unhanged. + * XXX: is this latter behaviour always correct? + */ +void MaybeGetSessionResumeData(const Security::SessionPointer &, Security::SessionStatePointer &data); + +/// Set the data for resuming a previous session. +/// Needs to be done before using the SessionPointer for a handshake. +void SetSessionResumeData(const Security::SessionPointer &, const Security::SessionStatePointer &); + } // namespace Security #endif /* SQUID_SRC_SECURITY_SESSION_H */ diff -u -r -N squid-4.0.13/src/ssl/PeekingPeerConnector.cc squid-4.0.14/src/ssl/PeekingPeerConnector.cc --- squid-4.0.13/src/ssl/PeekingPeerConnector.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/ssl/PeekingPeerConnector.cc 2016-09-09 02:12:03.000000000 +1200 @@ -134,9 +134,9 @@ } bool -Ssl::PeekingPeerConnector::initializeTls(Security::SessionPointer &serverSession) +Ssl::PeekingPeerConnector::initialize(Security::SessionPointer &serverSession) { - if (!Security::PeerConnector::initializeTls(serverSession)) + if (!Security::PeerConnector::initialize(serverSession)) return false; if (ConnStateData *csd = request->clientConnectionManager.valid()) { @@ -277,7 +277,7 @@ } void -Ssl::PeekingPeerConnector::noteSslNegotiationError(const int result, const int ssl_error, const int ssl_lib_error) +Ssl::PeekingPeerConnector::noteNegotiationError(const int result, const int ssl_error, const int ssl_lib_error) { const int fd = serverConnection()->fd; Security::SessionPtr ssl = fd_table[fd].ssl.get(); @@ -318,7 +318,7 @@ } // else call parent noteNegotiationError to produce an error page - Security::PeerConnector::noteSslNegotiationError(result, ssl_error, ssl_lib_error); + Security::PeerConnector::noteNegotiationError(result, ssl_error, ssl_lib_error); } void diff -u -r -N squid-4.0.13/src/ssl/PeekingPeerConnector.h squid-4.0.14/src/ssl/PeekingPeerConnector.h --- squid-4.0.13/src/ssl/PeekingPeerConnector.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/ssl/PeekingPeerConnector.h 2016-09-09 02:12:03.000000000 +1200 @@ -37,10 +37,10 @@ } /* Security::PeerConnector API */ - virtual bool initializeTls(Security::SessionPointer &); + virtual bool initialize(Security::SessionPointer &); virtual Security::ContextPtr getSslContext(); virtual void noteWantWrite(); - virtual void noteSslNegotiationError(const int result, const int ssl_error, const int ssl_lib_error); + virtual void noteNegotiationError(const int result, const int ssl_error, const int ssl_lib_error); virtual void noteNegotiationDone(ErrorState *error); /// Updates associated client connection manager members diff -u -r -N squid-4.0.13/src/ssl/support.cc squid-4.0.14/src/ssl/support.cc --- squid-4.0.13/src/ssl/support.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/ssl/support.cc 2016-09-09 02:12:03.000000000 +1200 @@ -202,9 +202,12 @@ char cn[1024]; const char *server = (const char *)check_data; - if (cn_data->length > (int)sizeof(cn) - 1) { + if (cn_data->length == 0) + return 1; // zero length cn, ignore + + if (cn_data->length > (int)sizeof(cn) - 1) return 1; //if does not fit our buffer just ignore - } + char *s = reinterpret_cast(cn_data->data); char *d = cn; for (int i = 0; i < cn_data->length; ++i, ++d, ++s) { @@ -214,7 +217,7 @@ } cn[cn_data->length] = '\0'; debugs(83, 4, "Verifying server domain " << server << " to certificate name/subjectAltName " << cn); - return matchDomainName(server, cn[0] == '*' ? cn + 1 : cn); + return matchDomainName(server, (cn[0] == '*' ? cn + 1 : cn), mdnRejectSubsubDomains); } bool Ssl::checkX509ServerValidity(X509 *cert, const char *server) @@ -286,8 +289,8 @@ broken_cert = peer_cert; Ssl::CertErrors *errs = static_cast(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)); + const int depth = X509_STORE_CTX_get_error_depth(ctx); if (!errs) { - const int depth = X509_STORE_CTX_get_error_depth(ctx); errs = new Ssl::CertErrors(Ssl::CertError(error_no, broken_cert, depth)); if (!SSL_set_ex_data(ssl, ssl_ex_index_ssl_errors, (void *)errs)) { debugs(83, 2, "Failed to set ssl error_no in ssl_verify_cb: Certificate " << buffer); @@ -295,7 +298,7 @@ errs = NULL; } } else // remember another error number - errs->push_back_unique(Ssl::CertError(error_no, broken_cert)); + errs->push_back_unique(Ssl::CertError(error_no, broken_cert, depth)); if (const char *err_descr = Ssl::GetErrorDescr(error_no)) debugs(83, 5, err_descr << ": " << buffer); @@ -1459,6 +1462,7 @@ Ssl::CertError::operator = (const CertError &old) { code = old.code; + depth = old.depth; cert.resetAndLock(old.cert.get()); return *this; } @@ -1466,13 +1470,13 @@ bool Ssl::CertError::operator == (const CertError &ce) const { - return code == ce.code && cert.get() == ce.cert.get(); + return code == ce.code && cert.get() == ce.cert.get() && depth == ce.depth; } bool Ssl::CertError::operator != (const CertError &ce) const { - return code != ce.code || cert.get() != ce.cert.get(); + return code != ce.code || cert.get() != ce.cert.get() || depth != ce.depth; } static int diff -u -r -N squid-4.0.13/src/stat.cc squid-4.0.14/src/stat.cc --- squid-4.0.13/src/stat.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/stat.cc 2016-09-09 02:12:03.000000000 +1200 @@ -288,8 +288,8 @@ if (EBIT_TEST(flags, ENTRY_SPECIAL)) strcat(buf, "SPECIAL,"); - if (EBIT_TEST(flags, ENTRY_REVALIDATE)) - strcat(buf, "REVALIDATE,"); + if (EBIT_TEST(flags, ENTRY_REVALIDATE_ALWAYS)) + strcat(buf, "REVALIDATE_ALWAYS,"); if (EBIT_TEST(flags, DELAY_SENDING)) strcat(buf, "DELAY_SENDING,"); @@ -300,6 +300,9 @@ if (EBIT_TEST(flags, REFRESH_REQUEST)) strcat(buf, "REFRESH_REQUEST,"); + if (EBIT_TEST(flags, ENTRY_REVALIDATE_STALE)) + strcat(buf, "REVALIDATE_STALE,"); + if (EBIT_TEST(flags, ENTRY_DISPATCHED)) strcat(buf, "DISPATCHED,"); diff -u -r -N squid-4.0.13/src/store/id_rewriters/file/storeid_file_rewrite.8 squid-4.0.14/src/store/id_rewriters/file/storeid_file_rewrite.8 --- squid-4.0.13/src/store/id_rewriters/file/storeid_file_rewrite.8 2016-08-06 02:26:53.000000000 +1200 +++ squid-4.0.14/src/store/id_rewriters/file/storeid_file_rewrite.8 2016-09-09 03:31:21.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "STOREID_FILE_REWRITE 8" -.TH STOREID_FILE_REWRITE 8 "2016-08-05" "perl v5.22.2" "User Contributed Perl Documentation" +.TH STOREID_FILE_REWRITE 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.0.13/src/store.cc squid-4.0.14/src/store.cc --- squid-4.0.13/src/store.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/store.cc 2016-09-09 02:12:03.000000000 +1200 @@ -2098,10 +2098,11 @@ // print only set flags, using unique letters if (e.flags) { if (EBIT_TEST(e.flags, ENTRY_SPECIAL)) os << 'S'; - if (EBIT_TEST(e.flags, ENTRY_REVALIDATE)) os << 'R'; + if (EBIT_TEST(e.flags, ENTRY_REVALIDATE_ALWAYS)) os << 'R'; if (EBIT_TEST(e.flags, DELAY_SENDING)) os << 'P'; if (EBIT_TEST(e.flags, RELEASE_REQUEST)) os << 'X'; if (EBIT_TEST(e.flags, REFRESH_REQUEST)) os << 'F'; + if (EBIT_TEST(e.flags, ENTRY_REVALIDATE_STALE)) os << 'E'; if (EBIT_TEST(e.flags, ENTRY_DISPATCHED)) os << 'D'; if (EBIT_TEST(e.flags, KEY_PRIVATE)) os << 'I'; if (EBIT_TEST(e.flags, ENTRY_FWD_HDR_WAIT)) os << 'W'; diff -u -r -N squid-4.0.13/src/tests/stub_HelperChildConfig.cc squid-4.0.14/src/tests/stub_HelperChildConfig.cc --- squid-4.0.13/src/tests/stub_HelperChildConfig.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/tests/stub_HelperChildConfig.cc 2016-09-09 02:12:03.000000000 +1200 @@ -23,6 +23,7 @@ n_running(0), n_active(0), queue_size(0), + onPersistentOverload(actDie), defaultQueueSize(true) {} @@ -34,6 +35,7 @@ n_running(0), n_active(0), queue_size(2 * m), + onPersistentOverload(actDie), defaultQueueSize(true) {} @@ -51,4 +53,5 @@ } void Helper::ChildConfig::parseConfig() STUB +Helper::ChildConfig & Helper::ChildConfig::updateLimits(const Helper::ChildConfig &) STUB_RETVAL(*this) diff -u -r -N squid-4.0.13/src/tests/stub_HttpRequest.cc squid-4.0.14/src/tests/stub_HttpRequest.cc --- squid-4.0.13/src/tests/stub_HttpRequest.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/tests/stub_HttpRequest.cc 2016-09-09 02:12:03.000000000 +1200 @@ -16,10 +16,10 @@ // void httpRequestPack(void *obj, Packable *p); HttpRequest::HttpRequest() : HttpMsg(hoRequest) {STUB} -HttpRequest::HttpRequest(const HttpRequestMethod &, AnyP::ProtocolType, const char *) : HttpMsg(hoRequest) {STUB} +HttpRequest::HttpRequest(const HttpRequestMethod &, AnyP::ProtocolType, const char *, const char *) : HttpMsg(hoRequest) {STUB} HttpRequest::~HttpRequest() STUB void HttpRequest::reset() STUB -void HttpRequest::initHTTP(const HttpRequestMethod &, AnyP::ProtocolType, const char *) STUB +void HttpRequest::initHTTP(const HttpRequestMethod &, AnyP::ProtocolType, const char *, const char *) STUB HttpRequest * HttpRequest::clone() const STUB_RETVAL(NULL) bool HttpRequest::maybeCacheable() STUB_RETVAL(false) bool HttpRequest::conditional() const STUB_RETVAL(false) diff -u -r -N squid-4.0.13/src/tests/stub_libsecurity.cc squid-4.0.14/src/tests/stub_libsecurity.cc --- squid-4.0.13/src/tests/stub_libsecurity.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/tests/stub_libsecurity.cc 2016-09-09 02:12:03.000000000 +1200 @@ -18,10 +18,11 @@ CBDATA_NAMESPACED_CLASS_INIT(Security, BlindPeerConnector); namespace Security { -bool BlindPeerConnector::initializeTls(Security::SessionPointer &) STUB_RETVAL(false) +bool BlindPeerConnector::initialize(Security::SessionPointer &) STUB_RETVAL(false) Security::ContextPtr BlindPeerConnector::getSslContext() STUB_RETVAL(nullptr) void BlindPeerConnector::noteNegotiationDone(ErrorState *) STUB } + #include "security/EncryptorAnswer.h" Security::EncryptorAnswer::~EncryptorAnswer() {} std::ostream &Security::operator <<(std::ostream &os, const Security::EncryptorAnswer &) STUB_RETVAL(os) @@ -52,13 +53,13 @@ void PeerConnector::connectionClosed(const char *) STUB bool PeerConnector::prepareSocket() STUB_RETVAL(false) void PeerConnector::setReadTimeout() STUB -bool PeerConnector::initializeTls(Security::SessionPointer &) STUB_RETVAL(false) -void PeerConnector::negotiateSsl() STUB +bool PeerConnector::initialize(Security::SessionPointer &) STUB_RETVAL(false) +void PeerConnector::negotiate() STUB bool PeerConnector::sslFinalized() STUB_RETVAL(false) void PeerConnector::handleNegotiateError(const int) STUB void PeerConnector::noteWantRead() STUB void PeerConnector::noteWantWrite() STUB -void PeerConnector::noteSslNegotiationError(const int, const int, const int) STUB +void PeerConnector::noteNegotiationError(const int, const int, const int) STUB // virtual Security::ContextPtr getSslContext() = 0; void PeerConnector::bail(ErrorState *) STUB void PeerConnector::callBack() STUB @@ -86,3 +87,10 @@ bool Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &) STUB_RETVAL(false) void Security::ServerOptions::updateContextEecdh(Security::ContextPtr &) STUB +#include "security/Session.h" +namespace Security { +bool SessionIsResumed(const Security::SessionPointer &) STUB_RETVAL(false) +void MaybeGetSessionResumeData(const Security::SessionPointer &, Security::SessionStatePointer &) STUB +void SetSessionResumeData(const Security::SessionPointer &, const Security::SessionStatePointer &) STUB +} // namespace Security + diff -u -r -N squid-4.0.13/src/tests/stub_pconn.cc squid-4.0.14/src/tests/stub_pconn.cc --- squid-4.0.13/src/tests/stub_pconn.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/tests/stub_pconn.cc 2016-09-09 02:12:03.000000000 +1200 @@ -16,11 +16,12 @@ #define STUB_API "pconn.cc" #include "tests/STUB.h" -IdleConnList::IdleConnList(const char *key, PconnPool *parent) STUB +IdleConnList::IdleConnList(const char *akey, PconnPool *parent) STUB IdleConnList::~IdleConnList() STUB void IdleConnList::push(const Comm::ConnectionPointer &conn) STUB -Comm::ConnectionPointer IdleConnList::findUseable(const Comm::ConnectionPointer &key) STUB_RETVAL(Comm::ConnectionPointer()) +Comm::ConnectionPointer IdleConnList::findUseable(const Comm::ConnectionPointer &akey) STUB_RETVAL(Comm::ConnectionPointer()) void IdleConnList::clearHandlers(const Comm::ConnectionPointer &conn) STUB +void IdleConnList::endingShutdown() STUB PconnPool::PconnPool(const char *, const CbcPointer&) STUB PconnPool::~PconnPool() STUB void PconnPool::moduleInit() STUB diff -u -r -N squid-4.0.13/src/tests/testUriScheme.cc squid-4.0.14/src/tests/testUriScheme.cc --- squid-4.0.13/src/tests/testUriScheme.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/tests/testUriScheme.cc 2016-09-09 02:12:03.000000000 +1200 @@ -112,9 +112,9 @@ void testUriScheme::testC_str() { - String lhs("wais"); + SBuf lhs("wais"); AnyP::UriScheme wais(AnyP::PROTO_WAIS); - String rhs(wais.c_str()); + SBuf rhs(wais.image()); CPPUNIT_ASSERT_EQUAL(lhs, rhs); } diff -u -r -N squid-4.0.13/src/tunnel.cc squid-4.0.14/src/tunnel.cc --- squid-4.0.13/src/tunnel.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/tunnel.cc 2016-09-09 02:12:03.000000000 +1200 @@ -174,7 +174,7 @@ void connectToPeer(); private: - /// Gives PeerConnector access to Answer in the TunnelStateData callback dialer. + /// Gives Security::PeerConnector access to Answer in the TunnelStateData callback dialer. class MyAnswerDialer: public CallDialer, public Security::PeerConnector::CbDialer { public: @@ -499,7 +499,7 @@ // we need to relay the 401/407 responses when login=PASS(THRU) const char *pwd = server.conn->getPeer()->login; - const bool relay = pwd && (strcmp(pwd, "PASS") != 0 || strcmp(pwd, "PASSTHRU") != 0) && + const bool relay = pwd && (strcmp(pwd, "PASS") == 0 || strcmp(pwd, "PASSTHRU") == 0) && (*status_ptr == Http::scProxyAuthenticationRequired || *status_ptr == Http::scUnauthorized); diff -u -r -N squid-4.0.13/src/url.cc squid-4.0.14/src/url.cc --- squid-4.0.13/src/url.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/url.cc 2016-09-09 02:12:03.000000000 +1200 @@ -18,6 +18,7 @@ static HttpRequest *urlParseFinish(const HttpRequestMethod& method, const AnyP::ProtocolType protocol, + const char *const protoStr, const char *const urlpath, const char *const host, const SBuf &login, @@ -96,6 +97,7 @@ assert(0 == matchDomainName("foo.com", ".foo.com")); assert(0 == matchDomainName(".foo.com", ".foo.com")); assert(0 == matchDomainName("x.foo.com", ".foo.com")); + assert(0 == matchDomainName("y.x.foo.com", ".foo.com")); assert(0 != matchDomainName("x.foo.com", "foo.com")); assert(0 != matchDomainName("foo.com", "x.foo.com")); assert(0 != matchDomainName("bar.com", "foo.com")); @@ -108,6 +110,17 @@ assert(0 < matchDomainName("bfoo.com", "afoo.com")); assert(0 > matchDomainName("afoo.com", "bfoo.com")); assert(0 < matchDomainName("x-foo.com", ".foo.com")); + + assert(0 == matchDomainName(".foo.com", ".foo.com", mdnRejectSubsubDomains)); + assert(0 == matchDomainName("x.foo.com", ".foo.com", mdnRejectSubsubDomains)); + assert(0 != matchDomainName("y.x.foo.com", ".foo.com", mdnRejectSubsubDomains)); + assert(0 != matchDomainName(".x.foo.com", ".foo.com", mdnRejectSubsubDomains)); + + assert(0 == matchDomainName("*.foo.com", "x.foo.com", mdnHonorWildcards)); + assert(0 == matchDomainName("*.foo.com", ".x.foo.com", mdnHonorWildcards)); + assert(0 == matchDomainName("*.foo.com", ".foo.com", mdnHonorWildcards)); + assert(0 != matchDomainName("*.foo.com", "foo.com", mdnHonorWildcards)); + /* more cases? */ } @@ -157,6 +170,9 @@ if (strncasecmp(b, "whois", len) == 0) return AnyP::PROTO_WHOIS; + if (len > 0) + return AnyP::PROTO_UNKNOWN; + return AnyP::PROTO_NONE; } @@ -214,8 +230,8 @@ } else if ((method == Http::METHOD_OPTIONS || method == Http::METHOD_TRACE) && URL::Asterisk().cmp(url) == 0) { protocol = AnyP::PROTO_HTTP; - port = AnyP::UriScheme(protocol).defaultPort(); - return urlParseFinish(method, protocol, url, host, SBuf(), port, request); + port = 80; // or the slow way ... AnyP::UriScheme(protocol,"http").defaultPort(); + return urlParseFinish(method, protocol, "http", url, host, SBuf(), port, request); } else if (!strncmp(url, "urn:", 4)) { return urnParse(method, url, request); } else { @@ -422,7 +438,7 @@ } } - return urlParseFinish(method, protocol, urlpath, host, SBuf(login), port, request); + return urlParseFinish(method, protocol, proto, urlpath, host, SBuf(login), port, request); } /** @@ -433,6 +449,7 @@ static HttpRequest * urlParseFinish(const HttpRequestMethod& method, const AnyP::ProtocolType protocol, + const char *const protoStr, // for unknown protocols const char *const urlpath, const char *const host, const SBuf &login, @@ -440,9 +457,9 @@ HttpRequest *request) { if (NULL == request) - request = new HttpRequest(method, protocol, urlpath); + request = new HttpRequest(method, protocol, protoStr, urlpath); else { - request->initHTTP(method, protocol, urlpath); + request->initHTTP(method, protocol, protoStr, urlpath); } request->url.host(host); @@ -456,11 +473,11 @@ { debugs(50, 5, "urnParse: " << urn); if (request) { - request->initHTTP(method, AnyP::PROTO_URN, urn + 4); + request->initHTTP(method, AnyP::PROTO_URN, "urn", urn + 4); return request; } - return new HttpRequest(method, AnyP::PROTO_URN, urn + 4); + return new HttpRequest(method, AnyP::PROTO_URN, "urn", urn + 4); } void @@ -496,7 +513,8 @@ // TODO: most URL will be much shorter, avoid allocating this much absolute_.reserveCapacity(MAX_URL); - absolute_.appendf("%s:", getScheme().c_str()); + absolute_.append(getScheme().image()); + absolute_.append(":",1); if (getScheme() != AnyP::PROTO_URN) { absolute_.append("//", 2); const bool omitUserInfo = getScheme() == AnyP::PROTO_HTTP || @@ -620,8 +638,9 @@ } SBuf authorityForm = req->url.authority(); // host[:port] - size_t urllen = snprintf(urlbuf, MAX_URL, "%s://" SQUIDSBUFPH "%s" SQUIDSBUFPH, - req->url.getScheme().c_str(), + const SBuf &scheme = req->url.getScheme().image(); + size_t urllen = snprintf(urlbuf, MAX_URL, SQUIDSBUFPH "://" SQUIDSBUFPH "%s" SQUIDSBUFPH, + SQUIDSBUFPRINT(scheme), SQUIDSBUFPRINT(req->url.userInfo()), !req->url.userInfo().isEmpty() ? "@" : "", SQUIDSBUFPRINT(authorityForm)); @@ -660,16 +679,20 @@ } int -matchDomainName(const char *h, const char *d, bool honorWildcards) +matchDomainName(const char *h, const char *d, uint flags) { int dl; int hl; + const bool hostIncludesSubdomains = (*h == '.'); while ('.' == *h) ++h; hl = strlen(h); + if (hl == 0) + return -1; + dl = strlen(d); /* @@ -707,9 +730,20 @@ * is a leading '.'. */ - if ('.' == d[0]) - return 0; - else + if ('.' == d[0]) { + if (flags & mdnRejectSubsubDomains) { + // Check for sub-sub domain and reject + while(--hl >= 0 && h[hl] != '.'); + if (hl < 0) { + // No sub-sub domain found, but reject if there is a + // leading dot in given host string (which is removed + // before the check is started). + return hostIncludesSubdomains ? 1 : 0; + } else + return 1; // sub-sub domain, reject + } else + return 0; + } else return 1; } } @@ -721,7 +755,7 @@ // If the h has a form of "*.foo.com" and d has a form of "x.foo.com" // then the h[hl] points to '*', h[hl+1] to '.' and d[dl] to 'x' // The following checks are safe, the "h[hl + 1]" in the worst case is '\0'. - if (honorWildcards && h[hl] == '*' && h[hl + 1] == '.') + if ((flags & mdnHonorWildcards) && h[hl] == '*' && h[hl + 1] == '.') return 0; /* @@ -797,11 +831,7 @@ case AnyP::PROTO_HTTPS: #if USE_OPENSSL - rc = 1; - - break; - #else /* * Squid can't originate an SSL connection, so it should @@ -809,8 +839,8 @@ * CONNECT instead. */ rc = 0; - #endif + break; default: break; diff -u -r -N squid-4.0.13/src/URL.h squid-4.0.14/src/URL.h --- squid-4.0.13/src/URL.h 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/URL.h 2016-09-09 02:12:03.000000000 +1200 @@ -28,6 +28,20 @@ public: URL() : hostIsNumeric_(false), port_(0) {*host_=0;} URL(AnyP::UriScheme const &aScheme); + URL(const URL &other) { + this->operator =(other); + } + URL &operator =(const URL &o) { + scheme_ = o.scheme_; + userInfo_ = o.userInfo_; + memcpy(host_, o.host_, sizeof(host_)); + hostIsNumeric_ = o.hostIsNumeric_; + hostAddr_ = o.hostAddr_; + port_ = o.port_; + path_ = o.path_; + touch(); + return *this; + } void clear() { scheme_=AnyP::PROTO_NONE; @@ -42,7 +56,10 @@ AnyP::UriScheme const & getScheme() const {return scheme_;} /// convert the URL scheme to that given - void setScheme(const AnyP::ProtocolType &p) {scheme_=p; touch();} + void setScheme(const AnyP::ProtocolType &p, const char *str) { + scheme_ = AnyP::UriScheme(p, str); + touch(); + } void userInfo(const SBuf &s) {userInfo_=s; touch();} const SBuf &userInfo() const {return userInfo_;} @@ -131,9 +148,17 @@ inline std::ostream & operator <<(std::ostream &os, const URL &url) { - if (const char *sc = url.getScheme().c_str()) - os << sc << ":"; - os << "//" << url.authority() << url.path(); + // none means explicit empty string for scheme. + if (url.getScheme() != AnyP::PROTO_NONE) + os << url.getScheme().image(); + os << ":"; + + // no authority section on URN + if (url.getScheme() != AnyP::PROTO_URN) + os << "//" << url.authority(); + + // path is what it is - including absent + os << url.path(); return os; } @@ -149,23 +174,29 @@ char *urlRInternal(const char *host, unsigned short port, const char *dir, const char *name); char *urlInternal(const char *dir, const char *name); +enum MatchDomainNameFlags { + mdnNone = 0, + mdnHonorWildcards = 1 << 0, + mdnRejectSubsubDomains = 1 << 1 +}; + /** - * matchDomainName() compares a hostname (usually extracted from traffic) - * with a domainname (usually from an ACL) according to the following rules: + * matchDomainName() matches a hostname (usually extracted from traffic) + * with a domainname when mdnNone or mdnRejectSubsubDomains flags are used + * according to the following rules: * - * HOST | DOMAIN | MATCH? - * -------------|-------------|------ - * foo.com | foo.com | YES - * .foo.com | foo.com | YES - * x.foo.com | foo.com | NO - * foo.com | .foo.com | YES - * .foo.com | .foo.com | YES - * x.foo.com | .foo.com | YES + * HOST | DOMAIN | mdnNone | mdnRejectSubsubDomains + * -------------|-------------|-----------|----------------------- + * foo.com | foo.com | YES | YES + * .foo.com | foo.com | YES | YES + * x.foo.com | foo.com | NO | NO + * foo.com | .foo.com | YES | YES + * .foo.com | .foo.com | YES | YES + * x.foo.com | .foo.com | YES | YES + * .x.foo.com | .foo.com | YES | NO + * y.x.foo.com | .foo.com | YES | NO * - * We strip leading dots on hosts (but not domains!) so that - * ".foo.com" is always the same as "foo.com". - * - * if honorWildcards is true then the matchDomainName() also accepts + * if mdnHonorWildcards flag is set then the matchDomainName() also accepts * optional wildcards on hostname: * * HOST | DOMAIN | MATCH? @@ -175,11 +206,14 @@ * *.foo.com | .foo.com | YES * *.foo.com | foo.com | NO * + * The combination of mdnHonorWildcards and mdnRejectSubsubDomains flags is + * supported. + * * \retval 0 means the host matches the domain * \retval 1 means the host is greater than the domain * \retval -1 means the host is less than the domain */ -int matchDomainName(const char *host, const char *domain, bool honorWildcards = false); +int matchDomainName(const char *host, const char *domain, uint flags = mdnNone); int urlCheckRequest(const HttpRequest *); char *urlHostname(const char *url); void urlExtMethodConfigure(void); diff -u -r -N squid-4.0.13/src/urn.cc squid-4.0.14/src/urn.cc --- squid-4.0.13/src/urn.cc 2016-08-06 00:52:55.000000000 +1200 +++ squid-4.0.14/src/urn.cc 2016-09-09 02:12:03.000000000 +1200 @@ -318,12 +318,7 @@ urls = urnParseReply(s, urnState->request->method); - for (i = 0; NULL != urls[i].url; ++i) - ++urlcnt; - - debugs(53, 3, "urnFindMinRtt: Counted " << i << " URLs"); - - if (urls == NULL) { /* unknown URN error */ + if (!urls) { /* unknown URN error */ debugs(52, 3, "urnTranslateDone: unknown URN " << e->url()); err = new ErrorState(ERR_URN_RESOLVE, Http::scNotFound, urnState->request.getRaw()); err->url = xstrdup(e->url()); @@ -332,6 +327,11 @@ return; } + for (i = 0; urls[i].url; ++i) + ++urlcnt; + + debugs(53, 3, "urnFindMinRtt: Counted " << i << " URLs"); + min_u = urnFindMinRtt(urls, urnState->request->method, NULL); qsort(urls, urlcnt, sizeof(*urls), url_entry_sort); e->buffer(); diff -u -r -N squid-4.0.13/tools/helper-mux/helper-mux.8 squid-4.0.14/tools/helper-mux/helper-mux.8 --- squid-4.0.13/tools/helper-mux/helper-mux.8 2016-08-06 02:29:36.000000000 +1200 +++ squid-4.0.14/tools/helper-mux/helper-mux.8 2016-09-09 03:33:04.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "HELPER-MUX 8" -.TH HELPER-MUX 8 "2016-08-05" "perl v5.22.2" "User Contributed Perl Documentation" +.TH HELPER-MUX 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l