diff -u -r -N squid-4.0.20/aclocal.m4 squid-4.0.21/aclocal.m4
--- squid-4.0.20/aclocal.m4	2017-06-02 00:51:04.000000000 +1200
+++ squid-4.0.21/aclocal.m4	2017-07-02 20:41:21.000000000 +1200
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10052,7 +10052,7 @@
 m4_ifndef([_LT_PROG_FC],		[AC_DEFUN([_LT_PROG_FC])])
 m4_ifndef([_LT_PROG_CXX],		[AC_DEFUN([_LT_PROG_CXX])])
 
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10067,7 +10067,7 @@
 [am__api_version='1.15'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.15], [],
+m4_if([$1], [1.15.1], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -10083,14 +10083,14 @@
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.15])dnl
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10142,7 +10142,7 @@
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10173,7 +10173,7 @@
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10364,7 +10364,7 @@
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
 
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10440,7 +10440,7 @@
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10637,7 +10637,7 @@
 done
 echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10658,7 +10658,7 @@
 fi
 AC_SUBST([install_sh])])
 
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10680,7 +10680,7 @@
 # Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
 # From Jim Meyering
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10715,7 +10715,7 @@
 
 # Check to see how 'make' treats includes.	            -*- Autoconf -*-
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10765,7 +10765,7 @@
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10804,7 +10804,7 @@
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10833,7 +10833,7 @@
 AC_DEFUN([_AM_IF_OPTION],
 [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10880,7 +10880,7 @@
 # For backward compatibility.
 AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10899,7 +10899,7 @@
 
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10980,7 +10980,7 @@
 rm -f conftest.file
 ])
 
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -11040,7 +11040,7 @@
 _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
 ])
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -11068,7 +11068,7 @@
 INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
-# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -11087,7 +11087,7 @@
 
 # Check how to create a tarball.                            -*- Autoconf -*-
 
-# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/cfgaux/depcomp squid-4.0.21/cfgaux/depcomp
--- squid-4.0.20/cfgaux/depcomp	2017-06-02 01:01:27.000000000 +1200
+++ squid-4.0.21/cfgaux/depcomp	2017-07-02 20:41:28.000000000 +1200
@@ -1,9 +1,9 @@
 #! /bin/sh
 # depcomp - compile a program generating dependencies as side-effects
 
-scriptversion=2013-05-30.07; # UTC
+scriptversion=2016-01-11.22; # UTC
 
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -786,6 +786,6 @@
 # eval: (add-hook 'write-file-hooks 'time-stamp)
 # time-stamp-start: "scriptversion="
 # time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
 # time-stamp-end: "; # UTC"
 # End:
diff -u -r -N squid-4.0.20/ChangeLog squid-4.0.21/ChangeLog
--- squid-4.0.20/ChangeLog	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/ChangeLog	2017-07-02 20:41:18.000000000 +1200
@@ -1,3 +1,22 @@
+Changes to squid-4.0.21 (02 Jul 2017):
+
+	- Bug 4730: segfault while processing internal HTTP requests
+	- Bug 4492: Chunk extension parser is too pedantic
+	- Bug 1961: Redesign urlParse() API
+	- TLS: recognise tls:: namespace on logformat tokens
+	- SSL-Bump: tproxy does not spoof spliced connections
+	- security_file_certgen: collapse queued requests
+	- Add a basic apparmour profile
+	- Add transaction_initiator ACL for detecting various unusual transactions
+	- Add ssl::server_name options to control matching logic
+	- Support for --long-acl-options
+	- Do not die silently when dying via std::terminate()
+	- Fix option --foreground to implement expected behavior
+	- Translations: update .po and .pot to latest texts
+	- ... and some documentation updates
+	- ... and many code cleanup and stability fixes
+	- ... and all fixes from 3.5.27
+
 Changes to squid-4.0.20 (01 Jun 2017):
 
 	- Bug #4692: SslBump breaks intercepted IPv6 connections
@@ -16,7 +35,7 @@
 	- ext_session_acl: cope with new logformat inputs
 	- ... and some documentation updates
 	- ... and some code stability fixes
-	- ... and all fixes from 3.5.25
+	- ... and all fixes from 3.5.26
 
 Changes to squid-4.0.19 (02 Apr 2017):
 
diff -u -r -N squid-4.0.20/compat/Makefile.in squid-4.0.21/compat/Makefile.in
--- squid-4.0.20/compat/Makefile.in	2017-06-02 00:52:42.000000000 +1200
+++ squid-4.0.21/compat/Makefile.in	2017-07-02 20:41:23.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/configure squid-4.0.21/configure
--- squid-4.0.20/configure	2017-06-02 01:01:44.000000000 +1200
+++ squid-4.0.21/configure	2017-07-02 20:41:29.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.20.
+# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.0.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='4.0.20'
-PACKAGE_STRING='Squid Web Proxy 4.0.20'
+PACKAGE_VERSION='4.0.21'
+PACKAGE_STRING='Squid Web Proxy 4.0.21'
 PACKAGE_BUGREPORT='http://bugs.squid-cache.org/'
 PACKAGE_URL=''
 
@@ -1647,7 +1647,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.20 to adapt to many kinds of systems.
+\`configure' configures Squid Web Proxy 4.0.21 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1718,7 +1718,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Squid Web Proxy 4.0.20:";;
+     short | recursive ) echo "Configuration of Squid Web Proxy 4.0.21:";;
    esac
   cat <<\_ACEOF
 
@@ -2147,7 +2147,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Squid Web Proxy configure 4.0.20
+Squid Web Proxy configure 4.0.21
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -3251,7 +3251,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.20, which was
+It was created by Squid Web Proxy $as_me 4.0.21, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -4118,7 +4118,7 @@
 
 # Define the identity of the package.
  PACKAGE='squid'
- VERSION='4.0.20'
+ VERSION='4.0.21'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -42910,7 +42910,7 @@
 
 rm -f core
 
-ac_config_files="$ac_config_files Makefile compat/Makefile contrib/Makefile doc/Makefile doc/manuals/Makefile doc/release-notes/Makefile errors/Makefile icons/Makefile lib/Makefile lib/libTrie/Makefile lib/libTrie/test/Makefile lib/ntlmauth/Makefile lib/profiler/Makefile lib/rfcnb/Makefile lib/smblib/Makefile lib/snmplib/Makefile scripts/Makefile src/Makefile src/acl/Makefile src/acl/external/Makefile src/acl/external/AD_group/Makefile src/acl/external/delayer/Makefile src/acl/external/eDirectory_userip/Makefile src/acl/external/file_userip/Makefile src/acl/external/kerberos_ldap_group/Makefile src/acl/external/LDAP_group/Makefile src/acl/external/LM_group/Makefile src/acl/external/session/Makefile src/acl/external/SQL_session/Makefile src/acl/external/unix_group/Makefile src/acl/external/wbinfo_group/Makefile src/acl/external/time_quota/Makefile src/adaptation/Makefile src/adaptation/icap/Makefile src/adaptation/ecap/Makefile src/anyp/Makefile src/auth/Makefile src/auth/basic/Makefile src/auth/basic/DB/Makefile src/auth/basic/fake/Makefile src/auth/basic/getpwnam/Makefile src/auth/basic/LDAP/Makefile src/auth/basic/NCSA/Makefile src/auth/basic/NIS/Makefile src/auth/basic/PAM/Makefile src/auth/basic/POP3/Makefile src/auth/basic/RADIUS/Makefile src/auth/basic/SASL/Makefile src/auth/basic/SMB/Makefile src/auth/basic/SMB_LM/Makefile src/auth/basic/SSPI/Makefile src/auth/digest/Makefile src/auth/digest/eDirectory/Makefile src/auth/digest/file/Makefile src/auth/digest/LDAP/Makefile src/auth/negotiate/Makefile src/auth/negotiate/kerberos/Makefile src/auth/negotiate/SSPI/Makefile src/auth/negotiate/wrapper/Makefile src/auth/ntlm/Makefile src/auth/ntlm/fake/Makefile src/auth/ntlm/SMB_LM/Makefile src/auth/ntlm/SSPI/Makefile src/base/Makefile src/clients/Makefile src/comm/Makefile src/dns/Makefile src/DiskIO/Makefile src/DiskIO/AIO/Makefile src/DiskIO/Blocking/Makefile src/DiskIO/DiskDaemon/Makefile src/DiskIO/DiskThreads/Makefile src/DiskIO/IpcIo/Makefile src/DiskIO/Mmapped/Makefile src/esi/Makefile src/eui/Makefile src/format/Makefile src/fs/Makefile src/ftp/Makefile src/helper/Makefile src/http/Makefile src/http/one/Makefile src/http/url_rewriters/Makefile src/http/url_rewriters/fake/Makefile src/http/url_rewriters/LFS/Makefile src/icmp/Makefile src/ident/Makefile src/ip/Makefile src/ipc/Makefile src/log/Makefile src/log/DB/Makefile src/log/file/Makefile src/mem/Makefile src/mgr/Makefile src/parser/Makefile src/repl/Makefile src/sbuf/Makefile src/security/Makefile src/security/cert_generators/Makefile src/security/cert_generators/file/Makefile src/security/cert_validators/Makefile src/security/cert_validators/fake/Makefile src/servers/Makefile src/snmp/Makefile src/ssl/Makefile src/store/Makefile src/store/id_rewriters/Makefile src/store/id_rewriters/file/Makefile test-suite/Makefile tools/Makefile tools/helper-mux/Makefile tools/purge/Makefile tools/squidclient/Makefile tools/systemd/Makefile tools/sysvinit/Makefile"
+ac_config_files="$ac_config_files Makefile compat/Makefile contrib/Makefile doc/Makefile doc/manuals/Makefile doc/release-notes/Makefile errors/Makefile icons/Makefile lib/Makefile lib/libTrie/Makefile lib/libTrie/test/Makefile lib/ntlmauth/Makefile lib/profiler/Makefile lib/rfcnb/Makefile lib/smblib/Makefile lib/snmplib/Makefile scripts/Makefile src/Makefile src/acl/Makefile src/acl/external/Makefile src/acl/external/AD_group/Makefile src/acl/external/delayer/Makefile src/acl/external/eDirectory_userip/Makefile src/acl/external/file_userip/Makefile src/acl/external/kerberos_ldap_group/Makefile src/acl/external/LDAP_group/Makefile src/acl/external/LM_group/Makefile src/acl/external/session/Makefile src/acl/external/SQL_session/Makefile src/acl/external/unix_group/Makefile src/acl/external/wbinfo_group/Makefile src/acl/external/time_quota/Makefile src/adaptation/Makefile src/adaptation/icap/Makefile src/adaptation/ecap/Makefile src/anyp/Makefile src/auth/Makefile src/auth/basic/Makefile src/auth/basic/DB/Makefile src/auth/basic/fake/Makefile src/auth/basic/getpwnam/Makefile src/auth/basic/LDAP/Makefile src/auth/basic/NCSA/Makefile src/auth/basic/NIS/Makefile src/auth/basic/PAM/Makefile src/auth/basic/POP3/Makefile src/auth/basic/RADIUS/Makefile src/auth/basic/SASL/Makefile src/auth/basic/SMB/Makefile src/auth/basic/SMB_LM/Makefile src/auth/basic/SSPI/Makefile src/auth/digest/Makefile src/auth/digest/eDirectory/Makefile src/auth/digest/file/Makefile src/auth/digest/LDAP/Makefile src/auth/negotiate/Makefile src/auth/negotiate/kerberos/Makefile src/auth/negotiate/SSPI/Makefile src/auth/negotiate/wrapper/Makefile src/auth/ntlm/Makefile src/auth/ntlm/fake/Makefile src/auth/ntlm/SMB_LM/Makefile src/auth/ntlm/SSPI/Makefile src/base/Makefile src/clients/Makefile src/comm/Makefile src/dns/Makefile src/DiskIO/Makefile src/DiskIO/AIO/Makefile src/DiskIO/Blocking/Makefile src/DiskIO/DiskDaemon/Makefile src/DiskIO/DiskThreads/Makefile src/DiskIO/IpcIo/Makefile src/DiskIO/Mmapped/Makefile src/esi/Makefile src/eui/Makefile src/format/Makefile src/fs/Makefile src/ftp/Makefile src/helper/Makefile src/http/Makefile src/http/one/Makefile src/http/url_rewriters/Makefile src/http/url_rewriters/fake/Makefile src/http/url_rewriters/LFS/Makefile src/icmp/Makefile src/ident/Makefile src/ip/Makefile src/ipc/Makefile src/log/Makefile src/log/DB/Makefile src/log/file/Makefile src/mem/Makefile src/mgr/Makefile src/parser/Makefile src/repl/Makefile src/sbuf/Makefile src/security/Makefile src/security/cert_generators/Makefile src/security/cert_generators/file/Makefile src/security/cert_validators/Makefile src/security/cert_validators/fake/Makefile src/servers/Makefile src/snmp/Makefile src/ssl/Makefile src/store/Makefile src/store/id_rewriters/Makefile src/store/id_rewriters/file/Makefile test-suite/Makefile tools/Makefile tools/apparmor/Makefile tools/helper-mux/Makefile tools/purge/Makefile tools/squidclient/Makefile tools/systemd/Makefile tools/sysvinit/Makefile"
 
 
 # must configure libltdl subdir unconditionally for "make distcheck" to work
@@ -43656,7 +43656,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.20, which was
+This file was extended by Squid Web Proxy $as_me 4.0.21, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -43722,7 +43722,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.20
+Squid Web Proxy config.status 4.0.21
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -44345,6 +44345,7 @@
     "src/store/id_rewriters/file/Makefile") CONFIG_FILES="$CONFIG_FILES src/store/id_rewriters/file/Makefile" ;;
     "test-suite/Makefile") CONFIG_FILES="$CONFIG_FILES test-suite/Makefile" ;;
     "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
+    "tools/apparmor/Makefile") CONFIG_FILES="$CONFIG_FILES tools/apparmor/Makefile" ;;
     "tools/helper-mux/Makefile") CONFIG_FILES="$CONFIG_FILES tools/helper-mux/Makefile" ;;
     "tools/purge/Makefile") CONFIG_FILES="$CONFIG_FILES tools/purge/Makefile" ;;
     "tools/squidclient/Makefile") CONFIG_FILES="$CONFIG_FILES tools/squidclient/Makefile" ;;
diff -u -r -N squid-4.0.20/configure.ac squid-4.0.21/configure.ac
--- squid-4.0.20/configure.ac	2017-06-02 01:01:44.000000000 +1200
+++ squid-4.0.21/configure.ac	2017-07-02 20:41:29.000000000 +1200
@@ -5,7 +5,7 @@
 ## Please see the COPYING and CONTRIBUTORS files for details.
 ##
 
-AC_INIT([Squid Web Proxy],[4.0.20],[http://bugs.squid-cache.org/],[squid])
+AC_INIT([Squid Web Proxy],[4.0.21],[http://bugs.squid-cache.org/],[squid])
 AC_PREREQ(2.61)
 AC_CONFIG_HEADERS([include/autoconf.h])
 AC_CONFIG_AUX_DIR(cfgaux)
@@ -3876,6 +3876,7 @@
 	src/store/id_rewriters/file/Makefile
 	test-suite/Makefile
 	tools/Makefile
+	tools/apparmor/Makefile
 	tools/helper-mux/Makefile
 	tools/purge/Makefile
 	tools/squidclient/Makefile
diff -u -r -N squid-4.0.20/contrib/Makefile.in squid-4.0.21/contrib/Makefile.in
--- squid-4.0.20/contrib/Makefile.in	2017-06-02 00:52:44.000000000 +1200
+++ squid-4.0.21/contrib/Makefile.in	2017-07-02 20:41:23.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/contrib/solaris/solaris-krb5-include.patch squid-4.0.21/contrib/solaris/solaris-krb5-include.patch
--- squid-4.0.20/contrib/solaris/solaris-krb5-include.patch	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/contrib/solaris/solaris-krb5-include.patch	2017-07-02 20:41:18.000000000 +1200
@@ -1,3 +1,11 @@
+/*
+ * Copyright (C) 1996-2017 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.
+ */
+
 --- /usr/include/kerberosv5/krb5.h.orig	Mon Aug 23 04:09:23 2010
 +++ /usr/include/kerberosv5/krb5.h	Mon Aug 23 04:10:53 2010
 @@ -171,6 +171,7 @@
diff -u -r -N squid-4.0.20/doc/Makefile.in squid-4.0.21/doc/Makefile.in
--- squid-4.0.20/doc/Makefile.in	2017-06-02 00:52:46.000000000 +1200
+++ squid-4.0.21/doc/Makefile.in	2017-07-02 20:41:23.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/doc/manuals/Makefile.in squid-4.0.21/doc/manuals/Makefile.in
--- squid-4.0.20/doc/manuals/Makefile.in	2017-06-02 00:52:48.000000000 +1200
+++ squid-4.0.21/doc/manuals/Makefile.in	2017-07-02 20:41:23.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/doc/release-notes/Makefile.in squid-4.0.21/doc/release-notes/Makefile.in
--- squid-4.0.20/doc/release-notes/Makefile.in	2017-06-02 00:52:50.000000000 +1200
+++ squid-4.0.21/doc/release-notes/Makefile.in	2017-07-02 20:41:23.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/doc/release-notes/release-4.html squid-4.0.21/doc/release-notes/release-4.html
--- squid-4.0.20/doc/release-notes/release-4.html	2017-06-02 09:49:09.000000000 +1200
+++ squid-4.0.21/doc/release-notes/release-4.html	2017-07-02 20:57:33.000000000 +1200
@@ -2,10 +2,10 @@
 <HTML>
 <HEAD>
  <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.72">
- <TITLE>Squid 4.0.20 release notes</TITLE>
+ <TITLE>Squid 4.0.21 release notes</TITLE>
 </HEAD>
 <BODY>
-<H1>Squid 4.0.20 release notes</H1>
+<H1>Squid 4.0.21 release notes</H1>
 
 <H2>Squid Developers</H2>
 <HR>
@@ -62,7 +62,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-4.0.20 for testing.</P>
+<P>The Squid Team are pleased to announce the release of Squid-4.0.21 for testing.</P>
 <P>This new release is available for download from 
 <A HREF="http://www.squid-cache.org/Versions/v4/">http://www.squid-cache.org/Versions/v4/</A> or the
 <A HREF="http://www.squid-cache.org/Download/http-mirrors.html">mirrors</A>.</P>
@@ -237,10 +237,9 @@
 integration with daemon managers such as Upstart or systemd which assume the
 process they initiated is the daemon with a PID to control.</P>
 
-<P>The squid binary now has a new <EM>--foreground</EM> command line option
-which prevents the process from exiting early while background workers
-continue their processing. When run with this option Squid will now wait
-for the worker(s) to finish before exiting. Unlike the old <EM>-N</EM> option
+<P>The squid binary now has a new <EM>--foreground</EM> command line option,
+which (only) prevents daemonizing the master process.
+Unlike the old <EM>-N</EM> option,
 <EM>--foreground</EM> supports SMP workers and multi-process features.
 <EM>--foreground</EM> is particularly useful for use with <EM>-z</EM> (disk
 cache structures creation), as it allows the caller to wait until Squid has
@@ -342,6 +341,11 @@
 including messages received from ICAP servers.</P>
 <P>New <EM>has</EM> type for matching whether or not Squid is able to provide
 certain sets of transaction state. For example HTTP reply headers.</P>
+<P>New <EM>transaction_initiator</EM> type for detecting various
+unusual transactions.</P>
+<P>New <EM>--consensus</EM>, <EM>--client-requested</EM> and
+<EM>--server-provided</EM> flags for the <EM>ssl::server_name</EM>
+type to control which server name to match against.</P>
 
 <DT><B>auth_param</B><DD>
 <P>New parameter <EM>queue-size=</EM> to set the maximum number
diff -u -r -N squid-4.0.20/errors/Makefile.in squid-4.0.21/errors/Makefile.in
--- squid-4.0.20/errors/Makefile.in	2017-06-02 00:52:54.000000000 +1200
+++ squid-4.0.21/errors/Makefile.in	2017-07-02 20:41:23.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/errors/TRANSLATORS squid-4.0.21/errors/TRANSLATORS
--- squid-4.0.20/errors/TRANSLATORS	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/errors/TRANSLATORS	2017-07-02 20:41:18.000000000 +1200
@@ -1,3 +1,9 @@
+ * Copyright (C) 1996-2017 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.
+
 Special thanks go to people who have volunteered their time, effort,
 and ideas to make Squid available as multi-langual software.
 
diff -u -r -N squid-4.0.20/icons/Makefile.in squid-4.0.21/icons/Makefile.in
--- squid-4.0.20/icons/Makefile.in	2017-06-02 00:52:57.000000000 +1200
+++ squid-4.0.21/icons/Makefile.in	2017-07-02 20:41:23.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/include/version.h squid-4.0.21/include/version.h
--- squid-4.0.20/include/version.h	2017-06-02 01:01:44.000000000 +1200
+++ squid-4.0.21/include/version.h	2017-07-02 20:41:29.000000000 +1200
@@ -7,7 +7,7 @@
  */
 
 #ifndef SQUID_RELEASE_TIME
-#define SQUID_RELEASE_TIME 1496321346
+#define SQUID_RELEASE_TIME 1498984863
 #endif
 
 /*
diff -u -r -N squid-4.0.20/lib/libTrie/Makefile.in squid-4.0.21/lib/libTrie/Makefile.in
--- squid-4.0.20/lib/libTrie/Makefile.in	2017-06-02 00:53:04.000000000 +1200
+++ squid-4.0.21/lib/libTrie/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/lib/libTrie/test/Makefile.in squid-4.0.21/lib/libTrie/test/Makefile.in
--- squid-4.0.20/lib/libTrie/test/Makefile.in	2017-06-02 00:53:07.000000000 +1200
+++ squid-4.0.21/lib/libTrie/test/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/lib/Makefile.in squid-4.0.21/lib/Makefile.in
--- squid-4.0.20/lib/Makefile.in	2017-06-02 00:53:01.000000000 +1200
+++ squid-4.0.21/lib/Makefile.in	2017-07-02 20:41:23.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/lib/ntlmauth/Makefile.in squid-4.0.21/lib/ntlmauth/Makefile.in
--- squid-4.0.20/lib/ntlmauth/Makefile.in	2017-06-02 00:53:09.000000000 +1200
+++ squid-4.0.21/lib/ntlmauth/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/lib/profiler/Makefile.in squid-4.0.21/lib/profiler/Makefile.in
--- squid-4.0.20/lib/profiler/Makefile.in	2017-06-02 00:53:16.000000000 +1200
+++ squid-4.0.21/lib/profiler/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/lib/rfcnb/Makefile.in squid-4.0.21/lib/rfcnb/Makefile.in
--- squid-4.0.20/lib/rfcnb/Makefile.in	2017-06-02 00:53:19.000000000 +1200
+++ squid-4.0.21/lib/rfcnb/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/lib/smblib/Makefile.in squid-4.0.21/lib/smblib/Makefile.in
--- squid-4.0.20/lib/smblib/Makefile.in	2017-06-02 00:53:20.000000000 +1200
+++ squid-4.0.21/lib/smblib/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/lib/snmplib/Makefile.in squid-4.0.21/lib/snmplib/Makefile.in
--- squid-4.0.20/lib/snmplib/Makefile.in	2017-06-02 00:53:22.000000000 +1200
+++ squid-4.0.21/lib/snmplib/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/libltdl/aclocal.m4 squid-4.0.21/libltdl/aclocal.m4
--- squid-4.0.20/libltdl/aclocal.m4	2017-06-02 00:52:00.000000000 +1200
+++ squid-4.0.21/libltdl/aclocal.m4	2017-07-02 20:41:56.000000000 +1200
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -20,7 +20,7 @@
 If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically 'autoreconf'.])])
 
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -35,7 +35,7 @@
 [am__api_version='1.15'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.15], [],
+m4_if([$1], [1.15.1], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -51,14 +51,14 @@
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.15])dnl
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -110,7 +110,7 @@
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -141,7 +141,7 @@
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -332,7 +332,7 @@
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
 
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -408,7 +408,7 @@
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -605,7 +605,7 @@
 done
 echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -626,7 +626,7 @@
 fi
 AC_SUBST([install_sh])])
 
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -647,7 +647,7 @@
 
 # Check to see how 'make' treats includes.	            -*- Autoconf -*-
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -697,7 +697,7 @@
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -736,7 +736,7 @@
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -765,7 +765,7 @@
 AC_DEFUN([_AM_IF_OPTION],
 [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -812,7 +812,7 @@
 # For backward compatibility.
 AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -831,7 +831,7 @@
 
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -912,7 +912,7 @@
 rm -f conftest.file
 ])
 
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -972,7 +972,7 @@
 _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
 ])
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1000,7 +1000,7 @@
 INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
-# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1019,7 +1019,7 @@
 
 # Check how to create a tarball.                            -*- Autoconf -*-
 
-# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/libltdl/Makefile.in squid-4.0.21/libltdl/Makefile.in
--- squid-4.0.20/libltdl/Makefile.in	2017-06-02 01:18:08.000000000 +1200
+++ squid-4.0.21/libltdl/Makefile.in	2017-07-02 20:41:56.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -933,7 +933,7 @@
 	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
 	|| chmod -R a+r "$(distdir)"
 dist-gzip: distdir
-	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
 	$(am__post_remove_distdir)
 
 dist-bzip2: distdir
@@ -959,7 +959,7 @@
 	@echo WARNING: "Support for shar distribution archives is" \
 	               "deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
-	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
 	$(am__post_remove_distdir)
 
 dist-zip: distdir
@@ -977,7 +977,7 @@
 distcheck: dist
 	case '$(DIST_ARCHIVES)' in \
 	*.tar.gz*) \
-	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
 	*.tar.bz2*) \
 	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
 	*.tar.lz*) \
@@ -987,7 +987,7 @@
 	*.tar.Z*) \
 	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
 	*.shar.gz*) \
-	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
 	*.zip*) \
 	  unzip $(distdir).zip ;;\
 	esac
diff -u -r -N squid-4.0.20/Makefile.in squid-4.0.21/Makefile.in
--- squid-4.0.20/Makefile.in	2017-06-02 00:52:41.000000000 +1200
+++ squid-4.0.21/Makefile.in	2017-07-02 20:41:23.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -746,7 +746,7 @@
 	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
 	|| chmod -R a+r "$(distdir)"
 dist-gzip: distdir
-	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
 	$(am__post_remove_distdir)
 dist-bzip2: distdir
 	tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
@@ -771,7 +771,7 @@
 	@echo WARNING: "Support for shar distribution archives is" \
 	               "deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
-	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
 	$(am__post_remove_distdir)
 
 dist-zip: distdir
@@ -789,7 +789,7 @@
 distcheck: dist
 	case '$(DIST_ARCHIVES)' in \
 	*.tar.gz*) \
-	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
 	*.tar.bz2*) \
 	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
 	*.tar.lz*) \
@@ -799,7 +799,7 @@
 	*.tar.Z*) \
 	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
 	*.shar.gz*) \
-	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
 	*.zip*) \
 	  unzip $(distdir).zip ;;\
 	esac
diff -u -r -N squid-4.0.20/po4a.conf squid-4.0.21/po4a.conf
--- squid-4.0.20/po4a.conf	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/po4a.conf	2017-07-02 20:41:18.000000000 +1200
@@ -2,46 +2,50 @@
 
 [po4a_paths] doc/manuals/manuals.pot $lang:doc/manuals/$lang.po
 
-[type: man] helpers/basic_auth/getpwnam/basic_getpwnam_auth.8 $lang:doc/manuals/$lang/basic_getpwnam_auth.8
+[type: man] src/acl/external/AD_group/ext_ad_group_acl.8 $lang:doc/manuals/$lang/ext_ad_group_acl.8
 
-[type: man] helpers/basic_auth/LDAP/basic_ldap_auth.8 $lang:doc/manuals/$lang/basic_ldap_auth.8
+[type: man] src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.8 $lang:doc/manuals/$lang/ext_edirectory_userip_acl.8
 
-[type: man] helpers/basic_auth/NCSA/basic_ncsa_auth.8 $lang:doc/manuals/$lang/basic_ncsa_auth.8
+[type: man] src/acl/external/file_userip/ext_file_userip_acl.8 $lang:doc/manuals/$lang/ext_file_userip_acl.8
 
-[type: man] helpers/basic_auth/PAM/basic_pam_auth.8 $lang:doc/manuals/$lang/basic_pam_auth.8
+[type: man] src/acl/external/kerberos_ldap_group/ext_kerberos_ldap_group_acl.8 $lang:doc/manuals/$lang/ext_kerberos_ldap_group_acl.8
 
-[type: man] helpers/basic_auth/RADIUS/basic_radius_auth.8 $lang:doc/manuals/$lang/basic_radius_auth.8
+[type: man] src/acl/external/LDAP_group/ext_ldap_group_acl.8 $lang:doc/manuals/$lang/ext_ldap_group_acl.8
 
-[type: man] helpers/basic_auth/SASL/basic_sasl_auth.8 $lang:doc/manuals/$lang/basic_sasl_auth.8
+[type: man] src/acl/external/LM_group/ext_lm_group_acl.8 $lang:doc/manuals/$lang/ext_lm_group_acl.8
 
-[type: man] helpers/basic_auth/SSPI/basic_sspi_auth.8 $lang:doc/manuals/$lang/basic_sspi_auth.8
+[type: man] src/acl/external/session/ext_session_acl.8 $lang:doc/manuals/$lang/ext_session_acl.8
 
-[type: man] helpers/digest_auth/file/digest_file_auth.8 $lang:doc/manuals/$lang/digest_file_auth.8
+[type: man] src/acl/external/time_quota/ext_time_quota_acl.8 $lang:doc/manuals/$lang/ext_time_quota_acl.8
 
-[type: man] helpers/external_acl/AD_group/ext_ad_group_acl.8 $lang:doc/manuals/$lang/ext_ad_group_acl.8
+[type: man] src/acl/external/unix_group/ext_unix_group_acl.8 $lang:doc/manuals/$lang/ext_unix_group_acl.8
 
-[type: man] helpers/external_acl/eDirectory_userip/ext_edirectory_userip_acl.8 $lang:doc/manuals/$lang/ext_edirectory_userip_acl.8
+[type: man] src/auth/basic/getpwnam/basic_getpwnam_auth.8 $lang:doc/manuals/$lang/basic_getpwnam_auth.8
 
-[type: man] helpers/external_acl/file_userip/ext_file_userip_acl.8 $lang:doc/manuals/$lang/ext_file_userip_acl.8
+[type: man] src/auth/basic/LDAP/basic_ldap_auth.8 $lang:doc/manuals/$lang/basic_ldap_auth.8
 
-[type: man] helpers/external_acl/kerberos_ldap_group/ext_kerberos_ldap_group_acl.8 $lang:doc/manuals/$lang/ext_kerberos_ldap_group_acl.8
+[type: man] src/auth/basic/NCSA/basic_ncsa_auth.8 $lang:doc/manuals/$lang/basic_ncsa_auth.8
 
-[type: man] helpers/external_acl/LDAP_group/ext_ldap_group_acl.8 $lang:doc/manuals/$lang/ext_ldap_group_acl.8
+[type: man] src/auth/basic/PAM/basic_pam_auth.8 $lang:doc/manuals/$lang/basic_pam_auth.8
 
-[type: man] helpers/external_acl/LM_group/ext_lm_group_acl.8 $lang:doc/manuals/$lang/ext_lm_group_acl.8
+[type: man] src/auth/basic/RADIUS/basic_radius_auth.8 $lang:doc/manuals/$lang/basic_radius_auth.8
 
-[type: man] helpers/external_acl/session/ext_session_acl.8 $lang:doc/manuals/$lang/ext_session_acl.8
+[type: man] src/auth/basic/SASL/basic_sasl_auth.8 $lang:doc/manuals/$lang/basic_sasl_auth.8
 
-[type: man] helpers/external_acl/time_quota/ext_time_quota_acl.8 $lang:doc/manuals/$lang/ext_time_quota_acl.8
+[type: man] src/auth/basic/SSPI/basic_sspi_auth.8 $lang:doc/manuals/$lang/basic_sspi_auth.8
 
-[type: man] helpers/external_acl/unix_group/ext_unix_group_acl.8 $lang:doc/manuals/$lang/ext_unix_group_acl.8
+[type: man] src/auth/digest/file/digest_file_auth.8 $lang:doc/manuals/$lang/digest_file_auth.8
 
-[type: man] helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.8 $lang:doc/manuals/$lang/negotiate_kerberos_auth.8
+[type: man] src/auth/negotiate/kerberos/negotiate_kerberos_auth.8 $lang:doc/manuals/$lang/negotiate_kerberos_auth.8
 
-[type: man] helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8 $lang:doc/manuals/$lang/ntlm_sspi_auth.8
+[type: man] src/auth/ntlm/SSPI/ntlm_sspi_auth.8 $lang:doc/manuals/$lang/ntlm_sspi_auth.8
+
+[type: man] src/security/cert_generators/file/security_file_certgen.8.in $lang:doc/manuals/$lang/security_file_certgen.8.in
 
 [type: man] src/squid.8.in $lang:doc/manuals/$lang/squid.8.in
 
 [type: man] tools/cachemgr.cgi.8.in $lang:doc/manuals/$lang/cachemgr.cgi.8.in
 
+[type: man] tools/purge/purge.1 $lang:doc/manuals/$lang/purge.1
+
 [type: man] tools/squidclient/squidclient.1 $lang:doc/manuals/$lang/squidclient.1
diff -u -r -N squid-4.0.20/RELEASENOTES.html squid-4.0.21/RELEASENOTES.html
--- squid-4.0.20/RELEASENOTES.html	2017-06-02 09:49:09.000000000 +1200
+++ squid-4.0.21/RELEASENOTES.html	2017-07-02 20:57:33.000000000 +1200
@@ -2,10 +2,10 @@
 <HTML>
 <HEAD>
  <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.72">
- <TITLE>Squid 4.0.20 release notes</TITLE>
+ <TITLE>Squid 4.0.21 release notes</TITLE>
 </HEAD>
 <BODY>
-<H1>Squid 4.0.20 release notes</H1>
+<H1>Squid 4.0.21 release notes</H1>
 
 <H2>Squid Developers</H2>
 <HR>
@@ -62,7 +62,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-4.0.20 for testing.</P>
+<P>The Squid Team are pleased to announce the release of Squid-4.0.21 for testing.</P>
 <P>This new release is available for download from 
 <A HREF="http://www.squid-cache.org/Versions/v4/">http://www.squid-cache.org/Versions/v4/</A> or the
 <A HREF="http://www.squid-cache.org/Download/http-mirrors.html">mirrors</A>.</P>
@@ -237,10 +237,9 @@
 integration with daemon managers such as Upstart or systemd which assume the
 process they initiated is the daemon with a PID to control.</P>
 
-<P>The squid binary now has a new <EM>--foreground</EM> command line option
-which prevents the process from exiting early while background workers
-continue their processing. When run with this option Squid will now wait
-for the worker(s) to finish before exiting. Unlike the old <EM>-N</EM> option
+<P>The squid binary now has a new <EM>--foreground</EM> command line option,
+which (only) prevents daemonizing the master process.
+Unlike the old <EM>-N</EM> option,
 <EM>--foreground</EM> supports SMP workers and multi-process features.
 <EM>--foreground</EM> is particularly useful for use with <EM>-z</EM> (disk
 cache structures creation), as it allows the caller to wait until Squid has
@@ -342,6 +341,11 @@
 including messages received from ICAP servers.</P>
 <P>New <EM>has</EM> type for matching whether or not Squid is able to provide
 certain sets of transaction state. For example HTTP reply headers.</P>
+<P>New <EM>transaction_initiator</EM> type for detecting various
+unusual transactions.</P>
+<P>New <EM>--consensus</EM>, <EM>--client-requested</EM> and
+<EM>--server-provided</EM> flags for the <EM>ssl::server_name</EM>
+type to control which server name to match against.</P>
 
 <DT><B>auth_param</B><DD>
 <P>New parameter <EM>queue-size=</EM> to set the maximum number
diff -u -r -N squid-4.0.20/scripts/Makefile.in squid-4.0.21/scripts/Makefile.in
--- squid-4.0.20/scripts/Makefile.in	2017-06-02 00:53:23.000000000 +1200
+++ squid-4.0.21/scripts/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/Acl.cc squid-4.0.21/src/acl/Acl.cc
--- squid-4.0.20/src/acl/Acl.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Acl.cc	2017-07-02 20:41:18.000000000 +1200
@@ -12,187 +12,68 @@
 #include "acl/Acl.h"
 #include "acl/Checklist.h"
 #include "acl/Gadgets.h"
+#include "acl/Options.h"
 #include "anyp/PortCfg.h"
 #include "cache_cf.h"
 #include "ConfigParser.h"
 #include "Debug.h"
-#include "dlink.h"
 #include "fatal.h"
 #include "globals.h"
 #include "profiler/Profiler.h"
+#include "sbuf/List.h"
+#include "sbuf/Stream.h"
 #include "SquidConfig.h"
 
-#include <vector>
-
-#define abortFlags(CONTENT) \
-   do { \
-    debugs(28, 0, CONTENT); \
-    self_destruct(); \
-   } while (0)
-
-const ACLFlag ACLFlags::NoFlags[1] = {ACL_F_END};
+#include <algorithm>
+#include <map>
 
 const char *AclMatchedName = NULL;
 
-ACLFlags::FlagsTokenizer::FlagsTokenizer(): tokPos(NULL) { }
+namespace Acl {
 
-ACLFlag
-ACLFlags::FlagsTokenizer::nextFlag()
-{
-    if (needNextToken()) {
-        if (!nextToken())
-            return 0;
-    } else
-        ++tokPos;
-    return *tokPos;
-}
-
-bool
-ACLFlags::FlagsTokenizer::hasParameter() const
-{
-    return tokPos && tokPos[0] && tokPos[1] == '=' && tokPos[2];
-}
+/// ACL type name comparison functor
+class TypeNameCmp {
+public:
+    bool operator()(TypeName a, TypeName b) const { return strcmp(a, b) < 0; }
+};
 
-SBuf
-ACLFlags::FlagsTokenizer::getParameter() const
-{
-    return hasParameter() ? SBuf(&tokPos[2]) : SBuf();
-}
+/// ACL makers indexed by ACL type name
+typedef std::map<TypeName, Maker, TypeNameCmp> Makers;
 
-bool
-ACLFlags::FlagsTokenizer::needNextToken() const
+/// registered ACL Makers
+static Makers &
+TheMakers()
 {
-    return !tokPos || !tokPos[0] || !tokPos[1] || tokPos[1] == '=';
-}
-
-bool
-ACLFlags::FlagsTokenizer::nextToken()
-{
-    char *t = ConfigParser::PeekAtToken();
-    if (t == NULL || t[0] != '-' || !t[1])
-        return false;
-    (void)ConfigParser::NextQuotedToken();
-    if (strcmp(t, "--") == 0)
-        return false;
-    tokPos = t + 1;
-    return true;
-}
-
-ACLFlags::~ACLFlags()
-{
-    delete delimiters_;
-}
-
-ACLFlags::Status
-ACLFlags::flagStatus(const ACLFlag f) const
-{
-    if (f == ACL_F_REGEX_CASE)
-        return noParameter;
-    if (f == ACL_F_SUBSTRING)
-        return parameterOptional;
-    if (supported_.find(f) != std::string::npos)
-        return noParameter;
-    return notSupported;
-}
-
-bool
-ACLFlags::parameterSupported(const ACLFlag f, const SBuf &val) const
-{
-    if (f == ACL_F_SUBSTRING)
-        return val.findFirstOf(CharacterSet::ALPHA + CharacterSet::DIGIT) == SBuf::npos;
-    return true;
+    static Makers Registry;
+    return Registry;
 }
 
-void
-ACLFlags::makeSet(const ACLFlag f, const SBuf &param)
-{
-    flags_ |= flagToInt(f);
-    if (!param.isEmpty())
-        flagParameters_[f].append(param);
-}
-
-void
-ACLFlags::makeUnSet(const ACLFlag f)
-{
-    flags_ &= ~flagToInt(f);
-    flagParameters_[f].clear();
-}
-
-void
-ACLFlags::parseFlags()
+/// creates an ACL object of the named (and already registered) ACL child type
+static
+ACL *
+Make(TypeName typeName)
 {
-    FlagsTokenizer tokenizer;
-    ACLFlag flag('\0');
-    while ((flag = tokenizer.nextFlag())) {
-        switch (flagStatus(flag))
-        {
-        case notSupported:
-            abortFlags("Flag '" << flag << "' not supported");
-            break;
-        case noParameter:
-            makeSet(flag);
-            break;
-        case parameterRequired:
-            if (!tokenizer.hasParameter()) {
-                abortFlags("Flag '" << flag << "' must have a parameter");
-                break;
-            }
-        case parameterOptional:
-            SBuf param;
-            if (tokenizer.hasParameter()) {
-                param = tokenizer.getParameter();
-                if (!parameterSupported(flag, param))
-                    abortFlags("Parameter '" << param << "' for flag '" << flag << "' not supported");
-            }
-            makeSet(flag, param);
-            break;
-        }
-    }
-
-    /*Regex code needs to parse -i file*/
-    if ( isSet(ACL_F_REGEX_CASE)) {
-        ConfigParser::TokenPutBack("-i");
-        makeUnSet('i');
+    const auto pos = TheMakers().find(typeName);
+    if (pos == TheMakers().end()) {
+        debugs(28, DBG_CRITICAL, "FATAL: Invalid ACL type '" << typeName << "'");
+        self_destruct();
+        assert(false); // not reached
     }
-}
 
-SBuf
-ACLFlags::parameter(const ACLFlag f) const
-{
-    assert(static_cast<uint32_t>(f - 'A') < FlagIndexMax);
-    auto p = flagParameters_.find(f);
-    return p == flagParameters_.end() ? SBuf() : p->second;
+    ACL *result = (pos->second)(pos->first);
+    debugs(28, 4, typeName << '=' << result);
+    assert(result);
+    return result;
 }
 
-const CharacterSet *
-ACLFlags::delimiters()
-{
-    if (isSet(ACL_F_SUBSTRING) && !delimiters_) {
-        static const SBuf defaultParameter(",");
-        SBuf rawParameter = parameter(ACL_F_SUBSTRING);
-        if (rawParameter.isEmpty())
-            rawParameter = defaultParameter;
-        delimiters_ = new CharacterSet("ACLFlags::delimiters", rawParameter.c_str());
-    }
-    return delimiters_;
-}
+} // namespace Acl
 
-const char *
-ACLFlags::flagsStr() const
+void
+Acl::RegisterMaker(TypeName typeName, Maker maker)
 {
-    static char buf[64];
-    if (flags_ == 0)
-        return "";
-
-    char *s = buf;
-    *s++ = '-';
-    for (ACLFlag f = 'A'; f <= 'z'; f++) {
-        // ACL_F_REGEX_CASE (-i) flag handled by ACLRegexData class, ignore
-        if (isSet(f) && f != ACL_F_REGEX_CASE)
-            *s++ = f;
-    }
-    *s = '\0';
-    return buf;
+    assert(typeName);
+    assert(*typeName);
+    TheMakers().emplace(typeName, maker);
 }
 
 void *
@@ -223,17 +104,6 @@
     return NULL;
 }
 
-ACL *
-ACL::Factory (char const *type)
-{
-    ACL *result = Prototype::Factory (type);
-
-    if (!result)
-        fatal ("Unknown acl type in ACL::Factory");
-
-    return result;
-}
-
 ACL::ACL() :
     cfgline(nullptr),
     next(nullptr),
@@ -242,15 +112,6 @@
     *name = 0;
 }
 
-ACL::ACL(const ACLFlag flgs[]) :
-    cfgline(NULL),
-    next(NULL),
-    flags(flgs),
-    registered(false)
-{
-    *name = 0;
-}
-
 bool ACL::valid () const
 {
     return true;
@@ -365,16 +226,9 @@
         return; // ignore the line
     }
 
-    if (!Prototype::Registered(theType)) {
-        debugs(28, DBG_CRITICAL, "FATAL: Invalid ACL type '" << theType << "'");
-        // XXX: make this an ERROR and skip the ACL creation. We *may* die later when its use is attempted. Or may not.
-        parser.destruct();
-        return;
-    }
-
     if ((A = FindByName(aclname)) == NULL) {
         debugs(28, 3, "aclParseAclLine: Creating ACL '" << aclname << "'");
-        A = ACL::Factory(theType);
+        A = Acl::Make(theType);
         A->context(aclname, config_input_line);
         new_acl = 1;
     } else {
@@ -394,7 +248,7 @@
      */
     AclMatchedName = A->name;   /* ugly */
 
-    A->flags.parseFlags();
+    A->parseFlags();
 
     /*split the function here */
     A->parse();
@@ -431,6 +285,30 @@
     return false;
 }
 
+void
+ACL::parseFlags()
+{
+    // ACL kids that carry ACLData which supports parameter flags override this
+    Acl::ParseFlags(options(), Acl::NoFlags());
+}
+
+SBufList
+ACL::dumpOptions()
+{
+    SBufList result;
+    const auto &myOptions = options();
+    // optimization: most ACLs do not have myOptions
+    // this check also works around dump_SBufList() adding ' ' after empty items
+    if (!myOptions.empty()) {
+        SBufStream stream;
+        stream << myOptions;
+        const SBuf optionsImage = stream.buf();
+        if (!optionsImage.isEmpty())
+            result.push_back(optionsImage);
+    }
+    return result;
+}
+
 /* ACL result caching routines */
 
 int
@@ -522,69 +400,6 @@
     AclMatchedName = NULL; // in case it was pointing to our name
 }
 
-ACL::Prototype::Prototype() : prototype (NULL), typeString (NULL) {}
-
-ACL::Prototype::Prototype (ACL const *aPrototype, char const *aType) : prototype (aPrototype), typeString (aType)
-{
-    registerMe ();
-}
-
-std::vector<ACL::Prototype const *> * ACL::Prototype::Registry;
-void *ACL::Prototype::Initialized;
-
-bool
-ACL::Prototype::Registered(char const *aType)
-{
-    debugs(28, 7, "ACL::Prototype::Registered: invoked for type " << aType);
-
-    for (iterator i = Registry->begin(); i != Registry->end(); ++i)
-        if (!strcmp (aType, (*i)->typeString)) {
-            debugs(28, 7, "ACL::Prototype::Registered:    yes");
-            return true;
-        }
-
-    debugs(28, 7, "ACL::Prototype::Registered:    no");
-    return false;
-}
-
-void
-ACL::Prototype::registerMe ()
-{
-    if (!Registry || (Initialized != ((char *)Registry - 5))  ) {
-        /* TODO: extract this */
-        /* Not initialised */
-        Registry = new std::vector<ACL::Prototype const *>;
-        Initialized = (char *)Registry - 5;
-    }
-
-    if (Registered (typeString))
-        fatalf ("Attempt to register %s twice", typeString);
-
-    Registry->push_back (this);
-}
-
-ACL::Prototype::~Prototype()
-{
-    // TODO: unregister me
-}
-
-ACL *
-ACL::Prototype::Factory (char const *typeToClone)
-{
-    debugs(28, 4, "ACL::Prototype::Factory: cloning an object for type '" << typeToClone << "'");
-
-    for (iterator i = Registry->begin(); i != Registry->end(); ++i)
-        if (!strcmp (typeToClone, (*i)->typeString)) {
-            ACL *A = (*i)->prototype->clone();
-            A->flags = (*i)->prototype->flags;
-            return A;
-        }
-
-    debugs(28, 4, "ACL::Prototype::Factory: cloning failed, no type '" << typeToClone << "' available");
-
-    return NULL;
-}
-
 void
 ACL::Initialize()
 {
diff -u -r -N squid-4.0.20/src/acl/Acl.h squid-4.0.21/src/acl/Acl.h
--- squid-4.0.20/src/acl/Acl.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Acl.h	2017-07-02 20:41:18.000000000 +1200
@@ -10,109 +10,27 @@
 #define SQUID_ACL_H
 
 #include "acl/forward.h"
-#include "base/CharacterSet.h"
+#include "acl/Options.h"
 #include "cbdata.h"
 #include "defines.h"
 #include "dlink.h"
-#include "sbuf/List.h"
+#include "sbuf/forward.h"
 
-#include <map>
+#include <algorithm>
 #include <ostream>
-#include <string>
-#include <vector>
 
 class ConfigParser;
 
-typedef char ACLFlag;
-// ACLData Flags
-#define ACL_F_REGEX_CASE 'i'
-#define ACL_F_NO_LOOKUP 'n'
-#define ACL_F_STRICT 's'
-#define ACL_F_SUBSTRING 'm'
-#define ACL_F_END '\0'
-
-/**
- * \ingroup ACLAPI
- * Used to hold a list of one-letter flags which can be passed as parameters
- * to acls  (eg '-i', '-n' etc)
- */
-class ACLFlags
-{
-public:
-    enum Status
-    {
-        notSupported,
-        noParameter,
-        parameterOptional,
-        parameterRequired
-    };
-
-    explicit ACLFlags(const ACLFlag flags[]) : supported_(flags), flags_(0), delimiters_(nullptr) {}
-    ACLFlags() : flags_(0), delimiters_(nullptr) {}
-    ~ACLFlags();
-    /// \return a Status for the given ACLFlag.
-    Status flagStatus(const ACLFlag f) const;
-    /// \return true if the parameter for the given flag is acceptable.
-    bool parameterSupported(const ACLFlag f, const SBuf &val) const;
-    /// Set the given flag
-    void makeSet(const ACLFlag f, const SBuf &param = SBuf(""));
-    void makeUnSet(const ACLFlag f); ///< Unset the given flag
-    /// \return true if the given flag is set.
-    bool isSet(const ACLFlag f) const { return flags_ & flagToInt(f);}
-    /// \return the parameter value of the given flag if set.
-    SBuf parameter(const ACLFlag f) const;
-    /// \return ACL_F_SUBSTRING parameter value(if set) converted to CharacterSet.
-    const CharacterSet *delimiters();
-    /// Parse optional flags given in the form -[A..Z|a..z]
-    void parseFlags();
-    const char *flagsStr() const; ///< Convert the flags to a string representation
-    /**
-     * Lexical analyzer for ACL flags
-     *
-     * Support tokens in the form:
-     *   flag := '-' [A-Z|a-z]+ ['=' parameter ]
-     * Each token consist by one or more single-letter flags, which may
-     * followed by a parameter string.
-     * The parameter can belongs only to the last flag in token.
-     */
-    class FlagsTokenizer
-    {
-    public:
-        FlagsTokenizer();
-        ACLFlag nextFlag(); ///< The next flag or '\0' if finished
-        /// \return true if a parameter follows the last parsed flag.
-        bool hasParameter() const;
-        /// \return the parameter of last parsed flag, if exist.
-        SBuf getParameter() const;
-
-    private:
-        /// \return true if the current token parsing is finished.
-        bool needNextToken() const;
-        /// Peeks at the next token and return false if the next token
-        /// is not flag, or a '--' is read.
-        bool nextToken();
+namespace Acl {
 
-        char *tokPos;
-    };
+/// the ACL type name known to admins
+typedef const char *TypeName;
+/// a "factory" function for making ACL objects (of some ACL child type)
+typedef ACL *(*Maker)(TypeName typeName);
+/// use the given ACL Maker for all ACLs of the named type
+void RegisterMaker(TypeName typeName, Maker maker);
 
-private:
-    /// Convert a flag to a 64bit unsigned integer.
-    /// The characters from 'A' to 'z' represented by the values from 65 to 122.
-    /// They are 57 different characters which can be fit to the bits of an 64bit
-    /// integer.
-    uint64_t flagToInt(const ACLFlag f) const {
-        assert('A' <= f && f <= 'z');
-        return ((uint64_t)1 << (f - 'A'));
-    }
-
-    std::string supported_; ///< The supported character flags
-    uint64_t flags_; ///< The flags which are set
-    static const uint32_t FlagIndexMax = 'z' - 'A';
-    std::map<ACLFlag, SBuf> flagParameters_;
-    CharacterSet *delimiters_;
-public:
-    static const ACLFlag NoFlags[1]; ///< An empty flags list
-};
+} // namespace Acl
 
 /// A configurable condition. A node in the ACL expression tree.
 /// Can evaluate itself in FilledChecklist context.
@@ -125,13 +43,11 @@
     void *operator new(size_t);
     void operator delete(void *);
 
-    static ACL *Factory(char const *);
     static void ParseAclLine(ConfigParser &parser, ACL ** head);
     static void Initialize();
     static ACL *FindByName(const char *name);
 
     ACL();
-    explicit ACL(const ACLFlag flgs[]);
     virtual ~ACL();
 
     /// sets user-specified ACL name and squid.conf context
@@ -143,7 +59,11 @@
     /// Updates the checklist state on match, async, and failure.
     bool matches(ACLChecklist *checklist) const;
 
-    virtual ACL *clone() const = 0;
+    /// \returns (linked) Options supported by this ACL
+    virtual const Acl::Options &options() { return Acl::NoOptions(); }
+
+    /// configures ACL options, throwing on configuration errors
+    virtual void parseFlags();
 
     /// parses node represenation in squid.conf; dies on failures
     virtual void parse() = 0;
@@ -158,36 +78,13 @@
 
     virtual void prepareForUse() {}
 
+    SBufList dumpOptions(); ///< \returns approximate options configuration
+
     char name[ACL_NAME_SZ];
     char *cfgline;
     ACL *next; // XXX: remove or at least use refcounting
-    ACLFlags flags; ///< The list of given ACL flags
     bool registered; ///< added to the global list of ACLs via aclRegister()
 
-public:
-
-    class Prototype
-    {
-
-    public:
-        Prototype();
-        Prototype(ACL const *, char const *);
-        ~Prototype();
-        static bool Registered(char const *);
-        static ACL *Factory(char const *);
-
-    private:
-        ACL const *prototype;
-        char const *typeString;
-
-    private:
-        static std::vector<Prototype const *> * Registry;
-        static void *Initialized;
-        typedef std::vector<Prototype const*>::iterator iterator;
-        typedef std::vector<Prototype const*>::const_iterator const_iterator;
-        void registerMe();
-    };
-
 private:
     /// Matches the actual data in checklist against this ACL.
     virtual int match(ACLChecklist *checklist) = 0; // XXX: missing const
@@ -237,6 +134,22 @@
         return code;
     }
 
+    /// Whether an "allow" rule matched. If in doubt, use this popular method.
+    /// Also use this method to treat exceptional ACCESS_DUNNO and
+    /// ACCESS_AUTH_REQUIRED outcomes as if a "deny" rule matched.
+    /// See also: denied().
+    bool allowed() const { return code == ACCESS_ALLOWED; }
+
+    /// Whether a "deny" rule matched. Avoid this rarely used method.
+    /// Use this method (only) to treat exceptional ACCESS_DUNNO and
+    /// ACCESS_AUTH_REQUIRED outcomes as if an "allow" rule matched.
+    /// See also: allowed().
+    bool denied() const { return code == ACCESS_DENIED; }
+
+    /// whether there was either a default rule, a rule without any ACLs, or a
+    /// a rule with ACLs that all matched
+    bool someRuleMatched() const { return allowed() || denied(); }
+
     aclMatchCode code; ///< ACCESS_* code
     int kind; ///< which custom access list verb matched
 };
diff -u -r -N squid-4.0.20/src/acl/AdaptationService.cc squid-4.0.21/src/acl/AdaptationService.cc
--- squid-4.0.20/src/acl/AdaptationService.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/AdaptationService.cc	2017-07-02 20:41:18.000000000 +1200
@@ -8,14 +8,14 @@
 
 #include "squid.h"
 #include "acl/AdaptationService.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/IntRange.h"
 #include "adaptation/Config.h"
 #include "adaptation/History.h"
 #include "HttpRequest.h"
 
 int
-ACLAdaptationServiceStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLAdaptationServiceStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     HttpRequest::Pointer request = checklist->request;
     if (request == NULL)
@@ -33,11 +33,3 @@
     return 0;
 }
 
-ACLAdaptationServiceStrategy *
-ACLAdaptationServiceStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLAdaptationServiceStrategy ACLAdaptationServiceStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/AdaptationService.h squid-4.0.21/src/acl/AdaptationService.h
--- squid-4.0.20/src/acl/AdaptationService.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/AdaptationService.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,7 +9,6 @@
 #ifndef SQUID_ACLADAPTATIONSERVICE_H
 #define SQUID_ACLADAPTATIONSERVICE_H
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 
 /// \ingroup ACLAPI
@@ -17,27 +16,7 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLAdaptationServiceStrategy *Instance();
-    /**
-     * Not implemented to prevent copies of the instance.
-     */
-    ACLAdaptationServiceStrategy(ACLAdaptationServiceStrategy const &);
-
-private:
-    static ACLAdaptationServiceStrategy Instance_;
-    ACLAdaptationServiceStrategy() {}
-
-    ACLAdaptationServiceStrategy &operator = (ACLAdaptationServiceStrategy const &);
-};
-
-/// \ingroup ACLAPI
-class ACLAdaptationService
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<const char *> RegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* SQUID_ACLADAPTATIONSERVICE_H */
diff -u -r -N squid-4.0.20/src/acl/AllOf.h squid-4.0.21/src/acl/AllOf.h
--- squid-4.0.20/src/acl/AllOf.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/AllOf.h	2017-07-02 20:41:18.000000000 +1200
@@ -31,9 +31,6 @@
 private:
     /* Acl::InnerNode API */
     virtual int doMatch(ACLChecklist *checklist, Nodes::const_iterator start) const;
-
-    static Prototype RegistryProtoype;
-    static AllOf RegistryEntry_;
 };
 
 } // namespace Acl
diff -u -r -N squid-4.0.20/src/acl/AnyOf.h squid-4.0.21/src/acl/AnyOf.h
--- squid-4.0.20/src/acl/AnyOf.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/AnyOf.h	2017-07-02 20:41:18.000000000 +1200
@@ -24,10 +24,6 @@
     virtual char const *typeString() const;
     virtual ACL *clone() const;
     virtual void parse();
-
-private:
-    static Prototype RegistryProtoype;
-    static AnyOf RegistryEntry_;
 };
 
 } // namespace Acl
diff -u -r -N squid-4.0.20/src/acl/Arp.h squid-4.0.21/src/acl/Arp.h
--- squid-4.0.20/src/acl/Arp.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Arp.h	2017-07-02 20:41:18.000000000 +1200
@@ -10,7 +10,6 @@
 #define SQUID_ACLARP_H
 
 #include "acl/Acl.h"
-#include "acl/Checklist.h"
 
 #include <set>
 
@@ -38,8 +37,6 @@
     virtual bool empty () const;
 
 protected:
-    static Prototype RegistryProtoype;
-    static ACLARP RegistryEntry_;
     char const *class_;
     typedef std::set<Eui::Eui48> AclArpData_t;
     AclArpData_t aclArpData;
diff -u -r -N squid-4.0.20/src/acl/Asn.cc squid-4.0.21/src/acl/Asn.cc
--- squid-4.0.20/src/acl/Asn.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Asn.cc	2017-07-02 20:41:18.000000000 +1200
@@ -15,10 +15,12 @@
 #include "acl/DestinationAsn.h"
 #include "acl/DestinationIp.h"
 #include "acl/SourceAsn.h"
+#include "acl/Strategised.h"
 #include "FwdState.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "ipcache.h"
+#include "MasterXaction.h"
 #include "mgr/Registration.h"
 #include "radix.h"
 #include "RequestFlags.h"
@@ -239,7 +241,8 @@
     debugs(53, 3, "AS " << as);
     snprintf(asres, 4096, "whois://%s/!gAS%d", Config.as_whois_server, as);
     asState->as_number = as;
-    asState->request = HttpRequest::CreateFromUrl(asres);
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initAsn);
+    asState->request = HttpRequest::FromUrl(asres, mx);
     assert(asState->request != NULL);
 
     if ((e = storeGetPublic(asres, Http::METHOD_GET)) == NULL) {
@@ -577,30 +580,14 @@
 
 template class ACLStrategised<Ip::Address>;
 
-ACL::Prototype ACLASN::SourceRegistryProtoype(&ACLASN::SourceRegistryEntry_, "src_as");
-
-ACLStrategised<Ip::Address> ACLASN::SourceRegistryEntry_(new ACLASN, ACLSourceASNStrategy::Instance(), "src_as");
-
-ACL::Prototype ACLASN::DestinationRegistryProtoype(&ACLASN::DestinationRegistryEntry_, "dst_as");
-
-ACLStrategised<Ip::Address> ACLASN::DestinationRegistryEntry_(new ACLASN, ACLDestinationASNStrategy::Instance(), "dst_as");
-
 int
-ACLSourceASNStrategy::match (ACLData<Ip::Address> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLSourceASNStrategy::match (ACLData<Ip::Address> * &data, ACLFilledChecklist *checklist)
 {
     return data->match(checklist->src_addr);
 }
 
-ACLSourceASNStrategy *
-ACLSourceASNStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLSourceASNStrategy ACLSourceASNStrategy::Instance_;
-
 int
-ACLDestinationASNStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLDestinationASNStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     const ipcache_addrs *ia = ipcache_gethostbyname(checklist->request->url.host(), IP_LOOKUP_IF_MISS);
 
@@ -624,11 +611,3 @@
     return data->match(noaddr);
 }
 
-ACLDestinationASNStrategy *
-ACLDestinationASNStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLDestinationASNStrategy ACLDestinationASNStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/Asn.h squid-4.0.21/src/acl/Asn.h
--- squid-4.0.20/src/acl/Asn.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Asn.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,9 +9,7 @@
 #ifndef SQUID_ACLASN_H
 #define SQUID_ACLASN_H
 
-#include "acl/Checklist.h"
 #include "acl/Data.h"
-#include "acl/Strategised.h"
 #include "base/CbDataList.h"
 #include "ip/Address.h"
 
@@ -40,10 +38,6 @@
     virtual void prepareForUse();
 
 private:
-    static ACL::Prototype SourceRegistryProtoype;
-    static ACLStrategised<Ip::Address> SourceRegistryEntry_;
-    static ACL::Prototype DestinationRegistryProtoype;
-    static ACLStrategised<Ip::Address> DestinationRegistryEntry_;
     CbDataList<int> *data;
 };
 
diff -u -r -N squid-4.0.20/src/acl/AtStep.cc squid-4.0.21/src/acl/AtStep.cc
--- squid-4.0.20/src/acl/AtStep.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/AtStep.cc	2017-07-02 20:41:18.000000000 +1200
@@ -12,13 +12,13 @@
 
 #include "acl/AtStep.h"
 #include "acl/AtStepData.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "client_side.h"
 #include "http/Stream.h"
 #include "ssl/ServerBump.h"
 
 int
-ACLAtStepStrategy::match (ACLData<Ssl::BumpStep> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLAtStepStrategy::match (ACLData<Ssl::BumpStep> * &data, ACLFilledChecklist *checklist)
 {
     Ssl::ServerBump *bump = NULL;
     if (checklist->conn() != NULL && (bump = checklist->conn()->serverBump()))
@@ -28,13 +28,5 @@
     return 0;
 }
 
-ACLAtStepStrategy *
-ACLAtStepStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLAtStepStrategy ACLAtStepStrategy::Instance_;
-
 #endif /* USE_OPENSSL */
 
diff -u -r -N squid-4.0.20/src/acl/AtStep.h squid-4.0.21/src/acl/AtStep.h
--- squid-4.0.20/src/acl/AtStep.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/AtStep.h	2017-07-02 20:41:18.000000000 +1200
@@ -11,7 +11,6 @@
 
 #if USE_OPENSSL
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 #include "ssl/support.h"
 
@@ -20,25 +19,7 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLAtStepStrategy *Instance();
-
-    // Not implemented to prevent copies of the instance.
-    ACLAtStepStrategy(ACLAtStepStrategy const &);
-
-private:
-    static ACLAtStepStrategy Instance_;
-    ACLAtStepStrategy() {}
-
-    ACLAtStepStrategy&operator=(ACLAtStepStrategy const &);
-};
-
-class ACLAtStep
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<Ssl::BumpStep> RegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* USE_OPENSSL */
diff -u -r -N squid-4.0.20/src/acl/BoolOps.cc squid-4.0.21/src/acl/BoolOps.cc
--- squid-4.0.20/src/acl/BoolOps.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/BoolOps.cc	2017-07-02 20:41:18.000000000 +1200
@@ -10,6 +10,7 @@
 #include "acl/BoolOps.h"
 #include "acl/Checklist.h"
 #include "Debug.h"
+#include "sbuf/SBuf.h"
 
 /* Acl::NotNode */
 
diff -u -r -N squid-4.0.20/src/acl/Browser.cc squid-4.0.21/src/acl/Browser.cc
--- squid-4.0.20/src/acl/Browser.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Browser.cc	1970-01-01 12:00:00.000000000 +1200
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 1996-2017 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 28    Access Control */
-
-#include "squid.h"
-#include "acl/Browser.h"
-#include "acl/Checklist.h"
-#include "acl/RegexData.h"
-
-/* explicit template instantiation required for some systems */
-
-template class ACLRequestHeaderStrategy<Http::HdrType::USER_AGENT>;
-
diff -u -r -N squid-4.0.20/src/acl/Browser.h squid-4.0.21/src/acl/Browser.h
--- squid-4.0.20/src/acl/Browser.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Browser.h	1970-01-01 12:00:00.000000000 +1200
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 1996-2017 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_ACLBROWSER_H
-#define SQUID_ACLBROWSER_H
-
-#include "acl/Acl.h"
-#include "acl/Data.h"
-#include "acl/RequestHeaderStrategy.h"
-#include "acl/Strategised.h"
-
-/// \ingroup ACLAPI
-class ACLBrowser
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<char const *> RegistryEntry_;
-};
-
-#endif /* SQUID_ACLBROWSER_H */
-
diff -u -r -N squid-4.0.20/src/acl/Certificate.cc squid-4.0.21/src/acl/Certificate.cc
--- squid-4.0.20/src/acl/Certificate.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Certificate.cc	2017-07-02 20:41:18.000000000 +1200
@@ -25,7 +25,7 @@
 #include "HttpRequest.h"
 
 int
-ACLCertificateStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLCertificateStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     const int fd = checklist->fd();
     const bool goodDescriptor = 0 <= fd && fd <= Biggest_FD;
@@ -36,13 +36,5 @@
     return res;
 }
 
-ACLCertificateStrategy *
-ACLCertificateStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLCertificateStrategy ACLCertificateStrategy::Instance_;
-
 #endif /* USE_OPENSSL */
 
diff -u -r -N squid-4.0.20/src/acl/Certificate.h squid-4.0.21/src/acl/Certificate.h
--- squid-4.0.20/src/acl/Certificate.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Certificate.h	2017-07-02 20:41:18.000000000 +1200
@@ -20,29 +20,7 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLCertificateStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLCertificateStrategy(ACLCertificateStrategy const &);
-
-private:
-    static ACLCertificateStrategy Instance_;
-    ACLCertificateStrategy() {}
-
-    ACLCertificateStrategy&operator=(ACLCertificateStrategy const &);
-};
-
-/// \ingroup ACLAPI
-class ACLCertificate
-{
-
-private:
-    static ACL::Prototype UserRegistryProtoype;
-    static ACLStrategised<X509*> UserRegistryEntry_;
-    static ACL::Prototype CARegistryProtoype;
-    static ACLStrategised<X509 *> CARegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
 };
 
 #endif /* SQUID_ACLCERTIFICATE_H */
diff -u -r -N squid-4.0.20/src/acl/CharacterSetOption.h squid-4.0.21/src/acl/CharacterSetOption.h
--- squid-4.0.20/src/acl/CharacterSetOption.h	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.21/src/acl/CharacterSetOption.h	2017-07-02 20:41:18.000000000 +1200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1996-2017 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_ACL_CHARACTER_SET_OPTION_H
+#define SQUID_ACL_CHARACTER_SET_OPTION_H
+
+#include "acl/Options.h"
+#include "base/CharacterSet.h"
+#include "sbuf/SBuf.h"
+
+namespace Acl {
+
+typedef OptionValue<CharacterSet> CharacterSetOptionValue;
+
+/* TypedOption<CharacterSetOptionValue> specializations */
+
+template <>
+inline
+void
+TypedOption<CharacterSetOptionValue>::import(const SBuf &rawValue) const
+{
+    SBuf chars = rawValue; // because c_str() is not constant
+    recipient_->value = CharacterSet(__FILE__, chars.c_str());
+}
+
+template <>
+inline
+void
+TypedOption<CharacterSetOptionValue>::print(std::ostream &os) const
+{
+    recipient_->value.printChars(os); // TODO: Quote if needed.
+}
+
+/// option value to configure one or more characters (e.g., -m=",;")
+class CharacterSetOption: public TypedOption<CharacterSetOptionValue>
+{
+public:
+    typedef TypedOption<CharacterSetOptionValue> Parent;
+    CharacterSetOption(): Parent(valueOptional) {}
+};
+
+} // namespace Acl
+
+#endif /* SQUID_ACL_CHARACTER_SET_OPTION_H */
+
diff -u -r -N squid-4.0.20/src/acl/ConnectionsEncrypted.h squid-4.0.21/src/acl/ConnectionsEncrypted.h
--- squid-4.0.20/src/acl/ConnectionsEncrypted.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/ConnectionsEncrypted.h	2017-07-02 20:41:18.000000000 +1200
@@ -33,8 +33,6 @@
     virtual bool empty () const;
 
 protected:
-    static Prototype RegistryProtoype;
-    static ConnectionsEncrypted RegistryEntry_;
     char const *class_;
 };
 
diff -u -r -N squid-4.0.20/src/acl/Data.h squid-4.0.21/src/acl/Data.h
--- squid-4.0.20/src/acl/Data.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Data.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,9 +9,10 @@
 #ifndef SQUID_ACLDATA_H
 #define SQUID_ACLDATA_H
 
+#include "acl/Options.h"
 #include "sbuf/List.h"
 
-/// \ingroup ACLAPI
+/// Configured ACL parameter(s) (e.g., domain names in dstdomain ACL).
 template <class M>
 class ACLData
 {
@@ -20,6 +21,9 @@
 
     virtual ~ACLData() {}
 
+    /// \returns the flags supported by these ACL parameters (e.g., "-i")
+    virtual const Acl::ParameterFlags &supportedFlags() const { return Acl::NoFlags(); }
+
     virtual bool match(M) =0;
     virtual SBufList dump() const =0;
     virtual void parse() =0;
diff -u -r -N squid-4.0.20/src/acl/DestinationAsn.h squid-4.0.21/src/acl/DestinationAsn.h
--- squid-4.0.20/src/acl/DestinationAsn.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/DestinationAsn.h	2017-07-02 20:41:18.000000000 +1200
@@ -18,24 +18,8 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    static ACLDestinationASNStrategy *Instance();
-
-    /**
-     * Not implemented to prevent copies of the instance.
-     \par
-     * Not private to prevent brain dead g++ warnings about
-     * private constructors with no friends
-     */
-    ACLDestinationASNStrategy(ACLDestinationASNStrategy const &);
-
-private:
-    static ACLDestinationASNStrategy Instance_;
-    ACLDestinationASNStrategy() {}
-
-    ACLDestinationASNStrategy&operator=(ACLDestinationASNStrategy const &);
 };
 
 #endif /* SQUID_ACLDESTINATIONASN_H */
diff -u -r -N squid-4.0.20/src/acl/DestinationDomain.cc squid-4.0.21/src/acl/DestinationDomain.cc
--- squid-4.0.20/src/acl/DestinationDomain.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/DestinationDomain.cc	2017-07-02 20:41:18.000000000 +1200
@@ -41,8 +41,19 @@
     checklist->resumeNonBlockingCheck(DestinationDomainLookup::Instance());
 }
 
+/* ACLDestinationDomainStrategy */
+
+const Acl::Options &
+ACLDestinationDomainStrategy::options()
+{
+    static const Acl::BooleanOption LookupBanFlag;
+    static const Acl::Options MyOptions = { { "-n", &LookupBanFlag } };
+    LookupBanFlag.linkWith(&lookupBanned);
+    return MyOptions;
+}
+
 int
-ACLDestinationDomainStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &flags)
+ACLDestinationDomainStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     assert(checklist != NULL && checklist->request != NULL);
 
@@ -50,7 +61,7 @@
         return 1;
     }
 
-    if (flags.isSet(ACL_F_NO_LOOKUP)) {
+    if (lookupBanned) {
         debugs(28, 3, "No-lookup DNS ACL '" << AclMatchedName << "' for " << checklist->request->url.host());
         return 0;
     }
@@ -91,11 +102,3 @@
     return data->match("none");
 }
 
-ACLDestinationDomainStrategy *
-ACLDestinationDomainStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLDestinationDomainStrategy ACLDestinationDomainStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/DestinationDomain.h squid-4.0.21/src/acl/DestinationDomain.h
--- squid-4.0.20/src/acl/DestinationDomain.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/DestinationDomain.h	2017-07-02 20:41:18.000000000 +1200
@@ -20,23 +20,13 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLDestinationDomainStrategy *Instance();
+    /* ACLStrategy API */
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    /**
-     * Not implemented to prevent copies of the instance.
-     \par
-     * Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends
-     */
-    ACLDestinationDomainStrategy(ACLDestinationDomainStrategy const &);
+    virtual const Acl::Options &options();
 
 private:
-    static ACLDestinationDomainStrategy Instance_;
-    ACLDestinationDomainStrategy() {}
-
-    ACLDestinationDomainStrategy&operator=(ACLDestinationDomainStrategy const &);
+    Acl::BooleanOptionValue lookupBanned; ///< Are DNS lookups allowed?
 };
 
 /// \ingroup ACLAPI
@@ -52,16 +42,5 @@
     static void LookupDone(const char *, const Dns::LookupDetails &, void *);
 };
 
-/// \ingroup ACLAPI
-class ACLDestinationDomain
-{
-
-private:
-    static ACL::Prototype LiteralRegistryProtoype;
-    static ACLStrategised<char const *> LiteralRegistryEntry_;
-    static ACL::Prototype RegexRegistryProtoype;
-    static ACLStrategised<char const *> RegexRegistryEntry_;
-};
-
 #endif /* SQUID_ACLDESTINATIONDOMAIN_H */
 
diff -u -r -N squid-4.0.20/src/acl/DestinationIp.cc squid-4.0.21/src/acl/DestinationIp.cc
--- squid-4.0.20/src/acl/DestinationIp.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/DestinationIp.cc	2017-07-02 20:41:18.000000000 +1200
@@ -17,14 +17,21 @@
 #include "HttpRequest.h"
 #include "SquidConfig.h"
 
-ACLFlag ACLDestinationIP::SupportedFlags[] = {ACL_F_NO_LOOKUP, ACL_F_END};
-
 char const *
 ACLDestinationIP::typeString() const
 {
     return "dst";
 }
 
+const Acl::Options &
+ACLDestinationIP::options()
+{
+    static const Acl::BooleanOption LookupBan;
+    static const Acl::Options MyOptions = { { "-n", &LookupBan } };
+    LookupBan.linkWith(&lookupBanned);
+    return MyOptions;
+}
+
 int
 ACLDestinationIP::match(ACLChecklist *cl)
 {
@@ -44,7 +51,7 @@
                ACLIP::match(conn->clientConnection->local) : -1;
     }
 
-    if (flags.isSet(ACL_F_NO_LOOKUP)) {
+    if (lookupBanned) {
         if (!checklist->request->url.hostIsNumeric()) {
             debugs(28, 3, "No-lookup DNS ACL '" << AclMatchedName << "' for " << checklist->request->url.host());
             return 0;
diff -u -r -N squid-4.0.20/src/acl/DestinationIp.h squid-4.0.21/src/acl/DestinationIp.h
--- squid-4.0.20/src/acl/DestinationIp.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/DestinationIp.h	2017-07-02 20:41:18.000000000 +1200
@@ -30,16 +30,14 @@
     MEMPROXY_CLASS(ACLDestinationIP);
 
 public:
-    ACLDestinationIP(): ACLIP(ACLDestinationIP::SupportedFlags) {}
     virtual char const *typeString() const;
+    virtual const Acl::Options &options();
     virtual int match(ACLChecklist *checklist);
 
     virtual ACL *clone()const;
 
-    static ACLFlag SupportedFlags[];
 private:
-    static Prototype RegistryProtoype;
-    static ACLDestinationIP RegistryEntry_;
+    Acl::BooleanOptionValue lookupBanned; ///< are DNS lookups allowed?
 };
 
 #endif /* SQUID_ACLDESTINATIONIP_H */
diff -u -r -N squid-4.0.20/src/acl/Eui64.h squid-4.0.21/src/acl/Eui64.h
--- squid-4.0.20/src/acl/Eui64.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Eui64.h	2017-07-02 20:41:18.000000000 +1200
@@ -10,7 +10,6 @@
 #define SQUID_ACLEUI64_H
 
 #include "acl/Acl.h"
-#include "acl/Checklist.h"
 
 #include <set>
 
@@ -37,8 +36,6 @@
     virtual bool empty () const;
 
 protected:
-    static Prototype RegistryProtoype;
-    static ACLEui64 RegistryEntry_;
     typedef std::set<Eui::Eui64> Eui64Data_t;
     Eui64Data_t eui64Data;
     char const *class_;
diff -u -r -N squid-4.0.20/src/acl/external/AD_group/Makefile.in squid-4.0.21/src/acl/external/AD_group/Makefile.in
--- squid-4.0.20/src/acl/external/AD_group/Makefile.in	2017-06-02 00:54:32.000000000 +1200
+++ squid-4.0.21/src/acl/external/AD_group/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/delayer/ext_delayer_acl.8 squid-4.0.21/src/acl/external/delayer/ext_delayer_acl.8
--- squid-4.0.20/src/acl/external/delayer/ext_delayer_acl.8	2017-06-02 09:52:23.000000000 +1200
+++ squid-4.0.21/src/acl/external/delayer/ext_delayer_acl.8	2017-07-02 20:57:34.000000000 +1200
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_DELAYER_ACL 8"
-.TH EXT_DELAYER_ACL 8 "2017-06-01" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH EXT_DELAYER_ACL 8 "2017-07-02" "perl v5.24.1" "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
@@ -221,7 +221,7 @@
 Report ideas for new improvements to the \fISquid Developers mailing list <squid\-dev@squid\-cache.org\fR>
 .SH "SEE ALSO"
 .IX Header "SEE ALSO"
-squid (8), \s-1GPL\s0 (7),
+squid (8), \s-1GPL \\fIs0\fR\|(7),
 .PP
 The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq
 .PP
diff -u -r -N squid-4.0.20/src/acl/external/delayer/Makefile.in squid-4.0.21/src/acl/external/delayer/Makefile.in
--- squid-4.0.20/src/acl/external/delayer/Makefile.in	2017-06-02 00:54:53.000000000 +1200
+++ squid-4.0.21/src/acl/external/delayer/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/eDirectory_userip/Makefile.in squid-4.0.21/src/acl/external/eDirectory_userip/Makefile.in
--- squid-4.0.20/src/acl/external/eDirectory_userip/Makefile.in	2017-06-02 00:54:57.000000000 +1200
+++ squid-4.0.21/src/acl/external/eDirectory_userip/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/file_userip/example.conf squid-4.0.21/src/acl/external/file_userip/example.conf
--- squid-4.0.20/src/acl/external/file_userip/example.conf	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/external/file_userip/example.conf	2017-07-02 20:41:18.000000000 +1200
@@ -43,3 +43,8 @@
 #
 # Users of the "tol" group may authenticate from their VLAN
 # 10.0.0.0/255.255.0.0	@tol
+#
+# User "diniz" may authenticate from the LAN, but deny all others
+# 192.168.1.0/255.255.255.0	diniz
+# 0.0.0.0/0.0.0.0	NONE
+
diff -u -r -N squid-4.0.20/src/acl/external/file_userip/example-deny_all_but.conf squid-4.0.21/src/acl/external/file_userip/example-deny_all_but.conf
--- squid-4.0.20/src/acl/external/file_userip/example-deny_all_but.conf	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/external/file_userip/example-deny_all_but.conf	1970-01-01 12:00:00.000000000 +1200
@@ -1,2 +0,0 @@
-192.168.1.0/255.255.255.0	diniz
-0.0.0.0/0.0.0.0	NONE
diff -u -r -N squid-4.0.20/src/acl/external/file_userip/Makefile.am squid-4.0.21/src/acl/external/file_userip/Makefile.am
--- squid-4.0.20/src/acl/external/file_userip/Makefile.am	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/external/file_userip/Makefile.am	2017-07-02 20:41:18.000000000 +1200
@@ -19,6 +19,5 @@
 
 EXTRA_DIST = \
 	example.conf \
-	example-deny_all_but.conf \
 	ext_file_userip_acl.8 \
 	required.m4
diff -u -r -N squid-4.0.20/src/acl/external/file_userip/Makefile.in squid-4.0.21/src/acl/external/file_userip/Makefile.in
--- squid-4.0.20/src/acl/external/file_userip/Makefile.in	2017-06-02 00:55:01.000000000 +1200
+++ squid-4.0.21/src/acl/external/file_userip/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -712,7 +712,6 @@
 
 EXTRA_DIST = \
 	example.conf \
-	example-deny_all_but.conf \
 	ext_file_userip_acl.8 \
 	required.m4
 
diff -u -r -N squid-4.0.20/src/acl/external/kerberos_ldap_group/Makefile.in squid-4.0.21/src/acl/external/kerberos_ldap_group/Makefile.in
--- squid-4.0.20/src/acl/external/kerberos_ldap_group/Makefile.in	2017-06-02 00:55:06.000000000 +1200
+++ squid-4.0.21/src/acl/external/kerberos_ldap_group/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/LDAP_group/Makefile.in squid-4.0.21/src/acl/external/LDAP_group/Makefile.in
--- squid-4.0.20/src/acl/external/LDAP_group/Makefile.in	2017-06-02 00:54:36.000000000 +1200
+++ squid-4.0.21/src/acl/external/LDAP_group/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/LM_group/Makefile.in squid-4.0.21/src/acl/external/LM_group/Makefile.in
--- squid-4.0.20/src/acl/external/LM_group/Makefile.in	2017-06-02 00:54:43.000000000 +1200
+++ squid-4.0.21/src/acl/external/LM_group/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/Makefile.in squid-4.0.21/src/acl/external/Makefile.in
--- squid-4.0.20/src/acl/external/Makefile.in	2017-06-02 00:54:46.000000000 +1200
+++ squid-4.0.21/src/acl/external/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/session/Makefile.in squid-4.0.21/src/acl/external/session/Makefile.in
--- squid-4.0.20/src/acl/external/session/Makefile.in	2017-06-02 00:55:13.000000000 +1200
+++ squid-4.0.21/src/acl/external/session/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/SQL_session/ext_sql_session_acl.8 squid-4.0.21/src/acl/external/SQL_session/ext_sql_session_acl.8
--- squid-4.0.20/src/acl/external/SQL_session/ext_sql_session_acl.8	2017-06-02 09:52:58.000000000 +1200
+++ squid-4.0.21/src/acl/external/SQL_session/ext_sql_session_acl.8	2017-07-02 20:57:34.000000000 +1200
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_SQL_SESSION_ACL 8"
-.TH EXT_SQL_SESSION_ACL 8 "2017-06-01" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH EXT_SQL_SESSION_ACL 8 "2017-07-02" "perl v5.24.1" "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
@@ -150,7 +150,7 @@
 Taking an identity token to be validated (as determined by the external_acl_type format)
 it returns a username or tag associated with the identity token passed in.
 .PP
-Common forms of identifiers are \s-1IP\s0 address, \s-1EUI\s0 (\s-1MAC\s0) address, passwords, or \s-1UUID\s0 tokens.
+Common forms of identifiers are \s-1IP\s0 address, \s-1EUI \s0(\s-1MAC\s0) address, passwords, or \s-1UUID\s0 tokens.
 .PP
 This program uses Squid concurrency support.
 .SH "OPTIONS"
@@ -221,7 +221,7 @@
 Report ideas for new improvements to the \fISquid Developers mailing list <squid\-dev@squid\-cache.org\fR>
 .SH "SEE ALSO"
 .IX Header "SEE ALSO"
-squid (8), \s-1GPL\s0 (7),
+squid (8), \s-1GPL \\fIs0\fR\|(7),
 .PP
 The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq
 .PP
diff -u -r -N squid-4.0.20/src/acl/external/SQL_session/Makefile.in squid-4.0.21/src/acl/external/SQL_session/Makefile.in
--- squid-4.0.20/src/acl/external/SQL_session/Makefile.in	2017-06-02 00:54:49.000000000 +1200
+++ squid-4.0.21/src/acl/external/SQL_session/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/time_quota/Makefile.in squid-4.0.21/src/acl/external/time_quota/Makefile.in
--- squid-4.0.20/src/acl/external/time_quota/Makefile.in	2017-06-02 00:55:21.000000000 +1200
+++ squid-4.0.21/src/acl/external/time_quota/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/unix_group/Makefile.in squid-4.0.21/src/acl/external/unix_group/Makefile.in
--- squid-4.0.20/src/acl/external/unix_group/Makefile.in	2017-06-02 00:55:24.000000000 +1200
+++ squid-4.0.21/src/acl/external/unix_group/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 squid-4.0.21/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8
--- squid-4.0.20/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8	2017-06-02 09:53:11.000000000 +1200
+++ squid-4.0.21/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8	2017-07-02 20:57:34.000000000 +1200
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_WBINFO_GROUP_ACL 8"
-.TH EXT_WBINFO_GROUP_ACL 8 "2017-06-01" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH EXT_WBINFO_GROUP_ACL 8 "2017-07-02" "perl v5.24.1" "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.20/src/acl/external/wbinfo_group/Makefile.in squid-4.0.21/src/acl/external/wbinfo_group/Makefile.in
--- squid-4.0.20/src/acl/external/wbinfo_group/Makefile.in	2017-06-02 00:55:29.000000000 +1200
+++ squid-4.0.21/src/acl/external/wbinfo_group/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/acl/ExtUser.cc squid-4.0.21/src/acl/ExtUser.cc
--- squid-4.0.20/src/acl/ExtUser.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/ExtUser.cc	2017-07-02 20:41:18.000000000 +1200
@@ -44,6 +44,12 @@
 }
 
 void
+ACLExtUser::parseFlags()
+{
+    ParseFlags(Acl::NoOptions(), data->supportedFlags());
+}
+
+void
 ACLExtUser::parse()
 {
     data->parse();
diff -u -r -N squid-4.0.20/src/acl/ExtUser.h squid-4.0.21/src/acl/ExtUser.h
--- squid-4.0.20/src/acl/ExtUser.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/ExtUser.h	2017-07-02 20:41:18.000000000 +1200
@@ -25,19 +25,16 @@
     ACLExtUser & operator= (ACLExtUser const &rhs);
     ~ACLExtUser();
 
+    /* ACL API */
     virtual char const *typeString() const;
     virtual void parse();
-
+    virtual void parseFlags();
     virtual int match(ACLChecklist *checklist);
     virtual SBufList dump() const;
     virtual bool empty () const;
     virtual ACL *clone()const;
 
 private:
-    static Prototype UserRegistryProtoype;
-    static ACLExtUser UserRegistryEntry_;
-    static Prototype RegexRegistryProtoype;
-    static ACLExtUser RegexRegistryEntry_;
     ACLData<char const *> *data;
     char const *type_;
 };
diff -u -r -N squid-4.0.20/src/acl/forward.h squid-4.0.21/src/acl/forward.h
--- squid-4.0.20/src/acl/forward.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/forward.h	2017-07-02 20:41:18.000000000 +1200
@@ -29,6 +29,9 @@
 class OrNode;
 class Tree;
 
+/// prepares to parse ACLs configuration
+void Init(void);
+
 } // namespace Acl
 
 class allow_t;
diff -u -r -N squid-4.0.20/src/acl/HasComponent.cc squid-4.0.21/src/acl/HasComponent.cc
--- squid-4.0.20/src/acl/HasComponent.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/HasComponent.cc	2017-07-02 20:41:18.000000000 +1200
@@ -11,18 +11,10 @@
 #include "acl/HasComponentData.h"
 
 int
-ACLHasComponentStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &flags)
+ACLHasComponentStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     ACLHasComponentData *cdata = dynamic_cast<ACLHasComponentData*>(data);
     assert(cdata);
     return cdata->match(checklist);
 }
 
-ACLHasComponentStrategy *
-ACLHasComponentStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLHasComponentStrategy ACLHasComponentStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/HasComponent.h squid-4.0.21/src/acl/HasComponent.h
--- squid-4.0.20/src/acl/HasComponent.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/HasComponent.h	2017-07-02 20:41:18.000000000 +1200
@@ -16,22 +16,7 @@
 class ACLHasComponentStrategy : public ACLStrategy<ACLChecklist *>
 {
 public:
-    static ACLHasComponentStrategy *Instance();
-    ACLHasComponentStrategy(ACLHasComponentStrategy const &) = delete;
-    ACLHasComponentStrategy& operator=(ACLHasComponentStrategy const &) = delete;
-    virtual int match(ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-
-private:
-    static ACLHasComponentStrategy Instance_;
-    ACLHasComponentStrategy() { }
-};
-
-/// \ingroup ACLAPI
-class ACLHasComponent
-{
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<ACLChecklist *> RegistryEntry_;
+    virtual int match(ACLData<MatchType> * &, ACLFilledChecklist *);
 };
 
 #endif
diff -u -r -N squid-4.0.20/src/acl/HierCode.cc squid-4.0.21/src/acl/HierCode.cc
--- squid-4.0.20/src/acl/HierCode.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/HierCode.cc	2017-07-02 20:41:18.000000000 +1200
@@ -10,6 +10,7 @@
 #include "acl/Checklist.h"
 #include "acl/HierCode.h"
 #include "acl/HierCodeData.h"
+#include "acl/Strategised.h"
 #include "HttpRequest.h"
 
 /* explicit template instantiation required for some systems */
@@ -17,16 +18,8 @@
 template class ACLStrategised<hier_code>;
 
 int
-ACLHierCodeStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLHierCodeStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     return data->match (checklist->request->hier.code);
 }
 
-ACLHierCodeStrategy *
-ACLHierCodeStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLHierCodeStrategy ACLHierCodeStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/HierCode.h squid-4.0.21/src/acl/HierCode.h
--- squid-4.0.20/src/acl/HierCode.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/HierCode.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,7 +9,6 @@
 #ifndef SQUID_ACLHIERCODE_H
 #define SQUID_ACLHIERCODE_H
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 #include "hier_code.h"
 
@@ -18,33 +17,8 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    static ACLHierCodeStrategy *Instance();
-
-    /**
-     * Not implemented to prevent copies of the instance.
-     \par
-     * Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends
-     */
-    ACLHierCodeStrategy(ACLHierCodeStrategy const &);
-
-private:
-    static ACLHierCodeStrategy Instance_;
-    ACLHierCodeStrategy() {}
-
-    ACLHierCodeStrategy &operator=(ACLHierCodeStrategy const &);
-};
-
-/// \ingroup ACLAPI
-class ACLHierCode
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<hier_code> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLHIERCODE_H */
diff -u -r -N squid-4.0.20/src/acl/HttpRepHeader.cc squid-4.0.21/src/acl/HttpRepHeader.cc
--- squid-4.0.20/src/acl/HttpRepHeader.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/HttpRepHeader.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,22 +7,14 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/HttpHeaderData.h"
 #include "acl/HttpRepHeader.h"
 #include "HttpReply.h"
 
 int
-ACLHTTPRepHeaderStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLHTTPRepHeaderStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     return data->match (&checklist->reply->header);
 }
 
-ACLHTTPRepHeaderStrategy *
-ACLHTTPRepHeaderStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLHTTPRepHeaderStrategy ACLHTTPRepHeaderStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/HttpRepHeader.h squid-4.0.21/src/acl/HttpRepHeader.h
--- squid-4.0.20/src/acl/HttpRepHeader.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/HttpRepHeader.h	2017-07-02 20:41:18.000000000 +1200
@@ -18,32 +18,8 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
     virtual bool requiresReply() const { return true; }
-
-    static ACLHTTPRepHeaderStrategy *Instance();
-    /**
-     * Not implemented to prevent copies of the instance.
-     \par
-     * Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends
-     */
-    ACLHTTPRepHeaderStrategy(ACLHTTPRepHeaderStrategy const &);
-
-private:
-    static ACLHTTPRepHeaderStrategy Instance_;
-    ACLHTTPRepHeaderStrategy() { }
-
-    ACLHTTPRepHeaderStrategy&operator = (ACLHTTPRepHeaderStrategy const &);
-};
-
-/// \ingroup ACLAPI
-class ACLHTTPRepHeader
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<HttpHeader*> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLHTTPREPHEADER_H */
diff -u -r -N squid-4.0.20/src/acl/HttpReqHeader.cc squid-4.0.21/src/acl/HttpReqHeader.cc
--- squid-4.0.20/src/acl/HttpReqHeader.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/HttpReqHeader.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,22 +7,14 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/HttpHeaderData.h"
 #include "acl/HttpReqHeader.h"
 #include "HttpRequest.h"
 
 int
-ACLHTTPReqHeaderStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLHTTPReqHeaderStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     return data->match (&checklist->request->header);
 }
 
-ACLHTTPReqHeaderStrategy *
-ACLHTTPReqHeaderStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLHTTPReqHeaderStrategy ACLHTTPReqHeaderStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/HttpReqHeader.h squid-4.0.21/src/acl/HttpReqHeader.h
--- squid-4.0.20/src/acl/HttpReqHeader.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/HttpReqHeader.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,7 +9,6 @@
 #ifndef SQUID_ACLHTTPREQHEADER_H
 #define SQUID_ACLHTTPREQHEADER_H
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 #include "HttpHeader.h"
 
@@ -18,29 +17,8 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const { return true; }
-
-    static ACLHTTPReqHeaderStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLHTTPReqHeaderStrategy(ACLHTTPReqHeaderStrategy const &);
-
-private:
-    static ACLHTTPReqHeaderStrategy Instance_;
-    ACLHTTPReqHeaderStrategy() { }
-
-    ACLHTTPReqHeaderStrategy&operator = (ACLHTTPReqHeaderStrategy const &);
-};
-
-/// \ingroup ACLAPI
-class ACLHTTPReqHeader
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<HttpHeader*> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLHTTPREQHEADER_H */
diff -u -r -N squid-4.0.20/src/acl/HttpStatus.h squid-4.0.21/src/acl/HttpStatus.h
--- squid-4.0.20/src/acl/HttpStatus.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/HttpStatus.h	2017-07-02 20:41:18.000000000 +1200
@@ -43,8 +43,6 @@
     virtual bool requiresReply() const { return true; }
 
 protected:
-    static Prototype RegistryProtoype;
-    static ACLHTTPStatus RegistryEntry_;
     Splay<acl_httpstatus_data*> *data;
     char const *class_;
 };
diff -u -r -N squid-4.0.20/src/acl/Ip.cc squid-4.0.21/src/acl/Ip.cc
--- squid-4.0.20/src/acl/Ip.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Ip.cc	2017-07-02 20:41:18.000000000 +1200
@@ -477,8 +477,6 @@
     if (data == NULL)
         data = new IPSplay();
 
-    flags.parseFlags();
-
     while (char *t = ConfigParser::strtokFile()) {
         acl_ip_data *q = acl_ip_data::FactoryParse(t);
 
diff -u -r -N squid-4.0.20/src/acl/Ip.h squid-4.0.21/src/acl/Ip.h
--- squid-4.0.20/src/acl/Ip.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Ip.h	2017-07-02 20:41:18.000000000 +1200
@@ -48,8 +48,6 @@
     void operator delete(void *);
 
     ACLIP() : data(NULL) {}
-    explicit ACLIP(const ACLFlag flgs[]) : ACL(flgs), data(NULL) {}
-
     ~ACLIP();
 
     typedef Splay<acl_ip_data *> IPSplay;
diff -u -r -N squid-4.0.20/src/acl/LocalIp.h squid-4.0.21/src/acl/LocalIp.h
--- squid-4.0.20/src/acl/LocalIp.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/LocalIp.h	2017-07-02 20:41:18.000000000 +1200
@@ -17,15 +17,9 @@
     MEMPROXY_CLASS(ACLLocalIP);
 
 public:
-    static ACLLocalIP const &RegistryEntry();
-
     virtual char const *typeString() const;
     virtual int match(ACLChecklist *checklist);
     virtual ACL *clone()const;
-
-private:
-    static Prototype RegistryProtoype;
-    static ACLLocalIP RegistryEntry_;
 };
 
 #endif /* SQUID_ACLLOCALIP_H */
diff -u -r -N squid-4.0.20/src/acl/LocalPort.cc squid-4.0.21/src/acl/LocalPort.cc
--- squid-4.0.20/src/acl/LocalPort.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/LocalPort.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,21 +7,12 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
-#include "acl/IntRange.h"
+#include "acl/FilledChecklist.h"
 #include "acl/LocalPort.h"
 
 int
-ACLLocalPortStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLLocalPortStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     return data->match (checklist->my_addr.port());
 }
 
-ACLLocalPortStrategy *
-ACLLocalPortStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLLocalPortStrategy ACLLocalPortStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/LocalPort.h squid-4.0.21/src/acl/LocalPort.h
--- squid-4.0.20/src/acl/LocalPort.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/LocalPort.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,7 +9,6 @@
 #ifndef SQUID_ACLLOCALPORT_H
 #define SQUID_ACLLOCALPORT_H
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 
 /// \ingroup ACLAPI
@@ -17,30 +16,7 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLLocalPortStrategy *Instance();
-    /**
-     * Not implemented to prevent copies of the instance.
-     \par
-     * Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends
-     */
-    ACLLocalPortStrategy(ACLLocalPortStrategy const &);
-
-private:
-    static ACLLocalPortStrategy Instance_;
-    ACLLocalPortStrategy() {}
-
-    ACLLocalPortStrategy&operator=(ACLLocalPortStrategy const &);
-};
-
-/// \ingroup ACLAPI
-class ACLLocalPort
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<int> RegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* SQUID_ACLLOCALPORT_H */
diff -u -r -N squid-4.0.20/src/acl/Makefile.am squid-4.0.21/src/acl/Makefile.am
--- squid-4.0.20/src/acl/Makefile.am	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Makefile.am	2017-07-02 20:41:18.000000000 +1200
@@ -23,12 +23,15 @@
 	forward.h \
 	InnerNode.cc \
 	InnerNode.h \
+	Options.h \
+	Options.cc \
 	Tree.cc \
 	Tree.h
 
 ## Data-dependent Squid/transaction state used by specific ACLs.
 ## Does not refer to specific ACLs to avoid circular dependencies.
 libstate_la_SOURCES = \
+	CharacterSetOption.h \
 	Data.h \
 	Strategy.h \
 	Strategised.cc \
@@ -56,8 +59,6 @@
 	AnyOf.h \
 	Asn.cc \
 	Asn.h \
-	Browser.cc \
-	Browser.h \
 	ConnectionsEncrypted.cc \
 	ConnectionsEncrypted.h \
 	DestinationAsn.h \
@@ -111,13 +112,9 @@
 	Protocol.h \
 	Random.cc \
 	Random.h \
-	Referer.cc \
-	Referer.h \
 	ReplyHeaderStrategy.h \
-	ReplyMimeType.cc \
 	ReplyMimeType.h \
 	RequestHeaderStrategy.h \
-	RequestMimeType.cc \
 	RequestMimeType.h \
 	SourceAsn.h \
 	SourceDomain.cc \
@@ -130,6 +127,8 @@
 	SquidErrorData.h \
 	Tag.cc \
 	Tag.h \
+	TransactionInitiator.cc \
+	TransactionInitiator.h \
 	Url.cc \
 	Url.h \
 	UrlLogin.cc \
diff -u -r -N squid-4.0.20/src/acl/Makefile.in squid-4.0.21/src/acl/Makefile.in
--- squid-4.0.20/src/acl/Makefile.in	2017-06-02 00:54:27.000000000 +1200
+++ squid-4.0.21/src/acl/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -169,35 +169,34 @@
 am__libacls_la_SOURCES_DIST = IntRange.cc IntRange.h RegexData.cc \
 	RegexData.h StringData.cc StringData.h Time.cc Time.h \
 	TimeData.cc TimeData.h AllOf.cc AllOf.h AnyOf.cc AnyOf.h \
-	Asn.cc Asn.h Browser.cc Browser.h ConnectionsEncrypted.cc \
-	ConnectionsEncrypted.h DestinationAsn.h DestinationDomain.cc \
-	DestinationDomain.h DestinationIp.cc DestinationIp.h \
-	DomainData.cc DomainData.h ExtUser.cc ExtUser.h \
-	HasComponent.cc HasComponent.h HasComponentData.cc \
-	HasComponentData.h HierCodeData.cc HierCodeData.h HierCode.cc \
-	HierCode.h HttpHeaderData.cc HttpHeaderData.h HttpRepHeader.cc \
-	HttpRepHeader.h HttpReqHeader.cc HttpReqHeader.h HttpStatus.cc \
-	HttpStatus.h Ip.cc Ip.h LocalIp.cc LocalIp.h LocalPort.cc \
-	LocalPort.h MaxConnection.cc MaxConnection.h Method.cc \
-	MethodData.cc MethodData.h Method.h MyPortName.cc MyPortName.h \
-	Note.h Note.cc NoteData.h NoteData.cc PeerName.cc PeerName.h \
+	Asn.cc Asn.h ConnectionsEncrypted.cc ConnectionsEncrypted.h \
+	DestinationAsn.h DestinationDomain.cc DestinationDomain.h \
+	DestinationIp.cc DestinationIp.h DomainData.cc DomainData.h \
+	ExtUser.cc ExtUser.h HasComponent.cc HasComponent.h \
+	HasComponentData.cc HasComponentData.h HierCodeData.cc \
+	HierCodeData.h HierCode.cc HierCode.h HttpHeaderData.cc \
+	HttpHeaderData.h HttpRepHeader.cc HttpRepHeader.h \
+	HttpReqHeader.cc HttpReqHeader.h HttpStatus.cc HttpStatus.h \
+	Ip.cc Ip.h LocalIp.cc LocalIp.h LocalPort.cc LocalPort.h \
+	MaxConnection.cc MaxConnection.h Method.cc MethodData.cc \
+	MethodData.h Method.h MyPortName.cc MyPortName.h Note.h \
+	Note.cc NoteData.h NoteData.cc PeerName.cc PeerName.h \
 	Protocol.cc ProtocolData.cc ProtocolData.h Protocol.h \
-	Random.cc Random.h Referer.cc Referer.h ReplyHeaderStrategy.h \
-	ReplyMimeType.cc ReplyMimeType.h RequestHeaderStrategy.h \
-	RequestMimeType.cc RequestMimeType.h SourceAsn.h \
+	Random.cc Random.h ReplyHeaderStrategy.h ReplyMimeType.h \
+	RequestHeaderStrategy.h RequestMimeType.h SourceAsn.h \
 	SourceDomain.cc SourceDomain.h SourceIp.cc SourceIp.h \
 	SquidError.h SquidError.cc SquidErrorData.cc SquidErrorData.h \
-	Tag.cc Tag.h Url.cc Url.h UrlLogin.cc UrlLogin.h UrlPath.cc \
-	UrlPath.h UrlPort.cc UrlPort.h UserData.cc UserData.h \
-	AclNameList.h AclDenyInfoList.h Gadgets.cc Gadgets.h \
-	AclSizeLimit.cc AclSizeLimit.h AtStep.cc AtStep.h \
-	AtStepData.cc AtStepData.h CertificateData.cc \
-	CertificateData.h Certificate.cc Certificate.h \
-	ServerCertificate.cc ServerCertificate.h ServerName.cc \
-	ServerName.h SslError.cc SslError.h SslErrorData.cc \
-	SslErrorData.h AdaptationService.h AdaptationService.cc \
-	AdaptationServiceData.h AdaptationServiceData.cc Arp.cc Arp.h \
-	Eui64.cc Eui64.h
+	Tag.cc Tag.h TransactionInitiator.cc TransactionInitiator.h \
+	Url.cc Url.h UrlLogin.cc UrlLogin.h UrlPath.cc UrlPath.h \
+	UrlPort.cc UrlPort.h UserData.cc UserData.h AclNameList.h \
+	AclDenyInfoList.h Gadgets.cc Gadgets.h AclSizeLimit.cc \
+	AclSizeLimit.h AtStep.cc AtStep.h AtStepData.cc AtStepData.h \
+	CertificateData.cc CertificateData.h Certificate.cc \
+	Certificate.h ServerCertificate.cc ServerCertificate.h \
+	ServerName.cc ServerName.h SslError.cc SslError.h \
+	SslErrorData.cc SslErrorData.h AdaptationService.h \
+	AdaptationService.cc AdaptationServiceData.h \
+	AdaptationServiceData.cc Arp.cc Arp.h Eui64.cc Eui64.h
 am__objects_1 = AtStep.lo AtStepData.lo CertificateData.lo \
 	Certificate.lo ServerCertificate.lo ServerName.lo SslError.lo \
 	SslErrorData.lo
@@ -207,18 +206,17 @@
 am__objects_5 = Arp.lo Eui64.lo
 @ENABLE_EUI_TRUE@am__objects_6 = $(am__objects_5)
 am_libacls_la_OBJECTS = IntRange.lo RegexData.lo StringData.lo Time.lo \
-	TimeData.lo AllOf.lo AnyOf.lo Asn.lo Browser.lo \
-	ConnectionsEncrypted.lo DestinationDomain.lo DestinationIp.lo \
-	DomainData.lo ExtUser.lo HasComponent.lo HasComponentData.lo \
-	HierCodeData.lo HierCode.lo HttpHeaderData.lo HttpRepHeader.lo \
+	TimeData.lo AllOf.lo AnyOf.lo Asn.lo ConnectionsEncrypted.lo \
+	DestinationDomain.lo DestinationIp.lo DomainData.lo ExtUser.lo \
+	HasComponent.lo HasComponentData.lo HierCodeData.lo \
+	HierCode.lo HttpHeaderData.lo HttpRepHeader.lo \
 	HttpReqHeader.lo HttpStatus.lo Ip.lo LocalIp.lo LocalPort.lo \
 	MaxConnection.lo Method.lo MethodData.lo MyPortName.lo Note.lo \
 	NoteData.lo PeerName.lo Protocol.lo ProtocolData.lo Random.lo \
-	Referer.lo ReplyMimeType.lo RequestMimeType.lo SourceDomain.lo \
-	SourceIp.lo SquidError.lo SquidErrorData.lo Tag.lo Url.lo \
-	UrlLogin.lo UrlPath.lo UrlPort.lo UserData.lo Gadgets.lo \
-	AclSizeLimit.lo $(am__objects_2) $(am__objects_4) \
-	$(am__objects_6)
+	SourceDomain.lo SourceIp.lo SquidError.lo SquidErrorData.lo \
+	Tag.lo TransactionInitiator.lo Url.lo UrlLogin.lo UrlPath.lo \
+	UrlPort.lo UserData.lo Gadgets.lo AclSizeLimit.lo \
+	$(am__objects_2) $(am__objects_4) $(am__objects_6)
 libacls_la_OBJECTS = $(am_libacls_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -226,7 +224,7 @@
 am__v_lt_1 = 
 libapi_la_LIBADD =
 am_libapi_la_OBJECTS = Acl.lo BoolOps.lo Checklist.lo InnerNode.lo \
-	Tree.lo
+	Options.lo Tree.lo
 libapi_la_OBJECTS = $(am_libapi_la_OBJECTS)
 libstate_la_LIBADD =
 am_libstate_la_OBJECTS = Strategised.lo FilledChecklist.lo Address.lo
@@ -829,10 +827,13 @@
 	forward.h \
 	InnerNode.cc \
 	InnerNode.h \
+	Options.h \
+	Options.cc \
 	Tree.cc \
 	Tree.h
 
 libstate_la_SOURCES = \
+	CharacterSetOption.h \
 	Data.h \
 	Strategy.h \
 	Strategised.cc \
@@ -845,29 +846,28 @@
 libacls_la_SOURCES = IntRange.cc IntRange.h RegexData.cc RegexData.h \
 	StringData.cc StringData.h Time.cc Time.h TimeData.cc \
 	TimeData.h AllOf.cc AllOf.h AnyOf.cc AnyOf.h Asn.cc Asn.h \
-	Browser.cc Browser.h ConnectionsEncrypted.cc \
-	ConnectionsEncrypted.h DestinationAsn.h DestinationDomain.cc \
-	DestinationDomain.h DestinationIp.cc DestinationIp.h \
-	DomainData.cc DomainData.h ExtUser.cc ExtUser.h \
-	HasComponent.cc HasComponent.h HasComponentData.cc \
-	HasComponentData.h HierCodeData.cc HierCodeData.h HierCode.cc \
-	HierCode.h HttpHeaderData.cc HttpHeaderData.h HttpRepHeader.cc \
-	HttpRepHeader.h HttpReqHeader.cc HttpReqHeader.h HttpStatus.cc \
-	HttpStatus.h Ip.cc Ip.h LocalIp.cc LocalIp.h LocalPort.cc \
-	LocalPort.h MaxConnection.cc MaxConnection.h Method.cc \
-	MethodData.cc MethodData.h Method.h MyPortName.cc MyPortName.h \
-	Note.h Note.cc NoteData.h NoteData.cc PeerName.cc PeerName.h \
+	ConnectionsEncrypted.cc ConnectionsEncrypted.h \
+	DestinationAsn.h DestinationDomain.cc DestinationDomain.h \
+	DestinationIp.cc DestinationIp.h DomainData.cc DomainData.h \
+	ExtUser.cc ExtUser.h HasComponent.cc HasComponent.h \
+	HasComponentData.cc HasComponentData.h HierCodeData.cc \
+	HierCodeData.h HierCode.cc HierCode.h HttpHeaderData.cc \
+	HttpHeaderData.h HttpRepHeader.cc HttpRepHeader.h \
+	HttpReqHeader.cc HttpReqHeader.h HttpStatus.cc HttpStatus.h \
+	Ip.cc Ip.h LocalIp.cc LocalIp.h LocalPort.cc LocalPort.h \
+	MaxConnection.cc MaxConnection.h Method.cc MethodData.cc \
+	MethodData.h Method.h MyPortName.cc MyPortName.h Note.h \
+	Note.cc NoteData.h NoteData.cc PeerName.cc PeerName.h \
 	Protocol.cc ProtocolData.cc ProtocolData.h Protocol.h \
-	Random.cc Random.h Referer.cc Referer.h ReplyHeaderStrategy.h \
-	ReplyMimeType.cc ReplyMimeType.h RequestHeaderStrategy.h \
-	RequestMimeType.cc RequestMimeType.h SourceAsn.h \
+	Random.cc Random.h ReplyHeaderStrategy.h ReplyMimeType.h \
+	RequestHeaderStrategy.h RequestMimeType.h SourceAsn.h \
 	SourceDomain.cc SourceDomain.h SourceIp.cc SourceIp.h \
 	SquidError.h SquidError.cc SquidErrorData.cc SquidErrorData.h \
-	Tag.cc Tag.h Url.cc Url.h UrlLogin.cc UrlLogin.h UrlPath.cc \
-	UrlPath.h UrlPort.cc UrlPort.h UserData.cc UserData.h \
-	AclNameList.h AclDenyInfoList.h Gadgets.cc Gadgets.h \
-	AclSizeLimit.cc AclSizeLimit.h $(am__append_2) $(am__append_3) \
-	$(am__append_4)
+	Tag.cc Tag.h TransactionInitiator.cc TransactionInitiator.h \
+	Url.cc Url.h UrlLogin.cc UrlLogin.h UrlPath.cc UrlPath.h \
+	UrlPort.cc UrlPort.h UserData.cc UserData.h AclNameList.h \
+	AclDenyInfoList.h Gadgets.cc Gadgets.h AclSizeLimit.cc \
+	AclSizeLimit.h $(am__append_2) $(am__append_3) $(am__append_4)
 EXTRA_libacls_la_SOURCES = $(SSL_ACLS) $(ADAPT_ACLS) $(ARP_ACLS)
 SSL_ACLS = \
 	AtStep.cc \
@@ -976,7 +976,6 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AtStep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AtStepData.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BoolOps.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Browser.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Certificate.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CertificateData.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Checklist.Plo@am__quote@
@@ -1007,14 +1006,12 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MyPortName.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Note.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NoteData.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Options.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerName.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Protocol.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ProtocolData.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Random.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Referer.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RegexData.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ReplyMimeType.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestMimeType.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerCertificate.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerName.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SourceDomain.Plo@am__quote@
@@ -1028,6 +1025,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Tag.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Time.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeData.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TransactionInitiator.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Tree.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Url.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UrlLogin.Plo@am__quote@
diff -u -r -N squid-4.0.20/src/acl/MaxConnection.h squid-4.0.21/src/acl/MaxConnection.h
--- squid-4.0.20/src/acl/MaxConnection.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/MaxConnection.h	2017-07-02 20:41:18.000000000 +1200
@@ -10,7 +10,6 @@
 #define SQUID_ACLMAXCONNECTION_H
 
 #include "acl/Acl.h"
-#include "acl/Checklist.h"
 
 /// \ingroup ACLAPI
 class ACLMaxConnection : public ACL
@@ -33,8 +32,6 @@
     virtual void prepareForUse();
 
 protected:
-    static Prototype RegistryProtoype;
-    static ACLMaxConnection RegistryEntry_;
     char const *class_;
     int limit;
 };
diff -u -r -N squid-4.0.20/src/acl/Method.cc squid-4.0.21/src/acl/Method.cc
--- squid-4.0.20/src/acl/Method.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Method.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,9 +7,10 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/Method.h"
 #include "acl/MethodData.h"
+#include "acl/Strategised.h"
 #include "HttpRequest.h"
 
 /* explicit template instantiation required for some systems */
@@ -17,16 +18,8 @@
 template class ACLStrategised<HttpRequestMethod>;
 
 int
-ACLMethodStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLMethodStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     return data->match (checklist->request->method);
 }
 
-ACLMethodStrategy *
-ACLMethodStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLMethodStrategy ACLMethodStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/Method.h squid-4.0.21/src/acl/Method.h
--- squid-4.0.20/src/acl/Method.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Method.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,7 +9,6 @@
 #ifndef SQUID_ACLMETHOD_H
 #define SQUID_ACLMETHOD_H
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 #include "http/RequestMethod.h"
 
@@ -18,33 +17,8 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    static ACLMethodStrategy *Instance();
-
-    /**
-     * Not implemented to prevent copies of the instance.
-     \par
-     * Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends
-     */
-    ACLMethodStrategy(ACLMethodStrategy const &);
-
-private:
-    static ACLMethodStrategy Instance_;
-    ACLMethodStrategy() {}
-
-    ACLMethodStrategy&operator=(ACLMethodStrategy const &);
-};
-
-/// \ingroup ACLAPI
-class ACLMethod
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<HttpRequestMethod> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLMETHOD_H */
diff -u -r -N squid-4.0.20/src/acl/MyPortName.cc squid-4.0.21/src/acl/MyPortName.cc
--- squid-4.0.20/src/acl/MyPortName.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/MyPortName.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,7 +7,7 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/MyPortName.h"
 #include "acl/StringData.h"
 #include "anyp/PortCfg.h"
@@ -16,7 +16,7 @@
 #include "HttpRequest.h"
 
 int
-ACLMyPortNameStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLMyPortNameStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     if (checklist->conn() != NULL && checklist->conn()->port != NULL)
         return data->match(checklist->conn()->port->name);
@@ -25,11 +25,3 @@
     return 0;
 }
 
-ACLMyPortNameStrategy *
-ACLMyPortNameStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLMyPortNameStrategy ACLMyPortNameStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/MyPortName.h squid-4.0.21/src/acl/MyPortName.h
--- squid-4.0.20/src/acl/MyPortName.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/MyPortName.h	2017-07-02 20:41:18.000000000 +1200
@@ -8,33 +8,13 @@
 
 #ifndef SQUID_ACLMYPORTNAME_H
 #define SQUID_ACLMYPORTNAME_H
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 
 class ACLMyPortNameStrategy : public ACLStrategy<const char *>
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLMyPortNameStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLMyPortNameStrategy(ACLMyPortNameStrategy const &);
-
-private:
-    static ACLMyPortNameStrategy Instance_;
-    ACLMyPortNameStrategy() {}
-
-    ACLMyPortNameStrategy&operator=(ACLMyPortNameStrategy const &);
-};
-
-class ACLMyPortName
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<const char *> RegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* SQUID_ACLMYPORTNAME_H */
diff -u -r -N squid-4.0.20/src/acl/Note.cc squid-4.0.21/src/acl/Note.cc
--- squid-4.0.20/src/acl/Note.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Note.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,24 +7,38 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/HttpHeaderData.h"
 #include "acl/Note.h"
 #include "acl/NoteData.h"
 #include "HttpRequest.h"
-#include "Notes.h"
 #include "parser/Tokenizer.h"
 #include "sbuf/StringConvert.h"
 
+/* Acl::AnnotationStrategy */
+
+const Acl::Options &
+Acl::AnnotationStrategy::options()
+{
+    static const Acl::CharacterSetOption Delimiters;
+    static const Acl::Options MyOptions = {
+        { "-m", &Delimiters }
+    };
+    Delimiters.linkWith(&delimiters);
+    return MyOptions;
+}
+
+/* ACLNoteStrategy */
+
 int
-ACLNoteStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &flags)
+ACLNoteStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     if (const auto request = checklist->request) {
-        if (request->notes != NULL && matchNotes(data, request->notes.getRaw(), flags.delimiters()))
+        if (request->notes != NULL && matchNotes(data, request->notes.getRaw()))
             return 1;
 #if USE_ADAPTATION
         const Adaptation::History::Pointer ah = request->adaptLogHistory();
-        if (ah != NULL && ah->metaHeaders != NULL && matchNotes(data, ah->metaHeaders.getRaw(), flags.delimiters()))
+        if (ah != NULL && ah->metaHeaders != NULL && matchNotes(data, ah->metaHeaders.getRaw()))
             return 1;
 #endif
     }
@@ -32,14 +46,14 @@
 }
 
 bool
-ACLNoteStrategy::matchNotes(ACLData<MatchType> *noteData, const NotePairs *note, const CharacterSet *delimiters) const
+ACLNoteStrategy::matchNotes(ACLData<MatchType> *noteData, const NotePairs *note) const
 {
     for (auto &entry: note->entries) {
-        if (delimiters) {
+        if (!delimiters.value.isEmpty()) {
             NotePairs::Entry e(entry->name.termedBuf(), "");
             Parser::Tokenizer t(StringToSBuf(entry->value));
             SBuf s;
-            while (t.token(s, *delimiters)) {
+            while (t.token(s, delimiters.value)) {
                 e.value = s.c_str();
                 if (noteData->match(&e))
                     return true;
@@ -55,11 +69,3 @@
     return false;
 }
 
-ACLNoteStrategy *
-ACLNoteStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLNoteStrategy ACLNoteStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/Note.h squid-4.0.21/src/acl/Note.h
--- squid-4.0.20/src/acl/Note.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Note.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,42 +9,36 @@
 #ifndef SQUID_ACLNOTE_H
 #define SQUID_ACLNOTE_H
 
-#include "acl/Strategised.h"
+#include "acl/CharacterSetOption.h"
+#include "acl/Data.h"
 #include "acl/Strategy.h"
+#include "Notes.h"
 
-class ACLNoteData;
-class CharacterSet;
-class HttpRequest;
+namespace Acl {
 
-/// \ingroup ACLAPI
-class ACLNoteStrategy : public ACLStrategy<NotePairs::Entry *>
+/// common parent of several ACLs dealing with transaction annotations
+class AnnotationStrategy: public ACLStrategy<NotePairs::Entry *>
 {
-
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    virtual bool requiresRequest() const { return true; }
+    AnnotationStrategy(): delimiters(CharacterSet(__FILE__, ",")) {}
 
-    static ACLNoteStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLNoteStrategy(ACLNoteStrategy const &);
-
-private:
-    static ACLNoteStrategy Instance_;
-    ACLNoteStrategy() { }
+    virtual const Acl::Options &options() override;
 
-    ACLNoteStrategy& operator = (ACLNoteStrategy const &);
-    bool matchNotes(ACLData<MatchType> *, const NotePairs *, const CharacterSet *) const;
+    Acl::CharacterSetOptionValue delimiters; ///< annotation separators
 };
 
+} // namespace Acl
+
 /// \ingroup ACLAPI
-class ACLNote
+class ACLNoteStrategy: public Acl::AnnotationStrategy
 {
 
+public:
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
+    virtual bool requiresRequest() const { return true; }
+
 private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<NotePairs::Entry *> RegistryEntry_;
+    bool matchNotes(ACLData<MatchType> *, const NotePairs *) const;
 };
 
 #endif /* SQUID_ACLNOTE_H */
diff -u -r -N squid-4.0.20/src/acl/Options.cc squid-4.0.21/src/acl/Options.cc
--- squid-4.0.20/src/acl/Options.cc	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.21/src/acl/Options.cc	2017-07-02 20:41:18.000000000 +1200
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 1996-2017 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.
+ */
+
+#include "squid.h"
+#include "acl/Options.h"
+#include "ConfigParser.h"
+#include "Debug.h"
+#include "sbuf/Stream.h"
+
+#include <iostream>
+#include <vector>
+
+namespace Acl {
+
+/// low-level parser that extracts but does not interpret ACL options
+class OptionExtractor
+{
+public:
+    /// parses the next option and fills public members with its details
+    /// \returns whether option extraction was successful
+    bool extractOne();
+
+    /* extracted option details (after successful extraction */
+    SBuf name; ///< extracted option name, including dash(es)
+    bool hasValue = false; ///< whether the option has a value (-x=value)
+    const SBuf &value() const; ///< extracted option value (requires hasValue)
+
+protected:
+    bool advance();
+    void extractWhole();
+    void extractShort();
+
+private:
+    SBuf prefix_; ///< option name(s), including leading dash(es)
+    SBuf value_; ///< the last seen value of some option
+    SBuf::size_type letterPos_ = 0; ///< letter position inside an -xyz sequence
+    bool sawValue_ = false; ///< the current option sequence had a value
+};
+
+/// parses/validates/stores ACL options; skips/preserves parameter flags
+class OptionsParser
+{
+public:
+    OptionsParser(const Options &options, const ParameterFlags &flags);
+
+    // fill previously supplied options container, throwing on errors
+    void parse();
+
+private:
+    const Option *findOption(/* const */ SBuf &rawName);
+
+    /// ACL parameter flags in parsing order
+    typedef std::vector<OptionName> Names;
+    /// parsed ACL parameter flags that must be preserved for ACLData::parse()
+    static Names flagsToSkip;
+
+    const Options &options_; ///< caller-supported, linked options
+    const ParameterFlags &parameterFlags_; ///< caller-supported parameter flags
+};
+
+} // namespace Acl
+
+/* Acl::OptionNameCmp */
+
+bool
+Acl::OptionNameCmp::operator()(const OptionName a, const OptionName b) const
+{
+    return strcmp(a, b) < 0;
+}
+
+/* Acl::OptionExtractor */
+
+const SBuf &
+Acl::OptionExtractor::value() const
+{
+    Must(hasValue);
+    return value_;
+}
+
+bool
+Acl::OptionExtractor::extractOne()
+{
+    if (!prefix_.isEmpty()) {
+        extractShort(); // continue with the previously extracted flags
+        return true;
+    }
+
+    if (!advance())
+        return false; // end of options (and, possibly, the whole "acl" directive)
+
+    if (prefix_.length() < 2)
+        throw TexcHere(ToSBuf("truncated(?) ACL flag: ", prefix_)); // single - or +
+
+    if (prefix_[0] == '-' && prefix_[1] == '-') {
+        if (prefix_.length() == 2)
+            return false; // skipped "--", an explicit end-of-options marker
+        extractWhole();
+        return true;
+    }
+
+    if (prefix_.length() == 2) { // common trivial case: -x or +y
+        extractWhole();
+        return true;
+    }
+
+    // -xyz or +xyz
+    letterPos_ = 1;
+    extractShort();
+    return true;
+}
+
+/// extracts a token with the next option/flag(s) or returns false
+bool
+Acl::OptionExtractor::advance()
+{
+    const char *next = ConfigParser::PeekAtToken();
+    if (!next)
+        return false; // end of the "acl" line
+
+    const char nextChar = *next;
+    if (!(nextChar == '-' || nextChar == '+'))
+        return false; // start of ACL parameters
+
+    sawValue_ = strchr(next, '='); // TODO: Make ConfigParser reject '^=.*' tokens
+    if (sawValue_) {
+        char *rawPrefix = nullptr;
+        char *rawValue = nullptr;
+        if (!ConfigParser::NextKvPair(rawPrefix, rawValue))
+            throw TexcHere(ToSBuf("Malformed acl option=value: ", next));
+        prefix_.assign(rawPrefix);
+        value_.assign(rawValue);
+    } else {
+        prefix_.assign(next);
+        ConfigParser::NextToken(); // consume what we have peeked at
+    }
+    return true;
+}
+
+/// handles -x[=option] or --foo[=option]
+void
+Acl::OptionExtractor::extractWhole()
+{
+    debugs(28, 8, "from " << prefix_ << " value: " << sawValue_);
+    hasValue = sawValue_;
+    name = prefix_;
+    prefix_.clear();
+}
+
+/// handles one flag letter inside an -xyx[=option] or +xyz[=option] sequence
+void
+Acl::OptionExtractor::extractShort()
+{
+    debugs(28, 8, "from " << prefix_ << " at " << letterPos_ << " value: " << sawValue_);
+    name.assign(prefix_.rawContent(), 1); // leading - or +
+    name.append(prefix_.at(letterPos_++));
+    if (letterPos_ >= prefix_.length()) { // got last flag in the sequence
+        hasValue = sawValue_;
+        prefix_.clear();
+    } else {
+        hasValue = false;
+    }
+}
+
+/* Acl::OptionsParser */
+
+// being "static" is an optimization to avoid paying for vector creation/growth
+Acl::OptionsParser::Names Acl::OptionsParser::flagsToSkip;
+
+Acl::OptionsParser::OptionsParser(const Options &options, const ParameterFlags &flags):
+    options_(options),
+    parameterFlags_(flags)
+{
+}
+
+const Acl::Option *
+Acl::OptionsParser::findOption(/* const */ SBuf &rawNameBuf)
+{
+    // TODO: new std::map::find() in C++14 does not require this conversion
+    const auto rawName = rawNameBuf.c_str();
+
+    const auto optionPos = options_.find(rawName);
+    if (optionPos != options_.end())
+        return optionPos->second;
+
+    const auto flagPos = parameterFlags_.find(rawName);
+    if (flagPos != parameterFlags_.end()) {
+        flagsToSkip.push_back(*flagPos); // *flagPos is permanent unlike rawName
+        return nullptr;
+    }
+
+    throw TexcHere(ToSBuf("unsupported ACL option: ", rawNameBuf));
+}
+
+void
+Acl::OptionsParser::parse()
+{
+    flagsToSkip.clear();
+
+    OptionExtractor oex;
+    while (oex.extractOne()) {
+        /* const */ auto rawName = oex.name;
+        if (const Option *optionPtr = findOption(rawName)) {
+            const Option &option = *optionPtr;
+            if (option.configured())
+                debugs(28, 7, "acl uses multiple " << rawName << " options");
+            switch (option.valueExpectation)
+            {
+            case Option::valueNone:
+                if (oex.hasValue)
+                    throw TexcHere(ToSBuf("unexpected value for an ACL option: ", rawName, '=', oex.value()));
+                option.configureDefault();
+                break;
+            case Option::valueRequired:
+                if (!oex.hasValue)
+                    throw TexcHere(ToSBuf("missing required value for ACL option ", rawName));
+                option.configureWith(oex.value());
+                break;
+            case Option::valueOptional:
+                if (oex.hasValue)
+                    option.configureWith(oex.value());
+                else
+                    option.configureDefault();
+                break;
+            }
+        }
+        // else skip supported parameter flag
+    }
+
+    /* hack: regex code wants to parse all -i and +i flags itself */
+    for (const auto name: flagsToSkip)
+        ConfigParser::TokenPutBack(name);
+}
+
+void
+Acl::ParseFlags(const Options &options, const ParameterFlags &flags)
+{
+    OptionsParser parser(options, flags);
+    parser.parse();
+}
+
+const Acl::Options &
+Acl::NoOptions()
+{
+    static const Options none;
+    return none;
+}
+
+const Acl::ParameterFlags &
+Acl::NoFlags()
+{
+    static const ParameterFlags none;
+    return none;
+}
+
+std::ostream &
+operator <<(std::ostream &os, const Acl::Option &option)
+{
+    if (option.valued()) {
+        os << '=';
+        option.print(os);
+    }
+    return os;
+}
+
+std::ostream &
+operator <<(std::ostream &os, const Acl::Options &options)
+{
+    for (const auto pos: options) {
+        assert(pos.second);
+        const auto &option = *pos.second;
+        if (option.configured())
+            os << pos.first << option;
+    }
+    // TODO: Remember "--" presence and print that delimiter when present.
+    // Detecting its need is difficult because parameter flags start with "-".
+    return os;
+}
+
diff -u -r -N squid-4.0.20/src/acl/Options.h squid-4.0.21/src/acl/Options.h
--- squid-4.0.20/src/acl/Options.h	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.21/src/acl/Options.h	2017-07-02 20:41:18.000000000 +1200
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 1996-2017 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_ACL_OPTIONS_H
+#define SQUID_ACL_OPTIONS_H
+
+#include "acl/forward.h"
+#include "sbuf/forward.h"
+
+#include <iosfwd>
+#include <map>
+#include <set>
+
+// After all same-name acl configuration lines are merged into one ACL:
+//   configuration = acl name type [option...] [[flag...] parameter...]
+//   option = -x[=value] | --name[=value]
+//   flag = option
+//
+// Options and flags use the same syntax, but differ in scope and handling code:
+// * ACL options appear before all parameters and apply to all parameters.
+//   They are handled by ACL kids (or equivalent).
+// * Parameter flags may appear after some other parameters and apply only to
+//   the subsequent parameters (until they are overwritten by later flags).
+//   They are handled by ACLData kids.
+// ACL options parsing code skips and leaves leading parameter flags (if any)
+// for ACLData code to process.
+
+namespace Acl {
+
+typedef const char *OptionName;
+
+/// A single option supported by an ACL: -x[=value] or --name[=value]
+/// Unlike a parameter flag, this option applies to all ACL parameters.
+class Option
+{
+public:
+    typedef enum { valueNone, valueOptional, valueRequired } ValueExpectation;
+    explicit Option(ValueExpectation vex = valueNone): valueExpectation(vex) {}
+    virtual ~Option() {}
+
+    /// whether the admin explicitly specified this option
+    /// (i.e., whether configureWith() or configureDefault() has been called)
+    virtual bool configured() const = 0;
+
+    /// called after parsing -x or --name
+    virtual void configureDefault() const = 0;
+
+    /// called after parsing -x=value or --name=value
+    virtual void configureWith(const SBuf &rawValue) const = 0;
+
+    virtual bool valued() const = 0;
+
+    /// prints a configuration snippet (as an admin could have typed)
+    virtual void print(std::ostream &os) const = 0;
+
+    ValueExpectation valueExpectation = valueNone; ///< expect "=value" part?
+};
+
+/// Stores configuration of a typical boolean flag or a single-value Option.
+template <class Value>
+class OptionValue
+{
+public:
+    typedef Value value_type;
+
+    OptionValue(): value {} {}
+    explicit OptionValue(const Value &aValue): value(aValue) {}
+
+    explicit operator bool() const { return configured; }
+
+    Value value; ///< final value storage, possibly after conversions
+    bool configured = false; ///< whether the option was present in squid.conf
+    bool valued = false; ///< whether a configured option had a value
+};
+
+/// a type-specific Option (e.g., a boolean --toggle or -m=SBuf)
+template <class Recipient>
+class TypedOption: public Option
+{
+public:
+    //typedef typename Recipient::value_type value_type;
+    explicit TypedOption(ValueExpectation vex = valueNone): Option(vex) {}
+
+    /// who to tell when this option is enabled
+    void linkWith(Recipient *recipient) const
+    {
+        assert(recipient);
+        recipient_ = recipient;
+    }
+
+    /* Option API */
+
+    virtual bool configured() const override { return recipient_ && recipient_->configured; }
+    virtual bool valued() const override { return recipient_ && recipient_->valued; }
+
+    /// sets the default value when option is used without a value
+    virtual void configureDefault() const override
+    {
+        assert(recipient_);
+        recipient_->configured = true;
+        recipient_->valued = false;
+        // sets recipient_->value to default
+        setDefault();
+    }
+
+    /// sets the option value from rawValue
+    virtual void configureWith(const SBuf &rawValue) const override
+    {
+        assert(recipient_);
+        recipient_->configured = true;
+        recipient_->valued = true;
+        import(rawValue);
+    }
+
+    virtual void print(std::ostream &os) const override { if (valued()) os << recipient_->value; }
+
+private:
+    void import(const SBuf &rawValue) const { recipient_->value = rawValue; }
+    void setDefault() const { /*leave recipient_->value as is*/}
+
+    // The "mutable" specifier demarcates set-once Option kind/behavior from the
+    // ever-changing recipient of the actual admin-configured option value.
+    mutable Recipient *recipient_ = nullptr; ///< parsing results storage
+};
+
+/* two typical option kinds: --foo and --bar=text  */
+typedef OptionValue<bool> BooleanOptionValue;
+typedef OptionValue<SBuf> TextOptionValue;
+typedef TypedOption<BooleanOptionValue> BooleanOption;
+typedef TypedOption<TextOptionValue> TextOption;
+
+// this specialization should never be called until we start supporting
+// boolean option values like --name=enable or --name=false
+template <>
+inline void
+BooleanOption::import(const SBuf &) const
+{
+    assert(!"boolean options do not have ...=values (for now)");
+}
+
+template <>
+inline void
+BooleanOption::setDefault() const
+{
+    recipient_->value = true;
+}
+
+/// option name comparison functor
+class OptionNameCmp {
+public:
+    bool operator()(const OptionName a, const OptionName b) const;
+};
+/// name:option map
+typedef std::map<OptionName, const Option*, OptionNameCmp> Options;
+
+/// a set of parameter flag names
+typedef std::set<OptionName, OptionNameCmp> ParameterFlags;
+
+/// parses the flags part of the being-parsed ACL, filling Option values
+/// \param options options supported by the ACL as a whole (e.g., -n)
+/// \param flags options supported by ACL parameter(s) (e.g., -i)
+void ParseFlags(const Options &options, const ParameterFlags &flags);
+
+/* handy for Class::options() and Class::supportedFlags() defaults */
+const Options &NoOptions(); ///< \returns an empty Options container
+const ParameterFlags &NoFlags(); ///< \returns an empty ParameterFlags container
+
+} // namespace Acl
+
+std::ostream &operator <<(std::ostream &os, const Acl::Option &option);
+std::ostream &operator <<(std::ostream &os, const Acl::Options &options);
+
+#endif /* SQUID_ACL_OPTIONS_H */
+
diff -u -r -N squid-4.0.20/src/acl/PeerName.cc squid-4.0.21/src/acl/PeerName.cc
--- squid-4.0.20/src/acl/PeerName.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/PeerName.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,25 +7,16 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/PeerName.h"
 #include "acl/RegexData.h"
 #include "acl/StringData.h"
-#include "CachePeer.h"
 
 int
-ACLPeerNameStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLPeerNameStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     if (!checklist->dst_peer_name.isEmpty())
         return data->match(checklist->dst_peer_name.c_str());
     return 0;
 }
 
-ACLPeerNameStrategy *
-ACLPeerNameStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLPeerNameStrategy ACLPeerNameStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/PeerName.h squid-4.0.21/src/acl/PeerName.h
--- squid-4.0.20/src/acl/PeerName.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/PeerName.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,35 +9,13 @@
 #ifndef SQUID_ACLPEERNAME_H
 #define SQUID_ACLPEERNAME_H
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 
 class ACLPeerNameStrategy : public ACLStrategy<const char *>
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLPeerNameStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLPeerNameStrategy(ACLPeerNameStrategy const &);
-
-private:
-    static ACLPeerNameStrategy Instance_;
-    ACLPeerNameStrategy() {}
-
-    ACLPeerNameStrategy&operator=(ACLPeerNameStrategy const &);
-};
-
-class ACLPeerName
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<const char *> RegistryEntry_;
-    static ACL::Prototype RegexRegistryProtoype;
-    static ACLStrategised<char const *> RegexRegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* SQUID_ACLPEERNAME_H */
diff -u -r -N squid-4.0.20/src/acl/Protocol.cc squid-4.0.21/src/acl/Protocol.cc
--- squid-4.0.20/src/acl/Protocol.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Protocol.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,9 +7,10 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/Protocol.h"
 #include "acl/ProtocolData.h"
+#include "acl/Strategised.h"
 #include "HttpRequest.h"
 
 /* explicit template instantiation required for some systems */
@@ -17,16 +18,8 @@
 template class ACLStrategised<AnyP::ProtocolType>;
 
 int
-ACLProtocolStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLProtocolStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     return data->match(checklist->request->url.getScheme());
 }
 
-ACLProtocolStrategy *
-ACLProtocolStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLProtocolStrategy ACLProtocolStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/Protocol.h squid-4.0.21/src/acl/Protocol.h
--- squid-4.0.20/src/acl/Protocol.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Protocol.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,7 +9,6 @@
 #ifndef SQUID_ACLPROTOCOL_H
 #define SQUID_ACLPROTOCOL_H
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 #include "anyp/ProtocolType.h"
 
@@ -17,28 +16,8 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    static ACLProtocolStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLProtocolStrategy(ACLProtocolStrategy const &);
-
-private:
-    static ACLProtocolStrategy Instance_;
-    ACLProtocolStrategy() {}
-
-    ACLProtocolStrategy&operator=(ACLProtocolStrategy const &);
-};
-
-class ACLProtocol
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<AnyP::ProtocolType> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLPROTOCOL_H */
diff -u -r -N squid-4.0.20/src/acl/Random.h squid-4.0.21/src/acl/Random.h
--- squid-4.0.20/src/acl/Random.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Random.h	2017-07-02 20:41:18.000000000 +1200
@@ -10,7 +10,6 @@
 #define SQUID_ACL_RANDOM_H
 
 #include "acl/Acl.h"
-#include "acl/Checklist.h"
 
 class ACLRandom : public ACL
 {
@@ -31,8 +30,6 @@
     virtual bool valid() const;
 
 protected:
-    static Prototype RegistryProtoype;
-    static ACLRandom RegistryEntry_;
     double data;        // value to be exceeded before this ACL will match
     char pattern[256];  // pattern from config file. Used to generate 'data'
     char const *class_;
diff -u -r -N squid-4.0.20/src/acl/Referer.cc squid-4.0.21/src/acl/Referer.cc
--- squid-4.0.20/src/acl/Referer.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Referer.cc	1970-01-01 12:00:00.000000000 +1200
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 1996-2017 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 28    Access Control */
-
-#include "squid.h"
-#include "acl/Checklist.h"
-#include "acl/Referer.h"
-#include "acl/RegexData.h"
-
-/* explicit template instantiation required for some systems */
-
-template class ACLRequestHeaderStrategy<Http::HdrType::REFERER>;
-
diff -u -r -N squid-4.0.20/src/acl/Referer.h squid-4.0.21/src/acl/Referer.h
--- squid-4.0.20/src/acl/Referer.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Referer.h	1970-01-01 12:00:00.000000000 +1200
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 1996-2017 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_ACLREFERER_H
-#define SQUID_ACLREFERER_H
-#include "acl/Acl.h"
-#include "acl/Data.h"
-#include "acl/RequestHeaderStrategy.h"
-#include "acl/Strategised.h"
-
-class ACLReferer
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<char const *> RegistryEntry_;
-};
-
-#endif /* SQUID_ACLREFERER_H */
-
diff -u -r -N squid-4.0.20/src/acl/RegexData.cc squid-4.0.21/src/acl/RegexData.cc
--- squid-4.0.20/src/acl/RegexData.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/RegexData.cc	2017-07-02 20:41:18.000000000 +1200
@@ -27,6 +27,13 @@
 {
 }
 
+const Acl::ParameterFlags &
+ACLRegexData::supportedFlags() const
+{
+    static const Acl::ParameterFlags flags = { "-i", "+i" };
+    return flags;
+}
+
 bool
 ACLRegexData::match(char const *word)
 {
diff -u -r -N squid-4.0.20/src/acl/RegexData.h squid-4.0.21/src/acl/RegexData.h
--- squid-4.0.20/src/acl/RegexData.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/RegexData.h	2017-07-02 20:41:18.000000000 +1200
@@ -24,6 +24,7 @@
     virtual bool match(char const *user);
     virtual SBufList dump() const;
     virtual void parse();
+    virtual const Acl::ParameterFlags &supportedFlags() const;
     virtual bool empty() const;
     virtual ACLData<char const *> *clone() const;
 
diff -u -r -N squid-4.0.20/src/acl/ReplyHeaderStrategy.h squid-4.0.21/src/acl/ReplyHeaderStrategy.h
--- squid-4.0.20/src/acl/ReplyHeaderStrategy.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/ReplyHeaderStrategy.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,8 +9,6 @@
 #ifndef SQUID_ACLREPLYHEADERSTRATEGY_H
 #define SQUID_ACLREPLYHEADERSTRATEGY_H
 
-class ACLChecklist;
-
 #include "acl/Acl.h"
 #include "acl/Data.h"
 #include "acl/FilledChecklist.h"
@@ -22,25 +20,13 @@
 {
 
 public:
-    virtual int match (ACLData<char const *> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<char const *> * &, ACLFilledChecklist *);
     virtual bool requiresReply() const {return true;}
-
-    static ACLReplyHeaderStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLReplyHeaderStrategy(ACLReplyHeaderStrategy const &);
-
-private:
-    static ACLReplyHeaderStrategy *Instance_;
-    ACLReplyHeaderStrategy() {}
-
-    ACLReplyHeaderStrategy&operator=(ACLReplyHeaderStrategy const &);
 };
 
 template <Http::HdrType header>
 int
-ACLReplyHeaderStrategy<header>::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLReplyHeaderStrategy<header>::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist)
 {
     char const *theHeader = checklist->reply->header.getStr(header);
 
@@ -50,18 +36,5 @@
     return data->match(theHeader);
 }
 
-template <Http::HdrType header>
-ACLReplyHeaderStrategy<header> *
-ACLReplyHeaderStrategy<header>::Instance()
-{
-    if (!Instance_)
-        Instance_ = new ACLReplyHeaderStrategy<header>;
-
-    return Instance_;
-}
-
-template <Http::HdrType header>
-ACLReplyHeaderStrategy<header> * ACLReplyHeaderStrategy<header>::Instance_ = NULL;
-
 #endif /* SQUID_REPLYHEADERSTRATEGY_H */
 
diff -u -r -N squid-4.0.20/src/acl/ReplyMimeType.cc squid-4.0.21/src/acl/ReplyMimeType.cc
--- squid-4.0.20/src/acl/ReplyMimeType.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/ReplyMimeType.cc	1970-01-01 12:00:00.000000000 +1200
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 1996-2017 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 28    Access Control */
-
-#include "squid.h"
-#include "acl/Checklist.h"
-#include "acl/RegexData.h"
-#include "acl/ReplyMimeType.h"
-
-/* explicit template instantiation required for some systems */
-
-template class ACLReplyHeaderStrategy<Http::HdrType::CONTENT_TYPE>;
-
diff -u -r -N squid-4.0.20/src/acl/ReplyMimeType.h squid-4.0.21/src/acl/ReplyMimeType.h
--- squid-4.0.20/src/acl/ReplyMimeType.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/ReplyMimeType.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,26 +9,15 @@
 #ifndef SQUID_ACLREPLYMIMETYPE_H
 #define SQUID_ACLREPLYMIMETYPE_H
 
-#include "acl/Acl.h"
-#include "acl/Strategised.h"
-
-class ACLReplyMIMEType
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<char const *> RegistryEntry_;
-};
-
-/* partial specialisation */
-
-#include "acl/Checklist.h"
 #include "acl/Data.h"
+#include "acl/FilledChecklist.h"
 #include "acl/ReplyHeaderStrategy.h"
 
+/* partial specialisation */
+
 template <>
 inline int
-ACLReplyHeaderStrategy<Http::HdrType::CONTENT_TYPE>::match(ACLData<char const *> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLReplyHeaderStrategy<Http::HdrType::CONTENT_TYPE>::match(ACLData<char const *> * &data, ACLFilledChecklist *checklist)
 {
     char const *theHeader = checklist->reply->header.getStr(Http::HdrType::CONTENT_TYPE);
 
diff -u -r -N squid-4.0.20/src/acl/RequestHeaderStrategy.h squid-4.0.21/src/acl/RequestHeaderStrategy.h
--- squid-4.0.20/src/acl/RequestHeaderStrategy.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/RequestHeaderStrategy.h	2017-07-02 20:41:18.000000000 +1200
@@ -19,25 +19,13 @@
 {
 
 public:
-    virtual int match (ACLData<char const *> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<char const *> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    static ACLRequestHeaderStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLRequestHeaderStrategy(ACLRequestHeaderStrategy const &);
-
-private:
-    static ACLRequestHeaderStrategy *Instance_;
-    ACLRequestHeaderStrategy() {}
-
-    ACLRequestHeaderStrategy&operator=(ACLRequestHeaderStrategy const &);
 };
 
 template <Http::HdrType header>
 int
-ACLRequestHeaderStrategy<header>::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLRequestHeaderStrategy<header>::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist)
 {
     char const *theHeader = checklist->request->header.getStr(header);
 
@@ -47,18 +35,5 @@
     return data->match(theHeader);
 }
 
-template <Http::HdrType header>
-ACLRequestHeaderStrategy<header> *
-ACLRequestHeaderStrategy<header>::Instance()
-{
-    if (!Instance_)
-        Instance_ = new ACLRequestHeaderStrategy<header>;
-
-    return Instance_;
-}
-
-template <Http::HdrType header>
-ACLRequestHeaderStrategy<header> * ACLRequestHeaderStrategy<header>::Instance_ = NULL;
-
 #endif /* SQUID_REQUESTHEADERSTRATEGY_H */
 
diff -u -r -N squid-4.0.20/src/acl/RequestMimeType.cc squid-4.0.21/src/acl/RequestMimeType.cc
--- squid-4.0.20/src/acl/RequestMimeType.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/RequestMimeType.cc	1970-01-01 12:00:00.000000000 +1200
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 1996-2017 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 28    Access Control */
-
-#include "squid.h"
-#include "acl/Checklist.h"
-#include "acl/RegexData.h"
-#include "acl/RequestMimeType.h"
-
-/* explicit template instantiation required for some systems */
-
-template class ACLRequestHeaderStrategy<Http::HdrType::CONTENT_TYPE>;
-
diff -u -r -N squid-4.0.20/src/acl/RequestMimeType.h squid-4.0.21/src/acl/RequestMimeType.h
--- squid-4.0.20/src/acl/RequestMimeType.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/RequestMimeType.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,26 +9,15 @@
 #ifndef SQUID_ACLREQUESTMIMETYPE_H
 #define SQUID_ACLREQUESTMIMETYPE_H
 
-#include "acl/Acl.h"
-#include "acl/Strategised.h"
-
-class ACLRequestMIMEType
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<char const *> RegistryEntry_;
-};
-
-/* partial specialisation */
-
-#include "acl/Checklist.h"
 #include "acl/Data.h"
+#include "acl/FilledChecklist.h"
 #include "acl/RequestHeaderStrategy.h"
 
+/* partial specialisation */
+
 template <>
 inline int
-ACLRequestHeaderStrategy<Http::HdrType::CONTENT_TYPE>::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLRequestHeaderStrategy<Http::HdrType::CONTENT_TYPE>::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist)
 {
     char const *theHeader = checklist->request->header.getStr(Http::HdrType::CONTENT_TYPE);
 
diff -u -r -N squid-4.0.20/src/acl/ServerCertificate.cc squid-4.0.21/src/acl/ServerCertificate.cc
--- squid-4.0.20/src/acl/ServerCertificate.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/ServerCertificate.cc	2017-07-02 20:41:18.000000000 +1200
@@ -19,7 +19,7 @@
 #include "ssl/ServerBump.h"
 
 int
-ACLServerCertificateStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLServerCertificateStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     Security::CertPointer cert;
     if (checklist->serverCert)
@@ -33,13 +33,5 @@
     return data->match(cert.get());
 }
 
-ACLServerCertificateStrategy *
-ACLServerCertificateStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLServerCertificateStrategy ACLServerCertificateStrategy::Instance_;
-
 #endif /* USE_OPENSSL */
 
diff -u -r -N squid-4.0.20/src/acl/ServerCertificate.h squid-4.0.21/src/acl/ServerCertificate.h
--- squid-4.0.20/src/acl/ServerCertificate.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/ServerCertificate.h	2017-07-02 20:41:18.000000000 +1200
@@ -19,26 +19,7 @@
 class ACLServerCertificateStrategy : public ACLStrategy<X509 *>
 {
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLServerCertificateStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLServerCertificateStrategy(ACLServerCertificateStrategy const &);
-
-private:
-    static ACLServerCertificateStrategy Instance_;
-    ACLServerCertificateStrategy() {}
-
-    ACLServerCertificateStrategy&operator=(ACLServerCertificateStrategy const &);
-};
-
-/// \ingroup ACLAPI
-class ACLServerCertificate
-{
-private:
-    static ACL::Prototype X509FingerprintRegistryProtoype;
-    static ACLStrategised<X509*> X509FingerprintRegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* SQUID_ACLSERVERCERTIFICATE_H */
diff -u -r -N squid-4.0.20/src/acl/ServerName.cc squid-4.0.21/src/acl/ServerName.cc
--- squid-4.0.20/src/acl/ServerName.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/ServerName.cc	2017-07-02 20:41:18.000000000 +1200
@@ -9,8 +9,8 @@
 /* DEBUG: section 28    Access Control */
 
 #include "squid.h"
-#include "acl/Checklist.h"
 #include "acl/DomainData.h"
+#include "acl/FilledChecklist.h"
 #include "acl/RegexData.h"
 #include "acl/ServerName.h"
 #include "client_side.h"
@@ -87,26 +87,35 @@
 }
 
 int
-ACLServerNameStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &flags)
+ACLServerNameStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     assert(checklist != NULL && checklist->request != NULL);
 
     const char *serverName = nullptr;
-    SBuf serverNameKeeper; // because c_str() is not constant
+    SBuf clientSniKeeper; // because c_str() is not constant
     if (ConnStateData *conn = checklist->conn()) {
-
-        if (conn->serverBump()) {
-            if (X509 *peer_cert = conn->serverBump()->serverCert.get())
-                return Ssl::matchX509CommonNames(peer_cert, (void *)data, check_cert_domain<MatchType>);
-        }
-
-        if (conn->sslCommonName().isEmpty()) {
+        const char *clientRequestedServerName = nullptr;
+        clientSniKeeper = conn->tlsClientSni();
+        if (clientSniKeeper.isEmpty()) {
             const char *host = checklist->request->url.host();
             if (host && *host) // paranoid first condition: host() is never nil
-                serverName = host;
-        } else {
-            serverNameKeeper = conn->sslCommonName();
-            serverName = serverNameKeeper.c_str();
+                clientRequestedServerName = host;
+        } else
+            clientRequestedServerName = clientSniKeeper.c_str();
+
+        if (useConsensus) {
+            X509 *peer_cert = conn->serverBump() ? conn->serverBump()->serverCert.get() : nullptr;
+            // use the client requested name if it matches the server
+            // certificate or if the certificate is not available
+            if (!peer_cert || Ssl::checkX509ServerValidity(peer_cert, clientRequestedServerName))
+                serverName = clientRequestedServerName;
+        } else if (useClientRequested)
+            serverName = clientRequestedServerName;
+        else { // either no options or useServerProvided
+            if (X509 *peer_cert = (conn->serverBump() ? conn->serverBump()->serverCert.get() : nullptr))
+                return Ssl::matchX509CommonNames(peer_cert, (void *)data, check_cert_domain<MatchType>);
+            if (!useServerProvided)
+                serverName = clientRequestedServerName;
         }
     }
 
@@ -116,11 +125,40 @@
     return data->match(serverName);
 }
 
-ACLServerNameStrategy *
-ACLServerNameStrategy::Instance()
+const Acl::Options &
+ACLServerNameStrategy::options()
 {
-    return &Instance_;
+    static const Acl::BooleanOption ClientRequested;
+    static const Acl::BooleanOption ServerProvided;
+    static const Acl::BooleanOption Consensus;
+    static const Acl::Options MyOptions = {
+        {"--client-requested", &ClientRequested},
+        {"--server-provided", &ServerProvided},
+        {"--consensus", &Consensus}
+    };
+
+    ClientRequested.linkWith(&useClientRequested);
+    ServerProvided.linkWith(&useServerProvided);
+    Consensus.linkWith(&useConsensus);
+    return MyOptions;
 }
 
-ACLServerNameStrategy ACLServerNameStrategy::Instance_;
+bool
+ACLServerNameStrategy::valid() const
+{
+    int optionCount = 0;
+
+    if (useClientRequested)
+        optionCount++;
+    if (useServerProvided)
+        optionCount++;
+    if (useConsensus)
+        optionCount++;
+
+    if (optionCount > 1) {
+        debugs(28, DBG_CRITICAL, "ERROR: Multiple options given for the server_name ACL");
+        return false;
+    }
+    return true;
+}
 
diff -u -r -N squid-4.0.20/src/acl/ServerName.h squid-4.0.21/src/acl/ServerName.h
--- squid-4.0.20/src/acl/ServerName.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/ServerName.h	2017-07-02 20:41:18.000000000 +1200
@@ -10,10 +10,8 @@
 #define SQUID_ACLSERVERNAME_H
 
 #include "acl/Acl.h"
-#include "acl/Checklist.h"
-#include "acl/Data.h"
 #include "acl/DomainData.h"
-#include "acl/Strategised.h"
+#include "acl/Strategy.h"
 
 class ACLServerNameData : public ACLDomainData {
     MEMPROXY_CLASS(ACLServerNameData);
@@ -27,33 +25,16 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLServerNameStrategy *Instance();
+    /* ACLStrategy API */
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    /**
-     * Not implemented to prevent copies of the instance.
-     \par
-     * Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends
-     */
-    ACLServerNameStrategy(ACLServerNameStrategy const &);
-
-private:
-    static ACLServerNameStrategy Instance_;
-    ACLServerNameStrategy() {}
-
-    ACLServerNameStrategy&operator=(ACLServerNameStrategy const &);
-};
-
-class ACLServerName
-{
+    virtual const Acl::Options &options();
+    virtual bool valid() const;
 
 private:
-    static ACL::Prototype LiteralRegistryProtoype;
-    static ACLStrategised<char const *> LiteralRegistryEntry_;
-    static ACL::Prototype RegexRegistryProtoype;
-    static ACLStrategised<char const *> RegexRegistryEntry_;
+    Acl::BooleanOptionValue useClientRequested; ///< Ignore server-supplied names
+    Acl::BooleanOptionValue useServerProvided; ///< Ignore client-supplied names
+    Acl::BooleanOptionValue useConsensus; ///< Ignore mismatching names
 };
 
 #endif /* SQUID_ACLSERVERNAME_H */
diff -u -r -N squid-4.0.20/src/acl/SourceAsn.h squid-4.0.21/src/acl/SourceAsn.h
--- squid-4.0.20/src/acl/SourceAsn.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/SourceAsn.h	2017-07-02 20:41:18.000000000 +1200
@@ -18,18 +18,7 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLSourceASNStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLSourceASNStrategy(ACLSourceASNStrategy const &);
-
-private:
-    static ACLSourceASNStrategy Instance_;
-    ACLSourceASNStrategy() {}
-
-    ACLSourceASNStrategy&operator=(ACLSourceASNStrategy const &);
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* SQUID_ACL_SOURCEASN_H */
diff -u -r -N squid-4.0.20/src/acl/SourceDomain.cc squid-4.0.21/src/acl/SourceDomain.cc
--- squid-4.0.20/src/acl/SourceDomain.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/SourceDomain.cc	2017-07-02 20:41:18.000000000 +1200
@@ -11,6 +11,7 @@
 #include "squid.h"
 #include "acl/Checklist.h"
 #include "acl/DomainData.h"
+#include "acl/FilledChecklist.h"
 #include "acl/RegexData.h"
 #include "acl/SourceDomain.h"
 #include "fqdncache.h"
@@ -40,7 +41,7 @@
 }
 
 int
-ACLSourceDomainStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLSourceDomainStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     const char *fqdn = NULL;
     fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
@@ -58,11 +59,3 @@
     return data->match("none");
 }
 
-ACLSourceDomainStrategy *
-ACLSourceDomainStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLSourceDomainStrategy ACLSourceDomainStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/SourceDomain.h squid-4.0.21/src/acl/SourceDomain.h
--- squid-4.0.20/src/acl/SourceDomain.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/SourceDomain.h	2017-07-02 20:41:18.000000000 +1200
@@ -11,25 +11,14 @@
 #include "acl/Acl.h"
 #include "acl/Checklist.h"
 #include "acl/Data.h"
-#include "acl/Strategised.h"
+#include "acl/Strategy.h"
 #include "dns/forward.h"
 
 class ACLSourceDomainStrategy : public ACLStrategy<char const *>
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLSourceDomainStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLSourceDomainStrategy(ACLSourceDomainStrategy const &);
-
-private:
-    static ACLSourceDomainStrategy Instance_;
-    ACLSourceDomainStrategy() {}
-
-    ACLSourceDomainStrategy&operator=(ACLSourceDomainStrategy const &);
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 class SourceDomainLookup : public ACLChecklist::AsyncState
@@ -44,15 +33,5 @@
     static void LookupDone(const char *, const Dns::LookupDetails &, void *);
 };
 
-class ACLSourceDomain
-{
-
-private:
-    static ACL::Prototype LiteralRegistryProtoype;
-    static ACLStrategised<char const *> LiteralRegistryEntry_;
-    static ACL::Prototype RegexRegistryProtoype;
-    static ACLStrategised<char const *> RegexRegistryEntry_;
-};
-
 #endif /* SQUID_ACLSOURCEDOMAIN_H */
 
diff -u -r -N squid-4.0.20/src/acl/SourceIp.h squid-4.0.21/src/acl/SourceIp.h
--- squid-4.0.20/src/acl/SourceIp.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/SourceIp.h	2017-07-02 20:41:18.000000000 +1200
@@ -19,10 +19,6 @@
     virtual char const *typeString() const;
     virtual int match(ACLChecklist *checklist);
     virtual ACL *clone()const;
-
-private:
-    static Prototype RegistryProtoype;
-    static ACLSourceIP RegistryEntry_;
 };
 
 #endif /* SQUID_ACLSOURCEIP_H */
diff -u -r -N squid-4.0.20/src/acl/SquidError.cc squid-4.0.21/src/acl/SquidError.cc
--- squid-4.0.20/src/acl/SquidError.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/SquidError.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,12 +7,12 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/SquidError.h"
 #include "HttpRequest.h"
 
 int
-ACLSquidErrorStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLSquidErrorStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     if (checklist->requestErrorType != ERR_MAX)
         return data->match(checklist->requestErrorType);
@@ -21,11 +21,3 @@
     return 0;
 }
 
-ACLSquidErrorStrategy *
-ACLSquidErrorStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLSquidErrorStrategy ACLSquidErrorStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/SquidError.h squid-4.0.21/src/acl/SquidError.h
--- squid-4.0.20/src/acl/SquidError.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/SquidError.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,7 +9,6 @@
 #ifndef SQUID_ACLSQUIDERROR_H
 #define SQUID_ACLSQUIDERROR_H
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 #include "err_type.h"
 
@@ -17,27 +16,7 @@
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-
-    static ACLSquidErrorStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLSquidErrorStrategy(ACLSquidErrorStrategy const &);
-
-private:
-    static ACLSquidErrorStrategy Instance_;
-    ACLSquidErrorStrategy() {}
-
-    ACLSquidErrorStrategy&operator=(ACLSquidErrorStrategy const &);
-};
-
-class ACLSquidError
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<err_type> RegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* SQUID_ACLSQUIDERROR_H */
diff -u -r -N squid-4.0.20/src/acl/SslError.cc squid-4.0.21/src/acl/SslError.cc
--- squid-4.0.20/src/acl/SslError.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/SslError.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,21 +7,13 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/SslError.h"
 #include "acl/SslErrorData.h"
 
 int
-ACLSslErrorStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLSslErrorStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     return data->match (checklist->sslErrors);
 }
 
-ACLSslErrorStrategy *
-ACLSslErrorStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLSslErrorStrategy ACLSslErrorStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/SslError.h squid-4.0.21/src/acl/SslError.h
--- squid-4.0.20/src/acl/SslError.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/SslError.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,33 +9,14 @@
 #ifndef SQUID_ACLSSL_ERROR_H
 #define SQUID_ACLSSL_ERROR_H
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
+#include "security/forward.h"
 
 class ACLSslErrorStrategy : public ACLStrategy<const Security::CertErrors *>
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLSslErrorStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLSslErrorStrategy(ACLSslErrorStrategy const &);
-
-private:
-    static ACLSslErrorStrategy Instance_;
-    ACLSslErrorStrategy() {}
-
-    ACLSslErrorStrategy&operator=(ACLSslErrorStrategy const &);
-};
-
-class ACLSslError
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<const Security::CertErrors *> RegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* SQUID_ACLSSL_ERROR_H */
diff -u -r -N squid-4.0.20/src/acl/Strategised.h squid-4.0.21/src/acl/Strategised.h
--- squid-4.0.20/src/acl/Strategised.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Strategised.h	2017-07-02 20:41:18.000000000 +1200
@@ -14,6 +14,16 @@
 #include "acl/FilledChecklist.h"
 #include "acl/Strategy.h"
 
+// XXX: Replace with a much simpler abstract ACL child class without the
+// ACLStrategy parameter (and associated call forwarding). Duplicating key
+// portions of the ACL class API in ACLStrategy is not needed because
+// ACLStrategy is unused outside the ACLStrategised context. Existing classes
+// like ACLExtUser, ACLProxyAuth, and ACLIdent seem to confirm this assertion.
+// It also requires forwarding ACL info to ACLStrategy as method parameters.
+
+/// Splits the ACL API into two individually configurable components:
+/// * ACLStrategy that usually extracts information from the current transaction
+/// * ACLData that usually matches information against admin-configured values
 template <class M>
 class ACLStrategised : public ACL
 {
@@ -23,24 +33,24 @@
     typedef M MatchType;
 
     ~ACLStrategised();
-    ACLStrategised(ACLData<MatchType> *, ACLStrategy<MatchType> *, char const *, const ACLFlag flags[] = ACLFlags::NoFlags);
-    ACLStrategised (ACLStrategised const &);
-    ACLStrategised &operator= (ACLStrategised const &);
+    ACLStrategised(ACLData<MatchType> *, ACLStrategy<MatchType> *, char const *);
+    ACLStrategised(ACLStrategised const &&) = delete;
 
     virtual char const *typeString() const;
+    virtual void parseFlags();
+
     virtual bool requiresRequest() const {return matcher->requiresRequest();}
 
     virtual bool requiresReply() const {return matcher->requiresReply();}
 
     virtual void prepareForUse() { data->prepareForUse();}
-
+    virtual const Acl::Options &options() { return matcher->options(); }
     virtual void parse();
     virtual int match(ACLChecklist *checklist);
     virtual int match (M const &);
     virtual SBufList dump() const;
     virtual bool empty () const;
     virtual bool valid () const;
-    virtual ACL *clone()const;
 
 private:
     ACLData<MatchType> *data;
@@ -57,27 +67,21 @@
 }
 
 template <class MatchType>
-ACLStrategised<MatchType>::ACLStrategised(ACLData<MatchType> *newData, ACLStrategy<MatchType> *theStrategy, char const *theType, const ACLFlag flgs[]) : ACL(flgs), data (newData), type_(theType), matcher(theStrategy) {}
-
-template <class MatchType>
-ACLStrategised<MatchType>::ACLStrategised (ACLStrategised const &old) : data (old.data->clone()), type_(old.type_), matcher (old.matcher)
+ACLStrategised<MatchType>::ACLStrategised(ACLData<MatchType> *newData, ACLStrategy<MatchType> *theStrategy, char const *theType): data(newData), type_(theType), matcher(theStrategy)
 {}
 
 template <class MatchType>
-ACLStrategised<MatchType> &
-ACLStrategised<MatchType>::operator= (ACLStrategised const &rhs)
+char const *
+ACLStrategised<MatchType>::typeString() const
 {
-    data = rhs.data->clone();
-    type_ = rhs.type_;
-    matcher = rhs.matcher;
-    return *this;
+    return type_;
 }
 
 template <class MatchType>
-char const *
-ACLStrategised<MatchType>::typeString() const
+void
+ACLStrategised<MatchType>::parseFlags()
 {
-    return type_;
+    ParseFlags(options(), data->supportedFlags());
 }
 
 template <class MatchType>
@@ -100,7 +104,7 @@
 {
     ACLFilledChecklist *checklist = dynamic_cast<ACLFilledChecklist*>(cl);
     assert(checklist);
-    return matcher->match(data, checklist, flags);
+    return matcher->match(data, checklist);
 }
 
 template <class MatchType>
@@ -124,12 +128,5 @@
     return matcher->valid();
 }
 
-template <class MatchType>
-ACL *
-ACLStrategised<MatchType>::clone() const
-{
-    return new ACLStrategised(*this);
-}
-
 #endif /* SQUID_ACLSTRATEGISED_H */
 
diff -u -r -N squid-4.0.20/src/acl/Strategy.h squid-4.0.21/src/acl/Strategy.h
--- squid-4.0.20/src/acl/Strategy.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Strategy.h	2017-07-02 20:41:18.000000000 +1200
@@ -11,17 +11,22 @@
 
 #include "acl/Acl.h"
 #include "acl/Data.h"
+#include "acl/Options.h"
 
 class ACLFilledChecklist;
 
 template<class M>
 
+/// A matching algorithm.
 class ACLStrategy
 {
 
 public:
     typedef M MatchType;
-    virtual int match (ACLData<M> * &, ACLFilledChecklist *, ACLFlags &) = 0;
+
+    /* Replicate ACL API parts relevant to the matching algorithm. */
+    virtual const Acl::Options &options() { return Acl::NoOptions(); }
+    virtual int match (ACLData<M> * &, ACLFilledChecklist *) = 0;
     virtual bool requiresRequest() const {return false;}
 
     virtual bool requiresReply() const {return false;}
diff -u -r -N squid-4.0.20/src/acl/Tag.cc squid-4.0.21/src/acl/Tag.cc
--- squid-4.0.20/src/acl/Tag.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Tag.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,24 +7,16 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/StringData.h"
 #include "acl/Tag.h"
 #include "HttpRequest.h"
 
 int
-ACLTagStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLTagStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     if (checklist->request != NULL)
         return data->match (checklist->request->tag.termedBuf());
     return 0;
 }
 
-ACLTagStrategy *
-ACLTagStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLTagStrategy ACLTagStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/Tag.h squid-4.0.21/src/acl/Tag.h
--- squid-4.0.20/src/acl/Tag.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Tag.h	2017-07-02 20:41:18.000000000 +1200
@@ -9,33 +9,13 @@
 #ifndef SQUID_ACLTAG_H
 #define SQUID_ACLTAG_H
 
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 
 class ACLTagStrategy : public ACLStrategy<const char *>
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLTagStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLTagStrategy(ACLTagStrategy const &);
-
-private:
-    static ACLTagStrategy Instance_;
-    ACLTagStrategy() {}
-
-    ACLTagStrategy&operator=(ACLTagStrategy const &);
-};
-
-class ACLTag
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<const char *> RegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* SQUID_ACLMYPORTNAME_H */
diff -u -r -N squid-4.0.20/src/acl/Time.cc squid-4.0.21/src/acl/Time.cc
--- squid-4.0.20/src/acl/Time.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Time.cc	2017-07-02 20:41:18.000000000 +1200
@@ -14,16 +14,8 @@
 #include "SquidTime.h"
 
 int
-ACLTimeStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *, ACLFlags &)
+ACLTimeStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *)
 {
     return data->match(squid_curtime);
 }
 
-ACLTimeStrategy *
-ACLTimeStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLTimeStrategy ACLTimeStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/Time.h squid-4.0.21/src/acl/Time.h
--- squid-4.0.20/src/acl/Time.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Time.h	2017-07-02 20:41:18.000000000 +1200
@@ -8,36 +8,14 @@
 
 #ifndef SQUID_ACLTIME_H
 #define SQUID_ACLTIME_H
-#include "acl/Acl.h"
 #include "acl/Data.h"
 #include "acl/Strategised.h"
 
-class ACLChecklist; // XXX: we do not need it
-
 class ACLTimeStrategy : public ACLStrategy<time_t>
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLTimeStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLTimeStrategy(ACLTimeStrategy const &);
-
-private:
-    static ACLTimeStrategy Instance_;
-    ACLTimeStrategy() {}
-
-    ACLTimeStrategy&operator=(ACLTimeStrategy const &);
-};
-
-class ACLTime
-{
-
-public:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<time_t> RegistryEntry_;
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
 };
 
 #endif /* SQUID_ACLTIME_H */
diff -u -r -N squid-4.0.20/src/acl/TransactionInitiator.cc squid-4.0.21/src/acl/TransactionInitiator.cc
--- squid-4.0.20/src/acl/TransactionInitiator.cc	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.21/src/acl/TransactionInitiator.cc	2017-07-02 20:41:18.000000000 +1200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1996-2017 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 28    Access Control */
+
+#include "squid.h"
+#include "acl/FilledChecklist.h"
+#include "acl/TransactionInitiator.h"
+#include "cache_cf.h"
+#include "Debug.h"
+#include "HttpRequest.h"
+#include "MasterXaction.h"
+#include "SquidConfig.h"
+
+ACL *
+Acl::TransactionInitiator::clone() const
+{
+    return new Acl::TransactionInitiator(*this);
+}
+
+Acl::TransactionInitiator::TransactionInitiator (const char *aClass) : class_ (aClass), initiators_(0)
+{}
+
+char const *
+Acl::TransactionInitiator::typeString() const
+{
+    return class_;
+}
+
+bool
+Acl::TransactionInitiator::empty () const
+{
+    return false;
+}
+
+void
+Acl::TransactionInitiator::parse()
+{
+    while (const char *s = ConfigParser::strtokFile()) {
+        initiators_ |= XactionInitiator::ParseInitiators(s);
+        cfgWords.push_back(SBuf(s));
+    }
+}
+
+int
+Acl::TransactionInitiator::match(ACLChecklist *checklist)
+{
+    ACLFilledChecklist *filled = Filled((ACLChecklist*)checklist);
+    assert(filled->request);
+    assert(filled->request->masterXaction);
+    const XactionInitiator requestInitiator = filled->request->masterXaction->initiator;
+    return requestInitiator.in(initiators_) ? 1 : 0;
+}
+
+SBufList
+Acl::TransactionInitiator::dump() const
+{
+    return cfgWords;
+}
+
diff -u -r -N squid-4.0.20/src/acl/TransactionInitiator.h squid-4.0.21/src/acl/TransactionInitiator.h
--- squid-4.0.20/src/acl/TransactionInitiator.h	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.21/src/acl/TransactionInitiator.h	2017-07-02 20:41:18.000000000 +1200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1996-2017 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_ACL_TRANSACTION_INITIATOR_H
+#define SQUID_ACL_TRANSACTION_INITIATOR_H
+
+#include "acl/Acl.h"
+#include "acl/Checklist.h"
+#include "XactionInitiator.h"
+
+namespace Acl
+{
+
+/// transaction_initiator ACL
+class TransactionInitiator : public ACL
+{
+    MEMPROXY_CLASS(TransactionInitiator);
+
+public:
+    TransactionInitiator(char const *);
+
+    virtual ACL *clone()const;
+    virtual char const *typeString() const;
+    virtual void parse();
+    virtual int match(ACLChecklist *checklist);
+    virtual bool requiresRequest() const { return true; }
+    virtual SBufList dump() const;
+    virtual bool empty () const;
+
+protected:
+    char const *class_;
+    XactionInitiator::Initiators initiators_;
+    SBufList cfgWords; /// initiator names in the configured order
+};
+
+} // namespace Acl
+
+#endif /* SQUID_ACL_TRANSACTION_INITIATOR_H */
+
diff -u -r -N squid-4.0.20/src/acl/Tree.h squid-4.0.21/src/acl/Tree.h
--- squid-4.0.20/src/acl/Tree.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Tree.h	2017-07-02 20:41:18.000000000 +1200
@@ -52,7 +52,7 @@
 inline const char *
 AllowOrDeny(const allow_t &action)
 {
-    return action == ACCESS_ALLOWED ? "allow" : "deny";
+    return action.allowed() ? "allow" : "deny";
 }
 
 template <class ActionToStringConverter>
diff -u -r -N squid-4.0.20/src/acl/Url.cc squid-4.0.21/src/acl/Url.cc
--- squid-4.0.20/src/acl/Url.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Url.cc	2017-07-02 20:41:18.000000000 +1200
@@ -9,7 +9,7 @@
 /* DEBUG: section 28    Access Control */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/RegexData.h"
 #include "acl/Url.h"
 #include "HttpRequest.h"
@@ -17,7 +17,7 @@
 #include "src/URL.h"
 
 int
-ACLUrlStrategy::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLUrlStrategy::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist)
 {
     char *esc_buf = SBufToCstring(checklist->request->effectiveRequestUri());
     rfc1738_unescape(esc_buf);
@@ -26,11 +26,3 @@
     return result;
 }
 
-ACLUrlStrategy *
-ACLUrlStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLUrlStrategy ACLUrlStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/Url.h squid-4.0.21/src/acl/Url.h
--- squid-4.0.20/src/acl/Url.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/Url.h	2017-07-02 20:41:18.000000000 +1200
@@ -8,7 +8,7 @@
 
 #ifndef SQUID_ACLURL_H
 #define SQUID_ACLURL_H
-#include "acl/Acl.h"
+
 #include "acl/Data.h"
 #include "acl/Strategised.h"
 
@@ -16,29 +16,8 @@
 {
 
 public:
-    virtual int match (ACLData<char const *> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<char const *> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    static ACLUrlStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLUrlStrategy(ACLUrlStrategy const &);
-
-private:
-    static ACLUrlStrategy Instance_;
-    ACLUrlStrategy() {}
-
-    ACLUrlStrategy&operator=(ACLUrlStrategy const &);
-};
-
-class ACLUrl
-{
-
-public:
-    static ACL::Prototype RegistryProtoype;
-    static ACL::Prototype LegacyRegistryProtoype;
-    static ACLStrategised<char const *> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLURL_H */
diff -u -r -N squid-4.0.20/src/acl/UrlLogin.cc squid-4.0.21/src/acl/UrlLogin.cc
--- squid-4.0.20/src/acl/UrlLogin.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/UrlLogin.cc	2017-07-02 20:41:18.000000000 +1200
@@ -9,14 +9,14 @@
 /* DEBUG: section 28    Access Control */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/RegexData.h"
 #include "acl/UrlLogin.h"
 #include "HttpRequest.h"
 #include "rfc1738.h"
 
 int
-ACLUrlLoginStrategy::match(ACLData<char const *> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLUrlLoginStrategy::match(ACLData<char const *> * &data, ACLFilledChecklist *checklist)
 {
     if (checklist->request->url.userInfo().isEmpty()) {
         debugs(28, 5, "URL has no user-info details. cannot match");
@@ -31,11 +31,3 @@
     return data->match(str);
 }
 
-ACLUrlLoginStrategy *
-ACLUrlLoginStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLUrlLoginStrategy ACLUrlLoginStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/UrlLogin.h squid-4.0.21/src/acl/UrlLogin.h
--- squid-4.0.20/src/acl/UrlLogin.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/UrlLogin.h	2017-07-02 20:41:18.000000000 +1200
@@ -11,36 +11,14 @@
 
 #include "acl/Acl.h"
 #include "acl/Data.h"
-#include "acl/Strategised.h"
 #include "acl/Strategy.h"
 
 class ACLUrlLoginStrategy : public ACLStrategy<char const *>
 {
 
 public:
-    virtual int match (ACLData<char const *> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<char const *> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    static ACLUrlLoginStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLUrlLoginStrategy(ACLUrlLoginStrategy const &);
-
-private:
-    static ACLUrlLoginStrategy Instance_;
-    ACLUrlLoginStrategy() {}
-
-    ACLUrlLoginStrategy&operator=(ACLUrlLoginStrategy const &);
-};
-
-class ACLUrlLogin
-{
-
-public:
-    static ACL::Prototype RegistryProtoype;
-    static ACL::Prototype LegacyRegistryProtoype;
-    static ACLStrategised<char const *> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLURLLOGIN_H */
diff -u -r -N squid-4.0.20/src/acl/UrlPath.cc squid-4.0.21/src/acl/UrlPath.cc
--- squid-4.0.20/src/acl/UrlPath.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/UrlPath.cc	2017-07-02 20:41:18.000000000 +1200
@@ -9,14 +9,14 @@
 /* DEBUG: section 28    Access Control */
 
 #include "squid.h"
-#include "acl/Checklist.h"
+#include "acl/FilledChecklist.h"
 #include "acl/RegexData.h"
 #include "acl/UrlPath.h"
 #include "HttpRequest.h"
 #include "rfc1738.h"
 
 int
-ACLUrlPathStrategy::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLUrlPathStrategy::match (ACLData<char const *> * &data, ACLFilledChecklist *checklist)
 {
     if (checklist->request->url.path().isEmpty())
         return -1;
@@ -28,11 +28,3 @@
     return result;
 }
 
-ACLUrlPathStrategy *
-ACLUrlPathStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLUrlPathStrategy ACLUrlPathStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/UrlPath.h squid-4.0.21/src/acl/UrlPath.h
--- squid-4.0.20/src/acl/UrlPath.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/UrlPath.h	2017-07-02 20:41:18.000000000 +1200
@@ -8,38 +8,15 @@
 
 #ifndef SQUID_ACLURLPATH_H
 #define SQUID_ACLURLPATH_H
-#include "acl/Acl.h"
-#include "acl/Data.h"
-#include "acl/Strategised.h"
+
 #include "acl/Strategy.h"
 
 class ACLUrlPathStrategy : public ACLStrategy<char const *>
 {
 
 public:
-    virtual int match (ACLData<char const *> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<char const *> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    static ACLUrlPathStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLUrlPathStrategy(ACLUrlPathStrategy const &);
-
-private:
-    static ACLUrlPathStrategy Instance_;
-    ACLUrlPathStrategy() {}
-
-    ACLUrlPathStrategy&operator=(ACLUrlPathStrategy const &);
-};
-
-class ACLUrlPath
-{
-
-public:
-    static ACL::Prototype RegistryProtoype;
-    static ACL::Prototype LegacyRegistryProtoype;
-    static ACLStrategised<char const *> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLURLPATH_H */
diff -u -r -N squid-4.0.20/src/acl/UrlPort.cc squid-4.0.21/src/acl/UrlPort.cc
--- squid-4.0.20/src/acl/UrlPort.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/UrlPort.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,22 +7,13 @@
  */
 
 #include "squid.h"
-#include "acl/Checklist.h"
-#include "acl/IntRange.h"
+#include "acl/FilledChecklist.h"
 #include "acl/UrlPort.h"
 #include "HttpRequest.h"
 
 int
-ACLUrlPortStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLUrlPortStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     return data->match(checklist->request->url.port());
 }
 
-ACLUrlPortStrategy *
-ACLUrlPortStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLUrlPortStrategy ACLUrlPortStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/acl/UrlPort.h squid-4.0.21/src/acl/UrlPort.h
--- squid-4.0.20/src/acl/UrlPort.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/acl/UrlPort.h	2017-07-02 20:41:18.000000000 +1200
@@ -8,35 +8,15 @@
 
 #ifndef SQUID_ACLURLPORT_H
 #define SQUID_ACLURLPORT_H
-#include "acl/Strategised.h"
+
 #include "acl/Strategy.h"
 
 class ACLUrlPortStrategy : public ACLStrategy<int>
 {
 
 public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
+    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *);
     virtual bool requiresRequest() const {return true;}
-
-    static ACLUrlPortStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g+++ warnings about
-     * private constructors with no friends */
-    ACLUrlPortStrategy(ACLUrlPortStrategy const &);
-
-private:
-    static ACLUrlPortStrategy Instance_;
-    ACLUrlPortStrategy() {}
-
-    ACLUrlPortStrategy&operator=(ACLUrlPortStrategy const &);
-};
-
-class ACLUrlPort
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<int> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLURLPORT_H */
diff -u -r -N squid-4.0.20/src/AclRegs.cc squid-4.0.21/src/AclRegs.cc
--- squid-4.0.20/src/AclRegs.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/AclRegs.cc	2017-07-02 20:41:18.000000000 +1200
@@ -8,11 +8,6 @@
 
 #include "squid.h"
 
-/** This file exists to provide satic registration code to executables
-    that need ACLs. We cannot place this code in acl/lib*.la because it
-    does not get linked in, because nobody is using these classes by name.
-*/
-
 #if USE_ADAPTATION
 #include "acl/AdaptationService.h"
 #include "acl/AdaptationServiceData.h"
@@ -28,7 +23,6 @@
 #include "acl/AtStepData.h"
 #endif
 #include "acl/Asn.h"
-#include "acl/Browser.h"
 #include "acl/Checklist.h"
 #include "acl/ConnectionsEncrypted.h"
 #include "acl/Data.h"
@@ -40,6 +34,7 @@
 #include "acl/ExtUser.h"
 #endif
 #include "acl/FilledChecklist.h"
+#include "acl/forward.h"
 #include "acl/Gadgets.h"
 #include "acl/HasComponent.h"
 #include "acl/HasComponentData.h"
@@ -63,7 +58,6 @@
 #include "acl/Protocol.h"
 #include "acl/ProtocolData.h"
 #include "acl/Random.h"
-#include "acl/Referer.h"
 #include "acl/RegexData.h"
 #include "acl/ReplyHeaderStrategy.h"
 #include "acl/ReplyMimeType.h"
@@ -90,6 +84,7 @@
 #include "acl/Tag.h"
 #include "acl/Time.h"
 #include "acl/TimeData.h"
+#include "acl/TransactionInitiator.h"
 #include "acl/Url.h"
 #include "acl/UrlLogin.h"
 #include "acl/UrlPath.h"
@@ -100,143 +95,98 @@
 #include "auth/AclProxyAuth.h"
 #endif
 #include "base/RegexPattern.h"
+#include "ExternalACL.h"
 #if USE_IDENT
 #include "ident/AclIdent.h"
 #endif
+#if SQUID_SNMP
+#include "snmp_core.h"
+#endif
 
-ACL::Prototype ACLBrowser::RegistryProtoype(&ACLBrowser::RegistryEntry_, "browser");
-ACLStrategised<char const *> ACLBrowser::RegistryEntry_(new ACLRegexData, ACLRequestHeaderStrategy<Http::HdrType::USER_AGENT>::Instance(), "browser");
-ACLFlag  DestinationDomainFlags[] = {ACL_F_NO_LOOKUP, ACL_F_END};
-ACL::Prototype ACLDestinationDomain::LiteralRegistryProtoype(&ACLDestinationDomain::LiteralRegistryEntry_, "dstdomain");
-ACLStrategised<char const *> ACLDestinationDomain::LiteralRegistryEntry_(new ACLDomainData, ACLDestinationDomainStrategy::Instance(), "dstdomain", DestinationDomainFlags);
-ACL::Prototype ACLDestinationDomain::RegexRegistryProtoype(&ACLDestinationDomain::RegexRegistryEntry_, "dstdom_regex");
-ACLFlag  DestinationDomainRegexFlags[] = {ACL_F_NO_LOOKUP, ACL_F_REGEX_CASE, ACL_F_END};
-ACLStrategised<char const *> ACLDestinationDomain::RegexRegistryEntry_(new ACLRegexData,ACLDestinationDomainStrategy::Instance() ,"dstdom_regex", DestinationDomainRegexFlags);
-ACL::Prototype ACLDestinationIP::RegistryProtoype(&ACLDestinationIP::RegistryEntry_, "dst");
-ACLDestinationIP ACLDestinationIP::RegistryEntry_;
-#if USE_AUTH
-ACL::Prototype ACLExtUser::UserRegistryProtoype(&ACLExtUser::UserRegistryEntry_, "ext_user");
-ACLExtUser ACLExtUser::UserRegistryEntry_(new ACLUserData, "ext_user");
-ACL::Prototype ACLExtUser::RegexRegistryProtoype(&ACLExtUser::RegexRegistryEntry_, "ext_user_regex" );
-ACLExtUser ACLExtUser::RegexRegistryEntry_(new ACLRegexData, "ext_user_regex");
-#endif
-ACL::Prototype ACLHierCode::RegistryProtoype(&ACLHierCode::RegistryEntry_, "hier_code");
-ACLStrategised<hier_code> ACLHierCode::RegistryEntry_(new ACLHierCodeData, ACLHierCodeStrategy::Instance(), "hier_code");
-ACL::Prototype ACLHTTPRepHeader::RegistryProtoype(&ACLHTTPRepHeader::RegistryEntry_, "rep_header");
-ACLStrategised<HttpHeader*> ACLHTTPRepHeader::RegistryEntry_(new ACLHTTPHeaderData, ACLHTTPRepHeaderStrategy::Instance(), "rep_header");
-ACL::Prototype ACLHTTPReqHeader::RegistryProtoype(&ACLHTTPReqHeader::RegistryEntry_, "req_header");
-ACLStrategised<HttpHeader*> ACLHTTPReqHeader::RegistryEntry_(new ACLHTTPHeaderData, ACLHTTPReqHeaderStrategy::Instance(), "req_header");
-ACL::Prototype ACLHTTPStatus::RegistryProtoype(&ACLHTTPStatus::RegistryEntry_, "http_status");
-ACLHTTPStatus ACLHTTPStatus::RegistryEntry_("http_status");
-ACL::Prototype ACLMaxConnection::RegistryProtoype(&ACLMaxConnection::RegistryEntry_, "maxconn");
-ACLMaxConnection ACLMaxConnection::RegistryEntry_("maxconn");
-ACL::Prototype ACLMethod::RegistryProtoype(&ACLMethod::RegistryEntry_, "method");
-ACLStrategised<HttpRequestMethod> ACLMethod::RegistryEntry_(new ACLMethodData, ACLMethodStrategy::Instance(), "method");
-ACL::Prototype ACLLocalIP::RegistryProtoype(&ACLLocalIP::RegistryEntry_, "localip");
-ACLLocalIP ACLLocalIP::RegistryEntry_;
-ACL::Prototype ACLLocalPort::RegistryProtoype(&ACLLocalPort::RegistryEntry_, "localport");
-ACLStrategised<int> ACLLocalPort::RegistryEntry_(new ACLIntRange, ACLLocalPortStrategy::Instance(), "localport");
-ACL::Prototype ACLMyPortName::RegistryProtoype(&ACLMyPortName::RegistryEntry_, "myportname");
-ACLStrategised<const char *> ACLMyPortName::RegistryEntry_(new ACLStringData, ACLMyPortNameStrategy::Instance(), "myportname");
-ACL::Prototype ACLPeerName::RegistryProtoype(&ACLPeerName::RegistryEntry_, "peername");
-ACLStrategised<const char *> ACLPeerName::RegistryEntry_(new ACLStringData, ACLPeerNameStrategy::Instance(), "peername");
-ACL::Prototype ACLPeerName::RegexRegistryProtoype(&ACLPeerName::RegexRegistryEntry_, "peername_regex");
-ACLStrategised<char const *> ACLPeerName::RegexRegistryEntry_(new ACLRegexData, ACLPeerNameStrategy::Instance(), "peername_regex");
-ACL::Prototype ACLProtocol::RegistryProtoype(&ACLProtocol::RegistryEntry_, "proto");
-ACLStrategised<AnyP::ProtocolType> ACLProtocol::RegistryEntry_(new ACLProtocolData, ACLProtocolStrategy::Instance(), "proto");
-ACL::Prototype ACLRandom::RegistryProtoype(&ACLRandom::RegistryEntry_, "random");
-ACLRandom ACLRandom::RegistryEntry_("random");
-ACL::Prototype ACLReferer::RegistryProtoype(&ACLReferer::RegistryEntry_, "referer_regex");
-ACLStrategised<char const *> ACLReferer::RegistryEntry_(new ACLRegexData, ACLRequestHeaderStrategy<Http::HdrType::REFERER>::Instance(), "referer_regex");
-ACL::Prototype ACLReplyMIMEType::RegistryProtoype(&ACLReplyMIMEType::RegistryEntry_, "rep_mime_type");
-ACLStrategised<char const *> ACLReplyMIMEType::RegistryEntry_(new ACLRegexData, ACLReplyHeaderStrategy<Http::HdrType::CONTENT_TYPE>::Instance(), "rep_mime_type");
-ACL::Prototype ACLRequestMIMEType::RegistryProtoype(&ACLRequestMIMEType::RegistryEntry_, "req_mime_type");
-ACLStrategised<char const *> ACLRequestMIMEType::RegistryEntry_(new ACLRegexData, ACLRequestHeaderStrategy<Http::HdrType::CONTENT_TYPE>::Instance(), "req_mime_type");
-ACL::Prototype ACLSourceDomain::LiteralRegistryProtoype(&ACLSourceDomain::LiteralRegistryEntry_, "srcdomain");
-ACLStrategised<char const *> ACLSourceDomain::LiteralRegistryEntry_(new ACLDomainData, ACLSourceDomainStrategy::Instance(), "srcdomain");
-ACL::Prototype ACLSourceDomain::RegexRegistryProtoype(&ACLSourceDomain::RegexRegistryEntry_, "srcdom_regex");
-ACLStrategised<char const *> ACLSourceDomain::RegexRegistryEntry_(new ACLRegexData,ACLSourceDomainStrategy::Instance() ,"srcdom_regex");
-ACL::Prototype ACLSourceIP::RegistryProtoype(&ACLSourceIP::RegistryEntry_, "src");
-ACLSourceIP ACLSourceIP::RegistryEntry_;
-ACL::Prototype ACLTime::RegistryProtoype(&ACLTime::RegistryEntry_, "time");
-ACLStrategised<time_t> ACLTime::RegistryEntry_(new ACLTimeData, ACLTimeStrategy::Instance(), "time");
-ACL::Prototype ACLUrl::RegistryProtoype(&ACLUrl::RegistryEntry_, "url_regex");
-ACLStrategised<char const *> ACLUrl::RegistryEntry_(new ACLRegexData, ACLUrlStrategy::Instance(), "url_regex");
-ACL::Prototype ACLUrlLogin::RegistryProtoype(&ACLUrlLogin::RegistryEntry_, "urllogin");
-ACLStrategised<char const *> ACLUrlLogin::RegistryEntry_(new ACLRegexData, ACLUrlLoginStrategy::Instance(), "urllogin");
-ACL::Prototype ACLUrlPath::LegacyRegistryProtoype(&ACLUrlPath::RegistryEntry_, "pattern");
-ACL::Prototype ACLUrlPath::RegistryProtoype(&ACLUrlPath::RegistryEntry_, "urlpath_regex");
-ACLStrategised<char const *> ACLUrlPath::RegistryEntry_(new ACLRegexData, ACLUrlPathStrategy::Instance(), "urlpath_regex");
-ACL::Prototype ACLUrlPort::RegistryProtoype(&ACLUrlPort::RegistryEntry_, "port");
-ACLStrategised<int> ACLUrlPort::RegistryEntry_(new ACLIntRange, ACLUrlPortStrategy::Instance(), "port");
+// Not in src/acl/ because some of the ACLs it registers are not in src/acl/.
+void
+Acl::Init()
+{
+    /* the registration order does not matter */
+
+    // The explicit return type (ACL*) for lambdas is needed because the type
+    // of the return expression inside lambda is not ACL* but AclFoo* while
+    // Acl::Maker is defined to return ACL*.
+
+    RegisterMaker("all-of", [](TypeName)->ACL* { return new Acl::AllOf; }); // XXX: Add name parameter to ctor
+    RegisterMaker("any-of", [](TypeName)->ACL* { return new Acl::AnyOf; }); // XXX: Add name parameter to ctor
+    RegisterMaker("random", [](TypeName name)->ACL* { return new ACLRandom(name); });
+    RegisterMaker("time", [](TypeName name)->ACL* { return new ACLStrategised<time_t>(new ACLTimeData, new ACLTimeStrategy, name); });
+    RegisterMaker("src_as", [](TypeName name)->ACL* { return new ACLStrategised<Ip::Address>(new ACLASN, new ACLSourceASNStrategy, name); });
+    RegisterMaker("dst_as", [](TypeName name)->ACL* { return new ACLStrategised<Ip::Address>(new ACLASN, new ACLDestinationASNStrategy, name); });
+    RegisterMaker("browser", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLRequestHeaderStrategy<Http::HdrType::USER_AGENT>, name); });
+    RegisterMaker("dstdomain", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLDomainData, new ACLDestinationDomainStrategy, name); });
+    RegisterMaker("dstdom_regex", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLDestinationDomainStrategy , name); });
+    RegisterMaker("dst", [](TypeName)->ACL* { return new ACLDestinationIP; }); // XXX: Add name parameter to ctor
+    RegisterMaker("hier_code", [](TypeName name)->ACL* { return new ACLStrategised<hier_code>(new ACLHierCodeData, new ACLHierCodeStrategy, name); });
+    RegisterMaker("rep_header", [](TypeName name)->ACL* { return new ACLStrategised<HttpHeader*>(new ACLHTTPHeaderData, new ACLHTTPRepHeaderStrategy, name); });
+    RegisterMaker("req_header", [](TypeName name)->ACL* { return new ACLStrategised<HttpHeader*>(new ACLHTTPHeaderData, new ACLHTTPReqHeaderStrategy, name); });
+    RegisterMaker("http_status", [](TypeName name)->ACL* { return new ACLHTTPStatus(name); });
+    RegisterMaker("maxconn", [](TypeName name)->ACL* { return new ACLMaxConnection(name); });
+    RegisterMaker("method", [](TypeName name)->ACL* { return new ACLStrategised<HttpRequestMethod>(new ACLMethodData, new ACLMethodStrategy, name); });
+    RegisterMaker("localip", [](TypeName)->ACL* { return new ACLLocalIP; }); // XXX: Add name parameter to ctor
+    RegisterMaker("localport", [](TypeName name)->ACL* { return new ACLStrategised<int>(new ACLIntRange, new ACLLocalPortStrategy, name); });
+    RegisterMaker("myportname", [](TypeName name)->ACL* { return new ACLStrategised<const char *>(new ACLStringData, new ACLMyPortNameStrategy, name); });
+    RegisterMaker("peername", [](TypeName name)->ACL* { return new ACLStrategised<const char *>(new ACLStringData, new ACLPeerNameStrategy, name); });
+    RegisterMaker("peername_regex", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLPeerNameStrategy, name); });
+    RegisterMaker("proto", [](TypeName name)->ACL* { return new ACLStrategised<AnyP::ProtocolType>(new ACLProtocolData, new ACLProtocolStrategy, name); });
+    RegisterMaker("referer_regex", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLRequestHeaderStrategy<Http::HdrType::REFERER>, name); });
+    RegisterMaker("rep_mime_type", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLReplyHeaderStrategy<Http::HdrType::CONTENT_TYPE>, name); });
+    RegisterMaker("req_mime_type", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLRequestHeaderStrategy<Http::HdrType::CONTENT_TYPE>, name); });
+    RegisterMaker("srcdomain", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLDomainData, new ACLSourceDomainStrategy, name); });
+    RegisterMaker("srcdom_regex", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLSourceDomainStrategy, name); });
+    RegisterMaker("src", [](TypeName)->ACL* { return new ACLSourceIP; }); // XXX: Add name parameter to ctor
+    RegisterMaker("url_regex", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLUrlStrategy, name); });
+    RegisterMaker("urllogin", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLUrlLoginStrategy, name); });
+    RegisterMaker("urlpath_regex", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLUrlPathStrategy, name); });
+    RegisterMaker("port", [](TypeName name)->ACL* { return new ACLStrategised<int>(new ACLIntRange, new ACLUrlPortStrategy, name); });
+    RegisterMaker("external", [](TypeName name)->ACL* { return new ACLExternal(name); });
+    RegisterMaker("squid_error", [](TypeName name)->ACL* { return new ACLStrategised<err_type>(new ACLSquidErrorData, new ACLSquidErrorStrategy, name); });
+    RegisterMaker("connections_encrypted", [](TypeName name)->ACL* { return new Acl::ConnectionsEncrypted(name); });
+    RegisterMaker("tag", [](TypeName name)->ACL* { return new ACLStrategised<const char *>(new ACLStringData, new ACLTagStrategy, name); });
+    RegisterMaker("note", [](TypeName name)->ACL* { return new ACLStrategised<NotePairs::Entry*>(new ACLNoteData, new ACLNoteStrategy, name); });
+    RegisterMaker("has", [](TypeName name)->ACL* {return new ACLStrategised<ACLChecklist *>(new ACLHasComponentData, new ACLHasComponentStrategy, name); });
+    RegisterMaker("transaction_initiator", [](TypeName name)->ACL* {return new Acl::TransactionInitiator(name);});
 
 #if USE_OPENSSL
-ACL::Prototype ACLSslError::RegistryProtoype(&ACLSslError::RegistryEntry_, "ssl_error");
-ACLStrategised<const Security::CertErrors *> ACLSslError::RegistryEntry_(new ACLSslErrorData, ACLSslErrorStrategy::Instance(), "ssl_error");
-ACL::Prototype ACLCertificate::UserRegistryProtoype(&ACLCertificate::UserRegistryEntry_, "user_cert");
-ACLStrategised<X509 *> ACLCertificate::UserRegistryEntry_(new ACLCertificateData (Ssl::GetX509UserAttribute, "*"), ACLCertificateStrategy::Instance(), "user_cert");
-ACL::Prototype ACLCertificate::CARegistryProtoype(&ACLCertificate::CARegistryEntry_, "ca_cert");
-ACLStrategised<X509 *> ACLCertificate::CARegistryEntry_(new ACLCertificateData (Ssl::GetX509CAAttribute, "*"), ACLCertificateStrategy::Instance(), "ca_cert");
-ACL::Prototype ACLServerCertificate::X509FingerprintRegistryProtoype(&ACLServerCertificate::X509FingerprintRegistryEntry_, "server_cert_fingerprint");
-ACLStrategised<X509 *> ACLServerCertificate::X509FingerprintRegistryEntry_(new ACLCertificateData(Ssl::GetX509Fingerprint, "-sha1", true), ACLServerCertificateStrategy::Instance(), "server_cert_fingerprint");
-
-ACL::Prototype ACLAtStep::RegistryProtoype(&ACLAtStep::RegistryEntry_, "at_step");
-ACLStrategised<Ssl::BumpStep> ACLAtStep::RegistryEntry_(new ACLAtStepData, ACLAtStepStrategy::Instance(), "at_step");
-
-ACL::Prototype ACLServerName::LiteralRegistryProtoype(&ACLServerName::LiteralRegistryEntry_, "ssl::server_name");
-ACLStrategised<char const *> ACLServerName::LiteralRegistryEntry_(new ACLServerNameData, ACLServerNameStrategy::Instance(), "ssl::server_name");
-ACL::Prototype ACLServerName::RegexRegistryProtoype(&ACLServerName::RegexRegistryEntry_, "ssl::server_name_regex");
-ACLFlag  ServerNameRegexFlags[] = {ACL_F_REGEX_CASE, ACL_F_END};
-ACLStrategised<char const *> ACLServerName::RegexRegistryEntry_(new ACLRegexData, ACLServerNameStrategy::Instance(), "ssl::server_name_regex", ServerNameRegexFlags);
+    RegisterMaker("ssl_error", [](TypeName name)->ACL* { return new ACLStrategised<const Security::CertErrors *>(new ACLSslErrorData, new ACLSslErrorStrategy, name); });
+    RegisterMaker("user_cert", [](TypeName name)->ACL* { return new ACLStrategised<X509*>(new ACLCertificateData(Ssl::GetX509UserAttribute, "*"), new ACLCertificateStrategy, name); });
+    RegisterMaker("ca_cert", [](TypeName name)->ACL* { return new ACLStrategised<X509*>(new ACLCertificateData(Ssl::GetX509CAAttribute, "*"), new ACLCertificateStrategy, name); });
+    RegisterMaker("server_cert_fingerprint", [](TypeName name)->ACL* { return new ACLStrategised<X509*>(new ACLCertificateData(Ssl::GetX509Fingerprint, "-sha1", true), new ACLServerCertificateStrategy, name); });
+    RegisterMaker("at_step", [](TypeName name)->ACL* { return new ACLStrategised<Ssl::BumpStep>(new ACLAtStepData, new ACLAtStepStrategy, name); });
+    RegisterMaker("ssl::server_name", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLServerNameData, new ACLServerNameStrategy, name); });
+    RegisterMaker("ssl::server_name_regex", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLServerNameStrategy, name); });
 #endif
 
 #if USE_SQUID_EUI
-ACL::Prototype ACLARP::RegistryProtoype(&ACLARP::RegistryEntry_, "arp");
-ACLARP ACLARP::RegistryEntry_("arp");
-ACL::Prototype ACLEui64::RegistryProtoype(&ACLEui64::RegistryEntry_, "eui64");
-ACLEui64 ACLEui64::RegistryEntry_("eui64");
+    RegisterMaker("arp", [](TypeName name)->ACL* { return new ACLARP(name); });
+    RegisterMaker("eui64", [](TypeName name)->ACL* { return new ACLEui64(name); });
 #endif
 
 #if USE_IDENT
-ACL::Prototype ACLIdent::UserRegistryProtoype(&ACLIdent::UserRegistryEntry_, "ident");
-ACLIdent ACLIdent::UserRegistryEntry_(new ACLUserData, "ident");
-ACL::Prototype ACLIdent::RegexRegistryProtoype(&ACLIdent::RegexRegistryEntry_, "ident_regex" );
-ACLIdent ACLIdent::RegexRegistryEntry_(new ACLRegexData, "ident_regex");
+    RegisterMaker("ident", [](TypeName name)->ACL* { return new ACLIdent(new ACLUserData, name); });
+    RegisterMaker("ident_regex", [](TypeName name)->ACL* { return new ACLIdent(new ACLRegexData, name); });
 #endif
 
 #if USE_AUTH
-ACL::Prototype ACLProxyAuth::UserRegistryProtoype(&ACLProxyAuth::UserRegistryEntry_, "proxy_auth");
-ACLProxyAuth ACLProxyAuth::UserRegistryEntry_(new ACLUserData, "proxy_auth");
-ACL::Prototype ACLProxyAuth::RegexRegistryProtoype(&ACLProxyAuth::RegexRegistryEntry_, "proxy_auth_regex" );
-ACLProxyAuth ACLProxyAuth::RegexRegistryEntry_(new ACLRegexData, "proxy_auth_regex");
-
-ACL::Prototype ACLMaxUserIP::RegistryProtoype(&ACLMaxUserIP::RegistryEntry_, "max_user_ip");
-ACLMaxUserIP ACLMaxUserIP::RegistryEntry_("max_user_ip");
+    RegisterMaker("ext_user", [](TypeName name)->ACL* { return new ACLExtUser(new ACLUserData, name); });
+    RegisterMaker("ext_user_regex", [](TypeName name)->ACL* { return new ACLExtUser(new ACLRegexData, name); });
+    RegisterMaker("proxy_auth", [](TypeName name)->ACL* { return new ACLProxyAuth(new ACLUserData, name); });
+    RegisterMaker("proxy_auth_regex", [](TypeName name)->ACL* { return new ACLProxyAuth(new ACLRegexData, name); });
+    RegisterMaker("max_user_ip", [](TypeName name)->ACL* { return new ACLMaxUserIP(name); });
 #endif
 
-ACL::Prototype ACLTag::RegistryProtoype(&ACLTag::RegistryEntry_, "tag");
-ACLStrategised<const char *> ACLTag::RegistryEntry_(new ACLStringData, ACLTagStrategy::Instance(), "tag");
-
-ACL::Prototype Acl::AnyOf::RegistryProtoype(&Acl::AnyOf::RegistryEntry_, "any-of");
-Acl::AnyOf Acl::AnyOf::RegistryEntry_;
-
-ACL::Prototype Acl::AllOf::RegistryProtoype(&Acl::AllOf::RegistryEntry_, "all-of");
-Acl::AllOf Acl::AllOf::RegistryEntry_;
-
-ACL::Prototype ACLNote::RegistryProtoype(&ACLNote::RegistryEntry_, "note");
-ACLStrategised<NotePairs::Entry *> ACLNote::RegistryEntry_(new ACLNoteData, ACLNoteStrategy::Instance(), "note");
-
 #if USE_ADAPTATION
-ACL::Prototype ACLAdaptationService::RegistryProtoype(&ACLAdaptationService::RegistryEntry_, "adaptation_service");
-ACLStrategised<const char *> ACLAdaptationService::RegistryEntry_(new ACLAdaptationServiceData, ACLAdaptationServiceStrategy::Instance(), "adaptation_service");
+    RegisterMaker("adaptation_service", [](TypeName name)->ACL* { return new ACLStrategised<const char *>(new ACLAdaptationServiceData, new ACLAdaptationServiceStrategy, name); });
 #endif
 
-ACL::Prototype ACLSquidError::RegistryProtoype(&ACLSquidError::RegistryEntry_, "squid_error");
-ACLStrategised<err_type> ACLSquidError::RegistryEntry_(new ACLSquidErrorData, ACLSquidErrorStrategy::Instance(), "squid_error");
-
-ACL::Prototype Acl::ConnectionsEncrypted::RegistryProtoype(&Acl::ConnectionsEncrypted::RegistryEntry_, "connections_encrypted");
-Acl::ConnectionsEncrypted Acl::ConnectionsEncrypted::RegistryEntry_("connections_encrypted");
-
-ACL::Prototype ACLHasComponent::RegistryProtoype(&ACLHasComponent::RegistryEntry_, "has");
-ACLStrategised<ACLChecklist *> ACLHasComponent::RegistryEntry_(new ACLHasComponentData, ACLHasComponentStrategy::Instance(), "has");
+#if SQUID_SNMP
+    RegisterMaker("snmp_community", [](TypeName name)->ACL* { return new ACLStrategised<const char *>(new ACLStringData, new ACLSNMPCommunityStrategy, name); });
+#endif
+}
 
diff -u -r -N squid-4.0.20/src/adaptation/AccessCheck.cc squid-4.0.21/src/adaptation/AccessCheck.cc
--- squid-4.0.20/src/adaptation/AccessCheck.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/adaptation/AccessCheck.cc	2017-07-02 20:41:18.000000000 +1200
@@ -174,7 +174,7 @@
     Must(!candidates.empty()); // the candidate we were checking must be there
     debugs(93,5, HERE << topCandidate() << " answer=" << answer);
 
-    if (answer == ACCESS_ALLOWED) { // the rule matched
+    if (answer.allowed()) { // the rule matched
         ServiceGroupPointer g = topGroup();
         if (g != NULL) { // the corresponding group found
             callBack(g);
diff -u -r -N squid-4.0.20/src/adaptation/ecap/Host.cc squid-4.0.21/src/adaptation/ecap/Host.cc
--- squid-4.0.20/src/adaptation/ecap/Host.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/adaptation/ecap/Host.cc	2017-07-02 20:41:18.000000000 +1200
@@ -18,6 +18,7 @@
 #include "base/TextException.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
+#include "MasterXaction.h"
 
 const libecap::Name Adaptation::Ecap::protocolInternal("internal", libecap::Name::NextId());
 const libecap::Name Adaptation::Ecap::protocolCacheObj("cache_object", libecap::Name::NextId());
@@ -162,7 +163,8 @@
 Adaptation::Ecap::Host::MessagePtr
 Adaptation::Ecap::Host::newRequest() const
 {
-    return MessagePtr(new Adaptation::Ecap::MessageRep(new HttpRequest));
+    static const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initAdaptationOrphan_);
+    return MessagePtr(new Adaptation::Ecap::MessageRep(new HttpRequest(mx)));
 }
 
 Adaptation::Ecap::Host::MessagePtr
diff -u -r -N squid-4.0.20/src/adaptation/ecap/Makefile.in squid-4.0.21/src/adaptation/ecap/Makefile.in
--- squid-4.0.20/src/adaptation/ecap/Makefile.in	2017-06-02 00:55:40.000000000 +1200
+++ squid-4.0.21/src/adaptation/ecap/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/adaptation/ecap/MessageRep.cc squid-4.0.21/src/adaptation/ecap/MessageRep.cc
--- squid-4.0.20/src/adaptation/ecap/MessageRep.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/adaptation/ecap/MessageRep.cc	2017-07-02 20:41:18.000000000 +1200
@@ -199,11 +199,11 @@
 void
 Adaptation::Ecap::RequestLineRep::uri(const Area &aUri)
 {
-    // TODO: if method is not set, urlPath will assume it is not connect;
-    // Can we change urlParse API to remove the method parameter?
-    // TODO: optimize: urlPath should take constant URL buffer
+    // TODO: if method is not set, URL::parse will assume it is not connect;
+    // Can we change URL::parse API to remove the method parameter?
+    // TODO: optimize: URL::parse should take constant URL buffer
     char *buf = xstrdup(aUri.toString().c_str());
-    const bool ok = urlParse(theMessage.method, buf, &theMessage);
+    const bool ok = theMessage.url.parse(theMessage.method, buf);
     xfree(buf);
     Must(ok);
 }
diff -u -r -N squid-4.0.20/src/adaptation/ecap/XactionRep.cc squid-4.0.21/src/adaptation/ecap/XactionRep.cc
--- squid-4.0.20/src/adaptation/ecap/XactionRep.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/adaptation/ecap/XactionRep.cc	2017-07-02 20:41:18.000000000 +1200
@@ -23,6 +23,7 @@
 #include "format/Format.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
+#include "MasterXaction.h"
 #include "SquidTime.h"
 
 CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Ecap::XactionRep, XactionRep);
@@ -738,5 +739,13 @@
 Adaptation::Ecap::XactionRep::updateSources(HttpMsg *adapted)
 {
     adapted->sources |= service().cfg().connectionEncryption ? HttpMsg::srcEcaps : HttpMsg::srcEcap;
+
+    // Update masterXaction object for adapted HTTP requests.
+    if (HttpRequest *adaptedReq = dynamic_cast<HttpRequest*>(adapted)) {
+        HttpRequest *request = dynamic_cast<HttpRequest*> (theCauseRep ?
+                               theCauseRep->raw().header : theVirginRep.raw().header);
+        Must(request);
+        adaptedReq->masterXaction = request->masterXaction;
+    }
 }
 
diff -u -r -N squid-4.0.20/src/adaptation/icap/Launcher.cc squid-4.0.21/src/adaptation/icap/Launcher.cc
--- squid-4.0.20/src/adaptation/icap/Launcher.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/adaptation/icap/Launcher.cc	2017-07-02 20:41:18.000000000 +1200
@@ -147,7 +147,7 @@
     cl->reply = info.icapReply;
     HTTPMSGLOCK(cl->reply);
 
-    bool result = cl->fastCheck() == ACCESS_ALLOWED;
+    bool result = cl->fastCheck().allowed();
     delete cl;
     return result;
 }
diff -u -r -N squid-4.0.20/src/adaptation/icap/Makefile.in squid-4.0.21/src/adaptation/icap/Makefile.in
--- squid-4.0.20/src/adaptation/icap/Makefile.in	2017-06-02 00:55:45.000000000 +1200
+++ squid-4.0.21/src/adaptation/icap/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/adaptation/icap/ModXact.cc squid-4.0.21/src/adaptation/icap/ModXact.cc
--- squid-4.0.20/src/adaptation/icap/ModXact.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/adaptation/icap/ModXact.cc	2017-07-02 20:41:18.000000000 +1200
@@ -30,6 +30,7 @@
 #include "HttpMsg.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
+#include "MasterXaction.h"
 #include "SquidTime.h"
 #include "URL.h"
 
@@ -734,7 +735,7 @@
         setOutcome(service().cfg().method == ICAP::methodReqmod ?
                    xoSatisfied : xoModified);
     } else if (gotEncapsulated("req-hdr")) {
-        adapted.setHeader(new HttpRequest);
+        adapted.setHeader(new HttpRequest(virginRequest().masterXaction));
         setOutcome(xoModified);
     } else
         throw TexcHere("Neither res-hdr nor req-hdr in maybeAllocateHttpMsg()");
@@ -961,8 +962,8 @@
     Must(!adapted.header);
     {
         HttpMsg::Pointer newHead;
-        if (dynamic_cast<const HttpRequest*>(oldHead)) {
-            newHead = new HttpRequest;
+        if (const HttpRequest *r = dynamic_cast<const HttpRequest*>(oldHead)) {
+            newHead = new HttpRequest(r->masterXaction);
         } else if (dynamic_cast<const HttpReply*>(oldHead)) {
             newHead = new HttpReply;
         }
@@ -1547,7 +1548,7 @@
     HttpMsg::Pointer headClone;
 
     if (const HttpRequest* old_request = dynamic_cast<const HttpRequest*>(head)) {
-        HttpRequest::Pointer new_request(new HttpRequest);
+        HttpRequest::Pointer new_request(new HttpRequest(old_request->masterXaction));
         // copy the requst-line details
         new_request->method = old_request->method;
         new_request->url = old_request->url;
diff -u -r -N squid-4.0.20/src/adaptation/icap/Xaction.cc squid-4.0.21/src/adaptation/icap/Xaction.cc
--- squid-4.0.20/src/adaptation/icap/Xaction.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/adaptation/icap/Xaction.cc	2017-07-02 20:41:18.000000000 +1200
@@ -99,7 +99,8 @@
 {
     debugs(93,3, typeName << " constructed, this=" << this <<
            " [icapx" << id << ']'); // we should not call virtual status() here
-    icapRequest = new HttpRequest;
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initAdaptation);
+    icapRequest = new HttpRequest(mx);
     HTTPMSGLOCK(icapRequest);
     icap_tr_start = current_time;
     memset(&icap_tio_start, 0, sizeof(icap_tio_start));
diff -u -r -N squid-4.0.20/src/adaptation/Makefile.in squid-4.0.21/src/adaptation/Makefile.in
--- squid-4.0.20/src/adaptation/Makefile.in	2017-06-02 00:55:34.000000000 +1200
+++ squid-4.0.21/src/adaptation/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/adaptation/ServiceConfig.cc squid-4.0.21/src/adaptation/ServiceConfig.cc
--- squid-4.0.20/src/adaptation/ServiceConfig.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/adaptation/ServiceConfig.cc	2017-07-02 20:41:18.000000000 +1200
@@ -189,7 +189,7 @@
 Adaptation::ServiceConfig::grokUri(const char *value)
 {
     // TODO: find core code that parses URLs and extracts various parts
-    // AYJ: most of this is duplicate of urlParse() in src/url.cc
+    // AYJ: most of this is duplicate of URL::parse() in src/url.cc
 
     if (!value || !*value) {
         debugs(3, DBG_CRITICAL, HERE << cfg_filename << ':' << config_lineno << ": " <<
diff -u -r -N squid-4.0.20/src/anyp/Makefile.in squid-4.0.21/src/anyp/Makefile.in
--- squid-4.0.20/src/anyp/Makefile.in	2017-06-02 00:55:53.000000000 +1200
+++ squid-4.0.21/src/anyp/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/AclMaxUserIp.cc squid-4.0.21/src/auth/AclMaxUserIp.cc
--- squid-4.0.20/src/auth/AclMaxUserIp.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/auth/AclMaxUserIp.cc	2017-07-02 20:41:18.000000000 +1200
@@ -18,24 +18,11 @@
 #include "Parsing.h"
 #include "wordlist.h"
 
-ACLFlag ACLMaxUserIP::SupportedFlags[] = {ACL_F_STRICT, ACL_F_END};
-
 ACLMaxUserIP::ACLMaxUserIP(char const *theClass) :
-    ACL(SupportedFlags),
     class_(theClass),
     maximum(0)
 {}
 
-ACLMaxUserIP::ACLMaxUserIP(ACLMaxUserIP const &old) :
-    class_(old.class_),
-    maximum(old.maximum)
-{
-    flags = old.flags;
-}
-
-ACLMaxUserIP::~ACLMaxUserIP()
-{}
-
 ACL *
 ACLMaxUserIP::clone() const
 {
@@ -60,6 +47,15 @@
     return maximum > 0;
 }
 
+const Acl::Options &
+ACLMaxUserIP::options()
+{
+    static const Acl::BooleanOption BeStrict;
+    static const Acl::Options MyOptions = { { "-s", &BeStrict } };
+    BeStrict.linkWith(&beStrict);
+    return MyOptions;
+}
+
 void
 ACLMaxUserIP::parse()
 {
@@ -102,7 +98,7 @@
     debugs(28, DBG_IMPORTANT, "aclMatchUserMaxIP: user '" << auth_user_request->username() << "' tries to use too many IP addresses (max " << maximum << " allowed)!");
 
     /* this is a match */
-    if (flags.isSet(ACL_F_STRICT)) {
+    if (beStrict) {
         /*
          * simply deny access - the user name is already associated with
          * the request
diff -u -r -N squid-4.0.20/src/auth/AclMaxUserIp.h squid-4.0.21/src/auth/AclMaxUserIp.h
--- squid-4.0.20/src/auth/AclMaxUserIp.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/auth/AclMaxUserIp.h	2017-07-02 20:41:18.000000000 +1200
@@ -12,7 +12,6 @@
 #if USE_AUTH
 
 #include "acl/Acl.h"
-#include "acl/Checklist.h"
 #include "auth/UserRequest.h"
 
 class ACLMaxUserIP : public ACL
@@ -20,13 +19,11 @@
     MEMPROXY_CLASS(ACLMaxUserIP);
 
 public:
-    ACLMaxUserIP(char const *theClass);
-    ACLMaxUserIP(ACLMaxUserIP const &old);
-    ~ACLMaxUserIP();
-    ACLMaxUserIP &operator =(ACLMaxUserIP const &);
+    explicit ACLMaxUserIP(char const *theClass);
 
     virtual ACL *clone() const;
     virtual char const *typeString() const;
+    virtual const Acl::Options &options();
     virtual void parse();
     virtual int match(ACLChecklist *cl);
     virtual SBufList dump() const;
@@ -36,14 +33,13 @@
 
     int getMaximum() const {return maximum;}
 
-    bool getStrict() const {return flags.isSet(ACL_F_STRICT);}
-
 private:
-    static Prototype RegistryProtoype;
-    static ACLMaxUserIP RegistryEntry_;
-    static ACLFlag SupportedFlags[];
-
     int match(Auth::UserRequest::Pointer auth_user_request, Ip::Address const &src_addr);
+
+public:
+    Acl::BooleanOptionValue beStrict; ///< Enforce "one user, one device" policy?
+
+private:
     char const *class_;
     int maximum;
 };
diff -u -r -N squid-4.0.20/src/auth/AclProxyAuth.cc squid-4.0.21/src/auth/AclProxyAuth.cc
--- squid-4.0.20/src/auth/AclProxyAuth.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/auth/AclProxyAuth.cc	2017-07-02 20:41:18.000000000 +1200
@@ -51,6 +51,12 @@
 }
 
 void
+ACLProxyAuth::parseFlags()
+{
+    ParseFlags(Acl::NoOptions(), data->supportedFlags());
+}
+
+void
 ACLProxyAuth::parse()
 {
     data->parse();
diff -u -r -N squid-4.0.20/src/auth/AclProxyAuth.h squid-4.0.21/src/auth/AclProxyAuth.h
--- squid-4.0.20/src/auth/AclProxyAuth.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/auth/AclProxyAuth.h	2017-07-02 20:41:18.000000000 +1200
@@ -37,24 +37,20 @@
     ACLProxyAuth(ACLProxyAuth const &);
     ACLProxyAuth &operator =(ACLProxyAuth const &);
 
+    /* ACL API */
     virtual char const *typeString() const;
     virtual void parse();
     virtual bool isProxyAuth() const {return true;}
-
+    virtual void parseFlags();
     virtual int match(ACLChecklist *checklist);
     virtual SBufList dump() const;
     virtual bool valid() const;
     virtual bool empty() const;
     virtual bool requiresRequest() const {return true;}
-
     virtual ACL *clone() const;
     virtual int matchForCache(ACLChecklist *checklist);
 
 private:
-    static Prototype UserRegistryProtoype;
-    static ACLProxyAuth UserRegistryEntry_;
-    static Prototype RegexRegistryProtoype;
-    static ACLProxyAuth RegexRegistryEntry_;
     int matchProxyAuth(ACLChecklist *);
     ACLData<char const *> *data;
     char const *type_;
diff -u -r -N squid-4.0.20/src/auth/basic/DB/basic_db_auth.8 squid-4.0.21/src/auth/basic/DB/basic_db_auth.8
--- squid-4.0.20/src/auth/basic/DB/basic_db_auth.8	2017-06-02 09:55:21.000000000 +1200
+++ squid-4.0.21/src/auth/basic/DB/basic_db_auth.8	2017-07-02 20:57:35.000000000 +1200
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "BASIC_DB_AUTH 8"
-.TH BASIC_DB_AUTH 8 "2017-06-01" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH BASIC_DB_AUTH 8 "2017-07-02" "perl v5.24.1" "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
@@ -190,7 +190,7 @@
 Keep a persistent database connection open between queries.
 .IP "\fB\-\-joomla\fR" 12
 .IX Item "--joomla"
-Tells helper that user database is Joomla \s-1DB.\s0  So their unusual salt 
+Tells helper that user database is Joomla \s-1DB. \s0 So their unusual salt 
 hashing is understood.
 .SH "AUTHOR"
 .IX Header "AUTHOR"
@@ -229,7 +229,7 @@
 Report ideas for new improvements to the \fISquid Developers mailing list <squid\-dev@squid\-cache.org\fR>
 .SH "SEE ALSO"
 .IX Header "SEE ALSO"
-squid (8), \s-1GPL\s0 (7),
+squid (8), \s-1GPL \\fIs0\fR\|(7),
 .PP
 The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq
 .PP
diff -u -r -N squid-4.0.20/src/auth/basic/DB/Makefile.in squid-4.0.21/src/auth/basic/DB/Makefile.in
--- squid-4.0.20/src/auth/basic/DB/Makefile.in	2017-06-02 00:56:05.000000000 +1200
+++ squid-4.0.21/src/auth/basic/DB/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/fake/Makefile.in squid-4.0.21/src/auth/basic/fake/Makefile.in
--- squid-4.0.20/src/auth/basic/fake/Makefile.in	2017-06-02 00:57:29.000000000 +1200
+++ squid-4.0.21/src/auth/basic/fake/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/getpwnam/Makefile.in squid-4.0.21/src/auth/basic/getpwnam/Makefile.in
--- squid-4.0.20/src/auth/basic/getpwnam/Makefile.in	2017-06-02 00:57:34.000000000 +1200
+++ squid-4.0.21/src/auth/basic/getpwnam/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/LDAP/Makefile.in squid-4.0.21/src/auth/basic/LDAP/Makefile.in
--- squid-4.0.20/src/auth/basic/LDAP/Makefile.in	2017-06-02 00:56:16.000000000 +1200
+++ squid-4.0.21/src/auth/basic/LDAP/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/Makefile.in squid-4.0.21/src/auth/basic/Makefile.in
--- squid-4.0.20/src/auth/basic/Makefile.in	2017-06-02 00:56:22.000000000 +1200
+++ squid-4.0.21/src/auth/basic/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/NCSA/basic_ncsa_auth.8 squid-4.0.21/src/auth/basic/NCSA/basic_ncsa_auth.8
--- squid-4.0.20/src/auth/basic/NCSA/basic_ncsa_auth.8	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/auth/basic/NCSA/basic_ncsa_auth.8	2017-07-02 20:41:18.000000000 +1200
@@ -18,15 +18,15 @@
 .PP
 This authenticator accepts:
 .BR
-* Blowfish - for passwords 72 characters or less in length
+ * Blowfish \- for passwords 72 characters or less in length.
 .BR
-* SHA256 - with salting and magic strings
+ * SHA256 \- with salting and magic strings.
 .BR
-* SHA512 - with salting and magic strings
+ * SHA512 \- with salting and magic strings.
 .BR
-* MD5 - with optional salt and magic strings
+ * MD5 \- with optional salt and magic strings.
 .BR
-* DES - for passwords 8 characters or less in length
+ * DES \- for passwords 8 characters or less in length.
 .
 NOTE: Blowfish and SHA algorithms require system-specific support.
 .
diff -u -r -N squid-4.0.20/src/auth/basic/NCSA/Makefile.in squid-4.0.21/src/auth/basic/NCSA/Makefile.in
--- squid-4.0.20/src/auth/basic/NCSA/Makefile.in	2017-06-02 00:56:30.000000000 +1200
+++ squid-4.0.21/src/auth/basic/NCSA/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/NIS/Makefile.in squid-4.0.21/src/auth/basic/NIS/Makefile.in
--- squid-4.0.20/src/auth/basic/NIS/Makefile.in	2017-06-02 00:56:35.000000000 +1200
+++ squid-4.0.21/src/auth/basic/NIS/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/PAM/Makefile.in squid-4.0.21/src/auth/basic/PAM/Makefile.in
--- squid-4.0.20/src/auth/basic/PAM/Makefile.in	2017-06-02 00:56:46.000000000 +1200
+++ squid-4.0.21/src/auth/basic/PAM/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/POP3/basic_pop3_auth.8 squid-4.0.21/src/auth/basic/POP3/basic_pop3_auth.8
--- squid-4.0.20/src/auth/basic/POP3/basic_pop3_auth.8	2017-06-02 09:56:01.000000000 +1200
+++ squid-4.0.21/src/auth/basic/POP3/basic_pop3_auth.8	2017-07-02 20:57:35.000000000 +1200
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "BASIC_POP3_AUTH 8"
-.TH BASIC_POP3_AUTH 8 "2017-06-01" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH BASIC_POP3_AUTH 8 "2017-07-02" "perl v5.24.1" "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
@@ -198,7 +198,7 @@
 Report ideas for new improvements to the \fISquid Developers mailing list <squid\-dev@squid\-cache.org\fR>
 .SH "SEE ALSO"
 .IX Header "SEE ALSO"
-squid (8), \s-1GPL\s0 (7),
+squid (8), \s-1GPL \\fIs0\fR\|(7),
 .PP
 The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq
 .PP
diff -u -r -N squid-4.0.20/src/auth/basic/POP3/Makefile.in squid-4.0.21/src/auth/basic/POP3/Makefile.in
--- squid-4.0.20/src/auth/basic/POP3/Makefile.in	2017-06-02 00:56:53.000000000 +1200
+++ squid-4.0.21/src/auth/basic/POP3/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/RADIUS/Makefile.in squid-4.0.21/src/auth/basic/RADIUS/Makefile.in
--- squid-4.0.20/src/auth/basic/RADIUS/Makefile.in	2017-06-02 00:57:02.000000000 +1200
+++ squid-4.0.21/src/auth/basic/RADIUS/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/SASL/Makefile.in squid-4.0.21/src/auth/basic/SASL/Makefile.in
--- squid-4.0.20/src/auth/basic/SASL/Makefile.in	2017-06-02 00:57:07.000000000 +1200
+++ squid-4.0.21/src/auth/basic/SASL/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/SMB/Makefile.in squid-4.0.21/src/auth/basic/SMB/Makefile.in
--- squid-4.0.20/src/auth/basic/SMB/Makefile.in	2017-06-02 00:57:13.000000000 +1200
+++ squid-4.0.21/src/auth/basic/SMB/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/SMB_LM/Makefile.in squid-4.0.21/src/auth/basic/SMB_LM/Makefile.in
--- squid-4.0.20/src/auth/basic/SMB_LM/Makefile.in	2017-06-02 00:57:18.000000000 +1200
+++ squid-4.0.21/src/auth/basic/SMB_LM/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/basic/SSPI/Makefile.in squid-4.0.21/src/auth/basic/SSPI/Makefile.in
--- squid-4.0.20/src/auth/basic/SSPI/Makefile.in	2017-06-02 00:57:25.000000000 +1200
+++ squid-4.0.21/src/auth/basic/SSPI/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/digest/eDirectory/Makefile.in squid-4.0.21/src/auth/digest/eDirectory/Makefile.in
--- squid-4.0.20/src/auth/digest/eDirectory/Makefile.in	2017-06-02 00:57:48.000000000 +1200
+++ squid-4.0.21/src/auth/digest/eDirectory/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/digest/file/Makefile.in squid-4.0.21/src/auth/digest/file/Makefile.in
--- squid-4.0.20/src/auth/digest/file/Makefile.in	2017-06-02 00:57:53.000000000 +1200
+++ squid-4.0.21/src/auth/digest/file/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/digest/LDAP/ldap_backend.cc squid-4.0.21/src/auth/digest/LDAP/ldap_backend.cc
--- squid-4.0.20/src/auth/digest/LDAP/ldap_backend.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/auth/digest/LDAP/ldap_backend.cc	2017-07-02 20:41:18.000000000 +1200
@@ -655,7 +655,7 @@
     // use the -l delimiter to find realm, or
     // only honor the -r specified realm
     const bool lookup = (!*frealm && *delimiter) ||
-                        (*frealm && strcmp(requestData->realm, frealm) != 0);
+                        (*frealm && strcmp(requestData->realm, frealm) == 0);
 
     if (lookup)
         password = getpassword(requestData->user, requestData->realm);
diff -u -r -N squid-4.0.20/src/auth/digest/LDAP/Makefile.in squid-4.0.21/src/auth/digest/LDAP/Makefile.in
--- squid-4.0.20/src/auth/digest/LDAP/Makefile.in	2017-06-02 00:57:38.000000000 +1200
+++ squid-4.0.21/src/auth/digest/LDAP/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/digest/Makefile.in squid-4.0.21/src/auth/digest/Makefile.in
--- squid-4.0.20/src/auth/digest/Makefile.in	2017-06-02 00:57:42.000000000 +1200
+++ squid-4.0.21/src/auth/digest/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/Makefile.in squid-4.0.21/src/auth/Makefile.in
--- squid-4.0.20/src/auth/Makefile.in	2017-06-02 00:56:02.000000000 +1200
+++ squid-4.0.21/src/auth/Makefile.in	2017-07-02 20:41:25.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/negotiate/kerberos/Makefile.in squid-4.0.21/src/auth/negotiate/kerberos/Makefile.in
--- squid-4.0.20/src/auth/negotiate/kerberos/Makefile.in	2017-06-02 00:58:09.000000000 +1200
+++ squid-4.0.21/src/auth/negotiate/kerberos/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/negotiate/Makefile.in squid-4.0.21/src/auth/negotiate/Makefile.in
--- squid-4.0.20/src/auth/negotiate/Makefile.in	2017-06-02 00:58:00.000000000 +1200
+++ squid-4.0.21/src/auth/negotiate/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/negotiate/SSPI/Makefile.in squid-4.0.21/src/auth/negotiate/SSPI/Makefile.in
--- squid-4.0.20/src/auth/negotiate/SSPI/Makefile.in	2017-06-02 00:58:04.000000000 +1200
+++ squid-4.0.21/src/auth/negotiate/SSPI/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/negotiate/wrapper/Makefile.in squid-4.0.21/src/auth/negotiate/wrapper/Makefile.in
--- squid-4.0.20/src/auth/negotiate/wrapper/Makefile.in	2017-06-02 00:58:15.000000000 +1200
+++ squid-4.0.21/src/auth/negotiate/wrapper/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/ntlm/fake/Makefile.in squid-4.0.21/src/auth/ntlm/fake/Makefile.in
--- squid-4.0.20/src/auth/ntlm/fake/Makefile.in	2017-06-02 00:58:34.000000000 +1200
+++ squid-4.0.21/src/auth/ntlm/fake/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/ntlm/Makefile.in squid-4.0.21/src/auth/ntlm/Makefile.in
--- squid-4.0.20/src/auth/ntlm/Makefile.in	2017-06-02 00:58:20.000000000 +1200
+++ squid-4.0.21/src/auth/ntlm/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/ntlm/SMB_LM/Makefile.in squid-4.0.21/src/auth/ntlm/SMB_LM/Makefile.in
--- squid-4.0.20/src/auth/ntlm/SMB_LM/Makefile.in	2017-06-02 00:58:25.000000000 +1200
+++ squid-4.0.21/src/auth/ntlm/SMB_LM/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/auth/ntlm/SSPI/Makefile.in squid-4.0.21/src/auth/ntlm/SSPI/Makefile.in
--- squid-4.0.20/src/auth/ntlm/SSPI/Makefile.in	2017-06-02 00:58:29.000000000 +1200
+++ squid-4.0.21/src/auth/ntlm/SSPI/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/base/CharacterSet.cc squid-4.0.21/src/base/CharacterSet.cc
--- squid-4.0.20/src/base/CharacterSet.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/base/CharacterSet.cc	2017-07-02 20:41:18.000000000 +1200
@@ -97,6 +97,15 @@
         addRange(range.first, range.second);
 }
 
+void
+CharacterSet::printChars(std::ostream &os) const
+{
+    for (size_t idx = 0; idx < 256; ++idx) {
+        if (chars_[idx])
+            os << static_cast<char>(idx);
+    }
+}
+
 CharacterSet
 operator+ (CharacterSet lhs, const CharacterSet &rhs)
 {
diff -u -r -N squid-4.0.20/src/base/CharacterSet.h squid-4.0.21/src/base/CharacterSet.h
--- squid-4.0.20/src/base/CharacterSet.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/base/CharacterSet.h	2017-07-02 20:41:18.000000000 +1200
@@ -19,9 +19,8 @@
 public:
     typedef std::vector<uint8_t> Storage;
 
-    /// define a character set with the given label ("anonymous" if nullptr)
-    ///  with specified initial contents
-    CharacterSet(const char *label, const char * const initial);
+    /// a character set with a given label and contents
+    explicit CharacterSet(const char *label = "anonymous", const char * const chars = "");
 
     /// define a character set with the given label ("anonymous" if nullptr)
     ///  containing characters defined in the supplied ranges
@@ -33,6 +32,9 @@
     /// \see addRange
     CharacterSet(const char *label, std::initializer_list<std::pair<uint8_t,uint8_t>> ranges);
 
+    /// whether the set lacks any members
+    bool isEmpty() const { return chars_.empty(); }
+
     /// whether a given character exists in the set
     bool operator[](unsigned char c) const {return chars_[static_cast<uint8_t>(c)] != 0;}
 
@@ -60,6 +62,9 @@
     /// \note Ignores label
     bool operator != (const CharacterSet &cs) const { return !operator==(cs); }
 
+    /// prints all chars in arbitrary order, without any quoting/escaping
+    void printChars(std::ostream &os) const;
+
     /// optional set label for debugging (default: "anonymous")
     const char * name;
 
diff -u -r -N squid-4.0.20/src/base/Makefile.in squid-4.0.21/src/base/Makefile.in
--- squid-4.0.20/src/base/Makefile.in	2017-06-02 00:58:40.000000000 +1200
+++ squid-4.0.21/src/base/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/base/RefCount.h squid-4.0.21/src/base/RefCount.h
--- squid-4.0.20/src/base/RefCount.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/base/RefCount.h	2017-07-02 20:41:18.000000000 +1200
@@ -70,11 +70,12 @@
 
     C * operator-> () const {return const_cast<C *>(p_); }
 
-    C & operator * () const {return *const_cast<C *>(p_); }
+    C & operator * () const {
+        assert(p_);
+        return *const_cast<C *>(p_);
+    }
 
-    C const * getRaw() const {return p_; }
-
-    C * getRaw() {return const_cast<C *>(p_); }
+    C * getRaw() const { return const_cast<C *>(p_); }
 
     bool operator == (const RefCount& p) const {
         return p.p_ == p_;
diff -u -r -N squid-4.0.20/src/cache_cf.cc squid-4.0.21/src/cache_cf.cc
--- squid-4.0.20/src/cache_cf.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/cache_cf.cc	2017-07-02 20:41:18.000000000 +1200
@@ -567,8 +567,9 @@
     return err_count;
 }
 
+static
 int
-parseConfigFile(const char *file_name)
+parseConfigFileOrThrow(const char *file_name)
 {
     int err_count = 0;
 
@@ -609,6 +610,20 @@
     return err_count;
 }
 
+// TODO: Refactor main.cc to centrally handle (and report) all exceptions.
+int
+parseConfigFile(const char *file_name)
+{
+    try {
+        return parseConfigFileOrThrow(file_name);
+    }
+    catch (const std::exception &ex) {
+        debugs(3, DBG_CRITICAL, "FATAL: bad configuration: " << ex.what());
+        self_destruct();
+        return 1; // not reached
+    }
+}
+
 static void
 configDoConfigure(void)
 {
@@ -1308,12 +1323,14 @@
 {
     while (ae != NULL) {
         debugs(3, 3, "dump_acl: " << name << " " << ae->name);
-        storeAppendPrintf(entry, "%s %s %s %s ",
+        storeAppendPrintf(entry, "%s %s %s ",
                           name,
                           ae->name,
-                          ae->typeString(),
-                          ae->flags.flagsStr());
-        dump_SBufList(entry, ae->dump());
+                          ae->typeString());
+        SBufList tail;
+        tail.splice(tail.end(), ae->dumpOptions());
+        tail.splice(tail.end(), ae->dump()); // ACL parameters
+        dump_SBufList(entry, tail);
         ae = ae->next;
     }
 }
@@ -2403,7 +2420,7 @@
 
     CachePeer *p = peerFindByName(host);
     if (!p) {
-        debugs(15, DBG_CRITICAL, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
+        debugs(15, DBG_CRITICAL, "ERROR: " << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
         return;
     }
 
@@ -4038,7 +4055,7 @@
     debugs(3, 9, "possible " << cl->filename << " logformat: " << logdef_name);
 
     if (cl->type != Log::Format::CLF_UNKNOWN) {
-        debugs(3, DBG_CRITICAL, "Second logformat name in one access_log: " <<
+        debugs(3, DBG_CRITICAL, "FATAL: Second logformat name in one access_log: " <<
                logdef_name << " " << cl->type << " ? " << Log::Format::CLF_NONE);
         self_destruct();
         return false;
@@ -4077,7 +4094,7 @@
     } else if (strcmp(logdef_name, "referrer") == 0) {
         cl->type = Log::Format::CLF_REFERER;
     } else if (dieWhenMissing) {
-        debugs(3, DBG_CRITICAL, "Log format '" << logdef_name << "' is not defined");
+        debugs(3, DBG_CRITICAL, "FATAL: Log format '" << logdef_name << "' is not defined");
         self_destruct();
         return false;
     } else {
@@ -4112,7 +4129,8 @@
             break;
 
         case Log::Format::CLF_SQUID:
-            storeAppendPrintf(entry, "%s logformat=squid", log->filename);
+            // this is the default, no need to add to the dump
+            //storeAppendPrintf(entry, "%s logformat=squid", log->filename);
             break;
 
         case Log::Format::CLF_COMBINED:
diff -u -r -N squid-4.0.20/src/cbdata.h squid-4.0.21/src/cbdata.h
--- squid-4.0.20/src/cbdata.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/cbdata.h	2017-07-02 20:41:18.000000000 +1200
@@ -371,5 +371,25 @@
     void *data;
 };
 
+// Discouraged: Use CbcPointer<> and asynchronous calls instead if possible.
+/// an old-style void* callback parameter
+class CallbackData
+{
+public:
+    CallbackData(): data_(nullptr) {}
+    CallbackData(void *data): data_(cbdataReference(data)) {}
+    CallbackData(const CallbackData &other): data_(cbdataReference(other.data_)) {}
+    CallbackData(CallbackData &&other): data_(other.data_) { other.data_ = nullptr; }
+    ~CallbackData() { cbdataReferenceDone(data_); }
+
+    // implement if needed
+    CallbackData &operator =(const CallbackData &other) = delete;
+
+    void *validDone() { void *result; return cbdataReferenceValidDone(data_, &result) ? result : nullptr; }
+
+private:
+    void *data_; ///< raw callback data, maybe invalid
+};
+
 #endif /* SQUID_CBDATA_H */
 
diff -u -r -N squid-4.0.20/src/cf.data.pre squid-4.0.21/src/cf.data.pre
--- squid-4.0.20/src/cf.data.pre	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/cf.data.pre	2017-07-02 20:41:18.000000000 +1200
@@ -1242,6 +1242,28 @@
 	  # adaptation_meta because it starts matching immediately after
 	  # the service has been selected for adaptation.
 
+	acl aclname transaction_initiator initiator ...
+	  # Matches transaction's initiator [fast]
+	  #
+	  # Supported initiators are:
+	  #  esi: matches transactions fetching ESI resources
+	  #  certificate-fetching: matches transactions fetching
+	  #     a missing intermediate TLS certificate
+	  #  cache-digest: matches transactions fetching Cache Digests
+	  #     from a cache_peer
+	  #  htcp: matches HTCP requests from peers
+	  #  icp: matches ICP requests to peers
+	  #  icmp: matches ICMP RTT database (NetDB) requests to peers
+	  #  asn: matches asns db requests
+	  #  internal: matches any of the above
+	  #  client: matches transactions containing an HTTP or FTP
+	  #     client request received at a Squid *_port
+	  #  all: matches any transaction, including internal transactions
+	  #     without a configurable initiator and hopefully rare
+	  #     transactions without a known-to-Squid initiator
+	  #
+	  # Multiple initiators are ORed.
+
 	acl aclname has component
 	  # matches a transaction "component" [fast]
 	  #
@@ -1311,17 +1333,47 @@
 	  #   SslBump2: After getting SSL Client Hello info.
 	  #   SslBump3: After getting SSL Server Hello info.
 
-	acl aclname ssl::server_name .foo.com ...
+	acl aclname ssl::server_name [option] .foo.com ...
 	  # matches server name obtained from various sources [fast]
 	  #
-	  # The server name is obtained during Ssl-Bump steps from such sources
-	  # as CONNECT request URI, client SNI, and SSL server certificate CN.
-	  # During each Ssl-Bump step, Squid may improve its understanding of a
-	  # "true server name". Unlike dstdomain, this ACL does not perform
-	  # DNS lookups.
-	  # The "none" name can be used to match transactions where Squid
+	  # The ACL computes server name(s) using such information sources as
+	  # CONNECT request URI, TLS client SNI, and TLS server certificate 
+	  # subject (CN and SubjectAltName). The computed server name(s) usually
+	  # change with each SslBump step, as more info becomes available:
+	  # * SNI is used as the server name instead of the request URI,
+	  # * subject name(s) from the server certificate (CN and
+	  #   SubjectAltName) are used as the server names instead of SNI.
+	  #
+	  # When the ACL computes multiple server names, matching any single
+	  # computed name is sufficient for the ACL to match.
+	  #
+	  # The "none" name can be used to match transactions where the ACL
 	  # could not compute the server name using any information source
-	  # already available at the ACL evaluation time.
+	  # that was both available and allowed to be used by the ACL options at
+	  # the ACL evaluation time.
+	  #
+	  # Unlike dstdomain, this ACL does not perform DNS lookups.
+	  #
+	  # An ACL option below may be used to restrict what information 
+	  # sources are used to extract the server names from:
+	  #
+	  # --client-requested
+	  #   The server name is SNI regardless of what the server says.
+	  # --server-provided
+	  #   The server name(s) are the certificate subject name(s), regardless
+	  #   of what the client has requested. If the server certificate is
+	  #   unavailable, then the name is "none".
+	  # --consensus
+	  #   The server name is either SNI (if SNI matches at least one of the
+	  #   certificate subject names) or "none" (otherwise). When the server
+	  #   certificate is unavailable, the consensus server name is SNI.
+	  #
+	  # Combining multiple options in one ACL is a fatal configuration
+	  # error.
+	  #
+	  # For all options: If no SNI is available, then the CONNECT request
+	  # target (a.k.a. URI) is used instead of SNI (for an intercepted
+	  # connection, this target is the destination IP address).
 
 	acl aclname ssl::server_name_regex [-i] \.foo\.com ...
 	  # regex matches server name obtained from various sources [fast]
@@ -4350,9 +4402,7 @@
 				In all other cases, a single dash ("-") is
 				logged.
 
-		ssl::>sni	SSL client SNI sent to Squid. Available only
-				after the peek, stare, or splice SSL bumping
-				actions.
+		ssl::>sni	SSL client SNI sent to Squid.
 
 		ssl::>cert_subject
 				The Subject field of the received client
diff -u -r -N squid-4.0.20/src/clients/Client.cc squid-4.0.21/src/clients/Client.cc
--- squid-4.0.20/src/clients/Client.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/clients/Client.cc	2017-07-02 20:41:18.000000000 +1200
@@ -539,7 +539,7 @@
         ACLFilledChecklist ch(acl, originalRequest(), NULL);
         ch.reply = const_cast<HttpReply*>(entry->getReply()); // ACLFilledChecklist API bug
         HTTPMSGLOCK(ch.reply);
-        if (ch.fastCheck() != ACCESS_ALLOWED) { // when in doubt, block
+        if (!ch.fastCheck().allowed()) { // when in doubt, block
             debugs(20, 3, "store_miss prohibits caching");
             return true;
         }
diff -u -r -N squid-4.0.20/src/clients/FtpClient.cc squid-4.0.21/src/clients/FtpClient.cc
--- squid-4.0.20/src/clients/FtpClient.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/clients/FtpClient.cc	2017-07-02 20:41:18.000000000 +1200
@@ -705,7 +705,7 @@
         bool doEpsv = true;
         if (Config.accessList.ftp_epsv) {
             ACLFilledChecklist checklist(Config.accessList.ftp_epsv, fwd->request, NULL);
-            doEpsv = (checklist.fastCheck() == ACCESS_ALLOWED);
+            doEpsv = checklist.fastCheck().allowed();
         }
         if (!doEpsv) {
             debugs(9, 5, "EPSV support manually disabled. Sending PASV for FTP Channel (" << ctrl.conn->remote <<")");
diff -u -r -N squid-4.0.20/src/clients/FtpRelay.cc squid-4.0.21/src/clients/FtpRelay.cc
--- squid-4.0.20/src/clients/FtpRelay.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/clients/FtpRelay.cc	2017-07-02 20:41:18.000000000 +1200
@@ -211,9 +211,10 @@
                 mgr->unpinConnection(false);
                 ctrl.close();
             } else {
-                mgr->pinConnection(ctrl.conn, fwd->request,
-                                   ctrl.conn->getPeer(),
-                                   fwd->request->flags.connectionAuth);
+                CallJobHere1(9, 4, mgr,
+                             ConnStateData,
+                             notePinnedConnectionBecameIdle,
+                             ConnStateData::PinnedIdleContext(ctrl.conn, fwd->request));
                 ctrl.forget();
             }
         }
diff -u -r -N squid-4.0.20/src/clients/Makefile.in squid-4.0.21/src/clients/Makefile.in
--- squid-4.0.20/src/clients/Makefile.in	2017-06-02 00:58:46.000000000 +1200
+++ squid-4.0.21/src/clients/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/client_side.cc squid-4.0.21/src/client_side.cc
--- squid-4.0.20/src/client_side.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/client_side.cc	2017-07-02 20:41:18.000000000 +1200
@@ -461,7 +461,7 @@
             statsCheck.reply = al->reply;
             HTTPMSGLOCK(statsCheck.reply);
         }
-        updatePerformanceCounters = (statsCheck.fastCheck() == ACCESS_ALLOWED);
+        updatePerformanceCounters = statsCheck.fastCheck().allowed();
     }
 
     if (updatePerformanceCounters) {
@@ -592,6 +592,7 @@
     clientdbEstablished(clientConnection->remote, -1);  /* decrement */
     pipeline.terminateAll(0);
 
+    // XXX: Closing pinned conn is too harsh: The Client may want to continue!
     unpinConnection(true);
 
     Server::swanSong(); // closes the client connection
@@ -1526,7 +1527,7 @@
             if (Config.ssl_client.cert_error) {
                 ACLFilledChecklist check(Config.ssl_client.cert_error, request, dash_str);
                 check.sslErrors = new Security::CertErrors(Security::CertError(SQUID_X509_V_ERR_DOMAIN_MISMATCH, srvCert));
-                allowDomainMismatch = (check.fastCheck() == ACCESS_ALLOWED);
+                allowDomainMismatch = check.fastCheck().allowed();
                 delete check.sslErrors;
                 check.sslErrors = NULL;
             }
@@ -1580,7 +1581,7 @@
         checklist.my_addr = conn->clientConnection->local;
         checklist.conn(conn);
         allow_t answer = checklist.fastCheck();
-        if (answer == ACCESS_ALLOWED && answer.kind == 1) {
+        if (answer.allowed() && answer.kind == 1) {
             debugs(33, 3, "Request will be tunneled to server");
             if (context) {
                 assert(conn->pipeline.front() == context); // XXX: still assumes HTTP/1 semantics
@@ -1633,11 +1634,10 @@
     // this entire function to remove them from the FTP code path. Connection
     // setup and body_pipe preparation blobs are needed for FTP.
 
-    request->clientConnectionManager = conn;
+    request->manager(conn, http->al);
 
     request->flags.accelerated = http->flags.accel;
     request->flags.sslBumped=conn->switchedToHttps();
-    request->flags.ignoreCc = conn->port->ignore_cc;
     // TODO: decouple http->flags.accel from request->flags.sslBumped
     request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
                               !conn->port->allow_direct : 0;
@@ -1650,25 +1650,6 @@
     }
 #endif
 
-    /** \par
-     * If transparent or interception mode is working clone the transparent and interception flags
-     * from the port settings to the request.
-     */
-    if (http->clientConnection != NULL) {
-        request->flags.intercepted = ((http->clientConnection->flags & COMM_INTERCEPTION) != 0);
-        request->flags.interceptTproxy = ((http->clientConnection->flags & COMM_TRANSPARENT) != 0 ) ;
-        static const bool proxyProtocolPort = (conn->port != NULL) ? conn->port->flags.proxySurrogate : false;
-        if (request->flags.interceptTproxy && !proxyProtocolPort) {
-            if (Config.accessList.spoof_client_ip) {
-                ACLFilledChecklist *checklist = clientAclChecklistCreate(Config.accessList.spoof_client_ip, http);
-                request->flags.spoofClientIp = (checklist->fastCheck() == ACCESS_ALLOWED);
-                delete checklist;
-            } else
-                request->flags.spoofClientIp = true;
-        } else
-            request->flags.spoofClientIp = false;
-    }
-
     if (internalCheck(request->url.path())) {
         if (internalHostnameIs(request->url.host()) && request->url.port() == getMyPort()) {
             debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true));
@@ -1685,14 +1666,6 @@
 
     request->flags.internal = http->flags.internal;
     setLogUri (http, urlCanonicalClean(request.getRaw()));
-    request->client_addr = conn->clientConnection->remote; // XXX: remove request->client_addr member.
-#if FOLLOW_X_FORWARDED_FOR
-    // indirect client gets stored here because it is an HTTP header result (from X-Forwarded-For:)
-    // not details about the TCP connection itself
-    request->indirect_client_addr = conn->clientConnection->remote;
-#endif /* FOLLOW_X_FORWARDED_FOR */
-    request->my_addr = conn->clientConnection->local;
-    request->myportname = conn->port->name;
 
     if (!isFtp) {
         // XXX: for non-HTTP messages instantiate a different HttpMsg child type
@@ -1703,10 +1676,6 @@
         request->http_ver.minor = http_ver.minor;
     }
 
-    // Link this HttpRequest to ConnStateData relatively early so the following complex handling can use it
-    // TODO: this effectively obsoletes a lot of conn->FOO copying. That needs cleaning up later.
-    request->clientConnectionManager = conn;
-
     if (request->header.chunked()) {
         chunked = true;
     } else if (request->header.has(Http::HdrType::TRANSFER_ENCODING)) {
@@ -1857,7 +1826,7 @@
     ch.my_addr = clientConnection->local;
     ch.conn(this);
 
-    if (ch.fastCheck() != ACCESS_ALLOWED)
+    if (!ch.fastCheck().allowed())
         return proxyProtocolError("PROXY client not permitted by ACLs");
 
     return true;
@@ -2129,6 +2098,13 @@
     // On errors, bodyPipe may become nil, but readMore will be cleared
     while (!inBuf.isEmpty() && !bodyPipe && flags.readMore) {
 
+        // Prohibit concurrent requests when using a pinned to-server connection
+        // because our Client classes do not support request pipelining.
+        if (pinning.pinned && !pinning.readHandler) {
+            debugs(33, 3, clientConnection << " waits for busy " << pinning.serverConnection);
+            break;
+        }
+
         /* Limit the number of concurrent requests */
         if (concurrentRequestQueueFilled())
             break;
@@ -2477,7 +2453,7 @@
         ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
         identChecklist.src_addr = clientConnection->remote;
         identChecklist.my_addr = clientConnection->local;
-        if (identChecklist.fastCheck() == ACCESS_ALLOWED)
+        if (identChecklist.fastCheck().allowed())
             Ident::Start(clientConnection, clientIdentDone, this);
     }
 #endif
@@ -2505,7 +2481,7 @@
             if (pools[pool].access) {
                 ch.changeAcl(pools[pool].access);
                 allow_t answer = ch.fastCheck();
-                if (answer == ACCESS_ALLOWED) {
+                if (answer.allowed()) {
 
                     /*  request client information from db after we did all checks
                         this will save hash lookup if client failed checks */
@@ -2737,7 +2713,7 @@
     if (!connState->isOpen())
         return;
 
-    if (answer == ACCESS_ALLOWED) {
+    if (answer.allowed()) {
         debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
         connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
     } else {
@@ -2793,9 +2769,11 @@
             return;
         }
 
+        MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient);
+        mx->tcpClient = clientConnection;
         // Create a fake HTTP request for ssl_bump ACL check,
         // using tproxy/intercept provided destination IP and port.
-        HttpRequest *request = new HttpRequest();
+        HttpRequest *request = new HttpRequest(mx);
         static char ip[MAX_IPSTRLEN];
         assert(clientConnection->flags & (COMM_TRANSPARENT | COMM_INTERCEPTION));
         request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
@@ -2891,7 +2869,7 @@
                     (ca->alg == Ssl::algSetValidBefore && certProperties.setValidBefore) )
                 continue;
 
-            if (ca->aclList && checklist.fastCheck(ca->aclList) == ACCESS_ALLOWED) {
+            if (ca->aclList && checklist.fastCheck(ca->aclList).allowed()) {
                 const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
                 const char *param = ca->param;
 
@@ -2914,7 +2892,7 @@
 
         certProperties.signAlgorithm = Ssl::algSignEnd;
         for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != NULL; sg = sg->next) {
-            if (sg->aclList && checklist.fastCheck(sg->aclList) == ACCESS_ALLOWED) {
+            if (sg->aclList && checklist.fastCheck(sg->aclList).allowed()) {
                 certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
                 break;
             }
@@ -3157,8 +3135,7 @@
     clientConnection->tlsNegotiations()->retrieveParsedInfo(details);
     if (details && !details->serverName.isEmpty()) {
         resetSslCommonName(details->serverName.c_str());
-        if (sslServerBump)
-            sslServerBump->clientSni = details->serverName;
+        tlsClientSni_ = details->serverName;
     }
 
     // We should disable read/write handlers
@@ -3200,7 +3177,7 @@
     debugs(33, 5, "Answer: " << answer << " kind:" << answer.kind);
     assert(connState->serverBump());
     Ssl::BumpMode bumpAction;
-    if (answer == ACCESS_ALLOWED) {
+    if (answer.allowed()) {
         bumpAction = (Ssl::BumpMode)answer.kind;
     } else
         bumpAction = Ssl::bumpSplice;
@@ -3329,22 +3306,18 @@
 }
 
 void
-ConnStateData::httpsPeeked(Comm::ConnectionPointer serverConnection)
+ConnStateData::httpsPeeked(PinnedIdleContext pic)
 {
     Must(sslServerBump != NULL);
+    Must(sslServerBump->request == pic.request);
+    Must(pipeline.empty() || pipeline.front()->http == nullptr || pipeline.front()->http->request == pic.request.getRaw());
 
-    if (Comm::IsConnOpen(serverConnection)) {
-        pinConnection(serverConnection, NULL, NULL, false);
-
+    if (Comm::IsConnOpen(pic.connection)) {
+        notePinnedConnectionBecameIdle(pic);
         debugs(33, 5, HERE << "bumped HTTPS server: " << sslConnectHostOrIp);
-    } else {
+    } else
         debugs(33, 5, HERE << "Error while bumping: " << sslConnectHostOrIp);
 
-        //  copy error detail from bump-server-first request to CONNECT request
-        if (!pipeline.empty() && pipeline.front()->http != nullptr && pipeline.front()->http->request)
-            pipeline.front()->http->request->detailError(sslServerBump->request->errType, sslServerBump->request->errDetail);
-    }
-
     getSslContextStart();
 }
 
@@ -3391,8 +3364,8 @@
     const unsigned short connectPort = clientConnection->local.port();
 
 #if USE_OPENSSL
-    if (serverBump() && !serverBump()->clientSni.isEmpty())
-        connectHost.assign(serverBump()->clientSni);
+    if (!tlsClientSni_.isEmpty())
+        connectHost.assign(tlsClientSni_);
     else
 #endif
     {
@@ -3436,9 +3409,11 @@
 
     stream->registerWithConn();
 
+    MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient);
+    mx->tcpClient = clientConnection;
     // Setup Http::Request object. Maybe should be replaced by a call to (modified)
     // clientProcessRequest
-    HttpRequest::Pointer request = new HttpRequest();
+    HttpRequest::Pointer request = new HttpRequest(mx);
     AnyP::ProtocolType proto = (method == Http::METHOD_NONE) ? AnyP::PROTO_AUTHORITY_FORM : AnyP::PROTO_HTTP;
     request->url.setScheme(proto, nullptr);
     request->method = method;
@@ -3447,23 +3422,16 @@
     http->request = request.getRaw();
     HTTPMSGLOCK(http->request);
 
-    request->clientConnectionManager = this;
+    request->manager(this, http->al);
 
     if (proto == AnyP::PROTO_HTTP)
         request->header.putStr(Http::HOST, useHost.c_str());
-    request->flags.intercepted = ((clientConnection->flags & COMM_INTERCEPTION) != 0);
-    request->flags.interceptTproxy = ((clientConnection->flags & COMM_TRANSPARENT) != 0 );
+
     request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? HttpMsg::srcHttps : HttpMsg::srcHttp);
 #if USE_AUTH
     if (getAuth())
         request->auth_user_request = getAuth();
 #endif
-    request->client_addr = clientConnection->remote;
-#if FOLLOW_X_FORWARDED_FOR
-    request->indirect_client_addr = clientConnection->remote;
-#endif /* FOLLOW_X_FORWARDED_FOR */
-    request->my_addr = clientConnection->local;
-    request->myportname = port->name;
 
     inBuf = payload;
     flags.readMore = false;
@@ -3891,19 +3859,35 @@
 }
 
 void
-ConnStateData::pinConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth, bool monitor)
+ConnStateData::pinBusyConnection(const Comm::ConnectionPointer &pinServer, const HttpRequest::Pointer &request)
 {
-    if (!Comm::IsConnOpen(pinning.serverConnection) ||
-            pinning.serverConnection->fd != pinServer->fd)
-        pinNewConnection(pinServer, request, aPeer, auth);
+    pinConnection(pinServer, *request);
+}
 
-    if (monitor)
-        startPinnedConnectionMonitoring();
+void
+ConnStateData::notePinnedConnectionBecameIdle(PinnedIdleContext pic)
+{
+    Must(pic.connection);
+    Must(pic.request);
+    pinConnection(pic.connection, *pic.request);
+
+    // monitor pinned server connection for remote-end closures.
+    startPinnedConnectionMonitoring();
+
+    if (pipeline.empty())
+        kick(); // in case clientParseRequests() was blocked by a busy pic.connection
 }
 
+/// Forward future client requests using the given server connection.
 void
-ConnStateData::pinNewConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth)
+ConnStateData::pinConnection(const Comm::ConnectionPointer &pinServer, const HttpRequest &request)
 {
+    if (Comm::IsConnOpen(pinning.serverConnection) &&
+            pinning.serverConnection->fd == pinServer->fd) {
+        debugs(33, 3, "already pinned" << pinServer);
+        return;
+    }
+
     unpinConnection(true); // closes pinned connection, if any, and resets fields
 
     pinning.serverConnection = pinServer;
@@ -3912,23 +3896,18 @@
 
     Must(pinning.serverConnection != NULL);
 
-    // when pinning an SSL bumped connection, the request may be NULL
     const char *pinnedHost = "[unknown]";
-    if (request) {
-        pinning.host = xstrdup(request->url.host());
-        pinning.port = request->url.port();
-        pinnedHost = pinning.host;
-    } else {
-        pinning.port = pinServer->remote.port();
-    }
+    pinning.host = xstrdup(request.url.host());
+    pinning.port = request.url.port();
+    pinnedHost = pinning.host;
     pinning.pinned = true;
-    if (aPeer)
+    if (CachePeer *aPeer = pinServer->getPeer())
         pinning.peer = cbdataReference(aPeer);
-    pinning.auth = auth;
+    pinning.auth = request.flags.connectionAuth;
     char stmp[MAX_IPSTRLEN];
     char desc[FD_DESC_SZ];
     snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
-             (auth || !aPeer) ? pinnedHost : aPeer->name,
+             (pinning.auth || !pinning.peer) ? pinnedHost : pinning.peer->name,
              clientConnection->remote.toUrl(stmp,MAX_IPSTRLEN),
              clientConnection->fd);
     fd_note(pinning.serverConnection->fd, desc);
@@ -4127,6 +4106,7 @@
     /* Create a temporary ClientHttpRequest object. Its destructor will log. */
     ClientHttpRequest http(this);
     http.req_sz = inBuf.length();
+    // XXX: Or we died while waiting for the pinned connection to become idle.
     char const *uri = "error:transaction-end-before-headers";
     http.uri = xstrdup(uri);
     setLogUri(&http, uri);
@@ -4144,3 +4124,9 @@
            ;
 }
 
+std::ostream &
+operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic)
+{
+    return os << pic.connection << ", request=" << pic.request;
+}
+
diff -u -r -N squid-4.0.20/src/client_side.h squid-4.0.21/src/client_side.h
--- squid-4.0.20/src/client_side.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/client_side.h	2017-07-02 20:41:18.000000000 +1200
@@ -28,9 +28,14 @@
 #include "ssl/support.h"
 #endif
 
+#include <iosfwd>
+
 class ClientHttpRequest;
 class HttpHdrRangeSpec;
 
+class MasterXaction;
+typedef RefCount<MasterXaction> MasterXactionPointer;
+
 #if USE_OPENSSL
 namespace Ssl
 {
@@ -66,7 +71,7 @@
 {
 
 public:
-    explicit ConnStateData(const MasterXaction::Pointer &xact);
+    explicit ConnStateData(const MasterXactionPointer &xact);
     virtual ~ConnStateData();
 
     /* ::Server API */
@@ -155,9 +160,21 @@
 
     bool handleRequestBodyData();
 
-    /// Forward future client requests using the given server connection.
-    /// Optionally, monitor pinned server connection for remote-end closures.
-    void pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, CachePeer *peer, bool auth, bool monitor = true);
+    /// parameters for the async notePinnedConnectionBecameIdle() call
+    class PinnedIdleContext
+    {
+    public:
+        PinnedIdleContext(const Comm::ConnectionPointer &conn, const HttpRequest::Pointer &req): connection(conn), request(req) {}
+
+        Comm::ConnectionPointer connection; ///< to-server connection to be pinned
+        HttpRequest::Pointer request; ///< to-server request that initiated serverConnection
+    };
+
+    /// Called when a pinned connection becomes available for forwarding the next request.
+    void notePinnedConnectionBecameIdle(PinnedIdleContext pic);
+    /// Forward future client requests using the given to-server connection.
+    /// The connection is still being used by the current client request.
+    void pinBusyConnection(const Comm::ConnectionPointer &pinServerConn, const HttpRequest::Pointer &request);
     /// Undo pinConnection() and, optionally, close the pinned connection.
     void unpinConnection(const bool andClose);
     /// Returns validated pinnned server connection (and stops its monitoring).
@@ -211,7 +228,7 @@
     /// generated
     void doPeekAndSpliceStep();
     /// called by FwdState when it is done bumping the server
-    void httpsPeeked(Comm::ConnectionPointer serverConnection);
+    void httpsPeeked(PinnedIdleContext pic);
 
     /// Splice a bumped client connection on peek-and-splice mode
     bool splice();
@@ -241,6 +258,7 @@
     }
     const SBuf &sslCommonName() const {return sslCommonName_;}
     void resetSslCommonName(const char *name) {sslCommonName_ = name;}
+    const SBuf &tlsClientSni() const { return tlsClientSni_; }
     /// Fill the certAdaptParams with the required data for certificate adaptation
     /// and create the key for storing/retrieve the certificate to/from the cache
     void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
@@ -342,7 +360,7 @@
     void clientAfterReadingRequests();
     bool concurrentRequestQueueFilled() const;
 
-    void pinNewConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth);
+    void pinConnection(const Comm::ConnectionPointer &pinServerConn, const HttpRequest &request);
 
     /* PROXY protocol functionality */
     bool proxyProtocolValidateClient();
@@ -369,6 +387,9 @@
     /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
     String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
     SBuf sslCommonName_; ///< CN name for SSL certificate generation
+
+    /// TLS client delivered SNI value. Empty string if none has been received.
+    SBuf tlsClientSni_;
     String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
 
     /// HTTPS server cert. fetching state for bump-ssl-server-first
@@ -418,5 +439,7 @@
 void clientProcessRequest(ConnStateData *, const Http1::RequestParserPointer &, Http::Stream *);
 void clientPostHttpsAccept(ConnStateData *);
 
+std::ostream &operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic);
+
 #endif /* SQUID_CLIENTSIDE_H */
 
diff -u -r -N squid-4.0.20/src/client_side_reply.cc squid-4.0.21/src/client_side_reply.cc
--- squid-4.0.20/src/client_side_reply.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/client_side_reply.cc	2017-07-02 20:41:18.000000000 +1200
@@ -89,6 +89,7 @@
     reply(NULL),
     old_entry(NULL),
     old_sc(NULL),
+    old_lastmod(-1),
     deleting(false),
     collapsedRevalidation(crNone)
 {
@@ -204,6 +205,8 @@
     debugs(88, 3, "clientReplyContext::saveState: saving store context");
     old_entry = http->storeEntry();
     old_sc = sc;
+    old_lastmod = http->request->lastmod;
+    old_etag = http->request->etag;
     old_reqsize = reqsize;
     tempBuffer.offset = reqofs;
     /* Prevent accessing the now saved entries */
@@ -223,9 +226,13 @@
     sc = old_sc;
     reqsize = old_reqsize;
     reqofs = tempBuffer.offset;
+    http->request->lastmod = old_lastmod;
+    http->request->etag = old_etag;
     /* Prevent accessed the old saved entries */
     old_entry = NULL;
     old_sc = NULL;
+    old_lastmod = -1;
+    old_etag.clean();
     old_reqsize = 0;
     tempBuffer.offset = 0;
 }
@@ -415,8 +422,8 @@
     if (result.flags.error && !EBIT_TEST(http->storeEntry()->flags, ENTRY_ABORTED))
         return;
 
-    if (collapsedRevalidation == crSlave && EBIT_TEST(http->storeEntry()->flags, KEY_PRIVATE)) {
-        debugs(88, 3, "CF slave hit private " << *http->storeEntry() << ". MISS");
+    if (collapsedRevalidation == crSlave && !http->storeEntry()->mayStartHitting()) {
+        debugs(88, 3, "CF slave hit private non-shareable " << *http->storeEntry() << ". MISS");
         // restore context to meet processMiss() expectations
         restoreState();
         http->logType = LOG_TCP_MISS;
@@ -548,7 +555,7 @@
     // The previously identified hit suddenly became unsharable!
     // This is common for collapsed forwarding slaves but might also
     // happen to regular hits because we are called asynchronously.
-    if (EBIT_TEST(e->flags, KEY_PRIVATE)) {
+    if (!e->mayStartHitting()) {
         debugs(88, 3, "unsharable " << *e << ". MISS");
         http->logType = LOG_TCP_MISS;
         processMiss();
@@ -746,10 +753,13 @@
         return;
     }
 
+    Comm::ConnectionPointer conn = http->getConn() != nullptr ? http->getConn()->clientConnection : nullptr;
     /// Deny loops
     if (r->flags.loopDetected) {
         http->al->http.code = Http::scForbidden;
-        err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, NULL, http->getConn()->clientConnection->remote, http->request);
+        Ip::Address tmp_noaddr;
+        tmp_noaddr.setNoAddr();
+        err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, nullptr, conn ? conn->remote : tmp_noaddr, http->request);
         createStoreEntry(r->method, RequestFlags());
         errorAppendEntry(http->storeEntry(), err);
         triggerInitialStoreRead();
@@ -772,7 +782,6 @@
         assert(r->clientConnectionManager == http->getConn());
 
         /** Start forwarding to get the new object from network */
-        Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConnection : NULL;
         FwdState::Start(conn, http->storeEntry(), r, http->al);
     }
 }
@@ -788,8 +797,11 @@
 {
     debugs(88, 4, http->request->method << ' ' << http->uri);
     http->al->http.code = Http::scGatewayTimeout;
+    Ip::Address tmp_noaddr;
+    tmp_noaddr.setNoAddr();
     ErrorState *err = clientBuildError(ERR_ONLY_IF_CACHED_MISS, Http::scGatewayTimeout, NULL,
-                                       http->getConn()->clientConnection->remote, http->request);
+                                       http->getConn() ? http->getConn()->clientConnection->remote : tmp_noaddr,
+                                       http->request);
     removeClientStoreReference(&sc, http);
     startError(err);
 }
@@ -861,7 +873,7 @@
         std::unique_ptr<ACLFilledChecklist> chl(clientAclChecklistCreate(Config.accessList.sendHit, http));
         chl->reply = const_cast<HttpReply*>(rep); // ACLChecklist API bug
         HTTPMSGLOCK(chl->reply);
-        return chl->fastCheck() != ACCESS_ALLOWED; // when in doubt, block
+        return !chl->fastCheck().allowed(); // when in doubt, block
     }
 
     // This does not happen, I hope, because we are called from CacheHit, which
@@ -967,8 +979,11 @@
 
     if (EBIT_TEST(entry->flags, ENTRY_SPECIAL)) {
         http->logType = LOG_TCP_DENIED;
+        Ip::Address tmp_noaddr;
+        tmp_noaddr.setNoAddr(); // TODO: make a global const
         ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, NULL,
-                                           http->getConn()->clientConnection->remote, http->request);
+                                           http->getConn() ? http->getConn()->clientConnection->remote : tmp_noaddr,
+                                           http->request);
         startError(err);
         return; // XXX: leaking unused entry if some store does not keep it
     }
@@ -1005,7 +1020,10 @@
 
     if (!Config2.onoff.enable_purge) {
         http->logType = LOG_TCP_DENIED;
-        ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, NULL, http->getConn()->clientConnection->remote, http->request);
+        Ip::Address tmp_noaddr;
+        tmp_noaddr.setNoAddr();
+        ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, NULL,
+                                           http->getConn() ? http->getConn()->clientConnection->remote : tmp_noaddr, http->request);
         startError(err);
         return;
     }
@@ -1224,7 +1242,8 @@
 #if SIZEOF_INT64_T == 4
     if (http->out.size > 0x7FFF0000) {
         debugs(88, DBG_IMPORTANT, "WARNING: closing FD " << fd << " to prevent out.size counter overflow");
-        debugs(88, DBG_IMPORTANT, "\tclient " << http->getConn()->peer);
+        if (http->getConn())
+            debugs(88, DBG_IMPORTANT, "\tclient " << http->getConn()->peer);
         debugs(88, DBG_IMPORTANT, "\treceived " << http->out.size << " bytes");
         debugs(88, DBG_IMPORTANT, "\tURI " << http->log_uri);
         return 1;
@@ -1232,7 +1251,8 @@
 
     if (http->out.offset > 0x7FFF0000) {
         debugs(88, DBG_IMPORTANT, "WARNING: closing FD " << fd < " to prevent out.offset counter overflow");
-        debugs(88, DBG_IMPORTANT, "\tclient " << http->getConn()->peer);
+        if (http->getConn())
+            debugs(88, DBG_IMPORTANT, "\tclient " << http->getConn()->peer);
         debugs(88, DBG_IMPORTANT, "\treceived " << http->out.size << " bytes, offset " << http->out.offset);
         debugs(88, DBG_IMPORTANT, "\tURI " << http->log_uri);
         return 1;
@@ -1852,12 +1872,14 @@
         assert(http->out.size == 0);
         assert(http->out.offset == 0);
 
-        if (Ip::Qos::TheConfig.isHitTosActive()) {
-            Ip::Qos::doTosLocalHit(http->getConn()->clientConnection);
-        }
+        if (ConnStateData *conn = http->getConn()) {
+            if (Ip::Qos::TheConfig.isHitTosActive()) {
+                Ip::Qos::doTosLocalHit(conn->clientConnection);
+            }
 
-        if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
-            Ip::Qos::doNfmarkLocalHit(http->getConn()->clientConnection);
+            if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
+                Ip::Qos::doNfmarkLocalHit(conn->clientConnection);
+            }
         }
 
         localTempBuffer.offset = reqofs;
@@ -1971,9 +1993,11 @@
 clientReplyContext::sendPreconditionFailedError()
 {
     http->logType = LOG_TCP_HIT;
+    Ip::Address tmp_noaddr;
+    tmp_noaddr.setNoAddr();
     ErrorState *const err =
         clientBuildError(ERR_PRECONDITION_FAILED, Http::scPreconditionFailed,
-                         NULL, http->getConn()->clientConnection->remote, http->request);
+                         NULL, http->getConn() ? http->getConn()->clientConnection->remote : tmp_noaddr, http->request);
     removeClientStoreReference(&sc, http);
     HTTPMSGUNLOCK(reply);
     startError(err);
@@ -2072,7 +2096,7 @@
            << ' ' << http->uri << " is " << accessAllowed << ", because it matched "
            << (AclMatchedName ? AclMatchedName : "NO ACL's"));
 
-    if (accessAllowed != ACCESS_ALLOWED) {
+    if (!accessAllowed.allowed()) {
         ErrorState *err;
         err_type page_id;
         page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName, 1);
@@ -2272,7 +2296,8 @@
      */
 
     if (http->request == NULL) {
-        http->request = new HttpRequest(m, AnyP::PROTO_NONE, "http", null_string);
+        const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient);
+        http->request = new HttpRequest(m, AnyP::PROTO_NONE, "http", null_string, mx);
         HTTPMSGLOCK(http->request);
     }
 
diff -u -r -N squid-4.0.20/src/client_side_reply.h squid-4.0.21/src/client_side_reply.h
--- squid-4.0.20/src/client_side_reply.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/client_side_reply.h	2017-07-02 20:41:18.000000000 +1200
@@ -131,7 +131,11 @@
     void sendNotModifiedOrPreconditionFailedError();
 
     StoreEntry *old_entry;
-    store_client *old_sc;   /* ... for entry to be validated */
+    /* ... for entry to be validated */
+    store_client *old_sc;
+    time_t old_lastmod;
+    String old_etag;
+
     bool deleting;
 
     typedef enum {
diff -u -r -N squid-4.0.20/src/client_side_request.cc squid-4.0.21/src/client_side_request.cc
--- squid-4.0.20/src/client_side_request.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/client_side_request.cc	2017-07-02 20:41:18.000000000 +1200
@@ -320,7 +320,7 @@
 int
 clientBeginRequest(const HttpRequestMethod& method, char const *url, CSCB * streamcallback,
                    CSD * streamdetach, ClientStreamData streamdata, HttpHeader const *header,
-                   char *tailbuf, size_t taillen)
+                   char *tailbuf, size_t taillen, const MasterXaction::Pointer &mx)
 {
     size_t url_sz;
     ClientHttpRequest *http = new ClientHttpRequest(NULL);
@@ -346,15 +346,15 @@
     http->uri = (char *)xcalloc(url_sz, 1);
     strcpy(http->uri, url);
 
-    if ((request = HttpRequest::CreateFromUrl(http->uri, method)) == NULL) {
+    if ((request = HttpRequest::FromUrl(http->uri, mx, method)) == NULL) {
         debugs(85, 5, "Invalid URL: " << http->uri);
         return -1;
     }
 
     /*
-     * now update the headers in request with our supplied headers. urlParse
-     * should return a blank header set, but we use Update to be sure of
-     * correctness.
+     * now update the headers in request with our supplied headers.
+     * HttpRequest::FromUrl() should return a blank header set, but
+     * we use Update to be sure of correctness.
      */
     if (header)
         request->header.update(header);
@@ -368,8 +368,6 @@
      */
     request->flags.accelerated = http->flags.accel;
 
-    request->flags.internalClient = true;
-
     /* this is an internally created
      * request, not subject to acceleration
      * target overrides */
@@ -451,13 +449,7 @@
     ClientHttpRequest *http = calloutContext->http;
     HttpRequest *request = http->request;
 
-    /*
-     * answer should be be ACCESS_ALLOWED or ACCESS_DENIED if we are
-     * called as a result of ACL checks, or -1 if we are called when
-     * there's nothing left to do.
-     */
-    if (answer == ACCESS_ALLOWED &&
-            request->x_forwarded_for_iterator.size () != 0) {
+    if (answer.allowed() && request->x_forwarded_for_iterator.size() != 0) {
 
         /*
          * Remove the last comma-delimited element from the
@@ -499,8 +491,7 @@
             calloutContext->acl_checklist->nonBlockingCheck(clientFollowXForwardedForCheck, data);
             return;
         }
-    } /*if (answer == ACCESS_ALLOWED &&
-        request->x_forwarded_for_iterator.size () != 0)*/
+    }
 
     /* clean up, and pass control to clientAccessCheck */
     if (Config.onoff.log_uses_indirect_client) {
@@ -515,7 +506,7 @@
     request->x_forwarded_for_iterator.clean();
     request->flags.done_follow_x_forwarded_for = true;
 
-    if (answer != ACCESS_ALLOWED && answer != ACCESS_DENIED) {
+    if (!answer.someRuleMatched()) {
         debugs(28, DBG_CRITICAL, "ERROR: Processing X-Forwarded-For. Stopping at IP address: " << request->indirect_client_addr );
     }
 
@@ -771,7 +762,7 @@
         proxy_auth_msg = http->request->auth_user_request->denyMessage("<null>");
 #endif
 
-    if (answer != ACCESS_ALLOWED) {
+    if (!answer.allowed()) {
         // auth has a grace period where credentials can be expired but okay not to challenge.
 
         /* Send an auth challenge or error */
@@ -882,7 +873,7 @@
     ClientHttpRequest *http = context->http;
     context->acl_checklist = NULL;
 
-    if (answer == ACCESS_ALLOWED)
+    if (answer.allowed())
         redirectStart(http, clientRedirectDoneWrapper, context);
     else {
         Helper::Reply const nilReply(Helper::Error);
@@ -913,7 +904,7 @@
     ClientHttpRequest *http = context->http;
     context->acl_checklist = NULL;
 
-    if (answer == ACCESS_ALLOWED)
+    if (answer.allowed())
         storeIdStart(http, clientStoreIdDoneWrapper, context);
     else {
         debugs(85, 3, "access denied expected ERR reply handling: " << answer);
@@ -1273,10 +1264,10 @@
 
             // prevent broken helpers causing too much damage. If old URL == new URL skip the re-write.
             if (urlNote != NULL && strcmp(urlNote, http->uri)) {
-                // XXX: validate the URL properly *without* generating a whole new request object right here.
-                // XXX: the clone() should be done only AFTER we know the new URL is valid.
-                HttpRequest *new_request = old_request->clone();
-                if (urlParse(old_request->method, const_cast<char*>(urlNote), new_request)) {
+                URL tmpUrl;
+                if (tmpUrl.parse(old_request->method, const_cast<char*>(urlNote))) {
+                    HttpRequest *new_request = old_request->clone();
+                    new_request->url = tmpUrl;
                     debugs(61, 2, "URL-rewriter diverts URL from " << old_request->effectiveRequestUri() << " to " << new_request->effectiveRequestUri());
 
                     // update the new request to flag the re-writing was done on it
@@ -1298,7 +1289,6 @@
                 } else {
                     debugs(85, DBG_CRITICAL, "ERROR: URL-rewrite produces invalid request: " <<
                            old_request->method << " " << urlNote << " " << old_request->http_ver);
-                    delete new_request;
                 }
             }
         }
@@ -1399,7 +1389,7 @@
 ClientRequestContext::checkNoCacheDone(const allow_t &answer)
 {
     acl_checklist = NULL;
-    if (answer == ACCESS_DENIED) {
+    if (answer.denied()) {
         http->request->flags.noCache = true; // dont read reply from cache
         http->request->flags.cachable = false; // dont store reply into cache
     }
@@ -1498,7 +1488,7 @@
     if (!httpStateIsValid())
         return;
 
-    const Ssl::BumpMode bumpMode = answer == ACCESS_ALLOWED ?
+    const Ssl::BumpMode bumpMode = answer.allowed() ?
                                    static_cast<Ssl::BumpMode>(answer.kind) : Ssl::bumpSplice;
     http->sslBumpNeed(bumpMode); // for processRequest() to bump if needed
     http->al->ssl.bumpMode = bumpMode; // for logging
diff -u -r -N squid-4.0.20/src/client_side_request.h squid-4.0.21/src/client_side_request.h
--- squid-4.0.20/src/client_side_request.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/client_side_request.h	2017-07-02 20:41:18.000000000 +1200
@@ -13,6 +13,7 @@
 #include "acl/forward.h"
 #include "client_side.h"
 #include "clientStream.h"
+#include "http/forward.h"
 #include "HttpHeaderRange.h"
 #include "LogTags.h"
 
@@ -27,7 +28,7 @@
 class MemObject;
 
 /* client_side_request.c - client side request related routines (pure logic) */
-int clientBeginRequest(const HttpRequestMethod&, char const *, CSCB *, CSD *, ClientStreamData, HttpHeader const *, char *, size_t);
+int clientBeginRequest(const HttpRequestMethod&, char const *, CSCB *, CSD *, ClientStreamData, HttpHeader const *, char *, size_t, const MasterXactionPointer &);
 
 class ClientHttpRequest
 #if USE_ADAPTATION
diff -u -r -N squid-4.0.20/src/comm/Makefile.in squid-4.0.21/src/comm/Makefile.in
--- squid-4.0.20/src/comm/Makefile.in	2017-06-02 00:58:52.000000000 +1200
+++ squid-4.0.21/src/comm/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/comm/TcpAcceptor.cc squid-4.0.21/src/comm/TcpAcceptor.cc
--- squid-4.0.20/src/comm/TcpAcceptor.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/comm/TcpAcceptor.cc	2017-07-02 20:41:18.000000000 +1200
@@ -328,7 +328,7 @@
     if (theCallSub != NULL) {
         AsyncCall::Pointer call = theCallSub->callback();
         CommAcceptCbParams &params = GetCommParams<CommAcceptCbParams>(call);
-        params.xaction = new MasterXaction;
+        params.xaction = new MasterXaction(XactionInitiator::initClient);
         params.xaction->squidPort = listenPort_;
         params.fd = conn->fd;
         params.conn = params.xaction->tcpClient = newConnDetails;
diff -u -r -N squid-4.0.20/src/defines.h squid-4.0.21/src/defines.h
--- squid-4.0.20/src/defines.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/defines.h	2017-07-02 20:41:18.000000000 +1200
@@ -93,8 +93,6 @@
 
 #define NTLM_CHALLENGE_SZ 300
 
-#define  CONNECT_PORT        443
-
 #define current_stacksize(stack) ((stack)->top - (stack)->base)
 
 /* logfile status */
diff -u -r -N squid-4.0.20/src/DelayId.cc squid-4.0.21/src/DelayId.cc
--- squid-4.0.20/src/DelayId.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/DelayId.cc	2017-07-02 20:41:18.000000000 +1200
@@ -101,7 +101,7 @@
         if (http->getConn() != NULL)
             ch.conn(http->getConn());
 
-        if (DelayPools::delay_data[pool].theComposite().getRaw() && ch.fastCheck() == ACCESS_ALLOWED) {
+        if (DelayPools::delay_data[pool].theComposite().getRaw() && ch.fastCheck().allowed()) {
 
             DelayId result (pool + 1);
             CompositePoolNode::CompositeSelectionDetails details;
diff -u -r -N squid-4.0.20/src/DiskIO/AIO/Makefile.in squid-4.0.21/src/DiskIO/AIO/Makefile.in
--- squid-4.0.20/src/DiskIO/AIO/Makefile.in	2017-06-02 00:53:26.000000000 +1200
+++ squid-4.0.21/src/DiskIO/AIO/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/DiskIO/Blocking/Makefile.in squid-4.0.21/src/DiskIO/Blocking/Makefile.in
--- squid-4.0.20/src/DiskIO/Blocking/Makefile.in	2017-06-02 00:53:29.000000000 +1200
+++ squid-4.0.21/src/DiskIO/Blocking/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/DiskIO/DiskDaemon/Makefile.in squid-4.0.21/src/DiskIO/DiskDaemon/Makefile.in
--- squid-4.0.20/src/DiskIO/DiskDaemon/Makefile.in	2017-06-02 00:53:34.000000000 +1200
+++ squid-4.0.21/src/DiskIO/DiskDaemon/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/DiskIO/DiskThreads/Makefile.in squid-4.0.21/src/DiskIO/DiskThreads/Makefile.in
--- squid-4.0.20/src/DiskIO/DiskThreads/Makefile.in	2017-06-02 00:53:43.000000000 +1200
+++ squid-4.0.21/src/DiskIO/DiskThreads/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/DiskIO/IpcIo/Makefile.in squid-4.0.21/src/DiskIO/IpcIo/Makefile.in
--- squid-4.0.20/src/DiskIO/IpcIo/Makefile.in	2017-06-02 00:53:52.000000000 +1200
+++ squid-4.0.21/src/DiskIO/IpcIo/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/DiskIO/Makefile.in squid-4.0.21/src/DiskIO/Makefile.in
--- squid-4.0.20/src/DiskIO/Makefile.in	2017-06-02 00:53:57.000000000 +1200
+++ squid-4.0.21/src/DiskIO/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/DiskIO/Mmapped/Makefile.in squid-4.0.21/src/DiskIO/Mmapped/Makefile.in
--- squid-4.0.20/src/DiskIO/Mmapped/Makefile.in	2017-06-02 00:54:02.000000000 +1200
+++ squid-4.0.21/src/DiskIO/Mmapped/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/dns/Makefile.in squid-4.0.21/src/dns/Makefile.in
--- squid-4.0.20/src/dns/Makefile.in	2017-06-02 00:58:58.000000000 +1200
+++ squid-4.0.21/src/dns/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/Downloader.cc squid-4.0.21/src/Downloader.cc
--- squid-4.0.20/src/Downloader.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/Downloader.cc	2017-07-02 20:41:18.000000000 +1200
@@ -63,11 +63,12 @@
     os << " Http Status:" << status << Raw("body data", object.rawContent(), 64).hex();
 }
 
-Downloader::Downloader(SBuf &url, AsyncCall::Pointer &aCallback, unsigned int level):
+Downloader::Downloader(SBuf &url, AsyncCall::Pointer &aCallback, const XactionInitiator initiator, unsigned int level):
     AsyncJob("Downloader"),
     url_(url),
     callback_(aCallback),
-    level_(level)
+    level_(level),
+    initiator_(initiator)
 {
 }
 
@@ -128,7 +129,8 @@
     const HttpRequestMethod method = Http::METHOD_GET;
 
     char *uri = xstrdup(url_.c_str());
-    HttpRequest *const request = HttpRequest::CreateFromUrl(uri, method);
+    const MasterXaction::Pointer mx = new MasterXaction(initiator_);
+    HttpRequest *const request = HttpRequest::FromUrl(uri, mx, method);
     if (!request) {
         debugs(33, 5, "Invalid URI: " << url_);
         xfree(uri);
@@ -137,7 +139,6 @@
     request->http_ver = Http::ProtocolVersion();
     request->header.putStr(Http::HdrType::HOST, request->url.host());
     request->header.putTime(Http::HdrType::DATE, squid_curtime);
-    request->flags.internalClient = true;
     request->client_addr.setNoAddr();
 #if FOLLOW_X_FORWARDED_FOR
     request->indirect_client_addr.setNoAddr();
diff -u -r -N squid-4.0.20/src/Downloader.h squid-4.0.21/src/Downloader.h
--- squid-4.0.20/src/Downloader.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/Downloader.h	2017-07-02 20:41:18.000000000 +1200
@@ -14,6 +14,7 @@
 #include "http/forward.h"
 #include "http/StatusCode.h"
 #include "sbuf/SBuf.h"
+#include "XactionInitiator.h"
 
 class ClientHttpRequest;
 class StoreIOBuffer;
@@ -45,7 +46,7 @@
         Http::StatusCode status;
     };
 
-    Downloader(SBuf &url, AsyncCall::Pointer &aCallback, unsigned int level = 0);
+    Downloader(SBuf &url, AsyncCall::Pointer &aCallback, const XactionInitiator initiator, unsigned int level = 0);
     virtual ~Downloader();
     virtual void swanSong();
 
@@ -75,6 +76,8 @@
     AsyncCall::Pointer callback_; ///< callback to call when download finishes
     SBuf object_; ///< the object body data
     const unsigned int level_; ///< holds the nested downloads level
+    /// The initiator of the download request.
+    XactionInitiator initiator_;
 
     /// Pointer to an object that stores the clientStream required info
     DownloaderContextPointer context_;
diff -u -r -N squid-4.0.20/src/esi/Include.cc squid-4.0.21/src/esi/Include.cc
--- squid-4.0.20/src/esi/Include.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/esi/Include.cc	2017-07-02 20:41:18.000000000 +1200
@@ -299,8 +299,8 @@
     char const *tempUrl = vars->extractChar ();
 
     debugs(86, 5, "ESIIncludeStart: Starting subrequest with url '" << tempUrl << "'");
-
-    if (clientBeginRequest(Http::METHOD_GET, tempUrl, esiBufferRecipient, esiBufferDetach, stream.getRaw(), &tempheaders, stream->localbuffer->buf, HTTP_REQBUF_SZ)) {
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initEsi);
+    if (clientBeginRequest(Http::METHOD_GET, tempUrl, esiBufferRecipient, esiBufferDetach, stream.getRaw(), &tempheaders, stream->localbuffer->buf, HTTP_REQBUF_SZ, mx)) {
         debugs(86, DBG_CRITICAL, "starting new ESI subrequest failed");
     }
 
diff -u -r -N squid-4.0.20/src/esi/Makefile.in squid-4.0.21/src/esi/Makefile.in
--- squid-4.0.20/src/esi/Makefile.in	2017-06-02 00:59:03.000000000 +1200
+++ squid-4.0.21/src/esi/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/eui/Makefile.in squid-4.0.21/src/eui/Makefile.in
--- squid-4.0.20/src/eui/Makefile.in	2017-06-02 00:59:10.000000000 +1200
+++ squid-4.0.21/src/eui/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/external_acl.cc squid-4.0.21/src/external_acl.cc
--- squid-4.0.20/src/external_acl.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/external_acl.cc	2017-07-02 20:41:18.000000000 +1200
@@ -456,7 +456,7 @@
     if (result == ACCESS_DUNNO)
         return false; // non-cacheable response
 
-    if ((result == ACCESS_ALLOWED ? ttl : negative_ttl) <= 0)
+    if ((result.allowed() ? ttl : negative_ttl) <= 0)
         return false; // not caching this type of response
 
     return true;
@@ -615,7 +615,7 @@
             /* Make sure the user is authenticated */
             debugs(82, 3, HERE << acl->def->name << " check user authenticated.");
             const allow_t ti = AuthenticateAcl(ch);
-            if (ti != ACCESS_ALLOWED) {
+            if (!ti.allowed()) {
                 debugs(82, 2, HERE << acl->def->name << " user not authenticated (" << ti << ")");
                 return ti;
             }
@@ -802,7 +802,7 @@
     if (def->cache_size <= 0 || entry->result == ACCESS_DUNNO)
         return 1;
 
-    if (entry->date + (entry->result == ACCESS_ALLOWED ? def->ttl : def->negative_ttl) < squid_curtime)
+    if (entry->date + (entry->result.allowed() ? def->ttl : def->negative_ttl) < squid_curtime)
         return 1;
     else
         return 0;
@@ -815,7 +815,7 @@
         return 1;
 
     int ttl;
-    ttl = entry->result == ACCESS_ALLOWED ? def->ttl : def->negative_ttl;
+    ttl = entry->result.allowed() ? def->ttl : def->negative_ttl;
     ttl = (ttl * (100 - def->grace)) / 100;
 
     if (entry->date + ttl <= squid_curtime)
@@ -1149,17 +1149,6 @@
     checklist->resumeNonBlockingCheck(ExternalACLLookup::Instance());
 }
 
-/* This registers "external" in the registry. To do dynamic definitions
- * of external ACL's, rather than a static prototype, have a Prototype instance
- * prototype in the class that defines each external acl 'class'.
- * Then, then the external acl instance is created, it self registers under
- * it's name.
- * Be sure that clone is fully functional for that acl class though!
- */
-ACL::Prototype ACLExternal::RegistryProtoype(&ACLExternal::RegistryEntry_, "external");
-
-ACLExternal ACLExternal::RegistryEntry_("external");
-
 ACL *
 ACLExternal::clone() const
 {
diff -u -r -N squid-4.0.20/src/ExternalACL.h squid-4.0.21/src/ExternalACL.h
--- squid-4.0.20/src/ExternalACL.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/ExternalACL.h	2017-07-02 20:41:18.000000000 +1200
@@ -62,8 +62,6 @@
     virtual bool empty () const;
 
 protected:
-    static Prototype RegistryProtoype;
-    static ACLExternal RegistryEntry_;
     external_acl_data *data;
     char const *class_;
 };
diff -u -r -N squid-4.0.20/src/format/Format.cc squid-4.0.21/src/format/Format.cc
--- squid-4.0.20/src/format/Format.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/format/Format.cc	2017-07-02 20:41:18.000000000 +1200
@@ -1236,9 +1236,11 @@
 
         case LFT_SSL_CLIENT_SNI:
             if (al->request && al->request->clientConnectionManager.valid()) {
-                if (Ssl::ServerBump * srvBump = al->request->clientConnectionManager->serverBump()) {
-                    if (!srvBump->clientSni.isEmpty())
-                        out = srvBump->clientSni.c_str();
+                if (const ConnStateData *conn = al->request->clientConnectionManager.get()) {
+                    if (!conn->tlsClientSni().isEmpty()) {
+                        sb = conn->tlsClientSni();
+                        out = sb.c_str();
+                    }
                 }
             }
             break;
diff -u -r -N squid-4.0.20/src/format/Makefile.in squid-4.0.21/src/format/Makefile.in
--- squid-4.0.20/src/format/Makefile.in	2017-06-02 00:59:17.000000000 +1200
+++ squid-4.0.21/src/format/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/format/Token.cc squid-4.0.21/src/format/Token.cc
--- squid-4.0.20/src/format/Token.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/format/Token.cc	2017-07-02 20:41:18.000000000 +1200
@@ -210,7 +210,7 @@
 #endif
 
 #if USE_OPENSSL
-// SSL (ssl::) tokens
+// TLS/SSL (tls:: or ssl::) tokens
 static TokenTableEntry TokenTableSsl[] = {
     TokenTableEntry("bump_mode", LFT_SSL_BUMP_MODE),
     TokenTableEntry(">cert_subject", LFT_SSL_USER_CERT_SUBJECT),
@@ -245,6 +245,7 @@
     TheConfig.registerTokens(String("icap"),::Format::TokenTableIcap);
 #endif
 #if USE_OPENSSL
+    TheConfig.registerTokens(String("tls"),::Format::TokenTableSsl);
     TheConfig.registerTokens(String("ssl"),::Format::TokenTableSsl);
 #endif
 }
diff -u -r -N squid-4.0.20/src/fs/Makefile.in squid-4.0.21/src/fs/Makefile.in
--- squid-4.0.20/src/fs/Makefile.in	2017-06-02 00:59:23.000000000 +1200
+++ squid-4.0.21/src/fs/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/fs/rock/RockSwapDir.cc squid-4.0.21/src/fs/rock/RockSwapDir.cc
--- squid-4.0.20/src/fs/rock/RockSwapDir.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/fs/rock/RockSwapDir.cc	2017-07-02 20:41:18.000000000 +1200
@@ -137,7 +137,7 @@
     e.ping_status = PING_NONE;
 
     EBIT_CLR(e.flags, RELEASE_REQUEST);
-    EBIT_CLR(e.flags, KEY_PRIVATE);
+    e.clearPrivate();
     EBIT_SET(e.flags, ENTRY_VALIDATED);
 
     e.swap_dirn = index;
diff -u -r -N squid-4.0.20/src/fs/ufs/UFSSwapDir.cc squid-4.0.21/src/fs/ufs/UFSSwapDir.cc
--- squid-4.0.20/src/fs/ufs/UFSSwapDir.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/fs/ufs/UFSSwapDir.cc	2017-07-02 20:41:18.000000000 +1200
@@ -812,7 +812,7 @@
     e->refcount = refcount;
     e->flags = newFlags;
     EBIT_CLR(e->flags, RELEASE_REQUEST);
-    EBIT_CLR(e->flags, KEY_PRIVATE);
+    e->clearPrivate();
     e->ping_status = PING_NONE;
     EBIT_CLR(e->flags, ENTRY_VALIDATED);
     mapBitSet(e->swap_filen);
diff -u -r -N squid-4.0.20/src/ftp/Makefile.in squid-4.0.21/src/ftp/Makefile.in
--- squid-4.0.20/src/ftp/Makefile.in	2017-06-02 00:59:31.000000000 +1200
+++ squid-4.0.21/src/ftp/Makefile.in	2017-07-02 20:41:26.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/FwdState.cc squid-4.0.21/src/FwdState.cc
--- squid-4.0.20/src/FwdState.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/FwdState.cc	2017-07-02 20:41:18.000000000 +1200
@@ -254,7 +254,7 @@
 #if USE_OPENSSL
             if (request->flags.sslPeek && request->clientConnectionManager.valid()) {
                 CallJobHere1(17, 4, request->clientConnectionManager, ConnStateData,
-                             ConnStateData::httpsPeeked, Comm::ConnectionPointer(NULL));
+                             ConnStateData::httpsPeeked, ConnStateData::PinnedIdleContext(Comm::ConnectionPointer(nullptr), request));
             }
 #endif
         } else {
@@ -324,7 +324,7 @@
          */
         ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
         ch.src_addr = request->client_addr;
-        if (ch.fastCheck() == ACCESS_DENIED) {
+        if (ch.fastCheck().denied()) {
             err_type page_id;
             page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName, 1);
 
@@ -975,7 +975,7 @@
 #if USE_OPENSSL
     if (request->flags.sslPeek) {
         CallJobHere1(17, 4, request->clientConnectionManager, ConnStateData,
-                     ConnStateData::httpsPeeked, serverConnection());
+                     ConnStateData::httpsPeeked, ConnStateData::PinnedIdleContext(serverConnection(), request));
         unregister(serverConn); // async call owns it now
         complete(); // destroys us
         return;
@@ -1180,7 +1180,7 @@
     bool retriable = checkRetriable();
     if (!retriable && Config.accessList.serverPconnForNonretriable) {
         ACLFilledChecklist ch(Config.accessList.serverPconnForNonretriable, request, NULL);
-        retriable = (ch.fastCheck() == ACCESS_ALLOWED);
+        retriable = ch.fastCheck().allowed();
     }
     // always call shared pool first because we need to close an idle
     // connection there if we have to use a standby connection.
@@ -1232,7 +1232,7 @@
 aclMapTOS(acl_tos * head, ACLChecklist * ch)
 {
     for (acl_tos *l = head; l; l = l->next) {
-        if (!l->aclList || ch->fastCheck(l->aclList) == ACCESS_ALLOWED)
+        if (!l->aclList || ch->fastCheck(l->aclList).allowed())
             return l->tos;
     }
 
@@ -1244,7 +1244,7 @@
 aclMapNfmark(acl_nfmark * head, ACLChecklist * ch)
 {
     for (acl_nfmark *l = head; l; l = l->next) {
-        if (!l->aclList || ch->fastCheck(l->aclList) == ACCESS_ALLOWED)
+        if (!l->aclList || ch->fastCheck(l->aclList).allowed())
             return l->nfmark;
     }
 
@@ -1295,7 +1295,7 @@
         if (conn->remote.isIPv4() != l->addr.isIPv4()) continue;
 
         /* check ACLs for this outgoing address */
-        if (!l->aclList || ch.fastCheck(l->aclList) == ACCESS_ALLOWED) {
+        if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
             conn->local = l->addr;
             return;
         }
diff -u -r -N squid-4.0.20/src/helper/Makefile.in squid-4.0.21/src/helper/Makefile.in
--- squid-4.0.20/src/helper/Makefile.in	2017-06-02 00:59:35.000000000 +1200
+++ squid-4.0.21/src/helper/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/htcp.cc squid-4.0.21/src/htcp.cc
--- squid-4.0.20/src/htcp.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/htcp.cc	2017-07-02 20:41:18.000000000 +1200
@@ -678,7 +678,8 @@
     // Parse the request
     method.HttpRequestMethodXXX(s->method);
 
-    s->request = HttpRequest::CreateFromUrl(s->uri, method == Http::METHOD_NONE ? HttpRequestMethod(Http::METHOD_GET) : method);
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initHtcp);
+    s->request = HttpRequest::FromUrl(s->uri, mx, method == Http::METHOD_NONE ? HttpRequestMethod(Http::METHOD_GET) : method);
     return s;
 }
 
@@ -774,7 +775,7 @@
     ACLFilledChecklist checklist(acl, s->request.getRaw(), nullptr);
     checklist.src_addr = from;
     checklist.my_addr.setNoAddr();
-    return (checklist.fastCheck() == ACCESS_ALLOWED);
+    return checklist.fastCheck().allowed();
 }
 
 static void
diff -u -r -N squid-4.0.20/src/http/Makefile.in squid-4.0.21/src/http/Makefile.in
--- squid-4.0.20/src/http/Makefile.in	2017-06-02 00:59:43.000000000 +1200
+++ squid-4.0.21/src/http/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/http/one/Makefile.in squid-4.0.21/src/http/one/Makefile.in
--- squid-4.0.20/src/http/one/Makefile.in	2017-06-02 00:59:47.000000000 +1200
+++ squid-4.0.21/src/http/one/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/http/one/Parser.cc squid-4.0.21/src/http/one/Parser.cc
--- squid-4.0.20/src/http/one/Parser.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/http/one/Parser.cc	2017-07-02 20:41:18.000000000 +1200
@@ -47,7 +47,13 @@
     return RelaxedDels;
 }
 
-/// characters used to separate HTTP fields
+const CharacterSet &
+Http::One::Parser::WhitespaceCharacters()
+{
+    return Config.onoff.relaxed_header_parser ?
+           RelaxedDelimiterCharacters() : CharacterSet::WSP;
+}
+
 const CharacterSet &
 Http::One::Parser::DelimiterCharacters()
 {
@@ -259,11 +265,24 @@
     return NULL;
 }
 
-#if USE_HTTP_VIOLATIONS
 int
-Http::One::Parser::violationLevel() const
+Http::One::ErrorLevel()
 {
     return Config.onoff.relaxed_header_parser < 0 ? DBG_IMPORTANT : 5;
 }
-#endif
+
+// BWS = *( SP / HTAB ) ; WhitespaceCharacters() may relax this RFC 7230 rule
+bool
+Http::One::ParseBws(Tokenizer &tok)
+{
+    if (const auto count = tok.skipAll(Parser::WhitespaceCharacters())) {
+        // Generating BWS is a MUST-level violation so warn about it as needed.
+        debugs(33, ErrorLevel(), "found " << count << " BWS octets");
+        // RFC 7230 says we MUST parse BWS, so we fall through even if
+        // Config.onoff.relaxed_header_parser is off.
+    }
+    // else we successfully "parsed" an empty BWS sequence
+
+    return true;
+}
 
diff -u -r -N squid-4.0.20/src/http/one/Parser.h squid-4.0.21/src/http/one/Parser.h
--- squid-4.0.20/src/http/one/Parser.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/http/one/Parser.h	2017-07-02 20:41:18.000000000 +1200
@@ -91,11 +91,6 @@
     /// the remaining unprocessed section of buffer
     const SBuf &remaining() const {return buf_;}
 
-#if USE_HTTP_VIOLATIONS
-    /// the right debugs() level for parsing HTTP violation messages
-    int violationLevel() const;
-#endif
-
     /**
      * HTTP status code resulting from the parse process.
      * to be used on the invalid message handling.
@@ -106,8 +101,16 @@
      */
     Http::StatusCode parseStatusCode;
 
-    /// the characters which are to be considered valid whitespace
-    /// (WSP / BSP / OWS)
+    /// Whitespace between regular protocol elements.
+    /// Seen in RFCs as OWS, RWS, BWS, SP/HTAB but may be "relaxed" by us.
+    /// See also: DelimiterCharacters().
+    static const CharacterSet &WhitespaceCharacters();
+
+    /// Whitespace between protocol elements in restricted contexts like
+    /// request line, status line, asctime-date, and credentials
+    /// Seen in RFCs as SP but may be "relaxed" by us.
+    /// See also: WhitespaceCharacters().
+    /// XXX: Misnamed and overused.
     static const CharacterSet &DelimiterCharacters();
 
 protected:
@@ -155,6 +158,13 @@
     void unfoldMime();
 };
 
+/// skips and, if needed, warns about RFC 7230 BWS ("bad" whitespace)
+/// \returns true (always; unlike all the skip*() functions)
+bool ParseBws(Tokenizer &tok);
+
+/// the right debugs() level for logging HTTP violation messages
+int ErrorLevel();
+
 } // namespace One
 } // namespace Http
 
diff -u -r -N squid-4.0.20/src/http/one/RequestParser.cc squid-4.0.21/src/http/one/RequestParser.cc
--- squid-4.0.20/src/http/one/RequestParser.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/http/one/RequestParser.cc	2017-07-02 20:41:18.000000000 +1200
@@ -14,12 +14,6 @@
 #include "profiler/Profiler.h"
 #include "SquidConfig.h"
 
-// the right debugs() level for parsing errors
-inline static int
-ErrorLevel() {
-    return Config.onoff.relaxed_header_parser < 0 ? DBG_IMPORTANT : 5;
-}
-
 Http::One::RequestParser::RequestParser(bool preserveParsed) :
     Parser(),
     preserveParsed_(preserveParsed)
diff -u -r -N squid-4.0.20/src/http/one/TeChunkedParser.cc squid-4.0.21/src/http/one/TeChunkedParser.cc
--- squid-4.0.20/src/http/one/TeChunkedParser.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/http/one/TeChunkedParser.cc	2017-07-02 20:41:18.000000000 +1200
@@ -105,10 +105,10 @@
 }
 
 /**
- * Parses a set of RFC 7230 section 4.1.1 chunk-ext
- * http://tools.ietf.org/html/rfc7230#section-4.1.1
+ * Parses chunk metadata suffix, looking for interesting extensions and/or
+ * getting to the line terminator. RFC 7230 section 4.1.1 and its Errata #4667:
  *
- *   chunk-ext      = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+ *   chunk-ext = *( BWS  ";" BWS chunk-ext-name [ BWS "=" BWS chunk-ext-val ] )
  *   chunk-ext-name = token
  *   chunk-ext-val  = token / quoted-string
  *
@@ -117,17 +117,16 @@
 bool
 Http::One::TeChunkedParser::parseChunkExtension(Http1::Tokenizer &tok, bool skipKnown)
 {
-    // Bug 4492: IBM_HTTP_Server sends SP padding
-    if (auto n = tok.skipAll(CharacterSet::SP)) {
-        debugs(94, 3, "skipping " << n << " spurious whitespace at start of chunk extension");
-    }
-
     SBuf ext;
     SBuf value;
-    while (tok.skip(';') && tok.prefix(ext, CharacterSet::TCHAR)) {
+    while (
+        ParseBws(tok) && // Bug 4492: IBM_HTTP_Server sends SP after chunk-size
+        tok.skip(';') &&
+        ParseBws(tok) && // Bug 4492: ICAP servers send SP before chunk-ext-name
+        tok.prefix(ext, CharacterSet::TCHAR)) { // chunk-ext-name
 
         // whole value part is optional. if no '=' expect next chunk-ext
-        if (tok.skip('=')) {
+        if (ParseBws(tok) && tok.skip('=') && ParseBws(tok)) {
 
             if (!skipKnown) {
                 if (ext.cmp("use-original-body",17) == 0 && tok.int64(useOriginBody, 10)) {
diff -u -r -N squid-4.0.20/src/http/url_rewriters/fake/Makefile.in squid-4.0.21/src/http/url_rewriters/fake/Makefile.in
--- squid-4.0.20/src/http/url_rewriters/fake/Makefile.in	2017-06-02 01:00:01.000000000 +1200
+++ squid-4.0.21/src/http/url_rewriters/fake/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/http/url_rewriters/LFS/Makefile.in squid-4.0.21/src/http/url_rewriters/LFS/Makefile.in
--- squid-4.0.20/src/http/url_rewriters/LFS/Makefile.in	2017-06-02 00:59:51.000000000 +1200
+++ squid-4.0.21/src/http/url_rewriters/LFS/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/http/url_rewriters/LFS/url_lfs_rewrite.8 squid-4.0.21/src/http/url_rewriters/LFS/url_lfs_rewrite.8
--- squid-4.0.20/src/http/url_rewriters/LFS/url_lfs_rewrite.8	2017-06-02 09:57:33.000000000 +1200
+++ squid-4.0.21/src/http/url_rewriters/LFS/url_lfs_rewrite.8	2017-07-02 20:57:35.000000000 +1200
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "URL_LFS_REWRITE 8"
-.TH URL_LFS_REWRITE 8 "2017-06-01" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH URL_LFS_REWRITE 8 "2017-07-02" "perl v5.24.1" "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
@@ -234,7 +234,7 @@
 Report ideas for new improvements to the \fISquid Developers mailing list <squid\-dev@squid\-cache.org\fR>
 .SH "SEE ALSO"
 .IX Header "SEE ALSO"
-squid (8), \s-1GPL\s0 (7),
+squid (8), \s-1GPL \\fIs0\fR\|(7),
 .PP
 The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq
 .PP
diff -u -r -N squid-4.0.20/src/http/url_rewriters/Makefile.in squid-4.0.21/src/http/url_rewriters/Makefile.in
--- squid-4.0.20/src/http/url_rewriters/Makefile.in	2017-06-02 00:59:55.000000000 +1200
+++ squid-4.0.21/src/http/url_rewriters/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/http.cc squid-4.0.21/src/http.cc
--- squid-4.0.20/src/http.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/http.cc	2017-07-02 20:41:18.000000000 +1200
@@ -288,7 +288,9 @@
                     (Config.onoff.surrogate_is_remote
                      && sctusable->noStoreRemote())) {
                 surrogateNoStore = true;
-                entry->makePrivate();
+                // Be conservative for now and make it non-shareable because
+                // there is no enough information here to make the decision.
+                entry->makePrivate(false);
             }
 
             /* The HttpHeader logic cannot tell if the header it's parsing is a reply to an
@@ -313,8 +315,8 @@
     }
 }
 
-int
-HttpStateData::cacheableReply()
+HttpStateData::ReuseDecision::Answers
+HttpStateData::reusableReply(HttpStateData::ReuseDecision &decision)
 {
     HttpReply const *rep = finalReply();
     HttpHeader const *hdr = &rep->header;
@@ -335,24 +337,19 @@
 #define REFRESH_OVERRIDE(flag) 0
 #endif
 
-    if (EBIT_TEST(entry->flags, RELEASE_REQUEST)) {
-        debugs(22, 3, "NO because " << *entry << " has been released.");
-        return 0;
-    }
+    if (EBIT_TEST(entry->flags, RELEASE_REQUEST))
+        return decision.make(ReuseDecision::reuseNot, "the entry has been released");
 
     // RFC 7234 section 4: a cache MUST use the most recent response
     // (as determined by the Date header field)
-    if (sawDateGoBack) {
-        debugs(22, 3, "NO because " << *entry << " has an older date header.");
-        return 0;
-    }
+    // TODO: whether such responses could be shareable?
+    if (sawDateGoBack)
+        return decision.make(ReuseDecision::reuseNot, "the response has an older date header");
 
     // Check for Surrogate/1.0 protocol conditions
     // NP: reverse-proxy traffic our parent server has instructed us never to cache
-    if (surrogateNoStore) {
-        debugs(22, 3, HERE << "NO because Surrogate-Control:no-store");
-        return 0;
-    }
+    if (surrogateNoStore)
+        return decision.make(ReuseDecision::reuseNot, "Surrogate-Control:no-store");
 
     // RFC 2616: HTTP/1.1 Cache-Control conditions
     if (!ignoreCacheControl) {
@@ -362,10 +359,9 @@
 
         // RFC 2616 section 14.9.2 - MUST NOT cache any response with request CC:no-store
         if (request && request->cache_control && request->cache_control->hasNoStore() &&
-                !REFRESH_OVERRIDE(ignore_no_store)) {
-            debugs(22, 3, HERE << "NO because client request Cache-Control:no-store");
-            return 0;
-        }
+                !REFRESH_OVERRIDE(ignore_no_store))
+            return decision.make(ReuseDecision::reuseNot,
+                                 "client request Cache-Control:no-store");
 
         // NP: request CC:no-cache only means cache READ is forbidden. STORE is permitted.
         if (rep->cache_control && rep->cache_control->hasNoCacheWithParameters()) {
@@ -374,8 +370,8 @@
              * successfully (ie, must revalidate AND these headers are prohibited on stale replies).
              * That is a bit tricky for squid right now so we avoid caching entirely.
              */
-            debugs(22, 3, HERE << "NO because server reply Cache-Control:no-cache has parameters");
-            return 0;
+            return decision.make(ReuseDecision::reuseNot,
+                                 "server reply Cache-Control:no-cache has parameters");
         }
 
         // NP: request CC:private is undefined. We ignore.
@@ -383,10 +379,9 @@
 
         // RFC 2616 section 14.9.2 - MUST NOT cache any response with CC:no-store
         if (rep->cache_control && rep->cache_control->hasNoStore() &&
-                !REFRESH_OVERRIDE(ignore_no_store)) {
-            debugs(22, 3, HERE << "NO because server reply Cache-Control:no-store");
-            return 0;
-        }
+                !REFRESH_OVERRIDE(ignore_no_store))
+            return decision.make(ReuseDecision::reuseNot,
+                                 "server reply Cache-Control:no-store");
 
         // RFC 2616 section 14.9.1 - MUST NOT cache any response with CC:private in a shared cache like Squid.
         // CC:private overrides CC:public when both are present in a response.
@@ -399,23 +394,21 @@
              * successfully (ie, must revalidate AND these headers are prohibited on stale replies).
              * That is a bit tricky for squid right now so we avoid caching entirely.
              */
-            debugs(22, 3, HERE << "NO because server reply Cache-Control:private");
-            return 0;
+            return decision.make(ReuseDecision::reuseNot,
+                                 "server reply Cache-Control:private");
         }
     }
 
     // RFC 2068, sec 14.9.4 - MUST NOT cache any response with Authentication UNLESS certain CC controls are present
     // allow HTTP violations to IGNORE those controls (ie re-block caching Auth)
     if (request && (request->flags.auth || request->flags.authSent)) {
-        if (!rep->cache_control) {
-            debugs(22, 3, HERE << "NO because Authenticated and server reply missing Cache-Control");
-            return 0;
-        }
-
-        if (ignoreCacheControl) {
-            debugs(22, 3, HERE << "NO because Authenticated and ignoring Cache-Control");
-            return 0;
-        }
+        if (!rep->cache_control)
+            return decision.make(ReuseDecision::reuseNot,
+                                 "authenticated and server reply missing Cache-Control");
+
+        if (ignoreCacheControl)
+            return decision.make(ReuseDecision::reuseNot,
+                                 "authenticated and ignoring Cache-Control");
 
         bool mayStore = false;
         // HTTPbis pt6 section 3.2: a response CC:public is present
@@ -444,10 +437,8 @@
             mayStore = true;
         }
 
-        if (!mayStore) {
-            debugs(22, 3, HERE << "NO because Authenticated transaction");
-            return 0;
-        }
+        if (!mayStore)
+            return decision.make(ReuseDecision::reuseNot, "authenticated transaction");
 
         // NP: response CC:no-cache is equivalent to CC:must-revalidate,max-age=0. We MAY cache, and do so.
         // NP: other request CC flags are limiters on HIT/MISS/REFRESH. We don't care about here.
@@ -458,12 +449,26 @@
      * probably should not be cachable
      */
     if ((v = hdr->getStr(Http::HdrType::CONTENT_TYPE)))
-        if (!strncasecmp(v, "multipart/x-mixed-replace", 25)) {
-            debugs(22, 3, HERE << "NO because Content-Type:multipart/x-mixed-replace");
-            return 0;
-        }
+        if (!strncasecmp(v, "multipart/x-mixed-replace", 25))
+            return decision.make(ReuseDecision::reuseNot, "Content-Type:multipart/x-mixed-replace");
+
+    // TODO: if possible, provide more specific message for each status code
+    static const char *shareableError = "shareable error status code";
+    static const char *nonShareableError = "non-shareable error status code";
+    ReuseDecision::Answers statusAnswer = ReuseDecision::reuseNot;
+    const char *statusReason = nonShareableError;
 
     switch (rep->sline.status()) {
+
+    /* There are several situations when a non-cacheable response may be
+     * still shareable (e.g., among collapsed clients). We assume that these
+     * are 3xx and 5xx responses, indicating server problems and some of
+     * 4xx responses, common for all clients with a given cache key (e.g.,
+     * 404 Not Found or 414 URI Too Long). On the other hand, we should not
+     * share non-cacheable client-specific errors, such as 400 Bad Request
+     * or 406 Not Acceptable.
+     */
+
     /* Responses that are cacheable */
 
     case Http::scOkay:
@@ -481,111 +486,87 @@
          * unless we know how to refresh it.
          */
 
-        if (!refreshIsCachable(entry) && !REFRESH_OVERRIDE(store_stale)) {
-            debugs(22, 3, "NO because refreshIsCachable() returned non-cacheable..");
-            return 0;
-        } else {
-            debugs(22, 3, HERE << "YES because HTTP status " << rep->sline.status());
-            return 1;
-        }
-        /* NOTREACHED */
+        if (refreshIsCachable(entry) || REFRESH_OVERRIDE(store_stale))
+            decision.make(ReuseDecision::cachePositively, "refresh check returned cacheable");
+        else
+            decision.make(ReuseDecision::doNotCacheButShare, "refresh check returned non-cacheable");
         break;
 
     /* Responses that only are cacheable if the server says so */
 
     case Http::scFound:
     case Http::scTemporaryRedirect:
-        if (rep->date <= 0) {
-            debugs(22, 3, HERE << "NO because HTTP status " << rep->sline.status() << " and Date missing/invalid");
-            return 0;
-        }
-        if (rep->expires > rep->date) {
-            debugs(22, 3, HERE << "YES because HTTP status " << rep->sline.status() << " and Expires > Date");
-            return 1;
-        } else {
-            debugs(22, 3, HERE << "NO because HTTP status " << rep->sline.status() << " and Expires <= Date");
-            return 0;
-        }
-        /* NOTREACHED */
+        if (rep->date <= 0)
+            decision.make(ReuseDecision::doNotCacheButShare, "Date is missing/invalid");
+        else if (rep->expires > rep->date)
+            decision.make(ReuseDecision::cachePositively, "Expires > Date");
+        else
+            decision.make(ReuseDecision::doNotCacheButShare, "Expires <= Date");
         break;
 
-    /* Errors can be negatively cached */
-
+    /* These responses can be negatively cached. Most can also be shared. */
     case Http::scNoContent:
-
     case Http::scUseProxy:
-
-    case Http::scBadRequest:
-
     case Http::scForbidden:
-
     case Http::scNotFound:
-
     case Http::scMethodNotAllowed:
-
     case Http::scUriTooLong:
-
     case Http::scInternalServerError:
-
     case Http::scNotImplemented:
-
     case Http::scBadGateway:
-
     case Http::scServiceUnavailable:
-
     case Http::scGatewayTimeout:
     case Http::scMisdirectedRequest:
+        statusAnswer = ReuseDecision::doNotCacheButShare;
+        statusReason = shareableError;
+    // fall through to the actual decision making below
 
-        debugs(22, 3, "MAYBE because HTTP status " << rep->sline.status());
-        return -1;
-
-        /* NOTREACHED */
+    case Http::scBadRequest: // no sharing; perhaps the server did not like something specific to this request
+#if USE_HTTP_VIOLATIONS
+        if (Config.negativeTtl > 0)
+            decision.make(ReuseDecision::cacheNegatively, "Config.negativeTtl > 0");
+        else
+#endif
+            decision.make(statusAnswer, statusReason);
         break;
 
-    /* Some responses can never be cached */
-
-    case Http::scPartialContent:    /* Not yet supported */
-
+    /* these responses can never be cached, some
+       of them can be shared though */
     case Http::scSeeOther:
-
     case Http::scNotModified:
-
     case Http::scUnauthorized:
-
     case Http::scProxyAuthenticationRequired:
-
-    case Http::scInvalidHeader: /* Squid header parsing error */
-
-    case Http::scHeaderTooLarge:
-
     case Http::scPaymentRequired:
+    case Http::scInsufficientStorage:
+        // TODO: use more specific reason for non-error status codes
+        decision.make(ReuseDecision::doNotCacheButShare, shareableError);
+        break;
+
+    case Http::scPartialContent: /* Not yet supported. TODO: make shareable for suitable ranges */
     case Http::scNotAcceptable:
-    case Http::scRequestTimeout:
-    case Http::scConflict:
+    case Http::scRequestTimeout: // TODO: is this shareable?
+    case Http::scConflict: // TODO: is this shareable?
     case Http::scLengthRequired:
     case Http::scPreconditionFailed:
     case Http::scPayloadTooLarge:
     case Http::scUnsupportedMediaType:
     case Http::scUnprocessableEntity:
-    case Http::scLocked:
+    case Http::scLocked: // TODO: is this shareable?
     case Http::scFailedDependency:
-    case Http::scInsufficientStorage:
     case Http::scRequestedRangeNotSatisfied:
     case Http::scExpectationFailed:
-
-        debugs(22, 3, HERE << "NO because HTTP status " << rep->sline.status());
-        return 0;
+    case Http::scInvalidHeader: /* Squid header parsing error */
+    case Http::scHeaderTooLarge:
+        decision.make(ReuseDecision::reuseNot, nonShareableError);
+        break;
 
     default:
         /* RFC 2616 section 6.1.1: an unrecognized response MUST NOT be cached. */
-        debugs (11, 3, HERE << "NO because unknown HTTP status code " << rep->sline.status());
-        return 0;
-
-        /* NOTREACHED */
+        decision.make(ReuseDecision::reuseNot, "unknown status code");
         break;
     }
 
-    /* NOTREACHED */
+    return decision.answer;
 }
 
 /// assemble a variant key (vary-mark) from the given Vary header and HTTP request
@@ -826,7 +807,7 @@
         ACLFilledChecklist ch(Config.accessList.reply, originalRequest(), NULL);
         ch.reply = reply;
         HTTPMSGLOCK(ch.reply);
-        if (ch.fastCheck() != ACCESS_ALLOWED) { // TODO: support slow lookups?
+        if (!ch.fastCheck().allowed()) { // TODO: support slow lookups?
             debugs(11, 3, HERE << "ignoring denied 1xx");
             proceedAfter1xx();
             return;
@@ -921,11 +902,12 @@
 
     Ctx ctx = ctx_enter(entry->mem_obj->urlXXX());
     HttpReply *rep = finalReply();
+    const Http::StatusCode statusCode = rep->sline.status();
 
     entry->timestampsSet();
 
     /* Check if object is cacheable or not based on reply code */
-    debugs(11, 3, "HTTP CODE: " << rep->sline.status());
+    debugs(11, 3, "HTTP CODE: " << statusCode);
 
     if (const StoreEntry *oldEntry = findPreviouslyCachedEntry(entry))
         sawDateGoBack = rep->olderThan(oldEntry->getReply());
@@ -942,7 +924,9 @@
         const SBuf vary(httpMakeVaryMark(request, rep));
 
         if (vary.isEmpty()) {
-            entry->makePrivate();
+            // TODO: check whether such responses are shareable.
+            // Do not share for now.
+            entry->makePrivate(false);
             if (!fwd->reforwardableStatus(rep->sline.status()))
                 EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
             varyFailure = true;
@@ -965,30 +949,31 @@
         if (!fwd->reforwardableStatus(rep->sline.status()))
             EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
 
-        switch (cacheableReply()) {
+        ReuseDecision decision(entry, statusCode);
 
-        case 1:
-            entry->makePublic();
+        switch (reusableReply(decision)) {
+
+        case ReuseDecision::reuseNot:
+            entry->makePrivate(false);
             break;
 
-        case 0:
-            entry->makePrivate();
+        case ReuseDecision::cachePositively:
+            entry->makePublic();
             break;
 
-        case -1:
+        case ReuseDecision::cacheNegatively:
+            entry->cacheNegatively();
+            break;
 
-#if USE_HTTP_VIOLATIONS
-            if (Config.negativeTtl > 0)
-                entry->cacheNegatively();
-            else
-#endif
-                entry->makePrivate();
+        case ReuseDecision::doNotCacheButShare:
+            entry->makePrivate(true);
             break;
 
         default:
             assert(0);
             break;
         }
+        debugs(11, 3, "decided: " << decision);
     }
 
     if (!ignoreCacheControl) {
@@ -1409,9 +1394,6 @@
 void
 HttpStateData::processReplyBody()
 {
-    Ip::Address client_addr;
-    bool ispinned = false;
-
     if (!flags.headers_parsed) {
         flags.do_next_read = true;
         maybeReadVirginBody();
@@ -1464,35 +1446,49 @@
         }
         break;
 
-        case COMPLETE_PERSISTENT_MSG:
+        case COMPLETE_PERSISTENT_MSG: {
             debugs(11, 5, "processReplyBody: COMPLETE_PERSISTENT_MSG from " << serverConnection);
-            /* yes we have to clear all these! */
+
+            // TODO: Remove serverConnectionSaved but preserve exception safety.
+
             commUnsetConnTimeout(serverConnection);
             flags.do_next_read = false;
 
             comm_remove_close_handler(serverConnection->fd, closeHandler);
             closeHandler = NULL;
-            fwd->unregister(serverConnection);
 
+            Ip::Address client_addr; // XXX: Remove as unused. Why was it added?
             if (request->flags.spoofClientIp)
                 client_addr = request->client_addr;
 
+            auto serverConnectionSaved = serverConnection;
+            fwd->unregister(serverConnection);
+            serverConnection = nullptr;
+
+            bool ispinned = false; // TODO: Rename to isOrShouldBePinned
             if (request->flags.pinned) {
                 ispinned = true;
             } else if (request->flags.connectionAuth && request->flags.authSent) {
                 ispinned = true;
             }
 
-            if (ispinned && request->clientConnectionManager.valid()) {
-                request->clientConnectionManager->pinConnection(serverConnection, request, _peer,
-                        (request->flags.connectionAuth));
+            if (ispinned) {
+                if (request->clientConnectionManager.valid()) {
+                    CallJobHere1(11, 4, request->clientConnectionManager,
+                                 ConnStateData,
+                                 notePinnedConnectionBecameIdle,
+                                 ConnStateData::PinnedIdleContext(serverConnectionSaved, request));
+                } else {
+                    // must not pool/share ispinned connections, even orphaned ones
+                    serverConnectionSaved->close();
+                }
             } else {
-                fwd->pconnPush(serverConnection, request->url.host());
+                fwd->pconnPush(serverConnectionSaved, request->url.host());
             }
 
-            serverConnection = NULL;
             serverComplete();
             return;
+        }
 
         case COMPLETE_NONPERSISTENT_MSG:
             debugs(11, 5, "processReplyBody: COMPLETE_NONPERSISTENT_MSG from " << serverConnection);
@@ -2333,7 +2329,7 @@
     }
 
     ACLFilledChecklist ch(Config.accessList.brokenPosts, originalRequest(), NULL);
-    if (ch.fastCheck() != ACCESS_ALLOWED) {
+    if (!ch.fastCheck().allowed()) {
         debugs(11, 5, HERE << "didn't match brokenPosts");
         return false;
     }
@@ -2457,3 +2453,29 @@
     mustStop(reason);
 }
 
+HttpStateData::ReuseDecision::ReuseDecision(const StoreEntry *e, const Http::StatusCode code)
+    : answer(HttpStateData::ReuseDecision::reuseNot), reason(nullptr), entry(e), statusCode(code) {}
+
+HttpStateData::ReuseDecision::Answers
+HttpStateData::ReuseDecision::make(const HttpStateData::ReuseDecision::Answers ans, const char *why)
+{
+    answer = ans;
+    reason = why;
+    return answer;
+}
+
+std::ostream &operator <<(std::ostream &os, const HttpStateData::ReuseDecision &d)
+{
+    static const char *ReuseMessages[] = {
+        "do not cache and do not share", // reuseNot
+        "cache positively and share", // cachePositively
+        "cache negatively and share", // cacheNegatively
+        "do not cache but share" // doNotCacheButShare
+    };
+
+    assert(d.answer >= HttpStateData::ReuseDecision::reuseNot &&
+           d.answer <= HttpStateData::ReuseDecision::doNotCacheButShare);
+    return os << ReuseMessages[d.answer] << " because " << d.reason <<
+           "; HTTP status " << d.statusCode << " " << *(d.entry);
+}
+
diff -u -r -N squid-4.0.20/src/http.h squid-4.0.21/src/http.h
--- squid-4.0.20/src/http.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/http.h	2017-07-02 20:41:18.000000000 +1200
@@ -23,6 +23,23 @@
     CBDATA_CLASS(HttpStateData);
 
 public:
+
+    /// assists in making and relaying entry caching/sharing decision
+    class ReuseDecision
+    {
+    public:
+        enum Answers { reuseNot = 0, cachePositively, cacheNegatively, doNotCacheButShare };
+
+        ReuseDecision(const StoreEntry *e, const Http::StatusCode code);
+        /// stores the corresponding decision
+        Answers make(const Answers ans, const char *why);
+
+        Answers answer; ///< the decision id
+        const char *reason; ///< the decision reason
+        const StoreEntry *entry; ///< entry for debugging
+        const Http::StatusCode statusCode; ///< HTTP status for debugging
+    };
+
     HttpStateData(FwdState *);
     ~HttpStateData();
 
@@ -40,8 +57,8 @@
     void readReply(const CommIoCbParams &io);
     virtual void maybeReadVirginBody(); // read response data from the network
 
-    // Determine whether the response is a cacheable representation
-    int cacheableReply();
+    // Checks whether the response is cacheable/shareable.
+    ReuseDecision::Answers reusableReply(ReuseDecision &decision);
 
     CachePeer *_peer;       /* CachePeer request made to */
     int eof;            /* reached end-of-object? */
@@ -135,6 +152,8 @@
     bool sawDateGoBack;
 };
 
+std::ostream &operator <<(std::ostream &os, const HttpStateData::ReuseDecision &d);
+
 int httpCachable(const HttpRequestMethod&);
 void httpStart(FwdState *);
 SBuf httpMakeVaryMark(HttpRequest * request, HttpReply const * reply);
diff -u -r -N squid-4.0.20/src/HttpHeaderTools.cc squid-4.0.21/src/HttpHeaderTools.cc
--- squid-4.0.20/src/HttpHeaderTools.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/HttpHeaderTools.cc	2017-07-02 20:41:18.000000000 +1200
@@ -289,7 +289,7 @@
 
     ACLFilledChecklist checklist(hm->access_list, request, NULL);
 
-    if (checklist.fastCheck() == ACCESS_ALLOWED) {
+    if (checklist.fastCheck().allowed()) {
         /* aclCheckFast returns true for allow. */
         debugs(66, 7, "checklist for mangler is positive. Mangle");
         retval = 1;
@@ -478,7 +478,7 @@
     ACLFilledChecklist checklist(NULL, request, NULL);
 
     for (HeaderWithAclList::const_iterator hwa = headersAdd.begin(); hwa != headersAdd.end(); ++hwa) {
-        if (!hwa->aclList || checklist.fastCheck(hwa->aclList) == ACCESS_ALLOWED) {
+        if (!hwa->aclList || checklist.fastCheck(hwa->aclList).allowed()) {
             const char *fieldValue = NULL;
             MemBuf mb;
             if (hwa->quoted) {
diff -u -r -N squid-4.0.20/src/HttpReply.cc squid-4.0.21/src/HttpReply.cc
--- squid-4.0.20/src/HttpReply.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/HttpReply.cc	2017-07-02 20:41:18.000000000 +1200
@@ -517,7 +517,7 @@
     HTTPMSGLOCK(ch.reply);
     for (AclSizeLimit *l = Config.ReplyBodySize; l; l = l -> next) {
         /* if there is no ACL list or if the ACLs listed match use this size value */
-        if (!l->aclList || ch.fastCheck(l->aclList) == ACCESS_ALLOWED) {
+        if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
             debugs(58, 4, HERE << "bodySizeMax=" << bodySizeMax);
             bodySizeMax = l->size; // may be -1
             break;
diff -u -r -N squid-4.0.20/src/HttpRequest.cc squid-4.0.21/src/HttpRequest.cc
--- squid-4.0.20/src/HttpRequest.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/HttpRequest.cc	2017-07-02 20:41:18.000000000 +1200
@@ -13,6 +13,7 @@
 #include "acl/AclSizeLimit.h"
 #include "acl/FilledChecklist.h"
 #include "client_side.h"
+#include "client_side_request.h"
 #include "dns/LookupDetails.h"
 #include "Downloader.h"
 #include "err_detail_type.h"
@@ -38,15 +39,19 @@
 #include "adaptation/icap/icap_log.h"
 #endif
 
-HttpRequest::HttpRequest() :
-    HttpMsg(hoRequest)
+HttpRequest::HttpRequest(const MasterXaction::Pointer &mx) :
+    HttpMsg(hoRequest),
+    masterXaction(mx)
 {
+    assert(mx);
     init();
 }
 
-HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aSchemeImg, const char *aUrlpath) :
-    HttpMsg(hoRequest)
+HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aSchemeImg, const char *aUrlpath, const MasterXaction::Pointer &mx) :
+    HttpMsg(hoRequest),
+    masterXaction(mx)
 {
+    assert(mx);
     static unsigned int id = 1;
     debugs(93,7, HERE << "constructed, this=" << this << " id=" << ++id);
     init();
@@ -170,7 +175,7 @@
 HttpRequest *
 HttpRequest::clone() const
 {
-    HttpRequest *copy = new HttpRequest();
+    HttpRequest *copy = new HttpRequest(masterXaction);
     copy->method = method;
     // TODO: move common cloning clone to Msg::copyTo() or copy ctor
     copy->header.append(&header);
@@ -327,14 +332,11 @@
 
     * (char *) end = '\0';     // temp terminate URI, XXX dangerous?
 
-    HttpRequest *tmp = urlParse(method, (char *) start, this);
+    const bool ret = url.parse(method, (char *) start);
 
     * (char *) end = save;
 
-    if (NULL == tmp)
-        return false;
-
-    return true;
+    return ret;
 }
 
 /* swaps out request using httpRequestPack */
@@ -518,9 +520,14 @@
  * If the request cannot be created cleanly, NULL is returned
  */
 HttpRequest *
-HttpRequest::CreateFromUrl(char * url, const HttpRequestMethod& method)
+HttpRequest::FromUrl(char * url, const MasterXaction::Pointer &mx, const HttpRequestMethod& method)
 {
-    return urlParse(method, url, NULL);
+    std::unique_ptr<HttpRequest> req(new HttpRequest(mx));
+    if (req->url.parse(method, url)) {
+        req->method = method;
+        return req.release();
+    }
+    return nullptr;
 }
 
 /**
@@ -604,7 +611,7 @@
 
     for (AclSizeLimit *l = Config.rangeOffsetLimit; l; l = l -> next) {
         /* if there is no ACL list or if the ACLs listed match use this limit value */
-        if (!l->aclList || ch.fastCheck(l->aclList) == ACCESS_ALLOWED) {
+        if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
             debugs(58, 4, HERE << "rangeOffsetLimit=" << rangeOffsetLimit);
             rangeOffsetLimit = l->size; // may be -1
             break;
@@ -667,3 +674,42 @@
     return url.absolute();
 }
 
+void
+HttpRequest::manager(const CbcPointer<ConnStateData> &aMgr, const AccessLogEntryPointer &al)
+{
+    clientConnectionManager = aMgr;
+
+    if (!clientConnectionManager.valid())
+        return;
+
+    AnyP::PortCfgPointer port = clientConnectionManager->port;
+    if (port) {
+        myportname = port->name;
+        flags.ignoreCc = port->ignore_cc;
+    }
+
+    if (auto clientConnection = clientConnectionManager->clientConnection) {
+        client_addr = clientConnection->remote; // XXX: remove request->client_addr member.
+#if FOLLOW_X_FORWARDED_FOR
+        // indirect client gets stored here because it is an HTTP header result (from X-Forwarded-For:)
+        // not details about the TCP connection itself
+        indirect_client_addr = clientConnection->remote;
+#endif /* FOLLOW_X_FORWARDED_FOR */
+        my_addr = clientConnection->local;
+
+        flags.intercepted = ((clientConnection->flags & COMM_INTERCEPTION) != 0);
+        flags.interceptTproxy = ((clientConnection->flags & COMM_TRANSPARENT) != 0 ) ;
+        const bool proxyProtocolPort = port ? port->flags.proxySurrogate : false;
+        if (flags.interceptTproxy && !proxyProtocolPort) {
+            if (Config.accessList.spoof_client_ip) {
+                ACLFilledChecklist *checklist = new ACLFilledChecklist(Config.accessList.spoof_client_ip, this, clientConnection->rfc931);
+                checklist->al = al;
+                flags.spoofClientIp = checklist->fastCheck().allowed();
+                delete checklist;
+            } else
+                flags.spoofClientIp = true;
+        } else
+            flags.spoofClientIp = false;
+    }
+}
+
diff -u -r -N squid-4.0.20/src/HttpRequest.h squid-4.0.21/src/HttpRequest.h
--- squid-4.0.20/src/HttpRequest.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/HttpRequest.h	2017-07-02 20:41:18.000000000 +1200
@@ -15,6 +15,7 @@
 #include "HierarchyLogEntry.h"
 #include "http/RequestMethod.h"
 #include "HttpMsg.h"
+#include "MasterXaction.h"
 #include "Notes.h"
 #include "RequestFlags.h"
 #include "URL.h"
@@ -35,6 +36,8 @@
 
 class ConnStateData;
 class Downloader;
+class AccessLogEntry;
+typedef RefCount<AccessLogEntry> AccessLogEntryPointer;
 
 /*  Http Request */
 void httpRequestPack(void *obj, Packable *p);
@@ -48,8 +51,8 @@
 public:
     typedef RefCount<HttpRequest> Pointer;
 
-    HttpRequest();
-    HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *schemeImage, const char *aUrlpath);
+    HttpRequest(const MasterXaction::Pointer &);
+    HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *schemeImage, const char *aUrlpath, const MasterXaction::Pointer &);
     ~HttpRequest();
     virtual void reset();
 
@@ -87,6 +90,9 @@
     /// clear error details, useful for retries/repeats
     void clearError();
 
+    /// associates the request with a from-client connection manager
+    void manager(const CbcPointer<ConnStateData> &aMgr, const AccessLogEntryPointer &al);
+
 protected:
     void clean();
 
@@ -195,7 +201,7 @@
 
     static void httpRequestPack(void *obj, Packable *p);
 
-    static HttpRequest * CreateFromUrl(char * url, const HttpRequestMethod &method = Http::METHOD_GET);
+    static HttpRequest * FromUrl(char * url, const MasterXaction::Pointer &, const HttpRequestMethod &method = Http::METHOD_GET);
 
     ConnStateData *pinnedConnection();
 
@@ -216,6 +222,9 @@
     /// The Downloader object which initiated the HTTP request if any
     CbcPointer<Downloader> downloader;
 
+    /// the master transaction this request belongs to. Never nil.
+    MasterXaction::Pointer masterXaction;
+
     /// forgets about the cached Range header (for a reason)
     void ignoreRange(const char *reason);
     int64_t getRangeOffsetLimit(); /* the result of this function gets cached in rangeOffsetLimit */
diff -u -r -N squid-4.0.20/src/icmp/Makefile.in squid-4.0.21/src/icmp/Makefile.in
--- squid-4.0.20/src/icmp/Makefile.in	2017-06-02 01:00:08.000000000 +1200
+++ squid-4.0.21/src/icmp/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/icmp/net_db.cc squid-4.0.21/src/icmp/net_db.cc
--- squid-4.0.20/src/icmp/net_db.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/icmp/net_db.cc	2017-07-02 20:41:18.000000000 +1200
@@ -1286,7 +1286,8 @@
     char *uri = internalRemoteUri(p->host, p->http_port, "/squid-internal-dynamic/", netDB);
     debugs(38, 3, "netdbExchangeStart: Requesting '" << uri << "'");
     assert(NULL != uri);
-    HttpRequest *req = HttpRequest::CreateFromUrl(uri);
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initIcmp);
+    HttpRequest *req = HttpRequest::FromUrl(uri, mx);
 
     if (req == NULL) {
         debugs(38, DBG_IMPORTANT, "netdbExchangeStart: Bad URI " << uri);
diff -u -r -N squid-4.0.20/src/icp_v2.cc squid-4.0.21/src/icp_v2.cc
--- squid-4.0.20/src/icp_v2.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/icp_v2.cc	2017-07-02 20:41:18.000000000 +1200
@@ -417,7 +417,7 @@
     ACLFilledChecklist checklist(Config.accessList.icp, icp_request, NULL);
     checklist.src_addr = from;
     checklist.my_addr.setNoAddr();
-    return (checklist.fastCheck() == ACCESS_ALLOWED);
+    return checklist.fastCheck().allowed();
 }
 
 char const *
@@ -439,8 +439,8 @@
     }
 
     HttpRequest *result;
-
-    if ((result = HttpRequest::CreateFromUrl(url)) == NULL)
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initIcp);
+    if ((result = HttpRequest::FromUrl(url, mx)) == NULL)
         icpCreateAndSend(ICP_ERR, 0, url, reqnum, 0, fd, from);
 
     return result;
diff -u -r -N squid-4.0.20/src/ident/AclIdent.cc squid-4.0.21/src/ident/AclIdent.cc
--- squid-4.0.20/src/ident/AclIdent.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/ident/AclIdent.cc	2017-07-02 20:41:18.000000000 +1200
@@ -47,6 +47,12 @@
 }
 
 void
+ACLIdent::parseFlags()
+{
+    ParseFlags(Acl::NoOptions(), data->supportedFlags());
+}
+
+void
 ACLIdent::parse()
 {
     if (!data) {
diff -u -r -N squid-4.0.20/src/ident/AclIdent.h squid-4.0.21/src/ident/AclIdent.h
--- squid-4.0.20/src/ident/AclIdent.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/ident/AclIdent.h	2017-07-02 20:41:18.000000000 +1200
@@ -40,20 +40,17 @@
     ACLIdent & operator= (ACLIdent const &rhs);
     ~ACLIdent();
 
+    /* ACL API */
     virtual char const *typeString() const;
     virtual void parse();
     virtual bool isProxyAuth() const {return true;}
-
+    virtual void parseFlags();
     virtual int match(ACLChecklist *checklist);
     virtual SBufList dump() const;
     virtual bool empty () const;
     virtual ACL *clone()const;
 
 private:
-    static Prototype UserRegistryProtoype;
-    static ACLIdent UserRegistryEntry_;
-    static Prototype RegexRegistryProtoype;
-    static ACLIdent RegexRegistryEntry_;
     ACLData<char const *> *data;
     char const *type_;
 };
diff -u -r -N squid-4.0.20/src/ident/Makefile.in squid-4.0.21/src/ident/Makefile.in
--- squid-4.0.20/src/ident/Makefile.in	2017-06-02 01:00:11.000000000 +1200
+++ squid-4.0.21/src/ident/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/ip/Makefile.in squid-4.0.21/src/ip/Makefile.in
--- squid-4.0.20/src/ip/Makefile.in	2017-06-02 01:00:17.000000000 +1200
+++ squid-4.0.21/src/ip/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/ipc/Forwarder.cc squid-4.0.21/src/ipc/Forwarder.cc
--- squid-4.0.20/src/ipc/Forwarder.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/ipc/Forwarder.cc	2017-07-02 20:41:18.000000000 +1200
@@ -62,6 +62,7 @@
         // assume the pack() call failed because the message did not fit
         // TODO: add a more specific exception?
         handleError();
+        return;
     }
 
     SendMessage(Ipc::Port::CoordinatorAddr(), message);
diff -u -r -N squid-4.0.20/src/ipc/Forwarder.h squid-4.0.21/src/ipc/Forwarder.h
--- squid-4.0.20/src/ipc/Forwarder.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/ipc/Forwarder.h	2017-07-02 20:41:18.000000000 +1200
@@ -49,12 +49,14 @@
     virtual void handleError();
     virtual void handleTimeout();
     virtual void handleException(const std::exception& e);
-    virtual void handleRemoteAck();
 
 private:
     static void RequestTimedOut(void* param);
     void requestTimedOut();
     void removeTimeoutEvent();
+
+    void handleRemoteAck();
+
     static AsyncCall::Pointer DequeueRequest(unsigned int requestId);
 
 protected:
diff -u -r -N squid-4.0.20/src/ipc/Makefile.in squid-4.0.21/src/ipc/Makefile.in
--- squid-4.0.20/src/ipc/Makefile.in	2017-06-02 01:00:22.000000000 +1200
+++ squid-4.0.21/src/ipc/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/log/access_log.cc squid-4.0.21/src/log/access_log.cc
--- squid-4.0.20/src/log/access_log.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/log/access_log.cc	2017-07-02 20:41:18.000000000 +1200
@@ -84,7 +84,7 @@
         xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN);
 
     for (; log; log = log->next) {
-        if (log->aclList && checklist && checklist->fastCheck(log->aclList) != ACCESS_ALLOWED)
+        if (log->aclList && checklist && !checklist->fastCheck(log->aclList).allowed())
             continue;
 
         // The special-case "none" type has no logfile object set
diff -u -r -N squid-4.0.20/src/log/Config.cc squid-4.0.21/src/log/Config.cc
--- squid-4.0.20/src/log/Config.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/log/Config.cc	2017-07-02 20:41:18.000000000 +1200
@@ -20,7 +20,27 @@
     char *name, *def;
 
     if (!(name = ConfigParser::NextToken())) {
+        debugs(3, DBG_CRITICAL, "FATAL: missing logformat details in " << cfg_filename << " line " << config_lineno);
         self_destruct();
+        return;
+    }
+
+    // check for re-definition of built-in formats
+    if (strcmp(name, "squid") == 0 ||
+            strcmp(name, "common") == 0 ||
+            strcmp(name, "combined") == 0 ||
+            strcmp(name, "useragent") == 0 ||
+            strcmp(name, "referrer") == 0) {
+        debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: logformat " << name << " is already defined. Ignoring.");
+        return;
+    }
+
+    // check for re-definition of custom formats
+    for (auto i = logformats; i ; i = i->next) {
+        if (strcmp(i->name, name) == 0) {
+            debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: logformat " << name << " is already defined. Ignoring.");
+            return;
+        }
     }
 
     ::Format::Format *nlf = new ::Format::Format(name);
diff -u -r -N squid-4.0.20/src/log/DB/log_db_daemon.8 squid-4.0.21/src/log/DB/log_db_daemon.8
--- squid-4.0.20/src/log/DB/log_db_daemon.8	2017-06-02 09:57:57.000000000 +1200
+++ squid-4.0.21/src/log/DB/log_db_daemon.8	2017-07-02 20:57:36.000000000 +1200
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "LOG_DB_DAEMON 8"
-.TH LOG_DB_DAEMON 8 "2017-06-01" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH LOG_DB_DAEMON 8 "2017-07-02" "perl v5.24.1" "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.20/src/log/DB/Makefile.in squid-4.0.21/src/log/DB/Makefile.in
--- squid-4.0.20/src/log/DB/Makefile.in	2017-06-02 01:00:27.000000000 +1200
+++ squid-4.0.21/src/log/DB/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/log/file/Makefile.in squid-4.0.21/src/log/file/Makefile.in
--- squid-4.0.20/src/log/file/Makefile.in	2017-06-02 01:00:36.000000000 +1200
+++ squid-4.0.21/src/log/file/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/log/Makefile.in squid-4.0.21/src/log/Makefile.in
--- squid-4.0.20/src/log/Makefile.in	2017-06-02 01:00:31.000000000 +1200
+++ squid-4.0.21/src/log/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/main.cc squid-4.0.21/src/main.cc
--- squid-4.0.20/src/main.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/main.cc	2017-07-02 20:41:18.000000000 +1200
@@ -10,8 +10,9 @@
 
 #include "squid.h"
 #include "AccessLogEntry.h"
-#include "acl/Acl.h"
+//#include "acl/Acl.h"
 #include "acl/Asn.h"
+#include "acl/forward.h"
 #include "anyp/UriScheme.h"
 #include "AuthReg.h"
 #include "base/RunnersRegistry.h"
@@ -387,9 +388,9 @@
             "       -C        Do not catch fatal signals.\n"
             "       -D        OBSOLETE. Scheduled for removal.\n"
             "       -F        Don't serve any requests until store is rebuilt.\n"
-            "       -N        No daemon mode.\n"
+            "       -N        Master process runs in foreground and is a worker. No kids.\n"
             "       --foreground\n"
-            "                 Parent process does not exit until its children have finished.\n"
+            "                 Master process runs in foreground and creates worker kids.\n"
 #if USE_WIN32_SERVICE
             "       -O options\n"
             "                 Set Windows Service Command line options in Registry.\n"
@@ -1339,6 +1340,39 @@
     configured_once = 1;
 }
 
+/// describes active (i.e., thrown but not yet handled) exception
+static std::ostream &
+CurrentException(std::ostream &os)
+{
+    if (std::current_exception()) {
+        try {
+            throw; // re-throw to recognize the exception type
+        }
+        catch (const std::exception &ex) {
+            os << ex.what();
+        }
+        catch (...) {
+            os << "[unknown exception type]";
+        }
+    } else {
+        os << "[no active exception]";
+    }
+    return os;
+}
+
+static void
+OnTerminate()
+{
+    // ignore recursive calls to avoid termination loops
+    static bool terminating = false;
+    if (terminating)
+        return;
+    terminating = true;
+
+    debugs(1, DBG_CRITICAL, "FATAL: Dying from an exception handling failure; exception: " << CurrentException);
+    abort();
+}
+
 /// unsafe main routine -- may throw
 int SquidMain(int argc, char **argv);
 /// unsafe main routine wrapper to catch exceptions
@@ -1372,12 +1406,15 @@
 static int
 SquidMainSafe(int argc, char **argv)
 {
+    (void)std::set_terminate(&OnTerminate);
+    // XXX: This top-level catch works great for startup, but, during runtime,
+    // it erases valuable stack info. TODO: Let stack-preserving OnTerminate()
+    // handle FATAL runtime errors by splitting main code into protected
+    // startup, unprotected runtime, and protected termination sections!
     try {
         return SquidMain(argc, argv);
-    } catch (const std::exception &e) {
-        debugs(1, DBG_CRITICAL, "FATAL: " << e.what());
     } catch (...) {
-        debugs(1, DBG_CRITICAL, "FATAL: dying from an unhandled exception.");
+        debugs(1, DBG_CRITICAL, "FATAL: " << CurrentException);
     }
     return -1; // TODO: return EXIT_FAILURE instead
 }
@@ -1521,6 +1558,7 @@
 
         /* we may want the parsing process to set this up in the future */
         Store::Init();
+        Acl::Init();
         Auth::Init();      /* required for config parsing. NOP if !USE_AUTH */
         Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
 
@@ -1762,12 +1800,29 @@
     return (DebugSignal > 0 || RotateSignal > 0 || ReconfigureSignal > 0 || ShutdownSignal > 0);
 }
 
+#if !_SQUID_WINDOWS_
+/// makes the caller a daemon process running in the background
+static void
+GoIntoBackground()
+{
+    pid_t pid;
+    if ((pid = fork()) < 0) {
+        int xerrno = errno;
+        syslog(LOG_ALERT, "fork failed: %s", xstrerr(xerrno));
+        // continue anyway, mimicking --foreground mode (XXX?)
+    } else if (pid > 0) {
+        // parent
+        exit(EXIT_SUCCESS);
+    }
+    // child, running as a background daemon (or a failed-to-fork parent)
+}
+#endif /* !_SQUID_WINDOWS_ */
+
 static void
 watch_child(char *argv[])
 {
 #if !_SQUID_WINDOWS_
     char *prog;
-    PidStatus status_f, status;
     pid_t pid;
 #ifdef TIOCNOTTY
 
@@ -1780,21 +1835,12 @@
 
     openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
 
-    if ((pid = fork()) < 0) {
-        int xerrno = errno;
-        syslog(LOG_ALERT, "fork failed: %s", xstrerr(xerrno));
-    } else if (pid > 0) {
-        // parent
-        if (opt_foreground) {
-            if (WaitForAnyPid(status_f, 0) < 0) {
-                int xerrno = errno;
-                syslog(LOG_ALERT, "WaitForAnyPid failed: %s", xstrerr(xerrno));
-            }
-        }
-
-        exit(0);
-    }
+    if (!opt_foreground)
+        GoIntoBackground();
 
+    // TODO: Fails with --foreground if the calling process is process group
+    //       leader, which is always (?) the case. Should probably moved to
+    //       GoIntoBackground and executed only after successfully forking
     if (setsid() < 0) {
         int xerrno = errno;
         syslog(LOG_ALERT, "setsid failed: %s", xstrerr(xerrno));
@@ -1904,6 +1950,7 @@
         int waitFlag = 0;
         if (masterSignaled())
             waitFlag = WNOHANG;
+        PidStatus status;
         pid = WaitForAnyPid(status, waitFlag);
 
         // check for a stopped kid
diff -u -r -N squid-4.0.20/src/Makefile.am squid-4.0.21/src/Makefile.am
--- squid-4.0.20/src/Makefile.am	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/Makefile.am	2017-07-02 20:41:18.000000000 +1200
@@ -483,6 +483,8 @@
 	whois.cc \
 	wordlist.h \
 	wordlist.cc \
+	XactionInitiator.h \
+	XactionInitiator.cc \
 	$(WIN32_SOURCE) \
 	$(WINSVC_SOURCE)
 
diff -u -r -N squid-4.0.20/src/Makefile.in squid-4.0.21/src/Makefile.in
--- squid-4.0.20/src/Makefile.in	2017-06-02 00:54:20.000000000 +1200
+++ squid-4.0.21/src/Makefile.in	2017-07-02 20:41:24.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -309,8 +309,9 @@
 	MemStore.h time.cc TimeOrTag.h tools.h tools.cc tunnel.cc \
 	typedefs.h unlinkd.h unlinkd.cc url.cc URL.h urn.h urn.cc \
 	wccp.h wccp.cc wccp2.h wccp2.cc whois.h whois.cc wordlist.h \
-	wordlist.cc win32.cc WinSvc.cc LoadableModule.h \
-	LoadableModule.cc LoadableModules.h LoadableModules.cc
+	wordlist.cc XactionInitiator.h XactionInitiator.cc win32.cc \
+	WinSvc.cc LoadableModule.h LoadableModule.cc LoadableModules.h \
+	LoadableModules.cc
 am__objects_1 = AclRegs.$(OBJEXT) AuthReg.$(OBJEXT)
 am__objects_2 = delay_pools.$(OBJEXT) DelayId.$(OBJEXT) \
 	DelayBucket.$(OBJEXT) DelayConfig.$(OBJEXT) \
@@ -383,8 +384,8 @@
 	MemStore.$(OBJEXT) time.$(OBJEXT) tools.$(OBJEXT) \
 	tunnel.$(OBJEXT) $(am__objects_12) url.$(OBJEXT) urn.$(OBJEXT) \
 	wccp.$(OBJEXT) wccp2.$(OBJEXT) whois.$(OBJEXT) \
-	wordlist.$(OBJEXT) $(am__objects_13) $(am__objects_14) \
-	$(am__objects_16)
+	wordlist.$(OBJEXT) XactionInitiator.$(OBJEXT) \
+	$(am__objects_13) $(am__objects_14) $(am__objects_16)
 am__EXTRA_squid_SOURCES_DIST = ConfigOption.h CommonPool.h \
 	CompositePoolNode.h delay_pools.cc DelayId.cc DelayId.h \
 	DelayIdComposite.h DelayBucket.cc DelayBucket.h DelayConfig.cc \
@@ -2905,8 +2906,8 @@
 	MemStore.cc MemStore.h time.cc TimeOrTag.h tools.h tools.cc \
 	tunnel.cc typedefs.h $(UNLINKDSOURCE) url.cc URL.h urn.h \
 	urn.cc wccp.h wccp.cc wccp2.h wccp2.cc whois.h whois.cc \
-	wordlist.h wordlist.cc $(WIN32_SOURCE) $(WINSVC_SOURCE) \
-	$(am__append_9)
+	wordlist.h wordlist.cc XactionInitiator.h XactionInitiator.cc \
+	$(WIN32_SOURCE) $(WINSVC_SOURCE) $(am__append_9)
 EXTRA_squid_SOURCES = \
 	$(all_AUTHMODULES) \
 	ConfigOption.h \
@@ -6616,6 +6617,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/String.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Transients.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WinSvc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XactionInitiator.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache_cf.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache_manager.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/carp.Po@am__quote@
diff -u -r -N squid-4.0.20/src/MasterXaction.h squid-4.0.21/src/MasterXaction.h
--- squid-4.0.20/src/MasterXaction.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/MasterXaction.h	2017-07-02 20:41:18.000000000 +1200
@@ -10,9 +10,12 @@
 #define SQUID_SRC_MASTERXACTION_H
 
 #include "anyp/forward.h"
+#include "anyp/PortCfg.h"
 #include "base/InstanceId.h"
 #include "base/Lock.h"
+#include "base/RefCount.h"
 #include "comm/forward.h"
+#include "XactionInitiator.h"
 
 /** Master transaction details.
  *
@@ -38,6 +41,8 @@
 public:
     typedef RefCount<MasterXaction> Pointer;
 
+    explicit MasterXaction(const XactionInitiator anInitiator) : initiator(anInitiator) {};
+
     /// transaction ID.
     InstanceId<MasterXaction> id;
 
@@ -47,6 +52,9 @@
     /// the client TCP connection which originated this transaction
     Comm::ConnectionPointer tcpClient;
 
+    /// the initiator of this transaction
+    XactionInitiator initiator;
+
     // TODO: add state from other Jobs in the transaction
 };
 
diff -u -r -N squid-4.0.20/src/mem/Makefile.in squid-4.0.21/src/mem/Makefile.in
--- squid-4.0.20/src/mem/Makefile.in	2017-06-02 01:00:44.000000000 +1200
+++ squid-4.0.21/src/mem/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/MemStore.cc squid-4.0.21/src/MemStore.cc
--- squid-4.0.20/src/MemStore.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/MemStore.cc	2017-07-02 20:41:18.000000000 +1200
@@ -474,7 +474,7 @@
     e.ping_status = PING_NONE;
 
     EBIT_CLR(e.flags, RELEASE_REQUEST);
-    EBIT_CLR(e.flags, KEY_PRIVATE);
+    e.clearPrivate();
     EBIT_SET(e.flags, ENTRY_VALIDATED);
 
     MemObject::MemCache &mc = e.mem_obj->memCache;
diff -u -r -N squid-4.0.20/src/mgr/Forwarder.cc squid-4.0.21/src/mgr/Forwarder.cc
--- squid-4.0.20/src/mgr/Forwarder.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/mgr/Forwarder.cc	2017-07-02 20:41:18.000000000 +1200
@@ -102,17 +102,6 @@
     mustStop("commClosed");
 }
 
-/// called when Coordinator starts processing the request
-void
-Mgr::Forwarder::handleRemoteAck()
-{
-    Ipc::Forwarder::handleRemoteAck();
-
-    Must(entry != NULL);
-    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
-    entry->complete();
-}
-
 /// send error page
 void
 Mgr::Forwarder::sendError(ErrorState *error)
diff -u -r -N squid-4.0.20/src/mgr/Forwarder.h squid-4.0.21/src/mgr/Forwarder.h
--- squid-4.0.20/src/mgr/Forwarder.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/mgr/Forwarder.h	2017-07-02 20:41:18.000000000 +1200
@@ -42,7 +42,6 @@
     virtual void handleError();
     virtual void handleTimeout();
     virtual void handleException(const std::exception& e);
-    virtual void handleRemoteAck();
 
 private:
     void noteCommClosed(const CommCloseCbParams& params);
diff -u -r -N squid-4.0.20/src/mgr/Inquirer.cc squid-4.0.21/src/mgr/Inquirer.cc
--- squid-4.0.20/src/mgr/Inquirer.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/mgr/Inquirer.cc	2017-07-02 20:41:18.000000000 +1200
@@ -76,7 +76,8 @@
     if (strands.empty()) {
         LOCAL_ARRAY(char, url, MAX_URL);
         snprintf(url, MAX_URL, "%s", aggrAction->command().params.httpUri.termedBuf());
-        HttpRequest *req = HttpRequest::CreateFromUrl(url);
+        const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initIpc);
+        HttpRequest *req = HttpRequest::FromUrl(url, mx);
         ErrorState err(ERR_INVALID_URL, Http::scNotFound, req);
         std::unique_ptr<HttpReply> reply(err.BuildHttpReply());
         replyBuf.reset(reply->pack());
diff -u -r -N squid-4.0.20/src/mgr/Makefile.in squid-4.0.21/src/mgr/Makefile.in
--- squid-4.0.20/src/mgr/Makefile.in	2017-06-02 01:00:48.000000000 +1200
+++ squid-4.0.21/src/mgr/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/mime.cc squid-4.0.21/src/mime.cc
--- squid-4.0.20/src/mime.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/mime.cc	2017-07-02 20:41:18.000000000 +1200
@@ -402,7 +402,8 @@
     EBIT_SET(e->flags, ENTRY_SPECIAL);
     e->setPublicKey();
     e->buffer();
-    HttpRequest *r = HttpRequest::CreateFromUrl(url_);
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initIcon);
+    HttpRequest *r = HttpRequest::FromUrl(url_, mx);
 
     if (NULL == r)
         fatalf("mimeLoadIcon: cannot parse internal URL: %s", url_);
diff -u -r -N squid-4.0.20/src/neighbors.cc squid-4.0.21/src/neighbors.cc
--- squid-4.0.20/src/neighbors.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/neighbors.cc	2017-07-02 20:41:18.000000000 +1200
@@ -168,7 +168,7 @@
 
     ACLFilledChecklist checklist(p->access, request, NULL);
 
-    return (checklist.fastCheck() == ACCESS_ALLOWED);
+    return checklist.fastCheck().allowed();
 }
 
 /* Return TRUE if it is okay to send an ICP request to this CachePeer.   */
@@ -1382,7 +1382,8 @@
     p->in_addr.toUrl(url+7, MAX_URL -8 );
     strcat(url, "/");
     fake = storeCreateEntry(url, url, RequestFlags(), Http::METHOD_GET);
-    HttpRequest *req = HttpRequest::CreateFromUrl(url);
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initPeerMcast);
+    HttpRequest *req = HttpRequest::FromUrl(url, mx);
     psstate = new ps_state;
     psstate->request = req;
     HTTPMSGLOCK(psstate->request);
diff -u -r -N squid-4.0.20/src/Notes.cc squid-4.0.21/src/Notes.cc
--- squid-4.0.20/src/Notes.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/Notes.cc	2017-07-02 20:41:18.000000000 +1200
@@ -47,10 +47,10 @@
         HTTPMSGLOCK(ch.reply);
 
     for (VLI i = values.begin(); i != values.end(); ++i ) {
-        const int ret= ch.fastCheck((*i)->aclList);
+        const auto ret= ch.fastCheck((*i)->aclList);
         debugs(93, 5, HERE << "Check for header name: " << key << ": " << (*i)->value
                <<", HttpRequest: " << request << " HttpReply: " << reply << " matched: " << ret);
-        if (ret == ACCESS_ALLOWED) {
+        if (ret.allowed()) {
             if (al != NULL && (*i)->valueFormat != NULL) {
                 static MemBuf mb;
                 mb.reset();
diff -u -r -N squid-4.0.20/src/parser/Makefile.in squid-4.0.21/src/parser/Makefile.in
--- squid-4.0.20/src/parser/Makefile.in	2017-06-02 01:00:53.000000000 +1200
+++ squid-4.0.21/src/parser/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/peer_digest.cc squid-4.0.21/src/peer_digest.cc
--- squid-4.0.20/src/peer_digest.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/peer_digest.cc	2017-07-02 20:41:18.000000000 +1200
@@ -319,7 +319,8 @@
     else
         url = xstrdup(internalRemoteUri(p->host, p->http_port, "/squid-internal-periodic/", SBuf(StoreDigestFileName)));
 
-    req = HttpRequest::CreateFromUrl(url);
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initCacheDigest);
+    req = HttpRequest::FromUrl(url, mx);
 
     assert(req);
 
diff -u -r -N squid-4.0.20/src/PeerPoolMgr.cc squid-4.0.21/src/PeerPoolMgr.cc
--- squid-4.0.20/src/PeerPoolMgr.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/PeerPoolMgr.cc	2017-07-02 20:41:18.000000000 +1200
@@ -18,6 +18,7 @@
 #include "FwdState.h"
 #include "globals.h"
 #include "HttpRequest.h"
+#include "MasterXaction.h"
 #include "neighbors.h"
 #include "pconn.h"
 #include "PeerPoolMgr.h"
@@ -59,9 +60,10 @@
 {
     AsyncJob::start();
 
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initPeerPool);
     // 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, "http", "*");
+    request = new HttpRequest(Http::METHOD_OPTIONS, AnyP::PROTO_HTTP, "http", "*", mx);
     request->url.host(peer->host);
 
     checkpoint("peer initialized");
diff -u -r -N squid-4.0.20/src/redirect.cc squid-4.0.21/src/redirect.cc
--- squid-4.0.20/src/redirect.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/redirect.cc	2017-07-02 20:41:18.000000000 +1200
@@ -108,9 +108,9 @@
             // if we still have anything in other() after all that
             // parse it into status=, url= and rewrite-url= keys
             if (replySize) {
-                /* 2012-06-28: This cast is due to urlParse() truncating too-long URLs itself.
+                /* 2012-06-28: This cast is due to URL::parse() truncating too-long URLs itself.
                  * At this point altering the helper buffer in that way is not harmful, but annoying.
-                 * When Bug 1961 is resolved and urlParse has a const API, this needs to die.
+                 * When Bug 1961 is resolved and URL::parse has a const API, this needs to die.
                  */
                 MemBuf replyBuffer;
                 replyBuffer.init(replySize, replySize);
diff -u -r -N squid-4.0.20/src/repl/Makefile.in squid-4.0.21/src/repl/Makefile.in
--- squid-4.0.20/src/repl/Makefile.in	2017-06-02 01:00:57.000000000 +1200
+++ squid-4.0.21/src/repl/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/RequestFlags.h squid-4.0.21/src/RequestFlags.h
--- squid-4.0.20/src/RequestFlags.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/RequestFlags.h	2017-07-02 20:41:18.000000000 +1200
@@ -72,9 +72,6 @@
     bool spoofClientIp = false;
     /** set if the request is internal (\see ClientHttpRequest::flags.internal)*/
     bool internal = false;
-    //XXX this is set in in clientBeginRequest, but never tested.
-    /** set for internally-generated requests */
-    bool internalClient = false;
     /** if set, request to try very hard to keep the connection alive */
     bool mustKeepalive = false;
     /** set if the rquest wants connection oriented auth */
diff -u -r -N squid-4.0.20/src/sbuf/Makefile.in squid-4.0.21/src/sbuf/Makefile.in
--- squid-4.0.20/src/sbuf/Makefile.in	2017-06-02 01:00:59.000000000 +1200
+++ squid-4.0.21/src/sbuf/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/security/cert_generators/file/Makefile.in squid-4.0.21/src/security/cert_generators/file/Makefile.in
--- squid-4.0.20/src/security/cert_generators/file/Makefile.in	2017-06-02 01:01:04.000000000 +1200
+++ squid-4.0.21/src/security/cert_generators/file/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/security/cert_generators/Makefile.in squid-4.0.21/src/security/cert_generators/Makefile.in
--- squid-4.0.20/src/security/cert_generators/Makefile.in	2017-06-02 01:01:03.000000000 +1200
+++ squid-4.0.21/src/security/cert_generators/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/security/cert_validators/fake/Makefile.in squid-4.0.21/src/security/cert_validators/fake/Makefile.in
--- squid-4.0.20/src/security/cert_validators/fake/Makefile.in	2017-06-02 01:01:07.000000000 +1200
+++ squid-4.0.21/src/security/cert_validators/fake/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/security/cert_validators/fake/security_fake_certverify.8 squid-4.0.21/src/security/cert_validators/fake/security_fake_certverify.8
--- squid-4.0.20/src/security/cert_validators/fake/security_fake_certverify.8	2017-06-02 09:59:08.000000000 +1200
+++ squid-4.0.21/src/security/cert_validators/fake/security_fake_certverify.8	2017-07-02 20:57:36.000000000 +1200
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "SECURITY_FAKE_CERTVERIFY 8"
-.TH SECURITY_FAKE_CERTVERIFY 8 "2017-06-01" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH SECURITY_FAKE_CERTVERIFY 8 "2017-07-02" "perl v5.24.1" "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.20/src/security/cert_validators/Makefile.in squid-4.0.21/src/security/cert_validators/Makefile.in
--- squid-4.0.20/src/security/cert_validators/Makefile.in	2017-06-02 01:01:05.000000000 +1200
+++ squid-4.0.21/src/security/cert_validators/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/security/Makefile.in squid-4.0.21/src/security/Makefile.in
--- squid-4.0.20/src/security/Makefile.in	2017-06-02 01:01:01.000000000 +1200
+++ squid-4.0.21/src/security/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/security/PeerConnector.cc squid-4.0.21/src/security/PeerConnector.cc
--- squid-4.0.20/src/security/PeerConnector.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/security/PeerConnector.cc	2017-07-02 20:41:18.000000000 +1200
@@ -338,7 +338,7 @@
             bool allowed = false;
             if (check) {
                 check->sslErrors = new Security::CertErrors(Security::CertError(i->error_no, i->cert, i->error_depth));
-                if (check->fastCheck() == ACCESS_ALLOWED)
+                if (check->fastCheck().allowed())
                     allowed = true;
             }
             // else the Config.ssl_client.cert_error access list is not defined
@@ -633,7 +633,7 @@
                                       PeerConnectorCertDownloaderDialer(&Security::PeerConnector::certDownloadingDone, this));
 
     const Downloader *csd = (request ? dynamic_cast<const Downloader*>(request->downloader.valid()) : nullptr);
-    Downloader *dl = new Downloader(url, certCallback, csd ? csd->nestedLevel() + 1 : 1);
+    Downloader *dl = new Downloader(url, certCallback, XactionInitiator::initCertFetcher, csd ? csd->nestedLevel() + 1 : 1);
     AsyncJob::Start(dl);
 }
 
diff -u -r -N squid-4.0.20/src/security/Session.cc squid-4.0.21/src/security/Session.cc
--- squid-4.0.20/src/security/Session.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/security/Session.cc	2017-07-02 20:41:18.000000000 +1200
@@ -23,6 +23,11 @@
 #define SSL_SESSION_ID_SIZE 32
 #define SSL_SESSION_MAX_SIZE 10*1024
 
+#if USE_OPENSSL
+static Ipc::MemMap *SessionCache = nullptr;
+static const char *SessionCacheName = "tls_session_cache";
+#endif
+
 #if USE_OPENSSL || USE_GNUTLS
 static int
 tls_read_method(int fd, char *buf, int len)
@@ -274,6 +279,113 @@
     return false;
 }
 
+#if USE_OPENSSL
+static int
+store_session_cb(SSL *ssl, SSL_SESSION *session)
+{
+    if (!SessionCache)
+        return 0;
+
+    debugs(83, 5, "Request to store SSL_SESSION");
+
+    SSL_SESSION_set_timeout(session, Config.SSL.session_ttl);
+
+#if HAVE_LIBSSL_SSL_SESSION_GET_ID
+    unsigned int idlen;
+    const unsigned char *id = SSL_SESSION_get_id(session, &idlen);
+#else
+    unsigned char *id = session->session_id;
+    unsigned int idlen = session->session_id_length;
+#endif
+    // XXX: the other calls [to openForReading()] do not copy the sessionId to a char buffer, does this really have to?
+    unsigned char key[MEMMAP_SLOT_KEY_SIZE];
+    // Session ids are of size 32bytes. They should always fit to a
+    // MemMap::Slot::key
+    assert(idlen <= MEMMAP_SLOT_KEY_SIZE);
+    memset(key, 0, sizeof(key));
+    memcpy(key, id, idlen);
+    int pos;
+    if (auto slotW = SessionCache->openForWriting(static_cast<const cache_key*>(key), pos)) {
+        int lenRequired = i2d_SSL_SESSION(session, nullptr);
+        if (lenRequired <  MEMMAP_SLOT_DATA_SIZE) {
+            unsigned char *p = static_cast<unsigned char *>(slotW->p);
+            lenRequired = i2d_SSL_SESSION(session, &p);
+            slotW->set(key, nullptr, lenRequired, squid_curtime + Config.SSL.session_ttl);
+        }
+        SessionCache->closeForWriting(pos);
+        debugs(83, 5, "wrote an SSL_SESSION entry of size " << lenRequired << " at pos " << pos);
+    }
+    return 0;
+}
+
+static void
+remove_session_cb(SSL_CTX *, SSL_SESSION *sessionID)
+{
+    if (!SessionCache)
+        return;
+
+    debugs(83, 5, "Request to remove corrupted or not valid SSL_SESSION");
+    int pos;
+    if (SessionCache->openForReading(reinterpret_cast<const cache_key*>(sessionID), pos)) {
+        SessionCache->closeForReading(pos);
+        // TODO:
+        // What if we are not able to remove the session?
+        // Maybe schedule a job to remove it later?
+        // For now we just have an invalid entry in cache until will be expired
+        // The OpenSSL library will reject it when we try to use it
+        SessionCache->free(pos);
+    }
+}
+
+static SSL_SESSION *
+#if SQUID_USE_CONST_SSL_SESSION_CBID
+get_session_cb(SSL *, const unsigned char *sessionID, int len, int *copy)
+#else
+get_session_cb(SSL *, unsigned char *sessionID, int len, int *copy)
+#endif
+{
+    if (!SessionCache)
+        return nullptr;
+
+    const unsigned int *p = reinterpret_cast<const unsigned int *>(sessionID);
+    debugs(83, 5, "Request to search for SSL_SESSION of len: " <<
+           len << p[0] << ":" << p[1]);
+
+    SSL_SESSION *session = nullptr;
+    int pos;
+    if (const auto slot = SessionCache->openForReading(static_cast<const cache_key*>(sessionID), pos)) {
+        if (slot->expire > squid_curtime) {
+            const unsigned char *ptr = slot->p;
+            session = d2i_SSL_SESSION(nullptr, &ptr, slot->pSize);
+            debugs(83, 5, "SSL_SESSION retrieved from cache at pos " << pos);
+        } else
+            debugs(83, 5, "SSL_SESSION in cache expired");
+        SessionCache->closeForReading(pos);
+    }
+
+    if (!session)
+        debugs(83, 5, "Failed to retrieve SSL_SESSION from cache\n");
+
+    // With the parameter copy the callback can require the SSL engine
+    // to increment the reference count of the SSL_SESSION object, Normally
+    // the reference count is not incremented and therefore the session must
+    // not be explicitly freed with SSL_SESSION_free(3).
+    *copy = 0;
+    return session;
+}
+
+void
+Security::SetSessionCacheCallbacks(Security::ContextPointer &ctx)
+{
+    if (SessionCache) {
+        SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL);
+        SSL_CTX_sess_set_new_cb(ctx.get(), store_session_cb);
+        SSL_CTX_sess_set_remove_cb(ctx.get(), remove_session_cb);
+        SSL_CTX_sess_set_get_cb(ctx.get(), get_session_cb);
+    }
+}
+#endif /* USE_OPENSSL */
+
 void
 initializeSessionCache()
 {
@@ -285,15 +397,15 @@
 
     int configuredItems = ::Config.SSL.sessionCacheSize / sizeof(Ipc::MemMap::Slot);
     if (IamWorkerProcess() && configuredItems)
-        Ssl::SessionCache = new Ipc::MemMap(Ssl::SessionCacheName);
+        SessionCache = new Ipc::MemMap(SessionCacheName);
     else {
-        Ssl::SessionCache = nullptr;
+        SessionCache = nullptr;
         return;
     }
 
     for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
         if (s->secure.staticContext)
-            Ssl::SetSessionCallbacks(s->secure.staticContext);
+            Security::SetSessionCacheCallbacks(s->secure.staticContext);
     }
 #endif
 }
@@ -319,8 +431,8 @@
 void
 SharedSessionCacheRr::useConfig()
 {
-#if USE_OPENSSL // while Ssl:: bits in use
-    if (Ssl::SessionCache || !isTlsServer()) //no need to configure ssl session cache.
+#if USE_OPENSSL
+    if (SessionCache || !isTlsServer()) // no need to configure SSL_SESSION* cache.
         return;
 
     Ipc::Mem::RegisteredRunner::useConfig();
@@ -331,19 +443,19 @@
 void
 SharedSessionCacheRr::create()
 {
-    if (!isTlsServer()) //no need to configure ssl session cache.
+    if (!isTlsServer()) // no need to configure SSL_SESSION* cache.
         return;
 
-#if USE_OPENSSL // while Ssl:: bits in use
+#if USE_OPENSSL
     if (int items = Config.SSL.sessionCacheSize / sizeof(Ipc::MemMap::Slot))
-        owner = Ipc::MemMap::Init(Ssl::SessionCacheName, items);
+        owner = Ipc::MemMap::Init(SessionCacheName, items);
 #endif
 }
 
 SharedSessionCacheRr::~SharedSessionCacheRr()
 {
     // XXX: Enable after testing to reduce at-exit memory "leaks".
-    // delete Ssl::SessionCache;
+    // delete SessionCache;
 
     delete owner;
 }
diff -u -r -N squid-4.0.20/src/security/Session.h squid-4.0.21/src/security/Session.h
--- squid-4.0.20/src/security/Session.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/security/Session.h	2017-07-02 20:41:18.000000000 +1200
@@ -78,6 +78,10 @@
 void SetSessionResumeData(const Security::SessionPointer &, const Security::SessionStatePointer &);
 
 #if USE_OPENSSL
+// TODO: remove from public API. It is only public because of configureSslContext() in ssl/support.cc
+/// Setup the given TLS context with callbacks used to manage the session cache
+void SetSessionCacheCallbacks(Security::ContextPointer &);
+
 /// Helper function to retrieve a (non-locked) ContextPointer from a SessionPointer
 inline Security::ContextPointer
 GetFrom(Security::SessionPointer &s)
diff -u -r -N squid-4.0.20/src/servers/FtpServer.cc squid-4.0.21/src/servers/FtpServer.cc
--- squid-4.0.20/src/servers/FtpServer.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/servers/FtpServer.cc	2017-07-02 20:41:18.000000000 +1200
@@ -303,12 +303,8 @@
     Must(http != NULL);
     HttpRequest *const request = http->request;
     Must(request != NULL);
-
-    // this is not an idle connection, so we do not want I/O monitoring
-    const bool monitor = false;
-
     // make FTP peer connection exclusive to our request
-    pinConnection(conn, request, conn->getPeer(), false, monitor);
+    pinBusyConnection(conn, request);
 }
 
 void
@@ -728,7 +724,9 @@
                        &params : NULL;
     calcUri(path);
     char *newUri = xstrdup(uri.c_str());
-    HttpRequest *const request = HttpRequest::CreateFromUrl(newUri, method);
+    MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient);
+    mx->tcpClient = clientConnection;
+    HttpRequest *const request = HttpRequest::FromUrl(newUri, mx, method);
     if (!request) {
         debugs(33, 5, "Invalid FTP URL: " << uri);
         uri.clear();
@@ -1545,7 +1543,7 @@
         ClientHttpRequest *http = pipeline.front()->http;
         HttpRequest *request = http->request;
         ACLFilledChecklist bodyContinuationCheck(Config.accessList.forceRequestBodyContinuation, request, NULL);
-        if (bodyContinuationCheck.fastCheck() == ACCESS_ALLOWED) {
+        if (bodyContinuationCheck.fastCheck().allowed()) {
             request->forcedBodyContinuation = true;
             if (checkDataConnPost()) {
                 // Write control Msg
diff -u -r -N squid-4.0.20/src/servers/Http1Server.cc squid-4.0.21/src/servers/Http1Server.cc
--- squid-4.0.20/src/servers/Http1Server.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/servers/Http1Server.cc	2017-07-02 20:41:18.000000000 +1200
@@ -132,7 +132,9 @@
         return false;
     }
 
-    if ((request = HttpRequest::CreateFromUrl(http->uri, parser_->method())) == NULL) {
+    MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient);
+    mx->tcpClient = clientConnection;
+    if ((request = HttpRequest::FromUrl(http->uri, mx, parser_->method())) == NULL) {
         debugs(33, 5, "Invalid URL: " << http->uri);
         // setLogUri should called before repContext->setReplyToError
         setLogUri(http, http->uri, true);
@@ -248,7 +250,7 @@
 
         if (Config.accessList.forceRequestBodyContinuation) {
             ACLFilledChecklist bodyContinuationCheck(Config.accessList.forceRequestBodyContinuation, request.getRaw(), NULL);
-            if (bodyContinuationCheck.fastCheck() == ACCESS_ALLOWED) {
+            if (bodyContinuationCheck.fastCheck().allowed()) {
                 debugs(33, 5, "Body Continuation forced");
                 request->forcedBodyContinuation = true;
                 //sendControlMsg
diff -u -r -N squid-4.0.20/src/servers/Makefile.in squid-4.0.21/src/servers/Makefile.in
--- squid-4.0.20/src/servers/Makefile.in	2017-06-02 01:01:09.000000000 +1200
+++ squid-4.0.21/src/servers/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/servers/Server.h squid-4.0.21/src/servers/Server.h
--- squid-4.0.20/src/servers/Server.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/servers/Server.h	2017-07-02 20:41:18.000000000 +1200
@@ -19,6 +19,7 @@
 #include "CommCalls.h"
 #include "Pipeline.h"
 #include "sbuf/SBuf.h"
+#include "servers/forward.h"
 
 /**
  * Common base for all Server classes used
@@ -27,7 +28,7 @@
 class Server : virtual public AsyncJob, public BodyProducer
 {
 public:
-    Server(const MasterXaction::Pointer &xact);
+    Server(const MasterXactionPointer &xact);
     virtual ~Server() {}
 
     /* AsyncJob API */
diff -u -r -N squid-4.0.20/src/snmp/Makefile.in squid-4.0.21/src/snmp/Makefile.in
--- squid-4.0.20/src/snmp/Makefile.in	2017-06-02 01:01:11.000000000 +1200
+++ squid-4.0.21/src/snmp/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/snmp_core.cc squid-4.0.21/src/snmp_core.cc
--- squid-4.0.20/src/snmp_core.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/snmp_core.cc	2017-07-02 20:41:18.000000000 +1200
@@ -383,7 +383,6 @@
     u_char *Community;
     u_char *buf = rq->buf;
     int len = rq->len;
-    allow_t allow = ACCESS_DENIED;
 
     if (!Config.accessList.snmp) {
         debugs(49, DBG_IMPORTANT, "WARNING: snmp_access not configured. agent query DENIED from : " << rq->from);
@@ -402,9 +401,8 @@
         ACLFilledChecklist checklist(Config.accessList.snmp, NULL, NULL);
         checklist.src_addr = rq->from;
         checklist.snmp_community = (char *) Community;
-        allow = checklist.fastCheck();
 
-        if (allow == ACCESS_ALLOWED && (snmp_coexist_V2toV1(PDU))) {
+        if (checklist.fastCheck().allowed() && (snmp_coexist_V2toV1(PDU))) {
             rq->community = Community;
             rq->PDU = PDU;
             debugs(49, 5, "snmpAgentParse: reqid=[" << PDU->reqid << "]");
@@ -1130,51 +1128,9 @@
         addr = i6addr;
 }
 
-/* SNMP checklists */
-#include "acl/Strategised.h"
-#include "acl/Strategy.h"
-#include "acl/StringData.h"
-
-class ACLSNMPCommunityStrategy : public ACLStrategy<char const *>
-{
-
-public:
-    virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
-    static ACLSNMPCommunityStrategy *Instance();
-    /* Not implemented to prevent copies of the instance. */
-    /* Not private to prevent brain dead g++ warnings about
-     * private constructors with no friends */
-    ACLSNMPCommunityStrategy(ACLSNMPCommunityStrategy const &);
-
-private:
-    static ACLSNMPCommunityStrategy Instance_;
-    ACLSNMPCommunityStrategy() {}
-
-    ACLSNMPCommunityStrategy&operator=(ACLSNMPCommunityStrategy const &);
-};
-
-class ACLSNMPCommunity
-{
-
-private:
-    static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<char const *> RegistryEntry_;
-};
-
-ACL::Prototype ACLSNMPCommunity::RegistryProtoype(&ACLSNMPCommunity::RegistryEntry_, "snmp_community");
-ACLStrategised<char const *> ACLSNMPCommunity::RegistryEntry_(new ACLStringData, ACLSNMPCommunityStrategy::Instance(), "snmp_community");
-
 int
-ACLSNMPCommunityStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
+ACLSNMPCommunityStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
     return data->match (checklist->snmp_community);
 }
 
-ACLSNMPCommunityStrategy *
-ACLSNMPCommunityStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLSNMPCommunityStrategy ACLSNMPCommunityStrategy::Instance_;
-
diff -u -r -N squid-4.0.20/src/snmp_core.h squid-4.0.21/src/snmp_core.h
--- squid-4.0.20/src/snmp_core.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/snmp_core.h	2017-07-02 20:41:18.000000000 +1200
@@ -11,6 +11,7 @@
 #ifndef SQUID_SNMP_CORE_H
 #define SQUID_SNMP_CORE_H
 
+#include "acl/Strategy.h"
 #include "cache_snmp.h"
 #include "comm/forward.h"
 #include "ip/forward.h"
@@ -51,5 +52,11 @@
 void addr2oid(Ip::Address &addr, oid *Dest);
 void oid2addr(oid *Dest, Ip::Address &addr, u_int code);
 
+class ACLSNMPCommunityStrategy: public ACLStrategy<char const *>
+{
+public:
+    virtual int match (ACLData<MatchType> *&data, ACLFilledChecklist *checklist) override;
+};
+
 #endif /* SQUID_SNMP_CORE_H */
 
diff -u -r -N squid-4.0.20/src/squid.8.in squid-4.0.21/src/squid.8.in
--- squid-4.0.20/src/squid.8.in	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/squid.8.in	2017-07-02 20:41:18.000000000 +1200
@@ -271,11 +271,11 @@
 .SH SEE ALSO
 .if !'po4a'hide' .B cachemgr.cgi "(8), "
 .if !'po4a'hide' .B squidclient "(1), "
-.if !'po4a'hide' .B pam_auth "(8), "
-.if !'po4a'hide' .B squid_ldap_auth "(8), "
-.if !'po4a'hide' .B squid_ldap_group "(8), "
+.if !'po4a'hide' .B basic_pam_auth "(8), "
+.if !'po4a'hide' .B basic_ldap_auth "(8), "
+.if !'po4a'hide' .B ext_ldap_group_acl "(8), "
 .if !'po4a'hide' .B ext_session_acl "(8), "
-.if !'po4a'hide' .B squid_unix_group "(8), "
+.if !'po4a'hide' .B ext_unix_group_acl "(8), "
 .br
 The Squid FAQ wiki
 .if !'po4a'hide' http://wiki.squid-cache.org/SquidFaq
diff -u -r -N squid-4.0.20/src/ssl/helper.cc squid-4.0.21/src/ssl/helper.cc
--- squid-4.0.20/src/ssl/helper.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/ssl/helper.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,13 +7,13 @@
  */
 
 #include "squid.h"
-#include "../helper.h"
 #include "anyp/PortCfg.h"
 #include "fs_io.h"
 #include "helper/Reply.h"
 #include "SquidConfig.h"
 #include "SquidString.h"
 #include "SquidTime.h"
+#include "src/helper.h"
 #include "ssl/cert_validate_message.h"
 #include "ssl/Config.h"
 #include "ssl/helper.h"
@@ -22,6 +22,51 @@
 Ssl::CertValidationHelper::LruCache *Ssl::CertValidationHelper::HelperCache = nullptr;
 
 #if USE_SSL_CRTD
+
+namespace Ssl {
+
+/// Initiator of an Ssl::Helper query.
+class GeneratorRequestor {
+public:
+    GeneratorRequestor(HLPCB *aCallback, void *aData): callback(aCallback), data(aData) {}
+    HLPCB *callback;
+    CallbackData data;
+};
+
+/// A pending Ssl::Helper request, combining the original and collapsed queries.
+class GeneratorRequest {
+    CBDATA_CLASS(GeneratorRequest);
+
+public:
+    /// adds a GeneratorRequestor
+    void emplace(HLPCB *callback, void *data) { requestors.emplace_back(callback, data); }
+
+    SBuf query; ///< Ssl::Helper request message (GeneratorRequests key)
+
+    /// Ssl::Helper request initiators waiting for the same answer (FIFO).
+    typedef std::vector<GeneratorRequestor> GeneratorRequestors;
+    GeneratorRequestors requestors;
+};
+
+/// Ssl::Helper query:GeneratorRequest map
+typedef std::unordered_map<SBuf, GeneratorRequest*> GeneratorRequests;
+
+static void HandleGeneratorReply(void *data, const ::Helper::Reply &reply);
+
+} // namespace Ssl
+
+CBDATA_NAMESPACED_CLASS_INIT(Ssl, GeneratorRequest);
+
+/// prints Ssl::GeneratorRequest for debugging
+static std::ostream &
+operator <<(std::ostream &os, const Ssl::GeneratorRequest &gr)
+{
+    return os << "crtGenRq" << gr.query.id.value << "/" << gr.requestors.size();
+}
+
+/// pending Ssl::Helper requests (to all certificate generator helpers combined)
+static Ssl::GeneratorRequests TheGeneratorRequests;
+
 Ssl::Helper * Ssl::Helper::GetInstance()
 {
     static Ssl::Helper sslHelper;
@@ -82,14 +127,44 @@
 {
     assert(ssl_crtd);
 
-    std::string msg = message.compose();
-    msg += '\n';
-    if (!ssl_crtd->trySubmit(msg.c_str(), callback, data)) {
-        ::Helper::Reply failReply(::Helper::BrokenHelper);
-        failReply.notes.add("message", "error 45 Temporary network problem, please retry later");
-        callback(data, failReply);
+    SBuf rawMessage(message.compose().c_str()); // XXX: helpers cannot use SBuf
+    rawMessage.append("\n", 1);
+
+    const auto pending = TheGeneratorRequests.find(rawMessage);
+    if (pending != TheGeneratorRequests.end()) {
+        pending->second->emplace(callback, data);
+        debugs(83, 5, "collapsed request from " << data << " onto " << *pending->second);
         return;
     }
+
+    GeneratorRequest *request = new GeneratorRequest;
+    request->query = rawMessage;
+    request->emplace(callback, data);
+    TheGeneratorRequests.emplace(request->query, request);
+    debugs(83, 5, "request from " << data << " as " << *request);
+    if (ssl_crtd->trySubmit(request->query.c_str(), HandleGeneratorReply, request))
+        return;
+
+    ::Helper::Reply failReply(::Helper::BrokenHelper);
+    failReply.notes.add("message", "error 45 Temporary network problem, please retry later");
+    HandleGeneratorReply(request, failReply);
+}
+
+/// receives helper response
+static void
+Ssl::HandleGeneratorReply(void *data, const ::Helper::Reply &reply)
+{
+    const std::unique_ptr<Ssl::GeneratorRequest> request(static_cast<Ssl::GeneratorRequest*>(data));
+    assert(request);
+    const auto erased = TheGeneratorRequests.erase(request->query);
+    assert(erased);
+
+    for (auto &requestor: request->requestors) {
+        if (void *cbdata = requestor.data.validDone()) {
+            debugs(83, 5, "to " << cbdata << " in " << *request);
+            requestor.callback(cbdata, reply);
+        }
+    }
 }
 #endif //USE_SSL_CRTD
 
diff -u -r -N squid-4.0.20/src/ssl/Makefile.in squid-4.0.21/src/ssl/Makefile.in
--- squid-4.0.20/src/ssl/Makefile.in	2017-06-02 01:01:13.000000000 +1200
+++ squid-4.0.21/src/ssl/Makefile.in	2017-07-02 20:41:27.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/ssl/PeekingPeerConnector.cc squid-4.0.21/src/ssl/PeekingPeerConnector.cc
--- squid-4.0.20/src/ssl/PeekingPeerConnector.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/ssl/PeekingPeerConnector.cc	2017-07-02 20:41:18.000000000 +1200
@@ -36,7 +36,7 @@
 void
 Ssl::PeekingPeerConnector::checkForPeekAndSpliceDone(allow_t answer)
 {
-    const Ssl::BumpMode finalAction = (answer.code == ACCESS_ALLOWED) ?
+    const Ssl::BumpMode finalAction = answer.allowed() ?
                                       static_cast<Ssl::BumpMode>(answer.kind):
                                       checkForPeekAndSpliceGuess();
     checkForPeekAndSpliceMatched(finalAction);
diff -u -r -N squid-4.0.20/src/ssl/ServerBump.h squid-4.0.21/src/ssl/ServerBump.h
--- squid-4.0.20/src/ssl/ServerBump.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/ssl/ServerBump.h	2017-07-02 20:41:18.000000000 +1200
@@ -47,7 +47,6 @@
         Ssl::BumpMode step3; ///< The SSL bump mode at step3
     } act; ///< bumping actions at various bumping steps
     Ssl::BumpStep step; ///< The SSL bumping step
-    SBuf clientSni; ///< the SSL client SNI name
 
 private:
     Security::SessionPointer serverSession; ///< The TLS session object on server side.
diff -u -r -N squid-4.0.20/src/ssl/support.cc squid-4.0.21/src/ssl/support.cc
--- squid-4.0.20/src/ssl/support.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/ssl/support.cc	2017-07-02 20:41:18.000000000 +1200
@@ -38,9 +38,6 @@
 // TODO: Move ssl_ex_index_* global variables from global.cc here.
 int ssl_ex_index_ssl_untrusted_chain = -1;
 
-Ipc::MemMap *Ssl::SessionCache = NULL;
-const char *Ssl::SessionCacheName = "ssl_session_cache";
-
 static Ssl::CertsIndexedList SquidUntrustedCerts;
 
 const EVP_MD *Ssl::DefaultSignHash = NULL;
@@ -332,7 +329,7 @@
                 assert(!filledCheck->sslErrors);
                 filledCheck->sslErrors = new Security::CertErrors(Security::CertError(error_no, broken_cert));
                 filledCheck->serverCert = peer_cert;
-                if (check->fastCheck() == ACCESS_ALLOWED) {
+                if (check->fastCheck().allowed()) {
                     debugs(83, 3, "bypassing SSL error " << error_no << " in " << buffer);
                     ok = 1;
                 } else {
@@ -472,6 +469,7 @@
 
 #if HAVE_OPENSSL_ENGINE_H
     if (::Config.SSL.ssl_engine) {
+        ENGINE_load_builtin_engines();
         ENGINE *e;
         if (!(e = ENGINE_by_id(::Config.SSL.ssl_engine)))
             fatalf("Unable to find SSL engine '%s'\n", ::Config.SSL.ssl_engine);
@@ -564,7 +562,7 @@
     if (port.secure.parsedFlags & SSL_FLAG_DONT_VERIFY_DOMAIN)
         SSL_CTX_set_ex_data(ctx.get(), ssl_ctx_ex_index_dont_verify_domain, (void *) -1);
 
-    Ssl::SetSessionCallbacks(ctx);
+    Security::SetSessionCacheCallbacks(ctx);
 
     return true;
 }
@@ -1381,113 +1379,5 @@
     return Ssl::generateSslCertificate(untrustedCert, untrustedPkey, certProperties);
 }
 
-static int
-store_session_cb(SSL *ssl, SSL_SESSION *session)
-{
-    if (!Ssl::SessionCache)
-        return 0;
-
-    debugs(83, 5, "Request to store SSL Session ");
-
-    SSL_SESSION_set_timeout(session, Config.SSL.session_ttl);
-
-#if HAVE_LIBSSL_SSL_SESSION_GET_ID
-    unsigned int idlen;
-    const unsigned char *id = SSL_SESSION_get_id(session, &idlen);
-#else
-    unsigned char *id = session->session_id;
-    unsigned int idlen = session->session_id_length;
-#endif
-    unsigned char key[MEMMAP_SLOT_KEY_SIZE];
-    // Session ids are of size 32bytes. They should always fit to a
-    // MemMap::Slot::key
-    assert(idlen <= MEMMAP_SLOT_KEY_SIZE);
-    memset(key, 0, sizeof(key));
-    memcpy(key, id, idlen);
-    int pos;
-    Ipc::MemMap::Slot *slotW = Ssl::SessionCache->openForWriting((const cache_key*)key, pos);
-    if (slotW) {
-        int lenRequired =  i2d_SSL_SESSION(session, NULL);
-        if (lenRequired <  MEMMAP_SLOT_DATA_SIZE) {
-            unsigned char *p = (unsigned char *)slotW->p;
-            lenRequired = i2d_SSL_SESSION(session, &p);
-            slotW->set(key, NULL, lenRequired, squid_curtime + Config.SSL.session_ttl);
-        }
-        Ssl::SessionCache->closeForWriting(pos);
-        debugs(83, 5, "wrote an ssl session entry of size " << lenRequired << " at pos " << pos);
-    }
-    return 0;
-}
-
-static void
-remove_session_cb(SSL_CTX *, SSL_SESSION *sessionID)
-{
-    if (!Ssl::SessionCache)
-        return ;
-
-    debugs(83, 5, "Request to remove corrupted or not valid SSL Session ");
-    int pos;
-    Ipc::MemMap::Slot const *slot = Ssl::SessionCache->openForReading((const cache_key*)sessionID, pos);
-    if (slot == NULL)
-        return;
-    Ssl::SessionCache->closeForReading(pos);
-    // TODO:
-    // What if we are not able to remove the session?
-    // Maybe schedule a job to remove it later?
-    // For now we just have an invalid entry in cache until will be expired
-    // The openSSL will reject it when we try to use it
-    Ssl::SessionCache->free(pos);
-}
-
-static SSL_SESSION *
-#if SQUID_USE_CONST_SSL_SESSION_CBID
-get_session_cb(SSL *, const unsigned char *sessionID, int len, int *copy)
-#else
-get_session_cb(SSL *, unsigned char *sessionID, int len, int *copy)
-#endif
-{
-    if (!Ssl::SessionCache)
-        return NULL;
-
-    SSL_SESSION *session = NULL;
-    const unsigned int *p;
-    p = (unsigned int *)sessionID;
-    debugs(83, 5, "Request to search for SSL Session of len:" <<
-           len << p[0] << ":" << p[1]);
-
-    int pos;
-    Ipc::MemMap::Slot const *slot = Ssl::SessionCache->openForReading((const cache_key*)sessionID, pos);
-    if (slot != NULL) {
-        if (slot->expire > squid_curtime) {
-            const unsigned char *ptr = slot->p;
-            session = d2i_SSL_SESSION(NULL, &ptr, slot->pSize);
-            debugs(83, 5, "Session retrieved from cache at pos " << pos);
-        } else
-            debugs(83, 5, "Session in cache expired");
-        Ssl::SessionCache->closeForReading(pos);
-    }
-
-    if (!session)
-        debugs(83, 5, "Failed to retrieved from cache\n");
-
-    // With the parameter copy the callback can require the SSL engine
-    // to increment the reference count of the SSL_SESSION object, Normally
-    // the reference count is not incremented and therefore the session must
-    // not be explicitly freed with SSL_SESSION_free(3).
-    *copy = 0;
-    return session;
-}
-
-void
-Ssl::SetSessionCallbacks(Security::ContextPointer &ctx)
-{
-    if (Ssl::SessionCache) {
-        SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL);
-        SSL_CTX_sess_set_new_cb(ctx.get(), store_session_cb);
-        SSL_CTX_sess_set_remove_cb(ctx.get(), remove_session_cb);
-        SSL_CTX_sess_set_get_cb(ctx.get(), get_session_cb);
-    }
-}
-
 #endif /* USE_OPENSSL */
 
diff -u -r -N squid-4.0.20/src/ssl/support.h squid-4.0.21/src/ssl/support.h
--- squid-4.0.20/src/ssl/support.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/ssl/support.h	2017-07-02 20:41:18.000000000 +1200
@@ -73,10 +73,6 @@
 class CertValidationResponse;
 typedef RefCount<CertValidationResponse> CertValidationResponsePointer;
 
-void SetSessionCallbacks(Security::ContextPointer &);
-extern Ipc::MemMap *SessionCache;
-extern const char *SessionCacheName;
-
 /// initialize a TLS server context with OpenSSL specific settings
 bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &);
 
diff -u -r -N squid-4.0.20/src/store/id_rewriters/file/Makefile.in squid-4.0.21/src/store/id_rewriters/file/Makefile.in
--- squid-4.0.20/src/store/id_rewriters/file/Makefile.in	2017-06-02 01:01:17.000000000 +1200
+++ squid-4.0.21/src/store/id_rewriters/file/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/store/id_rewriters/file/storeid_file_rewrite.8 squid-4.0.21/src/store/id_rewriters/file/storeid_file_rewrite.8
--- squid-4.0.20/src/store/id_rewriters/file/storeid_file_rewrite.8	2017-06-02 09:54:12.000000000 +1200
+++ squid-4.0.21/src/store/id_rewriters/file/storeid_file_rewrite.8	2017-07-02 20:57:34.000000000 +1200
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "STOREID_FILE_REWRITE 8"
-.TH STOREID_FILE_REWRITE 8 "2017-06-01" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH STOREID_FILE_REWRITE 8 "2017-07-02" "perl v5.24.1" "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
@@ -209,7 +209,7 @@
 Report ideas for new improvements to the \fISquid Developers mailing list <squid\-dev@squid\-cache.org\fR>
 .SH "SEE ALSO"
 .IX Header "SEE ALSO"
-squid (8), \s-1GPL\s0 (7),
+squid (8), \s-1GPL \\fIs0\fR\|(7),
 .PP
 The Squid wiki http://wiki.squid\-cache.org/Features/StoreID
 .PP
diff -u -r -N squid-4.0.20/src/store/id_rewriters/Makefile.in squid-4.0.21/src/store/id_rewriters/Makefile.in
--- squid-4.0.20/src/store/id_rewriters/Makefile.in	2017-06-02 01:01:16.000000000 +1200
+++ squid-4.0.21/src/store/id_rewriters/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/store/Makefile.in squid-4.0.21/src/store/Makefile.in
--- squid-4.0.20/src/store/Makefile.in	2017-06-02 01:01:15.000000000 +1200
+++ squid-4.0.21/src/store/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/src/store.cc squid-4.0.21/src/store.cc
--- squid-4.0.20/src/store.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/store.cc	2017-07-02 20:41:18.000000000 +1200
@@ -147,11 +147,18 @@
 }
 
 void
-StoreEntry::makePrivate()
+StoreEntry::makePrivate(const bool shareable)
 {
     /* This object should never be cached at all */
     expireNow();
-    releaseRequest(); /* delete object when not used */
+    releaseRequest(shareable); /* delete object when not used */
+}
+
+void
+StoreEntry::clearPrivate()
+{
+    EBIT_CLR(flags, KEY_PRIVATE);
+    shareableWhenPrivate = false;
 }
 
 void
@@ -327,7 +334,8 @@
     ping_status(PING_NONE),
     store_status(STORE_PENDING),
     swap_status(SWAPOUT_NONE),
-    lock_count(0)
+    lock_count(0),
+    shareableWhenPrivate(false)
 {
     debugs(20, 5, "StoreEntry constructed, this=" << this);
 }
@@ -463,14 +471,14 @@
 }
 
 void
-StoreEntry::releaseRequest()
+StoreEntry::releaseRequest(const bool shareable)
 {
     if (EBIT_TEST(flags, RELEASE_REQUEST))
         return;
 
     setReleaseFlag(); // makes validToSend() false, preventing future hits
 
-    setPrivateKey();
+    setPrivateKey(shareable);
 }
 
 int
@@ -582,10 +590,14 @@
  * concept'.
  */
 void
-StoreEntry::setPrivateKey()
+StoreEntry::setPrivateKey(const bool shareable)
 {
-    if (key && EBIT_TEST(flags, KEY_PRIVATE))
-        return;                 /* is already private */
+    if (key && EBIT_TEST(flags, KEY_PRIVATE)) {
+        // The entry is already private, but it may be still shareable.
+        if (!shareable)
+            shareableWhenPrivate = false;
+        return;
+    }
 
     if (key) {
         setReleaseFlag(); // will markForUnlink(); all caches/workers will know
@@ -603,6 +615,7 @@
 
     assert(hash_lookup(store_table, newkey) == NULL);
     EBIT_SET(flags, KEY_PRIVATE);
+    shareableWhenPrivate = shareable;
     hashInsert(newkey);
 }
 
@@ -659,14 +672,17 @@
     if (StoreEntry *e2 = (StoreEntry *)hash_lookup(store_table, newkey)) {
         assert(e2 != this);
         debugs(20, 3, "Making old " << *e2 << " private.");
-        e2->setPrivateKey();
-        e2->release();
+
+        // TODO: check whether there is any sense in keeping old entry
+        // shareable here. Leaving it non-shareable for now.
+        e2->setPrivateKey(false);
+        e2->release(false);
     }
 
     if (key)
         hashDelete();
 
-    EBIT_CLR(flags, KEY_PRIVATE);
+    clearPrivate();
 
     hashInsert(newkey);
 
@@ -788,7 +804,7 @@
     e->lock("storeCreateEntry");
 
     if (neighbors_do_private_keys || !flags.hierarchical)
-        e->setPrivateKey();
+        e->setPrivateKey(false);
     else
         e->setPublicKey();
 
@@ -1232,7 +1248,7 @@
 
 /* release an object from a cache */
 void
-StoreEntry::release()
+StoreEntry::release(const bool shareable)
 {
     PROF_start(storeRelease);
     debugs(20, 3, "releasing " << *this << ' ' << getMD5Text());
@@ -1242,7 +1258,7 @@
     if (locked()) {
         expireNow();
         debugs(20, 3, "storeRelease: Only setting RELEASE_REQUEST bit");
-        releaseRequest();
+        releaseRequest(shareable);
         PROF_stop(storeRelease);
         return;
     }
@@ -1252,7 +1268,7 @@
 
         Store::Root().memoryUnlink(*this);
 
-        setPrivateKey();
+        setPrivateKey(shareable);
 
         // lock the entry until rebuilding is done
         lock("storeLateRelease");
@@ -2103,7 +2119,11 @@
         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 (e.shareableWhenPrivate)
+                os << 'H';
+        }
         if (EBIT_TEST(e.flags, KEY_PRIVATE)) os << 'I';
         if (EBIT_TEST(e.flags, ENTRY_FWD_HDR_WAIT)) os << 'W';
         if (EBIT_TEST(e.flags, ENTRY_NEGCACHED)) os << 'N';
diff -u -r -N squid-4.0.20/src/store_digest.cc squid-4.0.21/src/store_digest.cc
--- squid-4.0.20/src/store_digest.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/store_digest.cc	2017-07-02 20:41:18.000000000 +1200
@@ -421,7 +421,8 @@
     assert(e);
     sd_state.rewrite_lock = e;
     debugs(71, 3, "storeDigestRewrite: url: " << url << " key: " << e->getMD5Text());
-    HttpRequest *req = HttpRequest::CreateFromUrl(url);
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initCacheDigest);
+    HttpRequest *req = HttpRequest::FromUrl(url, mx);
     e->mem_obj->request = req;
     HTTPMSGLOCK(e->mem_obj->request);
     /* wait for rebuild (if any) to finish */
diff -u -r -N squid-4.0.20/src/Store.h squid-4.0.21/src/Store.h
--- squid-4.0.20/src/Store.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/Store.h	2017-07-02 20:41:18.000000000 +1200
@@ -83,15 +83,19 @@
 
     void abort();
     void makePublic(const KeyScope keyScope = ksDefault);
-    void makePrivate();
+    void makePrivate(const bool shareable);
+    /// A low-level method just resetting "private key" flags.
+    /// To avoid key inconsistency please use forcePublicKey()
+    /// or similar instead.
+    void clearPrivate();
     void setPublicKey(const KeyScope keyScope = ksDefault);
     /// Resets existing public key to a public key with default scope,
     /// releasing the old default-scope entry (if any).
     /// Does nothing if the existing public key already has default scope.
     void clearPublicKeyScope();
-    void setPrivateKey();
+    void setPrivateKey(const bool shareable);
     void expireNow();
-    void releaseRequest();
+    void releaseRequest(const bool shareable = false);
     void negativeCache();
     void cacheNegatively();     /** \todo argh, why both? */
     void invokeHandlers();
@@ -212,7 +216,13 @@
     /// update last reference timestamp and related Store metadata
     void touch();
 
-    virtual void release();
+    virtual void release(const bool shareable = false);
+
+    /// May the caller commit to treating this [previously locked]
+    /// entry as a cache hit?
+    bool mayStartHitting() const {
+        return !EBIT_TEST(flags, KEY_PRIVATE) || shareableWhenPrivate;
+    }
 
 #if USE_ADAPTATION
     /// call back producer when more buffer space is available
@@ -240,6 +250,13 @@
 
     unsigned short lock_count;      /* Assume < 65536! */
 
+    /// Nobody can find/lock KEY_PRIVATE entries, but some transactions
+    /// (e.g., collapsed requests) find/lock a public entry before it becomes
+    /// private. May such transactions start using the now-private entry
+    /// they previously locked? This member should not affect transactions
+    /// that already started reading from the entry.
+    bool shareableWhenPrivate;
+
 #if USE_ADAPTATION
     /// producer callback registered with deferProducer
     AsyncCall::Pointer deferredProducer;
@@ -247,6 +264,8 @@
 
     bool validLength() const;
     bool hasOneOfEtags(const String &reqETags, const bool allowWeakMatch) const;
+
+    friend std::ostream &operator <<(std::ostream &os, const StoreEntry &e);
 };
 
 std::ostream &operator <<(std::ostream &os, const StoreEntry &e);
diff -u -r -N squid-4.0.20/src/tests/stub_client_side.cc squid-4.0.21/src/tests/stub_client_side.cc
--- squid-4.0.20/src/tests/stub_client_side.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/stub_client_side.cc	2017-07-02 20:41:18.000000000 +1200
@@ -31,7 +31,8 @@
 void ConnStateData::noteBodyConsumerAborted(BodyPipe::Pointer) STUB
 bool ConnStateData::handleReadData() STUB_RETVAL(false)
 bool ConnStateData::handleRequestBodyData() STUB_RETVAL(false)
-void ConnStateData::pinConnection(const Comm::ConnectionPointer &, HttpRequest *, CachePeer *, bool, bool) STUB
+void ConnStateData::pinBusyConnection(const Comm::ConnectionPointer &, const HttpRequest::Pointer &) STUB
+void ConnStateData::notePinnedConnectionBecameIdle(PinnedIdleContext) STUB
 void ConnStateData::unpinConnection(const bool) STUB
 const Comm::ConnectionPointer ConnStateData::validatePinnedConnection(HttpRequest *, const CachePeer *) STUB_RETVAL(NULL)
 void ConnStateData::clientPinnedConnectionClosed(const CommCloseCbParams &) STUB
@@ -40,7 +41,7 @@
 void ConnStateData::swanSong() STUB
 void ConnStateData::quitAfterError(HttpRequest *) STUB
 #if USE_OPENSSL
-void ConnStateData::httpsPeeked(Comm::ConnectionPointer) STUB
+void ConnStateData::httpsPeeked(PinnedIdleContext) STUB
 void ConnStateData::getSslContextStart() STUB
 void ConnStateData::getSslContextDone(Security::ContextPointer &, bool) STUB
 void ConnStateData::sslCrtdHandleReplyWrapper(void *, const Helper::Reply &) STUB
diff -u -r -N squid-4.0.20/src/tests/stub_HttpRequest.cc squid-4.0.21/src/tests/stub_HttpRequest.cc
--- squid-4.0.20/src/tests/stub_HttpRequest.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/stub_HttpRequest.cc	2017-07-02 20:41:18.000000000 +1200
@@ -15,8 +15,8 @@
 
 // void httpRequestPack(void *obj, Packable *p);
 
-HttpRequest::HttpRequest() : HttpMsg(hoRequest) {STUB}
-HttpRequest::HttpRequest(const HttpRequestMethod &, AnyP::ProtocolType, const char *, const char *) : HttpMsg(hoRequest) {STUB}
+HttpRequest::HttpRequest(const MasterXaction::Pointer&) : HttpMsg(hoRequest) {STUB}
+HttpRequest::HttpRequest(const HttpRequestMethod &, AnyP::ProtocolType, const char *, const char *, const MasterXaction::Pointer &) : HttpMsg(hoRequest) {STUB}
 HttpRequest::~HttpRequest() STUB
 void HttpRequest::reset() STUB
 void HttpRequest::initHTTP(const HttpRequestMethod &, AnyP::ProtocolType, const char *, const char *) STUB
@@ -47,7 +47,7 @@
 void HttpRequest::swapOut(StoreEntry *) STUB
 void HttpRequest::pack(Packable *) const STUB
 void HttpRequest::httpRequestPack(void *, Packable *) STUB
-HttpRequest * HttpRequest::CreateFromUrl(char *, const HttpRequestMethod &) STUB_RETVAL(NULL)
+HttpRequest * HttpRequest::FromUrl(char *, const MasterXaction::Pointer &, const HttpRequestMethod &) STUB_RETVAL(NULL)
 ConnStateData *HttpRequest::pinnedConnection() STUB_RETVAL(NULL)
 const SBuf HttpRequest::storeId() STUB_RETVAL(SBuf("."))
 void HttpRequest::ignoreRange(const char *) STUB
diff -u -r -N squid-4.0.20/src/tests/stub_libauth_acls.cc squid-4.0.21/src/tests/stub_libauth_acls.cc
--- squid-4.0.20/src/tests/stub_libauth_acls.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/stub_libauth_acls.cc	2017-07-02 20:41:18.000000000 +1200
@@ -20,8 +20,6 @@
 #include "auth/AclMaxUserIp.h"
 ACL * ACLMaxUserIP::clone() const STUB_RETVAL(NULL)
 ACLMaxUserIP::ACLMaxUserIP (char const *) STUB
-ACLMaxUserIP::ACLMaxUserIP (ACLMaxUserIP const &) STUB
-ACLMaxUserIP::~ACLMaxUserIP() STUB
 char const * ACLMaxUserIP::typeString() const STUB_RETVAL(NULL)
 bool ACLMaxUserIP::empty () const STUB_RETVAL(false)
 bool ACLMaxUserIP::valid () const STUB_RETVAL(false)
@@ -29,6 +27,7 @@
 int ACLMaxUserIP::match(Auth::UserRequest::Pointer, Ip::Address const &) STUB_RETVAL(0)
 int ACLMaxUserIP::match(ACLChecklist *) STUB_RETVAL(0)
 SBufList ACLMaxUserIP::dump() const STUB_RETVAL(SBufList())
+const Acl::Options &ACLMaxUserIP::options() STUB_RETVAL(Acl::NoOptions())
 
 #include "auth/AclProxyAuth.h"
 ACLProxyAuth::~ACLProxyAuth() STUB
@@ -47,6 +46,7 @@
 ACL * ACLProxyAuth::clone() const STUB_RETVAL(NULL)
 int ACLProxyAuth::matchForCache(ACLChecklist *) STUB_RETVAL(0)
 int ACLProxyAuth::matchProxyAuth(ACLChecklist *) STUB_RETVAL(0)
+void ACLProxyAuth::parseFlags() STUB
 
 #endif /* USE_AUTH */
 
diff -u -r -N squid-4.0.20/src/tests/stub_libmgr.cc squid-4.0.21/src/tests/stub_libmgr.cc
--- squid-4.0.20/src/tests/stub_libmgr.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/stub_libmgr.cc	2017-07-02 20:41:18.000000000 +1200
@@ -100,7 +100,6 @@
 void Mgr::Forwarder::handleError() STUB
 void Mgr::Forwarder::handleTimeout() STUB
 void Mgr::Forwarder::handleException(const std::exception& e) STUB
-void Mgr::Forwarder::handleRemoteAck() STUB
 
 #include "mgr/FunAction.h"
 Mgr::Action::Pointer Mgr::FunAction::Create(const CommandPointer &cmd, OBJH *aHandler) STUB_RETVAL(dummyAction)
diff -u -r -N squid-4.0.20/src/tests/stub_libsecurity.cc squid-4.0.21/src/tests/stub_libsecurity.cc
--- squid-4.0.20/src/tests/stub_libsecurity.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/stub_libsecurity.cc	2017-07-02 20:41:18.000000000 +1200
@@ -102,6 +102,7 @@
 void MaybeGetSessionResumeData(const Security::SessionPointer &, Security::SessionStatePointer &) STUB
 void SetSessionResumeData(const Security::SessionPointer &, const Security::SessionStatePointer &) STUB
 #if USE_OPENSSL
+void SetSessionCacheCallbacks(Security::ContextPointer &) STUB
 Security::SessionPointer NewSessionObject(const Security::ContextPointer &) STUB_RETVAL(nullptr)
 #endif
 } // namespace Security
diff -u -r -N squid-4.0.20/src/tests/stub_SBuf.cc squid-4.0.21/src/tests/stub_SBuf.cc
--- squid-4.0.20/src/tests/stub_SBuf.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/stub_SBuf.cc	2017-07-02 20:41:18.000000000 +1200
@@ -7,6 +7,7 @@
  */
 
 #include "squid.h"
+#include "sbuf/DetailedStats.h"
 
 #define STUB_API "SBuf.cc"
 #include "tests/STUB.h"
diff -u -r -N squid-4.0.20/src/tests/stub_store.cc squid-4.0.21/src/tests/stub_store.cc
--- squid-4.0.20/src/tests/stub_store.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/stub_store.cc	2017-07-02 20:41:18.000000000 +1200
@@ -38,11 +38,11 @@
 void StoreEntry::trimMemory(const bool preserveSwappable) STUB
 void StoreEntry::abort() STUB
 void StoreEntry::makePublic(const KeyScope scope) STUB
-void StoreEntry::makePrivate() STUB
+void StoreEntry::makePrivate(const bool shareable) STUB
 void StoreEntry::setPublicKey(const KeyScope scope) STUB
-void StoreEntry::setPrivateKey() STUB
+void StoreEntry::setPrivateKey(const bool shareable) STUB
 void StoreEntry::expireNow() STUB
-void StoreEntry::releaseRequest() STUB
+void StoreEntry::releaseRequest(const bool shareable) STUB
 void StoreEntry::negativeCache() STUB
 void StoreEntry::cacheNegatively() STUB
 void StoreEntry::purgeMem() STUB
@@ -93,7 +93,7 @@
 int64_t StoreEntry::contentLen() const STUB_RETVAL(0)
 void StoreEntry::lock(const char *) STUB
 void StoreEntry::touch() STUB
-void StoreEntry::release() STUB
+void StoreEntry::release(const bool shareable) STUB
 void StoreEntry::append(char const *, int) STUB
 void StoreEntry::vappendf(const char *, va_list) STUB
 
diff -u -r -N squid-4.0.20/src/tests/testACLMaxUserIP.cc squid-4.0.21/src/tests/testACLMaxUserIP.cc
--- squid-4.0.20/src/tests/testACLMaxUserIP.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/testACLMaxUserIP.cc	2017-07-02 20:41:18.000000000 +1200
@@ -10,7 +10,9 @@
 
 #if USE_AUTH
 
+#include "acl/Acl.h"
 #include "auth/AclMaxUserIp.h"
+#include "auth/UserRequest.h"
 #include "ConfigParser.h"
 #include "testACLMaxUserIP.h"
 #include "unitTestMain.h"
@@ -26,13 +28,17 @@
     /* 0 is not a valid maximum, so we start at 0 */
     CPPUNIT_ASSERT_EQUAL(0,anACL.getMaximum());
     /* and we have no option to turn strict OFF, so start ON. */
-    CPPUNIT_ASSERT_EQUAL(false,anACL.getStrict());
+    CPPUNIT_ASSERT_EQUAL(false, static_cast<bool>(anACL.beStrict));
     /* an unparsed acl must not be valid - there is no sane default */
     CPPUNIT_ASSERT_EQUAL(false,anACL.valid());
 }
 
-ACL::Prototype ACLMaxUserIP::RegistryProtoype(&ACLMaxUserIP::RegistryEntry_, "max_user_ip");
-ACLMaxUserIP ACLMaxUserIP::RegistryEntry_("max_user_ip");
+void
+testACLMaxUserIP::setUp()
+{
+    CPPUNIT_NS::TestFixture::setUp();
+    Acl::RegisterMaker("max_user_ip", [](Acl::TypeName name)->ACL* { return new ACLMaxUserIP(name); });
+}
 
 void
 testACLMaxUserIP::testParseLine()
@@ -49,7 +55,7 @@
     if (maxUserIpACL) {
         /* we want a maximum of one, and strict to be true */
         CPPUNIT_ASSERT_EQUAL(1, maxUserIpACL->getMaximum());
-        CPPUNIT_ASSERT_EQUAL(true, maxUserIpACL->getStrict());
+        CPPUNIT_ASSERT_EQUAL(true, static_cast<bool>(maxUserIpACL->beStrict));
         /* the acl must be vaid */
         CPPUNIT_ASSERT_EQUAL(true, maxUserIpACL->valid());
     }
diff -u -r -N squid-4.0.20/src/tests/testACLMaxUserIP.h squid-4.0.21/src/tests/testACLMaxUserIP.h
--- squid-4.0.20/src/tests/testACLMaxUserIP.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/testACLMaxUserIP.h	2017-07-02 20:41:18.000000000 +1200
@@ -27,6 +27,7 @@
     CPPUNIT_TEST_SUITE_END();
 
 public:
+    virtual void setUp() override;
 
 protected:
     void testDefaults();
diff -u -r -N squid-4.0.20/src/tests/testHttpRequest.cc squid-4.0.21/src/tests/testHttpRequest.cc
--- squid-4.0.20/src/tests/testHttpRequest.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/testHttpRequest.cc	2017-07-02 20:41:18.000000000 +1200
@@ -12,6 +12,7 @@
 
 #include "HttpHeader.h"
 #include "HttpRequest.h"
+#include "MasterXaction.h"
 #include "mime_header.h"
 #include "testHttpRequest.h"
 #include "unitTestMain.h"
@@ -22,6 +23,7 @@
 class PrivateHttpRequest : public HttpRequest
 {
 public:
+    PrivateHttpRequest(const MasterXaction::Pointer &mx) : HttpRequest(mx) {}
     bool doSanityCheckStartLine(const char *b, const size_t h, Http::StatusCode *e) { return sanityCheckStartLine(b,h,e); };
 };
 
@@ -44,7 +46,8 @@
     /* vanilla url, implict method */
     unsigned short expected_port;
     char * url = xstrdup("http://foo:90/bar");
-    HttpRequest *aRequest = HttpRequest::CreateFromUrl(url);
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient);
+    HttpRequest *aRequest = HttpRequest::FromUrl(url, mx);
     expected_port = 90;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port());
     CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
@@ -56,7 +59,7 @@
 
     /* vanilla url */
     url = xstrdup("http://foo:90/bar");
-    aRequest = HttpRequest::CreateFromUrl(url, Http::METHOD_GET);
+    aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
     expected_port = 90;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port());
     CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
@@ -68,7 +71,7 @@
 
     /* vanilla url, different method */
     url = xstrdup("http://foo/bar");
-    aRequest = HttpRequest::CreateFromUrl(url, Http::METHOD_PUT);
+    aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_PUT);
     expected_port = 80;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port());
     CPPUNIT_ASSERT(aRequest->method == Http::METHOD_PUT);
@@ -81,13 +84,13 @@
     /* a connect url with non-CONNECT data */
     HttpRequest *nullRequest = nullptr;
     url = xstrdup(":foo/bar");
-    aRequest = HttpRequest::CreateFromUrl(url, Http::METHOD_CONNECT);
+    aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_CONNECT);
     xfree(url);
     CPPUNIT_ASSERT_EQUAL(nullRequest, aRequest);
 
     /* a CONNECT url with CONNECT data */
     url = xstrdup("foo:45");
-    aRequest = HttpRequest::CreateFromUrl(url, Http::METHOD_CONNECT);
+    aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_CONNECT);
     expected_port = 45;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port());
     CPPUNIT_ASSERT(aRequest->method == Http::METHOD_CONNECT);
@@ -112,7 +115,8 @@
 
     /* valid IPv6 address without port */
     url = xstrdup("http://[2000:800::45]/foo");
-    aRequest = HttpRequest::CreateFromUrl(url, Http::METHOD_GET);
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient);
+    aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
     expected_port = 80;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port());
     CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
@@ -124,7 +128,7 @@
 
     /* valid IPv6 address with port */
     url = xstrdup("http://[2000:800::45]:90/foo");
-    aRequest = HttpRequest::CreateFromUrl(url, Http::METHOD_GET);
+    aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
     expected_port = 90;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port());
     CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
@@ -136,7 +140,7 @@
 
     /* IPv6 address as invalid (bug trigger) */
     url = xstrdup("http://2000:800::45/foo");
-    aRequest = HttpRequest::CreateFromUrl(url, Http::METHOD_GET);
+    aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
     expected_port = 80;
     CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port());
     CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
@@ -151,7 +155,8 @@
 testHttpRequest::testSanityCheckStartLine()
 {
     MemBuf input;
-    PrivateHttpRequest engine;
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient);
+    PrivateHttpRequest engine(mx);
     Http::StatusCode error = Http::scNone;
     size_t hdr_len;
     input.init();
diff -u -r -N squid-4.0.20/src/tests/testStoreController.cc squid-4.0.21/src/tests/testStoreController.cc
--- squid-4.0.20/src/tests/testStoreController.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/testStoreController.cc	2017-07-02 20:41:18.000000000 +1200
@@ -114,7 +114,7 @@
     e->lastModified(squid_curtime);
     e->refcount = 1;
     EBIT_CLR(e->flags, RELEASE_REQUEST);
-    EBIT_CLR(e->flags, KEY_PRIVATE);
+    e->clearPrivate();
     e->ping_status = PING_NONE;
     EBIT_CLR(e->flags, ENTRY_VALIDATED);
     e->hashInsert((const cache_key *)name.termedBuf()); /* do it after we clear KEY_PRIVATE */
diff -u -r -N squid-4.0.20/src/tests/testStoreHashIndex.cc squid-4.0.21/src/tests/testStoreHashIndex.cc
--- squid-4.0.20/src/tests/testStoreHashIndex.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tests/testStoreHashIndex.cc	2017-07-02 20:41:18.000000000 +1200
@@ -92,7 +92,7 @@
     e->lastModified(squid_curtime);
     e->refcount = 1;
     EBIT_CLR(e->flags, RELEASE_REQUEST);
-    EBIT_CLR(e->flags, KEY_PRIVATE);
+    e->clearPrivate();
     e->ping_status = PING_NONE;
     EBIT_CLR(e->flags, ENTRY_VALIDATED);
     e->hashInsert((const cache_key *)name.termedBuf()); /* do it after we clear KEY_PRIVATE */
diff -u -r -N squid-4.0.20/src/tunnel.cc squid-4.0.21/src/tunnel.cc
--- squid-4.0.20/src/tunnel.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/tunnel.cc	2017-07-02 20:41:18.000000000 +1200
@@ -1084,7 +1084,7 @@
         ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
         ch.src_addr = request->client_addr;
         ch.my_addr = request->my_addr;
-        if (ch.fastCheck() == ACCESS_DENIED) {
+        if (ch.fastCheck().denied()) {
             debugs(26, 4, HERE << "MISS access forbidden.");
             err = new ErrorState(ERR_FORWARDING_DENIED, Http::scForbidden, request);
             http->al->http.code = Http::scForbidden;
diff -u -r -N squid-4.0.20/src/url.cc squid-4.0.21/src/url.cc
--- squid-4.0.20/src/url.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/url.cc	2017-07-02 20:41:18.000000000 +1200
@@ -16,15 +16,6 @@
 #include "SquidString.h"
 #include "URL.h"
 
-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,
-                                   const int port,
-                                   HttpRequest *request);
-static HttpRequest *urnParse(const HttpRequestMethod& method, char *urn, HttpRequest *request);
 static const char valid_hostname_chars_u[] =
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     "abcdefghijklmnopqrstuvwxyz"
@@ -179,8 +170,7 @@
 /*
  * Parse a URI/URL.
  *
- * If the 'request' arg is non-NULL, put parsed values there instead
- * of allocating a new HttpRequest.
+ * Stores parsed values in the `request` argument.
  *
  * This abuses HttpRequest as a way of representing the parsed url
  * and its components.
@@ -197,43 +187,54 @@
  * its partial or not (ie, it handles the case of no trailing slash as
  * being "end of host with implied path of /".
  */
-HttpRequest *
-urlParse(const HttpRequestMethod& method, char *url, HttpRequest *request)
+bool
+URL::parse(const HttpRequestMethod& method, char *url)
 {
     LOCAL_ARRAY(char, proto, MAX_URL);
     LOCAL_ARRAY(char, login, MAX_URL);
-    LOCAL_ARRAY(char, host, MAX_URL);
+    LOCAL_ARRAY(char, foundHost, MAX_URL);
     LOCAL_ARRAY(char, urlpath, MAX_URL);
     char *t = NULL;
     char *q = NULL;
-    int port;
+    int foundPort;
     AnyP::ProtocolType protocol = AnyP::PROTO_NONE;
     int l;
     int i;
     const char *src;
     char *dst;
-    proto[0] = host[0] = urlpath[0] = login[0] = '\0';
+    proto[0] = foundHost[0] = urlpath[0] = login[0] = '\0';
 
     if ((l = strlen(url)) + Config.appendDomainLen > (MAX_URL - 1)) {
         /* terminate so it doesn't overflow other buffers */
         *(url + (MAX_URL >> 1)) = '\0';
-        debugs(23, DBG_IMPORTANT, "urlParse: URL too large (" << l << " bytes)");
-        return NULL;
+        debugs(23, DBG_IMPORTANT, MYNAME << "URL too large (" << l << " bytes)");
+        return false;
     }
     if (method == Http::METHOD_CONNECT) {
-        port = CONNECT_PORT;
+        /*
+         * RFC 7230 section 5.3.3:  authority-form = authority
+         *  "excluding any userinfo and its "@" delimiter"
+         *
+         * RFC 3986 section 3.2:    authority = [ userinfo "@" ] host [ ":" port ]
+         *
+         * As an HTTP(S) proxy we assume HTTPS (443) if no port provided.
+         */
+        foundPort = 443;
 
-        if (sscanf(url, "[%[^]]]:%d", host, &port) < 1)
-            if (sscanf(url, "%[^:]:%d", host, &port) < 1)
-                return NULL;
+        if (sscanf(url, "[%[^]]]:%d", foundHost, &foundPort) < 1)
+            if (sscanf(url, "%[^:]:%d", foundHost, &foundPort) < 1)
+                return false;
 
     } else if ((method == Http::METHOD_OPTIONS || method == Http::METHOD_TRACE) &&
                URL::Asterisk().cmp(url) == 0) {
-        protocol = AnyP::PROTO_HTTP;
-        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);
+        parseFinish(AnyP::PROTO_HTTP, nullptr, url, foundHost, SBuf(), 80 /* HTTP default port */);
+        return true;
+    } else if (strncmp(url, "urn:", 4) == 0) {
+        debugs(23, 3, "Split URI '" << url << "' into proto='urn', path='" << (url+4) << "'");
+        debugs(50, 5, "urn=" << (url+4));
+        setScheme(AnyP::PROTO_URN, nullptr);
+        path(url + 4);
+        return true;
     } else {
         /* Parse the URL: */
         src = url;
@@ -243,12 +244,12 @@
             *dst = *src;
         }
         if (i >= l)
-            return NULL;
+            return false;
         *dst = '\0';
 
         /* Then its :// */
         if ((i+3) > l || *src != ':' || *(src + 1) != '/' || *(src + 2) != '/')
-            return NULL;
+            return false;
         i += 3;
         src += 3;
 
@@ -256,7 +257,7 @@
         // bug 1881: If we don't get a "/" then we imply it was there
         // bug 3074: We could just be given a "?" or "#". These also imply "/"
         // bug 3233: whitespace is also a hostname delimiter.
-        for (dst = host; i < l && *src != '/' && *src != '?' && *src != '#' && *src != '\0' && !xisspace(*src); ++i, ++src, ++dst) {
+        for (dst = foundHost; i < l && *src != '/' && *src != '?' && *src != '#' && *src != '\0' && !xisspace(*src); ++i, ++src, ++dst) {
             *dst = *src;
         }
 
@@ -266,7 +267,7 @@
          * been -given- a valid URL and the path is just '/'.
          */
         if (i > l)
-            return NULL;
+            return false;
         *dst = '\0';
 
         // bug 3074: received 'path' starting with '?', '#', or '\0' implies '/'
@@ -283,7 +284,7 @@
 
         /* We -could- be at the end of the buffer here */
         if (i > l)
-            return NULL;
+            return false;
         /* If the URL path is empty we set it to be "/" */
         if (dst == urlpath) {
             *dst = '/';
@@ -292,29 +293,29 @@
         *dst = '\0';
 
         protocol = urlParseProtocol(proto);
-        port = AnyP::UriScheme(protocol).defaultPort();
+        foundPort = AnyP::UriScheme(protocol).defaultPort();
 
         /* Is there any login information? (we should eventually parse it above) */
-        t = strrchr(host, '@');
+        t = strrchr(foundHost, '@');
         if (t != NULL) {
-            strncpy((char *) login, (char *) host, sizeof(login)-1);
+            strncpy((char *) login, (char *) foundHost, sizeof(login)-1);
             login[sizeof(login)-1] = '\0';
             t = strrchr(login, '@');
             *t = 0;
-            strncpy((char *) host, t + 1, sizeof(host)-1);
-            host[sizeof(host)-1] = '\0';
+            strncpy((char *) foundHost, t + 1, sizeof(foundHost)-1);
+            foundHost[sizeof(foundHost)-1] = '\0';
             // Bug 4498: URL-unescape the login info after extraction
             rfc1738_unescape(login);
         }
 
         /* Is there any host information? (we should eventually parse it above) */
-        if (*host == '[') {
+        if (*foundHost == '[') {
             /* strip any IPA brackets. valid under IPv6. */
-            dst = host;
+            dst = foundHost;
             /* only for IPv6 sadly, pre-IPv6/URL code can't handle the clean result properly anyway. */
-            src = host;
+            src = foundHost;
             ++src;
-            l = strlen(host);
+            l = strlen(foundHost);
             i = 1;
             for (; i < l && *src != ']' && *src != '\0'; ++i, ++src, ++dst) {
                 *dst = *src;
@@ -329,9 +330,9 @@
                 ++dst;
             t = dst;
         } else {
-            t = strrchr(host, ':');
+            t = strrchr(foundHost, ':');
 
-            if (t != strchr(host,':') ) {
+            if (t != strchr(foundHost,':') ) {
                 /* RFC 2732 states IPv6 "SHOULD" be bracketed. allowing for times when its not. */
                 /* RFC 3986 'update' simply modifies this to an "is" with no emphasis at all! */
                 /* therefore we MUST accept the case where they are not bracketed at all. */
@@ -340,24 +341,24 @@
         }
 
         // Bug 3183 sanity check: If scheme is present, host must be too.
-        if (protocol != AnyP::PROTO_NONE && host[0] == '\0') {
+        if (protocol != AnyP::PROTO_NONE && foundHost[0] == '\0') {
             debugs(23, DBG_IMPORTANT, "SECURITY ALERT: Missing hostname in URL '" << url << "'. see access.log for details.");
-            return NULL;
+            return false;
         }
 
         if (t && *t == ':') {
             *t = '\0';
             ++t;
-            port = atoi(t);
+            foundPort = atoi(t);
         }
     }
 
-    for (t = host; *t; ++t)
+    for (t = foundHost; *t; ++t)
         *t = xtolower(*t);
 
-    if (stringHasWhitespace(host)) {
+    if (stringHasWhitespace(foundHost)) {
         if (URI_WHITESPACE_STRIP == Config.uri_whitespace) {
-            t = q = host;
+            t = q = foundHost;
             while (*t) {
                 if (!xisspace(*t)) {
                     *q = *t;
@@ -369,48 +370,49 @@
         }
     }
 
-    debugs(23, 3, "urlParse: Split URL '" << url << "' into proto='" << proto << "', host='" << host << "', port='" << port << "', path='" << urlpath << "'");
+    debugs(23, 3, "Split URL '" << url << "' into proto='" << proto << "', host='" << foundHost << "', port='" << foundPort << "', path='" << urlpath << "'");
 
-    if (Config.onoff.check_hostnames && strspn(host, Config.onoff.allow_underscore ? valid_hostname_chars_u : valid_hostname_chars) != strlen(host)) {
-        debugs(23, DBG_IMPORTANT, "urlParse: Illegal character in hostname '" << host << "'");
-        return NULL;
+    if (Config.onoff.check_hostnames &&
+            strspn(foundHost, Config.onoff.allow_underscore ? valid_hostname_chars_u : valid_hostname_chars) != strlen(foundHost)) {
+        debugs(23, DBG_IMPORTANT, MYNAME << "Illegal character in hostname '" << foundHost << "'");
+        return false;
     }
 
     /* For IPV6 addresses also check for a colon */
-    if (Config.appendDomain && !strchr(host, '.') && !strchr(host, ':'))
-        strncat(host, Config.appendDomain, SQUIDHOSTNAMELEN - strlen(host) - 1);
+    if (Config.appendDomain && !strchr(foundHost, '.') && !strchr(foundHost, ':'))
+        strncat(foundHost, Config.appendDomain, SQUIDHOSTNAMELEN - strlen(foundHost) - 1);
 
     /* remove trailing dots from hostnames */
-    while ((l = strlen(host)) > 0 && host[--l] == '.')
-        host[l] = '\0';
+    while ((l = strlen(foundHost)) > 0 && foundHost[--l] == '.')
+        foundHost[l] = '\0';
 
     /* reject duplicate or leading dots */
-    if (strstr(host, "..") || *host == '.') {
-        debugs(23, DBG_IMPORTANT, "urlParse: Illegal hostname '" << host << "'");
-        return NULL;
+    if (strstr(foundHost, "..") || *foundHost == '.') {
+        debugs(23, DBG_IMPORTANT, MYNAME << "Illegal hostname '" << foundHost << "'");
+        return false;
     }
 
-    if (port < 1 || port > 65535) {
-        debugs(23, 3, "urlParse: Invalid port '" << port << "'");
-        return NULL;
+    if (foundPort < 1 || foundPort > 65535) {
+        debugs(23, 3, "Invalid port '" << foundPort << "'");
+        return false;
     }
 
 #if HARDCODE_DENY_PORTS
     /* These ports are filtered in the default squid.conf, but
      * maybe someone wants them hardcoded... */
-    if (port == 7 || port == 9 || port == 19) {
-        debugs(23, DBG_CRITICAL, "urlParse: Deny access to port " << port);
-        return NULL;
+    if (foundPort == 7 || foundPort == 9 || foundPort == 19) {
+        debugs(23, DBG_CRITICAL, MYNAME << "Deny access to port " << foundPort);
+        return false;
     }
 #endif
 
     if (stringHasWhitespace(urlpath)) {
-        debugs(23, 2, "urlParse: URI has whitespace: {" << url << "}");
+        debugs(23, 2, "URI has whitespace: {" << url << "}");
 
         switch (Config.uri_whitespace) {
 
         case URI_WHITESPACE_DENY:
-            return NULL;
+            return false;
 
         case URI_WHITESPACE_ALLOW:
             break;
@@ -438,46 +440,24 @@
         }
     }
 
-    return urlParseFinish(method, protocol, proto, urlpath, host, SBuf(login), port, request);
-}
-
-/**
- * Update request with parsed URI data.  If the request arg is
- * non-NULL, put parsed values there instead of allocating a new
- * HttpRequest.
- */
-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,
-               const int port,
-               HttpRequest *request)
-{
-    if (NULL == request)
-        request = new HttpRequest(method, protocol, protoStr, urlpath);
-    else {
-        request->initHTTP(method, protocol, protoStr, urlpath);
-    }
-
-    request->url.host(host);
-    request->url.userInfo(login);
-    request->url.port(port);
-    return request;
+    parseFinish(protocol, proto, urlpath, foundHost, SBuf(login), foundPort);
+    return true;
 }
 
-static HttpRequest *
-urnParse(const HttpRequestMethod& method, char *urn, HttpRequest *request)
+/// Update the URL object with parsed URI data.
+void
+URL::parseFinish(const AnyP::ProtocolType protocol,
+                 const char *const protoStr, // for unknown protocols
+                 const char *const aUrlPath,
+                 const char *const aHost,
+                 const SBuf &aLogin,
+                 const int aPort)
 {
-    debugs(50, 5, "urnParse: " << urn);
-    if (request) {
-        request->initHTTP(method, AnyP::PROTO_URN, "urn", urn + 4);
-        return request;
-    }
-
-    return new HttpRequest(method, AnyP::PROTO_URN, "urn", urn + 4);
+    setScheme(protocol, protoStr);
+    path(aUrlPath);
+    host(aHost);
+    userInfo(aLogin);
+    port(aPort);
 }
 
 void
diff -u -r -N squid-4.0.20/src/URL.h squid-4.0.21/src/URL.h
--- squid-4.0.20/src/URL.h	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/URL.h	2017-07-02 20:41:18.000000000 +1200
@@ -53,6 +53,8 @@
     }
     void touch(); ///< clear the cached URI display forms
 
+    bool parse(const HttpRequestMethod &, char *url);
+
     AnyP::UriScheme const & getScheme() const {return scheme_;}
 
     /// convert the URL scheme to that given
@@ -104,6 +106,8 @@
     SBuf &absolute() const;
 
 private:
+    void parseFinish(const AnyP::ProtocolType, const char *const, const char *const, const char *const, const SBuf &, const int);
+
     /**
      \par
      * The scheme of this URL. This has the 'type code' smell about it.
@@ -166,7 +170,7 @@
 class HttpRequestMethod;
 
 void urlInitialize(void);
-HttpRequest *urlParse(const HttpRequestMethod&, char *, HttpRequest *request = NULL);
+bool urlParse(const HttpRequestMethod&, char *, HttpRequest &request);
 char *urlCanonicalClean(const HttpRequest *);
 const char *urlCanonicalFakeHttps(const HttpRequest * request);
 bool urlIsRelative(const char *);
diff -u -r -N squid-4.0.20/src/urn.cc squid-4.0.21/src/urn.cc
--- squid-4.0.20/src/urn.cc	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/src/urn.cc	2017-07-02 20:41:18.000000000 +1200
@@ -151,7 +151,7 @@
     safe_free(host);
     safe_free(urlres);
     urlres = xstrdup(local_urlres);
-    urlres_r = HttpRequest::CreateFromUrl(urlres);
+    urlres_r = HttpRequest::FromUrl(urlres, r->masterXaction);
 
     if (urlres_r == NULL) {
         debugs(52, 3, "urnStart: Bad uri-res URL " << urlres);
diff -u -r -N squid-4.0.20/src/XactionInitiator.cc squid-4.0.21/src/XactionInitiator.cc
--- squid-4.0.20/src/XactionInitiator.cc	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.21/src/XactionInitiator.cc	2017-07-02 20:41:18.000000000 +1200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 1996-2017 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.
+ */
+
+#include "squid.h"
+#include "cache_cf.h"
+#include "Debug.h"
+#include "XactionInitiator.h"
+
+#include <map>
+#include <string>
+
+XactionInitiator::Initiators
+XactionInitiator::ParseInitiators(const char *name)
+{
+    typedef std::map<std::string, XactionInitiator::Initiators> InitiatorsMap;
+    static InitiatorsMap SupportedInitiators = {
+        {"client", initClient},
+        {"peer-pool", initPeerPool},
+        {"certificate-fetching", initCertFetcher},
+        {"esi", initEsi},
+        {"cache-digest", initCacheDigest},
+        {"server", initServer},
+        {"htcp", initHtcp},
+        {"icp", initIcp},
+        {"icmp", initIcmp},
+        {"asn", initAsn},
+        {"ipc", initIpc},
+        {"adaptation", initAdaptation},
+        {"icon", initIcon},
+        {"peer-mcast", initPeerMcast},
+        {"internal", InternalInitiators()},
+        {"all", AllInitiators()}
+    };
+    const auto it = SupportedInitiators.find(name);
+    if (it != SupportedInitiators.cend())
+        return it->second;
+
+    debugs(28, DBG_CRITICAL, "FATAL: Invalid transaction_initiator value near " << name);
+    self_destruct();
+    return 0;
+}
+
diff -u -r -N squid-4.0.20/src/XactionInitiator.h squid-4.0.21/src/XactionInitiator.h
--- squid-4.0.20/src/XactionInitiator.h	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.21/src/XactionInitiator.h	2017-07-02 20:41:18.000000000 +1200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 1996-2017 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_XACTION_INITIATOR_H
+#define SQUID_SRC_XACTION_INITIATOR_H
+
+/// identifies a protocol agent or Squid feature initiating transactions
+class XactionInitiator {
+public:
+    /// transaction triggers
+    enum Initiator {
+        initUnknown = 0,
+        initClient = 1 << 0, ///< HTTP or FTP client
+        initPeerPool = 1 << 1, ///< PeerPool manager
+        initCertFetcher = 1 << 2, ///< Missing intermediate certificates fetching code
+        initEsi = 1 << 3, ///< ESI processing code
+        initCacheDigest = 1 << 4, ///< Cache Digest fetching code
+        initHtcp = 1<< 5, ///< HTCP client
+        initIcp = 1 << 6, ///< the ICP/neighbors subsystem
+        initIcmp = 1 << 7, ///< the ICMP RTT database (NetDB) neighbors exchange subsystem
+        initAsn = 1 << 8, ///< the ASN db subsystem
+        initIpc = 1 << 9, ///< the IPC subsystem
+        initAdaptation = 1 << 10,  ///< ICAP/ECAP requests generated by Squid
+        initIcon = 1 << 11, ///< internal icons
+        initPeerMcast = 1 << 12, ///< neighbor multicast
+        initServer = 1 << 13, ///< HTTP/2 push request (not yet supported by Squid)
+
+        initAdaptationOrphan_ = 1 << 31 ///< eCAP-created HTTP message w/o an associated HTTP transaction (not ACL-detectable)
+    };
+
+    typedef uint32_t Initiators; ///< Initiator set
+
+    // this class is a just a trivial wrapper so we allow explicit conversions
+    XactionInitiator(Initiator i) : initiator(i) {}
+
+    /// whether this initiator belongs to the given set
+    bool in(Initiators setOfInitiators) const {return (initiator & setOfInitiators) != 0;}
+
+    /// whether the transaction was initiated by an internal subsystem
+    bool internalClient() const {
+        return (initiator & InternalInitiators()) != 0;
+    }
+
+    /// internally generated requests
+    static Initiators InternalInitiators() {
+        return initPeerPool | initCertFetcher | initEsi | initCacheDigest | initIcp | initIcmp | initIpc | initAdaptation | initIcon | initPeerMcast;
+    }
+
+    /// all initiators
+    static Initiators AllInitiators() {
+        return 0xFFFFFFFF;
+    }
+
+    static Initiators ParseInitiators(const char *name);
+
+private:
+    XactionInitiator() {}
+
+    Initiator initiator;
+};
+
+#endif // SQUID_SRC_XACTION_INITIATOR_H
+
diff -u -r -N squid-4.0.20/test-suite/Makefile.in squid-4.0.21/test-suite/Makefile.in
--- squid-4.0.20/test-suite/Makefile.in	2017-06-02 01:01:20.000000000 +1200
+++ squid-4.0.21/test-suite/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/test-suite/squidconf/regressions-4.0.18 squid-4.0.21/test-suite/squidconf/regressions-4.0.18
--- squid-4.0.20/test-suite/squidconf/regressions-4.0.18	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/test-suite/squidconf/regressions-4.0.18	2017-07-02 20:41:18.000000000 +1200
@@ -1,4 +1,13 @@
+## Copyright (C) 1996-2017 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.
+##
+
+#
 # see Bug 4674
+#
 delay_pools 5
 
 delay_class 1 1 64000/64000
diff -u -r -N squid-4.0.20/test-suite/stub_SBuf.cc squid-4.0.21/test-suite/stub_SBuf.cc
--- squid-4.0.20/test-suite/stub_SBuf.cc	2017-06-02 09:59:52.000000000 +1200
+++ squid-4.0.21/test-suite/stub_SBuf.cc	2017-07-02 20:57:36.000000000 +1200
@@ -7,6 +7,7 @@
  */
 
 #include "squid.h"
+#include "sbuf/DetailedStats.h"
 
 #define STUB_API "SBuf.cc"
 #include "tests/STUB.h"
diff -u -r -N squid-4.0.20/tools/apparmor/Makefile.am squid-4.0.21/tools/apparmor/Makefile.am
--- squid-4.0.20/tools/apparmor/Makefile.am	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.21/tools/apparmor/Makefile.am	2017-07-02 20:41:18.000000000 +1200
@@ -0,0 +1,8 @@
+## Copyright (C) 1996-2017 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.
+##
+
+EXTRA_DIST = usr.sbin.squid
diff -u -r -N squid-4.0.20/tools/apparmor/Makefile.in squid-4.0.21/tools/apparmor/Makefile.in
--- squid-4.0.20/tools/apparmor/Makefile.in	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.21/tools/apparmor/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -0,0 +1,603 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = tools/apparmor
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude/ax_with_prog.m4 \
+	$(top_srcdir)/acinclude/init.m4 \
+	$(top_srcdir)/acinclude/squid-util.m4 \
+	$(top_srcdir)/acinclude/compiler-flags.m4 \
+	$(top_srcdir)/acinclude/os-deps.m4 \
+	$(top_srcdir)/acinclude/krb5.m4 $(top_srcdir)/acinclude/pam.m4 \
+	$(top_srcdir)/acinclude/pkg.m4 \
+	$(top_srcdir)/acinclude/lib-checks.m4 \
+	$(top_srcdir)/acinclude/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/acinclude/ax_cxx_0x_types.m4 \
+	$(top_srcdir)/src/auth/basic/helpers.m4 \
+	$(top_srcdir)/src/auth/basic/DB/required.m4 \
+	$(top_srcdir)/src/auth/basic/LDAP/required.m4 \
+	$(top_srcdir)/src/auth/basic/NCSA/required.m4 \
+	$(top_srcdir)/src/auth/basic/NIS/required.m4 \
+	$(top_srcdir)/src/auth/basic/PAM/required.m4 \
+	$(top_srcdir)/src/auth/basic/POP3/required.m4 \
+	$(top_srcdir)/src/auth/basic/RADIUS/required.m4 \
+	$(top_srcdir)/src/auth/basic/SASL/required.m4 \
+	$(top_srcdir)/src/auth/basic/SMB/required.m4 \
+	$(top_srcdir)/src/auth/basic/SMB_LM/required.m4 \
+	$(top_srcdir)/src/auth/basic/SSPI/required.m4 \
+	$(top_srcdir)/src/auth/basic/fake/required.m4 \
+	$(top_srcdir)/src/auth/basic/getpwnam/required.m4 \
+	$(top_srcdir)/src/auth/digest/helpers.m4 \
+	$(top_srcdir)/src/auth/digest/eDirectory/required.m4 \
+	$(top_srcdir)/src/auth/digest/file/required.m4 \
+	$(top_srcdir)/src/auth/digest/LDAP/required.m4 \
+	$(top_srcdir)/src/auth/negotiate/helpers.m4 \
+	$(top_srcdir)/src/auth/negotiate/SSPI/required.m4 \
+	$(top_srcdir)/src/auth/negotiate/kerberos/required.m4 \
+	$(top_srcdir)/src/auth/negotiate/wrapper/required.m4 \
+	$(top_srcdir)/src/auth/ntlm/helpers.m4 \
+	$(top_srcdir)/src/auth/ntlm/fake/required.m4 \
+	$(top_srcdir)/src/auth/ntlm/SMB_LM/required.m4 \
+	$(top_srcdir)/src/auth/ntlm/SSPI/required.m4 \
+	$(top_srcdir)/src/log/helpers.m4 \
+	$(top_srcdir)/src/log/DB/required.m4 \
+	$(top_srcdir)/src/log/file/required.m4 \
+	$(top_srcdir)/src/acl/external/helpers.m4 \
+	$(top_srcdir)/src/acl/external/AD_group/required.m4 \
+	$(top_srcdir)/src/acl/external/LDAP_group/required.m4 \
+	$(top_srcdir)/src/acl/external/LM_group/required.m4 \
+	$(top_srcdir)/src/acl/external/delayer/required.m4 \
+	$(top_srcdir)/src/acl/external/SQL_session/required.m4 \
+	$(top_srcdir)/src/acl/external/eDirectory_userip/required.m4 \
+	$(top_srcdir)/src/acl/external/file_userip/required.m4 \
+	$(top_srcdir)/src/acl/external/kerberos_ldap_group/required.m4 \
+	$(top_srcdir)/src/acl/external/session/required.m4 \
+	$(top_srcdir)/src/acl/external/time_quota/required.m4 \
+	$(top_srcdir)/src/acl/external/unix_group/required.m4 \
+	$(top_srcdir)/src/acl/external/wbinfo_group/required.m4 \
+	$(top_srcdir)/src/http/url_rewriters/helpers.m4 \
+	$(top_srcdir)/src/http/url_rewriters/fake/required.m4 \
+	$(top_srcdir)/src/http/url_rewriters/LFS/required.m4 \
+	$(top_srcdir)/src/security/cert_validators/helpers.m4 \
+	$(top_srcdir)/src/security/cert_validators/fake/required.m4 \
+	$(top_srcdir)/src/security/cert_generators/helpers.m4 \
+	$(top_srcdir)/src/security/cert_generators/file/required.m4 \
+	$(top_srcdir)/src/store/id_rewriters/helpers.m4 \
+	$(top_srcdir)/src/store/id_rewriters/file/required.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/include/autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ADAPTATION_LIBS = @ADAPTATION_LIBS@
+AIOLIB = @AIOLIB@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AR_R = @AR_R@
+ATOMICLIB = @ATOMICLIB@
+AUTH_LIBS_TO_BUILD = @AUTH_LIBS_TO_BUILD@
+AUTH_MODULES = @AUTH_MODULES@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASIC_AUTH_HELPERS = @BASIC_AUTH_HELPERS@
+BUILDCXX = @BUILDCXX@
+BUILDCXXFLAGS = @BUILDCXXFLAGS@
+BZR = @BZR@
+CACHE_EFFECTIVE_USER = @CACHE_EFFECTIVE_USER@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CGIEXT = @CGIEXT@
+CHMOD = @CHMOD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CRYPTLIB = @CRYPTLIB@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_HOSTS = @DEFAULT_HOSTS@
+DEFAULT_LOG_DIR = @DEFAULT_LOG_DIR@
+DEFAULT_PID_FILE = @DEFAULT_PID_FILE@
+DEFAULT_SWAP_DIR = @DEFAULT_SWAP_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DIGEST_AUTH_HELPERS = @DIGEST_AUTH_HELPERS@
+DISK_LIBS = @DISK_LIBS@
+DISK_MODULES = @DISK_MODULES@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EPOLL_LIBS = @EPOLL_LIBS@
+EUILIB = @EUILIB@
+EXEEXT = @EXEEXT@
+EXPATLIB = @EXPATLIB@
+EXTERNAL_ACL_HELPERS = @EXTERNAL_ACL_HELPERS@
+EXT_LIBECAP_CFLAGS = @EXT_LIBECAP_CFLAGS@
+EXT_LIBECAP_LIBS = @EXT_LIBECAP_LIBS@
+FALSE = @FALSE@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+INCLTDL = @INCLTDL@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KRB5INCS = @KRB5INCS@
+KRB5LIBS = @KRB5LIBS@
+LBERLIB = @LBERLIB@
+LD = @LD@
+LDAPLIB = @LDAPLIB@
+LDFLAGS = @LDFLAGS@
+LIBADD_DL = @LIBADD_DL@
+LIBADD_DLD_LINK = @LIBADD_DLD_LINK@
+LIBADD_DLOPEN = @LIBADD_DLOPEN@
+LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@
+LIBCPPUNIT_CFLAGS = @LIBCPPUNIT_CFLAGS@
+LIBCPPUNIT_LIBS = @LIBCPPUNIT_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBLTDL = @LIBLTDL@
+LIBOBJS = @LIBOBJS@
+LIBOPENSSL_CFLAGS = @LIBOPENSSL_CFLAGS@
+LIBOPENSSL_LIBS = @LIBOPENSSL_LIBS@
+LIBPTHREADS = @LIBPTHREADS@
+LIBS = @LIBS@
+LIBSASL = @LIBSASL@
+LIBTOOL = @LIBTOOL@
+LIB_KRB5_CFLAGS = @LIB_KRB5_CFLAGS@
+LIB_KRB5_LIBS = @LIB_KRB5_LIBS@
+LINUXDOC = @LINUXDOC@
+LIPO = @LIPO@
+LN = @LN@
+LN_S = @LN_S@
+LOG_DAEMON_HELPERS = @LOG_DAEMON_HELPERS@
+LTDLDEPS = @LTDLDEPS@
+LTDLINCL = @LTDLINCL@
+LTDLOPEN = @LTDLOPEN@
+LTLIBOBJS = @LTLIBOBJS@
+LT_ARGZ_H = @LT_ARGZ_H@
+LT_CONFIG_H = @LT_CONFIG_H@
+LT_DLLOADERS = @LT_DLLOADERS@
+LT_DLPREOPEN = @LT_DLPREOPEN@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MINGW_LIBS = @MINGW_LIBS@
+MKDIR = @MKDIR@
+MKDIR_P = @MKDIR_P@
+MV = @MV@
+NEGOTIATE_AUTH_HELPERS = @NEGOTIATE_AUTH_HELPERS@
+NETTLELIB = @NETTLELIB@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NTLM_AUTH_HELPERS = @NTLM_AUTH_HELPERS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PO2HTML = @PO2HTML@
+PO2TEXT = @PO2TEXT@
+POD2MAN = @POD2MAN@
+RANLIB = @RANLIB@
+REGEXLIB = @REGEXLIB@
+REPL_LIBS = @REPL_LIBS@
+REPL_OBJS = @REPL_OBJS@
+REPL_POLICIES = @REPL_POLICIES@
+RM = @RM@
+SECURITY_CERTGEN_HELPERS = @SECURITY_CERTGEN_HELPERS@
+SECURITY_CERTV_HELPERS = @SECURITY_CERTV_HELPERS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SH = @SH@
+SHELL = @SHELL@
+SMBCLIENT = @SMBCLIENT@
+SNMPLIB = @SNMPLIB@
+SQUID_CFLAGS = @SQUID_CFLAGS@
+SQUID_CXXFLAGS = @SQUID_CXXFLAGS@
+SSLLIB = @SSLLIB@
+STOREID_REWRITE_HELPERS = @STOREID_REWRITE_HELPERS@
+STORE_LIBS_TO_ADD = @STORE_LIBS_TO_ADD@
+STORE_LIBS_TO_BUILD = @STORE_LIBS_TO_BUILD@
+STORE_TESTS = @STORE_TESTS@
+STRIP = @STRIP@
+TR = @TR@
+TRUE = @TRUE@
+URL_REWRITE_HELPERS = @URL_REWRITE_HELPERS@
+VERSION = @VERSION@
+WBINFO = @WBINFO@
+WIN32_PSAPI = @WIN32_PSAPI@
+XMLLIB = @XMLLIB@
+XTRA_LIBS = @XTRA_LIBS@
+XTRA_OBJS = @XTRA_OBJS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+krb5_config = @krb5_config@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+ltdl_LIBOBJS = @ltdl_LIBOBJS@
+ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sys_symbol_underscore = @sys_symbol_underscore@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = usr.sbin.squid
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/apparmor/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign tools/apparmor/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff -u -r -N squid-4.0.20/tools/apparmor/usr.sbin.squid squid-4.0.21/tools/apparmor/usr.sbin.squid
--- squid-4.0.20/tools/apparmor/usr.sbin.squid	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.21/tools/apparmor/usr.sbin.squid	2017-07-02 20:41:18.000000000 +1200
@@ -0,0 +1,47 @@
+## Copyright (C) 1996-2017 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.
+
+# Author: Simon Deziel
+#         Jamie Strandboge
+# vim:syntax=apparmor
+#include <tunables/global>
+
+/usr/sbin/squid {
+  #include <abstractions/base>
+  #include <abstractions/kerberosclient>
+  #include <abstractions/nameservice>
+
+  capability net_raw,
+  capability setuid,
+  capability setgid,
+  capability sys_chroot,
+
+  # allow child processes to run execvp(argv[0], [kidname, ...])
+  /usr/sbin/squid ix,
+
+  # pinger
+  network inet raw,
+  network inet6 raw,
+
+  /etc/mtab r,
+  @{PROC}/[0-9]*/mounts r,
+  @{PROC}/mounts r,
+
+  # squid configuration
+  /etc/squid/** r,
+  /{,var/}run/squid.pid rwk,
+  /var/spool/squid/ r,
+  /var/spool/squid/** rwk,
+  /usr/lib/squid/* rmix,
+  /usr/share/squid/** r,
+  /var/log/squid/* rw,
+
+  # allow SMP device access for kids
+  owner /dev/shm/** rmw,
+
+  # Site-specific additions and overrides. See local/README for details.
+  #include <local/usr.sbin.squid>
+}
diff -u -r -N squid-4.0.20/tools/helper-mux/helper-mux.8 squid-4.0.21/tools/helper-mux/helper-mux.8
--- squid-4.0.20/tools/helper-mux/helper-mux.8	2017-06-02 10:00:07.000000000 +1200
+++ squid-4.0.21/tools/helper-mux/helper-mux.8	2017-07-02 20:57:36.000000000 +1200
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "HELPER-MUX 8"
-.TH HELPER-MUX 8 "2017-06-01" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH HELPER-MUX 8 "2017-07-02" "perl v5.24.1" "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.20/tools/helper-mux/Makefile.in squid-4.0.21/tools/helper-mux/Makefile.in
--- squid-4.0.20/tools/helper-mux/Makefile.in	2017-06-02 01:01:24.000000000 +1200
+++ squid-4.0.21/tools/helper-mux/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/tools/Makefile.am squid-4.0.21/tools/Makefile.am
--- squid-4.0.20/tools/Makefile.am	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/tools/Makefile.am	2017-07-02 20:41:18.000000000 +1200
@@ -10,7 +10,7 @@
 ## we need our local files too (but avoid -I. at all costs)
 AM_CPPFLAGS += -I$(srcdir)
 
-SUBDIRS= helper-mux purge squidclient systemd sysvinit
+SUBDIRS= apparmor helper-mux purge squidclient systemd sysvinit
 EXTRA_DIST=
 man_MANS=
 DISTCLEANFILES=
diff -u -r -N squid-4.0.20/tools/Makefile.in squid-4.0.21/tools/Makefile.in
--- squid-4.0.20/tools/Makefile.in	2017-06-02 01:01:23.000000000 +1200
+++ squid-4.0.21/tools/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -776,7 +776,7 @@
 @ENABLE_XPROF_STATS_TRUE@LIBPROFILER = $(top_builddir)/lib/profiler/libprofiler.la
 COMPAT_LIB = $(top_builddir)/compat/libcompatsquid.la $(LIBPROFILER)
 subst_perlshell = sed -e 's,[@]PERL[@],$(PERL),g' <$(srcdir)/$@.pl.in >$@ || ($(RM) -f $@ ; exit 1)
-SUBDIRS = helper-mux purge squidclient systemd sysvinit
+SUBDIRS = apparmor helper-mux purge squidclient systemd sysvinit
 EXTRA_DIST = helper-ok-dying.pl helper-ok.pl cachemgr.conf \
 	cachemgr.cgi.8 cachemgr.cgi.8.in
 man_MANS = cachemgr.cgi.8
diff -u -r -N squid-4.0.20/tools/purge/Makefile.in squid-4.0.21/tools/purge/Makefile.in
--- squid-4.0.20/tools/purge/Makefile.in	2017-06-02 01:01:26.000000000 +1200
+++ squid-4.0.21/tools/purge/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/tools/purge/purge.1 squid-4.0.21/tools/purge/purge.1
--- squid-4.0.20/tools/purge/purge.1	2017-06-02 00:49:17.000000000 +1200
+++ squid-4.0.21/tools/purge/purge.1	2017-07-02 20:41:18.000000000 +1200
@@ -258,7 +258,7 @@
 .PP
 Based on original squidpurge README.
 .
-..SH COPYRIGHT
+.SH COPYRIGHT
 .PP
  * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
  *
diff -u -r -N squid-4.0.20/tools/squidclient/Makefile.in squid-4.0.21/tools/squidclient/Makefile.in
--- squid-4.0.20/tools/squidclient/Makefile.in	2017-06-02 01:01:28.000000000 +1200
+++ squid-4.0.21/tools/squidclient/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/tools/systemd/Makefile.in squid-4.0.21/tools/systemd/Makefile.in
--- squid-4.0.20/tools/systemd/Makefile.in	2017-06-02 01:01:29.000000000 +1200
+++ squid-4.0.21/tools/systemd/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff -u -r -N squid-4.0.20/tools/sysvinit/Makefile.in squid-4.0.21/tools/sysvinit/Makefile.in
--- squid-4.0.20/tools/sysvinit/Makefile.in	2017-06-02 01:01:30.000000000 +1200
+++ squid-4.0.21/tools/sysvinit/Makefile.in	2017-07-02 20:41:28.000000000 +1200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
