diff -u -r -N squid-3.5.20/aclocal.m4 squid-3.5.21/aclocal.m4
--- squid-3.5.20/aclocal.m4	2016-07-01 23:38:43.000000000 +1200
+++ squid-3.5.21/aclocal.m4	2016-09-09 06:58:28.000000000 +1200
@@ -744,7 +744,6 @@
     cat <<_LT_EOF >> "$cfgfile"
 #! $SHELL
 # Generated automatically by $as_me ($PACKAGE) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
 
 # Provide generalized library-building support services.
diff -u -r -N squid-3.5.20/cfgaux/ltmain.sh squid-3.5.21/cfgaux/ltmain.sh
--- squid-3.5.20/cfgaux/ltmain.sh	2016-07-01 23:38:54.000000000 +1200
+++ squid-3.5.21/cfgaux/ltmain.sh	2016-09-09 06:58:46.000000000 +1200
@@ -31,7 +31,7 @@
 
 PROGRAM=libtool
 PACKAGE=libtool
-VERSION="2.4.6 Debian-2.4.6-0.1"
+VERSION="2.4.6 Debian-2.4.6-2"
 package_revision=2.4.6
 
 
@@ -2068,7 +2068,7 @@
        compiler:       $LTCC
        compiler flags: $LTCFLAGS
        linker:         $LD (gnu? $with_gnu_ld)
-       version:        $progname (GNU libtool) 2.4.6
+       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-3.5.20/ChangeLog squid-3.5.21/ChangeLog
--- squid-3.5.20/ChangeLog	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/ChangeLog	2016-09-09 06:56:46.000000000 +1200
@@ -1,3 +1,16 @@
+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-3.5.20/configure squid-3.5.21/configure
--- squid-3.5.20/configure	2016-07-01 23:40:16.000000000 +1200
+++ squid-3.5.21/configure	2016-09-09 07:00:42.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 3.5.20.
+# Generated by GNU Autoconf 2.69 for Squid Web Proxy 3.5.21.
 #
 # Report bugs to <http://bugs.squid-cache.org/>.
 #
@@ -595,8 +595,8 @@
 # Identity of this package.
 PACKAGE_NAME='Squid Web Proxy'
 PACKAGE_TARNAME='squid'
-PACKAGE_VERSION='3.5.20'
-PACKAGE_STRING='Squid Web Proxy 3.5.20'
+PACKAGE_VERSION='3.5.21'
+PACKAGE_STRING='Squid Web Proxy 3.5.21'
 PACKAGE_BUGREPORT='http://bugs.squid-cache.org/'
 PACKAGE_URL=''
 
@@ -1636,7 +1636,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 3.5.20 to adapt to many kinds of systems.
+\`configure' configures Squid Web Proxy 3.5.21 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1707,7 +1707,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Squid Web Proxy 3.5.20:";;
+     short | recursive ) echo "Configuration of Squid Web Proxy 3.5.21:";;
    esac
   cat <<\_ACEOF
 
@@ -2119,7 +2119,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Squid Web Proxy configure 3.5.20
+Squid Web Proxy configure 3.5.21
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -3223,7 +3223,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 3.5.20, which was
+It was created by Squid Web Proxy $as_me 3.5.21, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -4090,7 +4090,7 @@
 
 # Define the identity of the package.
  PACKAGE='squid'
- VERSION='3.5.20'
+ VERSION='3.5.21'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -41876,7 +41876,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 3.5.20, which was
+This file was extended by Squid Web Proxy $as_me 3.5.21, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -41942,7 +41942,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 3.5.20
+Squid Web Proxy config.status 3.5.21
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -43262,7 +43262,6 @@
     cat <<_LT_EOF >> "$cfgfile"
 #! $SHELL
 # Generated automatically by $as_me ($PACKAGE) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
 
 # Provide generalized library-building support services.
diff -u -r -N squid-3.5.20/configure.ac squid-3.5.21/configure.ac
--- squid-3.5.20/configure.ac	2016-07-01 23:40:16.000000000 +1200
+++ squid-3.5.21/configure.ac	2016-09-09 07:00:41.000000000 +1200
@@ -5,7 +5,7 @@
 ## Please see the COPYING and CONTRIBUTORS files for details.
 ##
 
-AC_INIT([Squid Web Proxy],[3.5.20],[http://bugs.squid-cache.org/],[squid])
+AC_INIT([Squid Web Proxy],[3.5.21],[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-3.5.20/doc/release-notes/release-3.5.html squid-3.5.21/doc/release-notes/release-3.5.html
--- squid-3.5.20/doc/release-notes/release-3.5.html	2016-07-02 00:30:54.000000000 +1200
+++ squid-3.5.21/doc/release-notes/release-3.5.html	2016-09-09 08:06:08.000000000 +1200
@@ -2,10 +2,10 @@
 <HTML>
 <HEAD>
  <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.72">
- <TITLE>Squid 3.5.20 release notes</TITLE>
+ <TITLE>Squid 3.5.21 release notes</TITLE>
 </HEAD>
 <BODY>
-<H1>Squid 3.5.20 release notes</H1>
+<H1>Squid 3.5.21 release notes</H1>
 
 <H2>Squid Developers</H2>
 <HR>
@@ -64,7 +64,7 @@
 <HR>
 <H2><A NAME="s1">1.</A> <A HREF="#toc1">Notice</A></H2>
 
-<P>The Squid Team are pleased to announce the release of Squid-3.5.20.</P>
+<P>The Squid Team are pleased to announce the release of Squid-3.5.21.</P>
 <P>This new release is available for download from 
 <A HREF="http://www.squid-cache.org/Versions/v3/3.5/">http://www.squid-cache.org/Versions/v3/3.5/</A> or the
 <A HREF="http://www.squid-cache.org/Download/http-mirrors.html">mirrors</A>.</P>
diff -u -r -N squid-3.5.20/helpers/basic_auth/DB/basic_db_auth.8 squid-3.5.21/helpers/basic_auth/DB/basic_db_auth.8
--- squid-3.5.20/helpers/basic_auth/DB/basic_db_auth.8	2016-07-02 00:30:59.000000000 +1200
+++ squid-3.5.21/helpers/basic_auth/DB/basic_db_auth.8	2016-09-09 08:06:12.000000000 +1200
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "BASIC_DB_AUTH 8"
-.TH BASIC_DB_AUTH 8 "2016-07-01" "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-3.5.20/helpers/basic_auth/MSNT-multi-domain/basic_msnt_multi_domain_auth.8 squid-3.5.21/helpers/basic_auth/MSNT-multi-domain/basic_msnt_multi_domain_auth.8
--- squid-3.5.20/helpers/basic_auth/MSNT-multi-domain/basic_msnt_multi_domain_auth.8	2016-07-02 00:31:06.000000000 +1200
+++ squid-3.5.21/helpers/basic_auth/MSNT-multi-domain/basic_msnt_multi_domain_auth.8	2016-09-09 08:06:18.000000000 +1200
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "BASIC_MSNT_MULTI_DOMAIN_AUTH 1"
-.TH BASIC_MSNT_MULTI_DOMAIN_AUTH 1 "2016-07-01" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH BASIC_MSNT_MULTI_DOMAIN_AUTH 1 "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-3.5.20/helpers/basic_auth/POP3/basic_pop3_auth.8 squid-3.5.21/helpers/basic_auth/POP3/basic_pop3_auth.8
--- squid-3.5.20/helpers/basic_auth/POP3/basic_pop3_auth.8	2016-07-02 00:31:13.000000000 +1200
+++ squid-3.5.21/helpers/basic_auth/POP3/basic_pop3_auth.8	2016-09-09 08:06:24.000000000 +1200
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "BASIC_POP3_AUTH 8"
-.TH BASIC_POP3_AUTH 8 "2016-07-01" "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-3.5.20/helpers/external_acl/delayer/ext_delayer_acl.8 squid-3.5.21/helpers/external_acl/delayer/ext_delayer_acl.8
--- squid-3.5.20/helpers/external_acl/delayer/ext_delayer_acl.8	2016-07-02 00:31:28.000000000 +1200
+++ squid-3.5.21/helpers/external_acl/delayer/ext_delayer_acl.8	2016-09-09 08:06:41.000000000 +1200
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_DELAYER_ACL 8"
-.TH EXT_DELAYER_ACL 8 "2016-07-01" "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-3.5.20/helpers/external_acl/SQL_session/ext_sql_session_acl.8 squid-3.5.21/helpers/external_acl/SQL_session/ext_sql_session_acl.8
--- squid-3.5.20/helpers/external_acl/SQL_session/ext_sql_session_acl.8	2016-07-02 00:31:36.000000000 +1200
+++ squid-3.5.21/helpers/external_acl/SQL_session/ext_sql_session_acl.8	2016-09-09 08:06:50.000000000 +1200
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_SQL_SESSION_ACL 8"
-.TH EXT_SQL_SESSION_ACL 8 "2016-07-01" "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-3.5.20/helpers/external_acl/wbinfo_group/ext_wbinfo_group_acl.8 squid-3.5.21/helpers/external_acl/wbinfo_group/ext_wbinfo_group_acl.8
--- squid-3.5.20/helpers/external_acl/wbinfo_group/ext_wbinfo_group_acl.8	2016-07-02 00:31:40.000000000 +1200
+++ squid-3.5.21/helpers/external_acl/wbinfo_group/ext_wbinfo_group_acl.8	2016-09-09 08:06:55.000000000 +1200
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_WBINFO_GROUP_ACL 8"
-.TH EXT_WBINFO_GROUP_ACL 8 "2016-07-01" "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-3.5.20/helpers/log_daemon/DB/log_db_daemon.8 squid-3.5.21/helpers/log_daemon/DB/log_db_daemon.8
--- squid-3.5.20/helpers/log_daemon/DB/log_db_daemon.8	2016-07-02 00:31:43.000000000 +1200
+++ squid-3.5.21/helpers/log_daemon/DB/log_db_daemon.8	2016-09-09 08:06:58.000000000 +1200
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "LOG_DB_DAEMON 8"
-.TH LOG_DB_DAEMON 8 "2016-07-01" "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-3.5.20/helpers/storeid_rewrite/file/storeid_file_rewrite.8 squid-3.5.21/helpers/storeid_rewrite/file/storeid_file_rewrite.8
--- squid-3.5.20/helpers/storeid_rewrite/file/storeid_file_rewrite.8	2016-07-02 00:31:58.000000000 +1200
+++ squid-3.5.21/helpers/storeid_rewrite/file/storeid_file_rewrite.8	2016-09-09 08:07:15.000000000 +1200
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "STOREID_FILE_REWRITE 8"
-.TH STOREID_FILE_REWRITE 8 "2016-07-01" "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-3.5.20/include/version.h squid-3.5.21/include/version.h
--- squid-3.5.20/include/version.h	2016-07-01 23:40:17.000000000 +1200
+++ squid-3.5.21/include/version.h	2016-09-09 07:00:42.000000000 +1200
@@ -7,7 +7,7 @@
  */
 
 #ifndef SQUID_RELEASE_TIME
-#define SQUID_RELEASE_TIME 1467373063
+#define SQUID_RELEASE_TIME 1473360998
 #endif
 
 /*
diff -u -r -N squid-3.5.20/libltdl/configure squid-3.5.21/libltdl/configure
--- squid-3.5.20/libltdl/configure	2016-07-01 23:50:44.000000000 +1200
+++ squid-3.5.21/libltdl/configure	2016-09-09 07:19:37.000000000 +1200
@@ -14975,7 +14975,6 @@
     cat <<_LT_EOF >> "$cfgfile"
 #! $SHELL
 # Generated automatically by $as_me ($PACKAGE) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
 
 # Provide generalized library-building support services.
diff -u -r -N squid-3.5.20/libltdl/m4/libtool.m4 squid-3.5.21/libltdl/m4/libtool.m4
--- squid-3.5.20/libltdl/m4/libtool.m4	2016-07-01 23:38:55.000000000 +1200
+++ squid-3.5.21/libltdl/m4/libtool.m4	2016-09-09 06:58:47.000000000 +1200
@@ -728,7 +728,6 @@
     cat <<_LT_EOF >> "$cfgfile"
 #! $SHELL
 # Generated automatically by $as_me ($PACKAGE) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
 
 # Provide generalized library-building support services.
diff -u -r -N squid-3.5.20/RELEASENOTES.html squid-3.5.21/RELEASENOTES.html
--- squid-3.5.20/RELEASENOTES.html	2016-07-02 00:30:54.000000000 +1200
+++ squid-3.5.21/RELEASENOTES.html	2016-09-09 08:06:08.000000000 +1200
@@ -2,10 +2,10 @@
 <HTML>
 <HEAD>
  <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.72">
- <TITLE>Squid 3.5.20 release notes</TITLE>
+ <TITLE>Squid 3.5.21 release notes</TITLE>
 </HEAD>
 <BODY>
-<H1>Squid 3.5.20 release notes</H1>
+<H1>Squid 3.5.21 release notes</H1>
 
 <H2>Squid Developers</H2>
 <HR>
@@ -64,7 +64,7 @@
 <HR>
 <H2><A NAME="s1">1.</A> <A HREF="#toc1">Notice</A></H2>
 
-<P>The Squid Team are pleased to announce the release of Squid-3.5.20.</P>
+<P>The Squid Team are pleased to announce the release of Squid-3.5.21.</P>
 <P>This new release is available for download from 
 <A HREF="http://www.squid-cache.org/Versions/v3/3.5/">http://www.squid-cache.org/Versions/v3/3.5/</A> or the
 <A HREF="http://www.squid-cache.org/Download/http-mirrors.html">mirrors</A>.</P>
diff -u -r -N squid-3.5.20/src/acl/ServerName.cc squid-3.5.21/src/acl/ServerName.cc
--- squid-3.5.20/src/acl/ServerName.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/acl/ServerName.cc	2016-09-09 06:56:46.000000000 +1200
@@ -30,7 +30,7 @@
     const char *h = static_cast<const char *>(a);
     const char *d = static_cast<const char *>(b);
     debugs(28, 7, "Match:" << h << " <>  " << d);
-    return matchDomainName(h, d, true);
+    return matchDomainName(h, d, mdnHonorWildcards);
 }
 
 bool
diff -u -r -N squid-3.5.20/src/auth/User.cc squid-3.5.21/src/auth/User.cc
--- squid-3.5.20/src/auth/User.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/auth/User.cc	2016-09-09 06:56:46.000000000 +1200
@@ -284,7 +284,7 @@
             /* This ip has already been seen. */
             found = 1;
             /* update IP ttl */
-            ipdata->ip_expiretime = squid_curtime;
+            ipdata->ip_expiretime = squid_curtime + ::Config.authenticateIpTTL;
         } else if (ipdata->ip_expiretime <= squid_curtime) {
             /* This IP has expired - remove from the seen list */
             dlinkDelete(&ipdata->node, &ip_list);
diff -u -r -N squid-3.5.20/src/CacheDigest.cc squid-3.5.21/src/CacheDigest.cc
--- squid-3.5.20/src/CacheDigest.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/CacheDigest.cc	2016-09-09 06:56:46.000000000 +1200
@@ -35,12 +35,12 @@
 static uint32_t hashed_keys[4];
 
 static void
-cacheDigestInit(CacheDigest * cd, int capacity, int bpe)
+cacheDigestInit(CacheDigest * cd, uint64_t capacity, uint8_t bpe)
 {
-    const size_t mask_size = cacheDigestCalcMaskSize(capacity, bpe);
+    const uint32_t mask_size = cacheDigestCalcMaskSize(capacity, bpe);
     assert(cd);
     assert(capacity > 0 && bpe > 0);
-    assert(mask_size > 0);
+    assert(mask_size != 0);
     cd->capacity = capacity;
     cd->bits_per_entry = bpe;
     cd->mask_size = mask_size;
@@ -50,7 +50,7 @@
 }
 
 CacheDigest *
-cacheDigestCreate(int capacity, int bpe)
+cacheDigestCreate(uint64_t capacity, uint8_t bpe)
 {
     CacheDigest *cd = (CacheDigest *)memAllocate(MEM_CACHE_DIGEST);
     assert(SQUID_MD5_DIGEST_LENGTH == 16);  /* our hash functions rely on 16 byte keys */
@@ -97,7 +97,7 @@
 
 /* changes mask size, resets bits to 0, preserves "cd" pointer */
 void
-cacheDigestChangeCap(CacheDigest * cd, int new_cap)
+cacheDigestChangeCap(CacheDigest * cd, uint64_t new_cap)
 {
     assert(cd);
     cacheDigestClean(cd);
@@ -278,12 +278,12 @@
     storeAppendPrintf(e, "%s digest: size: %d bytes\n",
                       label ? label : "", stats.bit_count / 8
                      );
-    storeAppendPrintf(e, "\t entries: count: %d capacity: %d util: %d%%\n",
+    storeAppendPrintf(e, "\t entries: count: %" PRIu64 " capacity: %" PRIu64 " util: %d%%\n",
                       cd->count,
                       cd->capacity,
                       xpercentInt(cd->count, cd->capacity)
                      );
-    storeAppendPrintf(e, "\t deletion attempts: %d\n",
+    storeAppendPrintf(e, "\t deletion attempts: %" PRIu64 "\n",
                       cd->del_count
                      );
     storeAppendPrintf(e, "\t bits: per entry: %d on: %d capacity: %d util: %d%%\n",
@@ -297,16 +297,18 @@
                      );
 }
 
-size_t
-cacheDigestCalcMaskSize(int cap, int bpe)
+uint32_t
+cacheDigestCalcMaskSize(uint64_t cap, uint8_t bpe)
 {
-    return (size_t) (cap * bpe + 7) / 8;
+    uint64_t bitCount = (cap * bpe) + 7;
+    assert(bitCount < INT_MAX); // dont 31-bit overflow later
+    return static_cast<uint32_t>(bitCount / 8);
 }
 
 static void
 cacheDigestHashKey(const CacheDigest * cd, const cache_key * key)
 {
-    const unsigned int bit_count = cd->mask_size * 8;
+    const uint32_t bit_count = cd->mask_size * 8;
     unsigned int tmp_keys[4];
     /* we must memcpy to ensure alignment */
     memcpy(tmp_keys, key, sizeof(tmp_keys));
diff -u -r -N squid-3.5.20/src/CacheDigest.h squid-3.5.21/src/CacheDigest.h
--- squid-3.5.20/src/CacheDigest.h	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/CacheDigest.h	2016-09-09 06:56:46.000000000 +1200
@@ -22,23 +22,23 @@
 {
 public:
     /* public, read-only */
-    char *mask;         /* bit mask */
-    int mask_size;      /* mask size in bytes */
-    int capacity;       /* expected maximum for .count, not a hard limit */
-    int bits_per_entry;     /* number of bits allocated for each entry from capacity */
-    int count;          /* number of digested entries */
-    int del_count;      /* number of deletions performed so far */
+    uint64_t count;          /* number of digested entries */
+    uint64_t del_count;      /* number of deletions performed so far */
+    uint64_t capacity;       /* expected maximum for .count, not a hard limit */
+    char *mask;              /* bit mask */
+    uint32_t mask_size;      /* mask size in bytes */
+    int8_t bits_per_entry;   /* number of bits allocated for each entry from capacity */
 };
 
-CacheDigest *cacheDigestCreate(int capacity, int bpe);
+CacheDigest *cacheDigestCreate(uint64_t capacity, uint8_t bpe);
 void cacheDigestDestroy(CacheDigest * cd);
 CacheDigest *cacheDigestClone(const CacheDigest * cd);
 void cacheDigestClear(CacheDigest * cd);
-void cacheDigestChangeCap(CacheDigest * cd, int new_cap);
+void cacheDigestChangeCap(CacheDigest * cd, uint64_t new_cap);
 int cacheDigestTest(const CacheDigest * cd, const cache_key * key);
 void cacheDigestAdd(CacheDigest * cd, const cache_key * key);
 void cacheDigestDel(CacheDigest * cd, const cache_key * key);
-size_t cacheDigestCalcMaskSize(int cap, int bpe);
+uint32_t cacheDigestCalcMaskSize(uint64_t cap, uint8_t bpe);
 int cacheDigestBitUtil(const CacheDigest * cd);
 void cacheDigestGuessStatsUpdate(CacheDigestGuessStats * stats, int real_hit, int guess_hit);
 void cacheDigestGuessStatsReport(const CacheDigestGuessStats * stats, StoreEntry * sentry, const char *label);
diff -u -r -N squid-3.5.20/src/clients/FtpClient.cc squid-3.5.21/src/clients/FtpClient.cc
--- squid-3.5.20/src/clients/FtpClient.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/clients/FtpClient.cc	2016-09-09 06:56:46.000000000 +1200
@@ -314,6 +314,11 @@
         /* We've already read some reply data */
         handleControlReply();
     } else {
+
+        if (!Comm::IsConnOpen(ctrl.conn)) {
+            debugs(9, 3, "cannot read without ctrl " << ctrl.conn);
+            return;
+        }
         /*
          * Cancel the timeout on the Data socket (if any) and
          * establish one on the control socket.
diff -u -r -N squid-3.5.20/src/client_side_reply.cc squid-3.5.21/src/client_side_reply.cc
--- squid-3.5.20/src/client_side_reply.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/client_side_reply.cc	2016-09-09 06:56:46.000000000 +1200
@@ -1305,8 +1305,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(HDR_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(HDR_PROXY_AUTHENTICATE);
+    }
 
     reply->header.removeHopByHopEntries();
 
diff -u -r -N squid-3.5.20/src/client_side_request.cc squid-3.5.21/src/client_side_request.cc
--- squid-3.5.20/src/client_side_request.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/client_side_request.cc	2016-09-09 06:56:46.000000000 +1200
@@ -1811,7 +1811,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-3.5.20/src/client_side_request.h squid-3.5.21/src/client_side_request.h
--- squid-3.5.20/src/client_side_request.h	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/client_side_request.h	2016-09-09 06:56:46.000000000 +1200
@@ -140,6 +140,7 @@
 
 public:
     void startAdaptation(const Adaptation::ServiceGroupPointer &g);
+    bool requestSatisfactionMode() const { return request_satisfaction_mode; }
 
     // private but exposed for ClientRequestContext
     void handleAdaptationFailure(int errDetail, bool bypassable = false);
diff -u -r -N squid-3.5.20/src/enums.h squid-3.5.21/src/enums.h
--- squid-3.5.20/src/enums.h	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/enums.h	2016-09-09 06:56:46.000000000 +1200
@@ -95,11 +95,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-3.5.20/src/http.cc squid-3.5.21/src/http.cc
--- squid-3.5.20/src/http.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/http.cc	2016-09-09 06:56:46.000000000 +1200
@@ -572,43 +572,27 @@
     /* 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(HDR_VARY);
+    const char *pos = nullptr;
+    const char *item = nullptr;
+    int ilen = 0;
 
     while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
-        char *name = (char *)xmalloc(ilen + 1);
-        xstrncpy(name, item, ilen + 1);
-        Tolower(name);
-
-        if (strcmp(name, "*") == 0) {
-            /* Can not handle "Vary: *" withtout ETag support */
-            safe_free(name);
+        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);
-        safe_free(name);
-        value = hdr.termedBuf();
-
+        String hdr(request.header.getByName(name.c_str()));
+        const char *value = hdr.termedBuf();
         if (value) {
             value = rfc1738_escape_part(value);
             vstr.append("=\"", 2);
@@ -618,43 +602,26 @@
 
         hdr.clean();
     }
+}
 
-    vary.clean();
-#if X_ACCELERATOR_VARY
-
-    pos = NULL;
-    vary = reply->header.getList(HDR_X_ACCELERATOR_VARY);
-
-    while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
-        char *name = (char *)xmalloc(ilen + 1);
-        xstrncpy(name, item, ilen + 1);
-        Tolower(name);
-
-        if (strcmp(name, "*") == 0) {
-            /* Can not handle "Vary: *" withtout ETag support */
-            safe_free(name);
-            vstr.clear();
-            break;
-        }
-
-        if (!vstr.isEmpty())
-            vstr.append(", ", 2);
-        vstr.append(name);
-        hdr = request->header.getByName(name);
-        safe_free(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(HDR_VARY);
+    assembleVaryKey(vary, vstr, *request);
 
+#if X_ACCELERATOR_VARY
     vary.clean();
+    vary = reply->header.getList(HDR_X_ACCELERATOR_VARY);
+    assembleVaryKey(vary, vstr, *request);
 #endif
 
     debugs(11, 3, vstr);
@@ -991,8 +958,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 {
@@ -1002,7 +971,7 @@
              * but servers like "Active Imaging Webcast/2.0" sure do use it */
             if (rep->header.has(HDR_PRAGMA) &&
                     rep->header.hasListMember(HDR_PRAGMA,"no-cache",','))
-                EBIT_SET(entry->flags, ENTRY_REVALIDATE);
+                EBIT_SET(entry->flags, ENTRY_REVALIDATE_ALWAYS);
         }
 #endif
     }
diff -u -r -N squid-3.5.20/src/HttpHdrCc.cc squid-3.5.21/src/HttpHdrCc.cc
--- squid-3.5.20/src/HttpHdrCc.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/HttpHdrCc.cc	2016-09-09 06:56:46.000000000 +1200
@@ -257,6 +257,27 @@
 
             /* for all options having values, "=value" after the name */
             switch (flag) {
+            case CC_BADHDR:
+                break;
+            case CC_PUBLIC:
+                break;
+            case CC_PRIVATE:
+                if (Private().size())
+                    packerPrintf(p, "=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(Private()));
+                break;
+
+            case CC_NO_CACHE:
+                if (noCache().size())
+                    packerPrintf(p, "=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(noCache()));
+                break;
+            case CC_NO_STORE:
+                break;
+            case CC_NO_TRANSFORM:
+                break;
+            case CC_MUST_REVALIDATE:
+                break;
+            case CC_PROXY_REVALIDATE:
+                break;
             case CC_MAX_AGE:
                 packerPrintf(p, "=%d", (int) maxAge());
                 break;
@@ -272,8 +293,14 @@
             case CC_MIN_FRESH:
                 packerPrintf(p, "=%d", (int) minFresh());
                 break;
-            default:
-                /* do nothing, directive was already printed */
+            case CC_ONLY_IF_CACHED:
+                break;
+            case CC_STALE_IF_ERROR:
+                packerPrintf(p, "=%d", staleIfError());
+                break;
+            case CC_OTHER:
+            case CC_ENUM_END:
+                // done below after the loop
                 break;
             }
 
diff -u -r -N squid-3.5.20/src/HttpHeaderTools.cc squid-3.5.21/src/HttpHeaderTools.cc
--- squid-3.5.20/src/HttpHeaderTools.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/HttpHeaderTools.cc	2016-09-09 06:56:46.000000000 +1200
@@ -131,32 +131,30 @@
 }
 
 /**
- * return true if a given directive is found in at least one of
- * the "connection" header-fields note: if HDR_PROXY_CONNECTION is
- * present we ignore HDR_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->has(HDR_CONNECTION)) {
+        list = hdr->getList(HDR_CONNECTION);
+        return strListIsMember(&list, directive, ',') != 0;
+    }
 
 #if USE_HTTP_VIOLATIONS
-    if (hdr->has(HDR_PROXY_CONNECTION))
+    if (hdr->has(HDR_PROXY_CONNECTION)) {
         list = hdr->getList(HDR_PROXY_CONNECTION);
-    else
+        return strListIsMember(&list, directive, ',') != 0;
+    }
 #endif
-        if (hdr->has(HDR_CONNECTION))
-            list = hdr->getList(HDR_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 */
diff -u -r -N squid-3.5.20/src/HttpHeaderTools.h squid-3.5.21/src/HttpHeaderTools.h
--- squid-3.5.20/src/HttpHeaderTools.h	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/HttpHeaderTools.h	2016-09-09 06:56:46.000000000 +1200
@@ -120,7 +120,7 @@
 http_hdr_type httpHeaderIdByName(const char *name, size_t name_len, const HttpHeaderFieldInfo * attrs, int end);
 http_hdr_type httpHeaderIdByNameDef(const char *name, int name_len);
 const char *httpHeaderNameById(int id);
-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_hdr_type id, const char *fmt,...) PRINTF_FORMAT_ARG3;
 
diff -u -r -N squid-3.5.20/src/peer_digest.cc squid-3.5.21/src/peer_digest.cc
--- squid-3.5.20/src/peer_digest.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/peer_digest.cc	2016-09-09 06:56:46.000000000 +1200
@@ -754,7 +754,7 @@
     if (!reason && !size) {
         if (!pd->cd)
             reason = "null digest?!";
-        else if (fetch->mask_offset != (int)pd->cd->mask_size)
+        else if (fetch->mask_offset != pd->cd->mask_size)
             reason = "premature end of digest?!";
         else if (!peerDigestUseful(pd))
             reason = "useless digest";
diff -u -r -N squid-3.5.20/src/PeerDigest.h squid-3.5.21/src/PeerDigest.h
--- squid-3.5.20/src/PeerDigest.h	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/PeerDigest.h	2016-09-09 06:56:46.000000000 +1200
@@ -52,7 +52,7 @@
     store_client *old_sc;
     HttpRequest *request;
     int offset;
-    int mask_offset;
+    uint32_t mask_offset;
     time_t start_time;
     time_t resp_time;
     time_t expires;
diff -u -r -N squid-3.5.20/src/refresh.cc squid-3.5.21/src/refresh.cc
--- squid-3.5.20/src/refresh.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/refresh.cc	2016-09-09 06:56:46.000000000 +1200
@@ -356,12 +356,15 @@
      *   Cache-Control: proxy-revalidate
      * the spec says the response must always be revalidated if stale.
      */
-    if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1
+    const bool revalidateAlways = EBIT_TEST(entry->flags, ENTRY_REVALIDATE_ALWAYS);
+    bool revalidateStale = staleness > -1 && EBIT_TEST(entry->flags, ENTRY_REVALIDATE_STALE);
 #if USE_HTTP_VIOLATIONS
-            && !R->flags.ignore_must_revalidate
+    revalidateStale = revalidateStale && !R->flags.ignore_must_revalidate;
 #endif
-       ) {
-        debugs(22, 3, "YES: Must revalidate stale object (origin set must-revalidate or proxy-revalidate)");
+    if (revalidateAlways || revalidateStale) {
+        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-3.5.20/src/ssl/support.cc squid-3.5.21/src/ssl/support.cc
--- squid-3.5.20/src/ssl/support.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/ssl/support.cc	2016-09-09 06:56:46.000000000 +1200
@@ -199,9 +199,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<char*>(cn_data->data);
     char *d = cn;
     for (int i = 0; i < cn_data->length; ++i, ++d, ++s) {
@@ -211,7 +214,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)
diff -u -r -N squid-3.5.20/src/stat.cc squid-3.5.21/src/stat.cc
--- squid-3.5.20/src/stat.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/stat.cc	2016-09-09 06:56:46.000000000 +1200
@@ -286,8 +286,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,");
@@ -298,6 +298,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-3.5.20/src/store.cc squid-3.5.21/src/store.cc
--- squid-3.5.20/src/store.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/store.cc	2016-09-09 06:56:46.000000000 +1200
@@ -2122,10 +2122,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-3.5.20/src/store_digest.cc squid-3.5.21/src/store_digest.cc
--- squid-3.5.20/src/store_digest.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/store_digest.cc	2016-09-09 06:56:46.000000000 +1200
@@ -76,36 +76,63 @@
 static void storeDigestRewriteFinish(StoreEntry * e);
 static EVH storeDigestSwapOutStep;
 static void storeDigestCBlockSwapOut(StoreEntry * e);
-static int storeDigestCalcCap(void);
-static int storeDigestResize(void);
 static void storeDigestAdd(const StoreEntry *);
 
-#endif /* USE_CACHE_DIGESTS */
-
-static void
-storeDigestRegisterWithCacheManager(void)
+/// calculates digest capacity
+static uint64_t
+storeDigestCalcCap()
 {
-    Mgr::RegisterAction("store_digest", "Store Digest", storeDigestReport, 0, 1);
-}
+    /*
+     * To-Do: Bloom proved that the optimal filter utilization is 50% (half of
+     * the bits are off). However, we do not have a formula to calculate the
+     * number of _entries_ we want to pre-allocate for.
+     */
+    const uint64_t hi_cap = Store::Root().maxSize() / Config.Store.avgObjectSize;
+    const uint64_t lo_cap = 1 + Store::Root().currentSize() / Config.Store.avgObjectSize;
+    const uint64_t e_count = StoreEntry::inUseCount();
+    uint64_t cap = e_count ? e_count : hi_cap;
+    debugs(71, 2, "have: " << e_count << ", want " << cap <<
+           " entries; limits: [" << lo_cap << ", " << hi_cap << "]");
 
-/*
- * PUBLIC FUNCTIONS
- */
+    if (cap < lo_cap)
+        cap = lo_cap;
+
+    /* do not enforce hi_cap limit, average-based estimation may be wrong
+     *if (cap > hi_cap)
+     *  cap = hi_cap;
+     */
+
+    // Bug 4534: we still have to set an upper-limit at some reasonable value though.
+    // this matches cacheDigestCalcMaskSize doing (cap*bpe)+7 < INT_MAX
+    const uint64_t absolute_max = (INT_MAX -8) / Config.digest.bits_per_entry;
+    if (cap > absolute_max) {
+        static time_t last_loud = 0;
+        if (last_loud < squid_curtime - 86400) {
+            debugs(71, DBG_IMPORTANT, "WARNING: Cache Digest cannot store " << cap << " entries. Limiting to " << absolute_max);
+            last_loud = squid_curtime;
+        } else {
+            debugs(71, 3, "WARNING: Cache Digest cannot store " << cap << " entries. Limiting to " << absolute_max);
+        }
+        cap = absolute_max;
+    }
+
+    return cap;
+}
+#endif /* USE_CACHE_DIGESTS */
 
 void
 storeDigestInit(void)
 {
-    storeDigestRegisterWithCacheManager();
+    Mgr::RegisterAction("store_digest", "Store Digest", storeDigestReport, 0, 1);
 
 #if USE_CACHE_DIGESTS
-    const int cap = storeDigestCalcCap();
-
     if (!Config.onoff.digest_generation) {
         store_digest = NULL;
         debugs(71, 3, "Local cache digest generation disabled");
         return;
     }
 
+    const uint64_t cap = storeDigestCalcCap();
     store_digest = cacheDigestCreate(cap, Config.digest.bits_per_entry);
     debugs(71, DBG_IMPORTANT, "Local cache digest enabled; rebuild/rewrite every " <<
            (int) Config.digest.rebuild_period << "/" <<
@@ -290,6 +317,31 @@
     storeDigestRebuildResume();
 }
 
+/// \returns true if we actually resized the digest
+static bool
+storeDigestResize()
+{
+    const uint64_t cap = storeDigestCalcCap();
+    assert(store_digest);
+    uint64_t diff;
+    if (cap > store_digest->capacity)
+        diff = cap - store_digest->capacity;
+    else
+        diff = store_digest->capacity - cap;
+    debugs(71, 2, store_digest->capacity << " -> " << cap << "; change: " <<
+           diff << " (" << xpercentInt(diff, store_digest->capacity) << "%)" );
+    /* avoid minor adjustments */
+
+    if (diff <= store_digest->capacity / 10) {
+        debugs(71, 2, "small change, will not resize.");
+        return false;
+    } else {
+        debugs(71, 2, "big change, resizing.");
+        cacheDigestChangeCap(store_digest, cap);
+    }
+    return true;
+}
+
 /* called be Rewrite to push Rebuild forward */
 static void
 storeDigestRebuildResume(void)
@@ -439,7 +491,7 @@
     assert(e);
     /* _add_ check that nothing bad happened while we were waiting @?@ @?@ */
 
-    if (sd_state.rewrite_offset + chunk_size > store_digest->mask_size)
+    if (static_cast<uint32_t>(sd_state.rewrite_offset + chunk_size) > store_digest->mask_size)
         chunk_size = store_digest->mask_size - sd_state.rewrite_offset;
 
     e->append(store_digest->mask + sd_state.rewrite_offset, chunk_size);
@@ -451,7 +503,7 @@
     sd_state.rewrite_offset += chunk_size;
 
     /* are we done ? */
-    if (sd_state.rewrite_offset >= store_digest->mask_size)
+    if (static_cast<uint32_t>(sd_state.rewrite_offset) >= store_digest->mask_size)
         storeDigestRewriteFinish(e);
     else
         eventAdd("storeDigestSwapOutStep", storeDigestSwapOutStep, data, 0.0, 1, false);
@@ -467,60 +519,10 @@
     sd_state.cblock.count = htonl(store_digest->count);
     sd_state.cblock.del_count = htonl(store_digest->del_count);
     sd_state.cblock.mask_size = htonl(store_digest->mask_size);
-    sd_state.cblock.bits_per_entry = (unsigned char)
-                                     Config.digest.bits_per_entry;
+    sd_state.cblock.bits_per_entry = Config.digest.bits_per_entry;
     sd_state.cblock.hash_func_count = (unsigned char) CacheDigestHashFuncCount;
     e->append((char *) &sd_state.cblock, sizeof(sd_state.cblock));
 }
 
-/* calculates digest capacity */
-static int
-storeDigestCalcCap(void)
-{
-    /*
-     * To-Do: Bloom proved that the optimal filter utilization is 50% (half of
-     * the bits are off). However, we do not have a formula to calculate the
-     * number of _entries_ we want to pre-allocate for.
-     */
-    const int hi_cap = Store::Root().maxSize() / Config.Store.avgObjectSize;
-    const int lo_cap = 1 + Store::Root().currentSize() / Config.Store.avgObjectSize;
-    const int e_count = StoreEntry::inUseCount();
-    int cap = e_count ? e_count :hi_cap;
-    debugs(71, 2, "storeDigestCalcCap: have: " << e_count << ", want " << cap <<
-           " entries; limits: [" << lo_cap << ", " << hi_cap << "]");
-
-    if (cap < lo_cap)
-        cap = lo_cap;
-
-    /* do not enforce hi_cap limit, average-based estimation may be wrong
-     *if (cap > hi_cap)
-     *  cap = hi_cap;
-     */
-    return cap;
-}
-
-/* returns true if we actually resized the digest */
-static int
-storeDigestResize(void)
-{
-    const int cap = storeDigestCalcCap();
-    int diff;
-    assert(store_digest);
-    diff = abs(cap - store_digest->capacity);
-    debugs(71, 2, "storeDigestResize: " <<
-           store_digest->capacity << " -> " << cap << "; change: " <<
-           diff << " (" << xpercentInt(diff, store_digest->capacity) << "%)" );
-    /* avoid minor adjustments */
-
-    if (diff <= store_digest->capacity / 10) {
-        debugs(71, 2, "storeDigestResize: small change, will not resize.");
-        return 0;
-    } else {
-        debugs(71, 2, "storeDigestResize: big change, resizing.");
-        cacheDigestChangeCap(store_digest, cap);
-        return 1;
-    }
-}
-
 #endif /* USE_CACHE_DIGESTS */
 
diff -u -r -N squid-3.5.20/src/tests/stub_CacheDigest.cc squid-3.5.21/src/tests/stub_CacheDigest.cc
--- squid-3.5.20/src/tests/stub_CacheDigest.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/tests/stub_CacheDigest.cc	2016-09-09 06:56:46.000000000 +1200
@@ -16,11 +16,11 @@
 class CacheDigestGuessStats;
 class StoreEntry;
 
-CacheDigest * cacheDigestCreate(int, int) STUB_RETVAL(NULL)
+CacheDigest * cacheDigestCreate(uint64_t, uint8_t) STUB_RETVAL(NULL)
 void cacheDigestDestroy(CacheDigest *) STUB
 CacheDigest * cacheDigestClone(const CacheDigest *) STUB_RETVAL(NULL)
 void cacheDigestClear(CacheDigest * ) STUB
-void cacheDigestChangeCap(CacheDigest *,int) STUB
+void cacheDigestChangeCap(CacheDigest *,uint64_t) STUB
 int cacheDigestTest(const CacheDigest *, const cache_key *) STUB_RETVAL(1)
 void cacheDigestAdd(CacheDigest *, const cache_key *) STUB
 void cacheDigestDel(CacheDigest *, const cache_key *) STUB
@@ -28,5 +28,5 @@
 void cacheDigestGuessStatsUpdate(CacheDigestGuessStats *, int, int) STUB
 void cacheDigestGuessStatsReport(const CacheDigestGuessStats *, StoreEntry *, const char *) STUB
 void cacheDigestReport(CacheDigest *, const char *, StoreEntry *) STUB
-size_t cacheDigestCalcMaskSize(int, int) STUB_RETVAL(1)
+uint32_t cacheDigestCalcMaskSize(uint64_t, uint8_t) STUB_RETVAL(1)
 
diff -u -r -N squid-3.5.20/src/tests/stub_HelperChildConfig.cc squid-3.5.21/src/tests/stub_HelperChildConfig.cc
--- squid-3.5.20/src/tests/stub_HelperChildConfig.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/tests/stub_HelperChildConfig.cc	2016-09-09 06:56:46.000000000 +1200
@@ -47,4 +47,5 @@
 }
 
 void Helper::ChildConfig::parseConfig() STUB
+Helper::ChildConfig & Helper::ChildConfig::updateLimits(const Helper::ChildConfig &) STUB_RETVAL(*this)
 
diff -u -r -N squid-3.5.20/src/tunnel.cc squid-3.5.21/src/tunnel.cc
--- squid-3.5.20/src/tunnel.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/tunnel.cc	2016-09-09 06:56:46.000000000 +1200
@@ -476,7 +476,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-3.5.20/src/url.cc squid-3.5.21/src/url.cc
--- squid-3.5.20/src/url.cc	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/url.cc	2016-09-09 06:56:46.000000000 +1200
@@ -54,6 +54,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"));
@@ -66,6 +67,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? */
 }
 
@@ -690,16 +702,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);
 
     /*
@@ -737,9 +753,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;
         }
     }
@@ -751,7 +778,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;
 
     /*
diff -u -r -N squid-3.5.20/src/URL.h squid-3.5.21/src/URL.h
--- squid-3.5.20/src/URL.h	2016-07-01 23:37:50.000000000 +1200
+++ squid-3.5.21/src/URL.h	2016-09-09 06:56:46.000000000 +1200
@@ -73,23 +73,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:
- *
- *    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
+ * matchDomainName() matches a hostname (usually extracted from traffic)
+ * with a domainname when mdnNone or mdnRejectSubsubDomains flags are used
+ * according to the following rules:
  *
- *  We strip leading dots on hosts (but not domains!) so that
- *  ".foo.com" is always the same as "foo.com".
+ *    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
  *
- * 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?
@@ -99,11 +105,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 *);
 int urlDefaultPort(AnyP::ProtocolType p);
 char *urlHostname(const char *url);
