diff -u -r -N squid-4.0.14/ChangeLog squid-4.0.15/ChangeLog
--- squid-4.0.14/ChangeLog	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/ChangeLog	2016-10-10 08:05:51.000000000 +1300
@@ -1,3 +1,17 @@
+Changes to squid-4.0.15 (09 Oct 2016):
+
+	- Regression fix crash on reconfigure with TOS/DiffServ/MARK configured
+	- Bug 4610: compile errors on Solaris 11.3 with Oracle Studio 12.5
+	- Bug 4581: Secure ICAP segfault in checkForMissingCertificates
+	- Bug 4578: changes required to install squid.service
+	- Fix crash on shutdown while cleaning up idle ICAP connections
+	- Fix memory leak of Downloader-related objects
+	- HTTP/1.1: handle syntactically valid requests with unsupported HTTP versions
+	- Log TCP client port for error:transaction-end-before-headers and such
+	- ... and many portability and build fixes
+	- ... and some documentation updates
+	- ... and all fixes from 3.5.22
+
 Changes to squid-4.0.14 (08 Sep 2016):
 
 	- Regression Bug 4570: crash after rev.14755
@@ -13,7 +27,7 @@
 	- Do not log error:transaction-end-before-headers after invalid requests
 	- ... and many portability and build fixes
 	- ... and some documentation updates
-	- ... and all fixes from 3.5.20
+	- ... and all fixes from 3.5.21
 
 Changes to squid-4.0.13 (05 Aug 2016):
 
@@ -223,6 +237,20 @@
 	- ... and many documentation changes
 	- ... and much code cleanup and polishing
 
+Changes to squid-3.5.22 (09 Oct 2016):
+
+	- Bug 4594: build failure with clang 3.9
+	- Bug 4471: revalidation does not work when expired cached object lacks Last-Modified
+	- Bug 4302 pt2: IPv6 support for IPFilter v5 transparent interception
+	- Bug 4228: ./configure bug/typo in r14394
+	- Bug 3819: "fd >= 0" assertion in file_write() during reconfiguration
+	- Bug 2833: Collapse internal revalidation requests (SMP-unaware caches)
+	- Fix logged request size (%http::>st) and other size-related %codes
+	- Fix some memory leaks from putenv()
+	- Fix memory leaks from url_rewrite_extras and store_id_extras on reconfigure/shutdown
+	- Fix segfault crash when debugging section 4 at level 9
+	- HTTP: MUST ignore a [revalidation] response with an older Date header
+
 Changes to squid-3.5.21 (08 Sep 2016):
 
 	- Bug 4563: duplicate code in httpMakeVaryMark
diff -u -r -N squid-4.0.14/compat/debug.cc squid-4.0.15/compat/debug.cc
--- squid-4.0.14/compat/debug.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/compat/debug.cc	2016-10-10 08:05:51.000000000 +1300
@@ -12,7 +12,7 @@
 /* default off */
 int debug_enabled = 0;
 
-#ifndef __GNUC__
+#if !defined(__GNUC__) && !defined(__SUNPRO_CC)
 /* under gcc a macro define in compat/debug.h is used instead */
 
 void
@@ -26,5 +26,5 @@
     va_end(args);
 }
 
-#endif /* __GNUC__ */
+#endif /* __GNUC__ || __SUNPRO_CC */
 
diff -u -r -N squid-4.0.14/compat/debug.h squid-4.0.15/compat/debug.h
--- squid-4.0.14/compat/debug.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/compat/debug.h	2016-10-10 08:05:51.000000000 +1300
@@ -23,7 +23,7 @@
 SQUIDCEXTERN int debug_enabled;
 
 /* the macro overload style is really a gcc-ism */
-#ifdef __GNUC__
+#if defined(__GNUC__) || defined(__SUNPRO_CC)
 
 #define debug(X...) \
                      if (debug_enabled) { \
@@ -37,7 +37,7 @@
         << content << std::endl; \
     } else (void)0
 
-#else /* __GNUC__ */
+#else /* __GNUC__ || __SUNPRO_CC */
 
 /* non-GCC compilers can't do the above macro define yet. */
 void debug(const char *format,...);
diff -u -r -N squid-4.0.14/configure squid-4.0.15/configure
--- squid-4.0.14/configure	2016-09-09 02:15:20.000000000 +1200
+++ squid-4.0.15/configure	2016-10-10 08:20:15.000000000 +1300
@@ -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.14.
+# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.0.15.
 #
 # 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.14'
-PACKAGE_STRING='Squid Web Proxy 4.0.14'
+PACKAGE_VERSION='4.0.15'
+PACKAGE_STRING='Squid Web Proxy 4.0.15'
 PACKAGE_BUGREPORT='http://bugs.squid-cache.org/'
 PACKAGE_URL=''
 
@@ -1648,7 +1648,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures Squid Web Proxy 4.0.14 to adapt to many kinds of systems.
+\`configure' configures Squid Web Proxy 4.0.15 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1719,7 +1719,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Squid Web Proxy 4.0.14:";;
+     short | recursive ) echo "Configuration of Squid Web Proxy 4.0.15:";;
    esac
   cat <<\_ACEOF
 
@@ -2148,7 +2148,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Squid Web Proxy configure 4.0.14
+Squid Web Proxy configure 4.0.15
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -3252,7 +3252,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Squid Web Proxy $as_me 4.0.14, which was
+It was created by Squid Web Proxy $as_me 4.0.15, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -4119,7 +4119,7 @@
 
 # Define the identity of the package.
  PACKAGE='squid'
- VERSION='4.0.14'
+ VERSION='4.0.15'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -30590,7 +30590,7 @@
 
   fi
   if test "x$KRB5LIBS" = "x"; then
-    if test test "x$with_heimdal_krb5" = "xyes"; then
+    if test "x$with_heimdal_krb5" = "xyes"; then
       as_fn_error $? "Required Heimdal Kerberos library not found" "$LINENO" 5
     else
       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Heimdal Kerberos library not found" >&5
@@ -31108,7 +31108,7 @@
 
   fi
   if test "x$KRB5LIBS" = "x"; then
-    if test test "x$with_gnugss" = "xyes"; then
+    if test "x$with_gnugss" = "xyes"; then
       as_fn_error $? "Required GNU GSS Kerberos library not found" "$LINENO" 5
     else
       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GNU GSS Kerberos library not found" >&5
@@ -42599,7 +42599,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by Squid Web Proxy $as_me 4.0.14, which was
+This file was extended by Squid Web Proxy $as_me 4.0.15, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -42665,7 +42665,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-Squid Web Proxy config.status 4.0.14
+Squid Web Proxy config.status 4.0.15
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -u -r -N squid-4.0.14/configure.ac squid-4.0.15/configure.ac
--- squid-4.0.14/configure.ac	2016-09-09 02:15:20.000000000 +1200
+++ squid-4.0.15/configure.ac	2016-10-10 08:20:13.000000000 +1300
@@ -5,7 +5,7 @@
 ## Please see the COPYING and CONTRIBUTORS files for details.
 ##
 
-AC_INIT([Squid Web Proxy],[4.0.14],[http://bugs.squid-cache.org/],[squid])
+AC_INIT([Squid Web Proxy],[4.0.15],[http://bugs.squid-cache.org/],[squid])
 AC_PREREQ(2.61)
 AC_CONFIG_HEADERS([include/autoconf.h])
 AC_CONFIG_AUX_DIR(cfgaux)
@@ -1758,7 +1758,7 @@
     SQUID_CHECK_KRB5_FUNCS
   fi
   if test "x$KRB5LIBS" = "x"; then
-    if test test "x$with_heimdal_krb5" = "xyes"; then
+    if test "x$with_heimdal_krb5" = "xyes"; then
       AC_MSG_ERROR([Required Heimdal Kerberos library not found])
     else
       AC_MSG_WARN([Heimdal Kerberos library not found])
@@ -1828,7 +1828,7 @@
     SQUID_DEFINE_BOOL(HAVE_KRB5,$squid_cv_working_krb5,[KRB5 support])
   fi
   if test "x$KRB5LIBS" = "x"; then
-    if test test "x$with_gnugss" = "xyes"; then
+    if test "x$with_gnugss" = "xyes"; then
       AC_MSG_ERROR([Required GNU GSS Kerberos library not found])
     else
       AC_MSG_WARN([GNU GSS Kerberos library not found])
diff -u -r -N squid-4.0.14/doc/release-notes/release-4.html squid-4.0.15/doc/release-notes/release-4.html
--- squid-4.0.14/doc/release-notes/release-4.html	2016-09-09 03:30:00.000000000 +1200
+++ squid-4.0.15/doc/release-notes/release-4.html	2016-10-10 11:51:35.000000000 +1300
@@ -2,10 +2,10 @@
 <HTML>
 <HEAD>
  <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.72">
- <TITLE>Squid 4.0.14 release notes</TITLE>
+ <TITLE>Squid 4.0.15 release notes</TITLE>
 </HEAD>
 <BODY>
-<H1>Squid 4.0.14 release notes</H1>
+<H1>Squid 4.0.15 release notes</H1>
 
 <H2>Squid Developers</H2>
 <HR>
@@ -61,7 +61,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.14 for testing.</P>
+<P>The Squid Team are pleased to announce the release of Squid-4.0.15 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>
diff -u -r -N squid-4.0.14/include/version.h squid-4.0.15/include/version.h
--- squid-4.0.14/include/version.h	2016-09-09 02:15:21.000000000 +1200
+++ squid-4.0.15/include/version.h	2016-10-10 08:20:15.000000000 +1300
@@ -7,7 +7,7 @@
  */
 
 #ifndef SQUID_RELEASE_TIME
-#define SQUID_RELEASE_TIME 1473343915
+#define SQUID_RELEASE_TIME 1476039939
 #endif
 
 /*
diff -u -r -N squid-4.0.14/RELEASENOTES.html squid-4.0.15/RELEASENOTES.html
--- squid-4.0.14/RELEASENOTES.html	2016-09-09 03:30:00.000000000 +1200
+++ squid-4.0.15/RELEASENOTES.html	2016-10-10 11:51:35.000000000 +1300
@@ -2,10 +2,10 @@
 <HTML>
 <HEAD>
  <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.72">
- <TITLE>Squid 4.0.14 release notes</TITLE>
+ <TITLE>Squid 4.0.15 release notes</TITLE>
 </HEAD>
 <BODY>
-<H1>Squid 4.0.14 release notes</H1>
+<H1>Squid 4.0.15 release notes</H1>
 
 <H2>Squid Developers</H2>
 <HR>
@@ -61,7 +61,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.14 for testing.</P>
+<P>The Squid Team are pleased to announce the release of Squid-4.0.15 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>
diff -u -r -N squid-4.0.14/src/acl/external/delayer/ext_delayer_acl.8 squid-4.0.15/src/acl/external/delayer/ext_delayer_acl.8
--- squid-4.0.14/src/acl/external/delayer/ext_delayer_acl.8	2016-09-09 03:30:51.000000000 +1200
+++ squid-4.0.15/src/acl/external/delayer/ext_delayer_acl.8	2016-10-10 11:54:25.000000000 +1300
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -46,7 +46,7 @@
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" If the F register is >0, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.nr rF 0
-.if \n(.g .if rF .nr rF 1
-.if (\n(rF:(\n(.g==0)) \{
-.    if \nF \{
-.        de IX
-.        tm Index:\\$1\t\\n%\t"\\$2"
+.if !\nF .nr F 0
+.if \nF>0 \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.        if !\nF==2 \{
-.            nr % 0
-.            nr F 2
-.        \}
+.    if !\nF==2 \{\
+.        nr % 0
+.        nr F 2
 .    \}
 .\}
-.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -133,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_DELAYER_ACL 8"
-.TH EXT_DELAYER_ACL 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH EXT_DELAYER_ACL 8 "2016-10-09" "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
@@ -225,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 \\fIs0\fR\|(7),
+squid (8), \s-1GPL\s0 (7),
 .PP
 The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq
 .PP
diff -u -r -N squid-4.0.14/src/acl/external/SQL_session/ext_sql_session_acl.8 squid-4.0.15/src/acl/external/SQL_session/ext_sql_session_acl.8
--- squid-4.0.14/src/acl/external/SQL_session/ext_sql_session_acl.8	2016-09-09 03:31:02.000000000 +1200
+++ squid-4.0.15/src/acl/external/SQL_session/ext_sql_session_acl.8	2016-10-10 11:55:00.000000000 +1300
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -46,7 +46,7 @@
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" If the F register is >0, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.nr rF 0
-.if \n(.g .if rF .nr rF 1
-.if (\n(rF:(\n(.g==0)) \{
-.    if \nF \{
-.        de IX
-.        tm Index:\\$1\t\\n%\t"\\$2"
+.if !\nF .nr F 0
+.if \nF>0 \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.        if !\nF==2 \{
-.            nr % 0
-.            nr F 2
-.        \}
+.    if !\nF==2 \{\
+.        nr % 0
+.        nr F 2
 .    \}
 .\}
-.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -133,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_SQL_SESSION_ACL 8"
-.TH EXT_SQL_SESSION_ACL 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH EXT_SQL_SESSION_ACL 8 "2016-10-09" "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
@@ -154,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"
@@ -225,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 \\fIs0\fR\|(7),
+squid (8), \s-1GPL\s0 (7),
 .PP
 The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq
 .PP
diff -u -r -N squid-4.0.14/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 squid-4.0.15/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8
--- squid-4.0.14/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8	2016-09-09 03:31:06.000000000 +1200
+++ squid-4.0.15/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8	2016-10-10 11:55:22.000000000 +1300
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -46,7 +46,7 @@
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" If the F register is >0, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.nr rF 0
-.if \n(.g .if rF .nr rF 1
-.if (\n(rF:(\n(.g==0)) \{
-.    if \nF \{
-.        de IX
-.        tm Index:\\$1\t\\n%\t"\\$2"
+.if !\nF .nr F 0
+.if \nF>0 \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.        if !\nF==2 \{
-.            nr % 0
-.            nr F 2
-.        \}
+.    if !\nF==2 \{\
+.        nr % 0
+.        nr F 2
 .    \}
 .\}
-.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -133,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_WBINFO_GROUP_ACL 8"
-.TH EXT_WBINFO_GROUP_ACL 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH EXT_WBINFO_GROUP_ACL 8 "2016-10-09" "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.14/src/acl/FilledChecklist.h squid-4.0.15/src/acl/FilledChecklist.h
--- squid-4.0.14/src/acl/FilledChecklist.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/acl/FilledChecklist.h	2016-10-10 08:05:51.000000000 +1300
@@ -18,9 +18,7 @@
 #if USE_AUTH
 #include "auth/UserRequest.h"
 #endif
-#if USE_OPENSSL
-#include "ssl/support.h"
-#endif
+#include "security/CertError.h"
 
 class CachePeer;
 class ConnStateData;
@@ -83,12 +81,10 @@
     char *snmp_community;
 #endif
 
-#if USE_OPENSSL
     /// SSL [certificate validation] errors, in undefined order
-    const Ssl::CertErrors *sslErrors;
+    const Security::CertErrors *sslErrors;
     /// The peer certificate
     Security::CertPointer serverCert;
-#endif
 
     AccessLogEntry::Pointer al; ///< info for the future access.log, and external ACL
 
diff -u -r -N squid-4.0.14/src/acl/SslErrorData.cc squid-4.0.15/src/acl/SslErrorData.cc
--- squid-4.0.14/src/acl/SslErrorData.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/acl/SslErrorData.cc	2016-10-10 08:05:51.000000000 +1300
@@ -9,46 +9,29 @@
 #include "squid.h"
 #include "acl/Checklist.h"
 #include "acl/SslErrorData.h"
-#include "wordlist.h"
+#include "security/CertError.h"
+#include "ssl/ErrorDetail.h"
 
-ACLSslErrorData::ACLSslErrorData() : values (NULL)
+ACLSslErrorData::ACLSslErrorData(ACLSslErrorData const &o) :
+    values(o.values)
 {}
 
-ACLSslErrorData::ACLSslErrorData(ACLSslErrorData const &old) : values (NULL)
-{
-    assert (!old.values);
-}
-
-ACLSslErrorData::~ACLSslErrorData()
-{
-    if (values)
-        delete values;
-}
-
 bool
-ACLSslErrorData::match(const Ssl::CertErrors *toFind)
+ACLSslErrorData::match(const Security::CertErrors *toFind)
 {
-    for (const Ssl::CertErrors *err = toFind; err; err = err->next ) {
-        if (values->findAndTune(err->element.code))
+    for (const auto *err = toFind; err; err = err->next) {
+        if (values.count(err->element.code))
             return true;
     }
     return false;
 }
 
-/* explicit instantiation required for some systems */
-/** \cond AUTODOCS_IGNORE */
-// AYJ: 2009-05-20 : Removing. clashes with template <int> instantiation for other ACLs.
-// template cbdata_type Ssl::Errors::CBDATA_CbDataList;
-/** \endcond */
-
 SBufList
 ACLSslErrorData::dump() const
 {
     SBufList sl;
-    Ssl::Errors *data = values;
-    while (data != NULL) {
-        sl.push_back(SBuf(Ssl::GetErrorName(data->element)));
-        data = data->next;
+    for (const auto &e : values) {
+        sl.push_back(SBuf(Ssl::GetErrorName(e)));
     }
     return sl;
 }
@@ -56,27 +39,14 @@
 void
 ACLSslErrorData::parse()
 {
-    Ssl::Errors **Tail;
-
-    for (Tail = &values; *Tail; Tail = &((*Tail)->next));
     while (char *t = ConfigParser::strtokFile()) {
-        Ssl::Errors *q = Ssl::ParseErrorString(t);
-        *(Tail) = q;
-        Tail = &q->tail()->next;
+        Ssl::ParseErrorString(t, values);
     }
 }
 
-bool
-ACLSslErrorData::empty() const
-{
-    return values == NULL;
-}
-
 ACLSslErrorData *
 ACLSslErrorData::clone() const
 {
-    /* Splay trees don't clone yet. */
-    assert (!values);
     return new ACLSslErrorData(*this);
 }
 
diff -u -r -N squid-4.0.14/src/acl/SslErrorData.h squid-4.0.15/src/acl/SslErrorData.h
--- squid-4.0.14/src/acl/SslErrorData.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/acl/SslErrorData.h	2016-10-10 08:05:51.000000000 +1300
@@ -11,27 +11,24 @@
 
 #include "acl/Acl.h"
 #include "acl/Data.h"
-#include "base/CbDataList.h"
-#include "ssl/ErrorDetail.h"
-#include "ssl/support.h"
-#include <vector>
+#include "security/forward.h"
 
-class ACLSslErrorData : public ACLData<const Ssl::CertErrors *>
+class ACLSslErrorData : public ACLData<const Security::CertErrors *>
 {
     MEMPROXY_CLASS(ACLSslErrorData);
 
 public:
-    ACLSslErrorData();
+    ACLSslErrorData() = default;
     ACLSslErrorData(ACLSslErrorData const &);
     ACLSslErrorData &operator= (ACLSslErrorData const &);
-    virtual ~ACLSslErrorData();
-    bool match(const Ssl::CertErrors *);
+    virtual ~ACLSslErrorData() {}
+    bool match(const Security::CertErrors *);
     virtual SBufList dump() const;
     void parse();
-    bool empty() const;
+    bool empty() const { return values.empty(); }
     virtual  ACLSslErrorData *clone() const;
 
-    Ssl::Errors *values;
+    Security::Errors values;
 };
 
 #endif /* SQUID_ACLSSL_ERRORDATA_H */
diff -u -r -N squid-4.0.14/src/acl/SslError.h squid-4.0.15/src/acl/SslError.h
--- squid-4.0.14/src/acl/SslError.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/acl/SslError.h	2016-10-10 08:05:51.000000000 +1300
@@ -8,11 +8,11 @@
 
 #ifndef SQUID_ACLSSL_ERROR_H
 #define SQUID_ACLSSL_ERROR_H
+
 #include "acl/Strategised.h"
 #include "acl/Strategy.h"
-#include "ssl/support.h"
 
-class ACLSslErrorStrategy : public ACLStrategy<const Ssl::CertErrors *>
+class ACLSslErrorStrategy : public ACLStrategy<const Security::CertErrors *>
 {
 
 public:
@@ -35,7 +35,7 @@
 
 private:
     static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<const Ssl::CertErrors *> RegistryEntry_;
+    static ACLStrategised<const Security::CertErrors *> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLSSL_ERROR_H */
diff -u -r -N squid-4.0.14/src/AclRegs.cc squid-4.0.15/src/AclRegs.cc
--- squid-4.0.14/src/AclRegs.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/AclRegs.cc	2016-10-10 08:05:51.000000000 +1300
@@ -170,7 +170,7 @@
 
 #if USE_OPENSSL
 ACL::Prototype ACLSslError::RegistryProtoype(&ACLSslError::RegistryEntry_, "ssl_error");
-ACLStrategised<const Ssl::CertErrors *> ACLSslError::RegistryEntry_(new ACLSslErrorData, ACLSslErrorStrategy::Instance(), "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");
diff -u -r -N squid-4.0.14/src/adaptation/icap/ModXact.cc squid-4.0.15/src/adaptation/icap/ModXact.cc
--- squid-4.0.14/src/adaptation/icap/ModXact.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/adaptation/icap/ModXact.cc	2016-10-10 08:05:51.000000000 +1300
@@ -1265,31 +1265,32 @@
 
 void Adaptation::Icap::ModXact::finalizeLogInfo()
 {
-    HttpRequest * request_ = NULL;
-    HttpRequest * adapted_request_ = NULL;
-    HttpReply * reply_ = NULL;
-    request_ = (virgin.cause? virgin.cause: dynamic_cast<HttpRequest*>(virgin.header));
+    HttpRequest *adapted_request_ = nullptr;
+    HttpReply *adapted_reply_ = nullptr;
+    HttpRequest *virgin_request_ = const_cast<HttpRequest*>(&virginRequest());
     if (!(adapted_request_ = dynamic_cast<HttpRequest*>(adapted.header))) {
-        adapted_request_ = request_;
-        reply_ = dynamic_cast<HttpReply*>(adapted.header);
+        // if the request was not adapted, use virgin request to simplify
+        // the code further below
+        adapted_request_ = virgin_request_;
+        adapted_reply_ = dynamic_cast<HttpReply*>(adapted.header);
     }
 
-    Adaptation::Icap::History::Pointer h = (request_ ? request_->icapHistory() : NULL);
+    Adaptation::Icap::History::Pointer h = virgin_request_->icapHistory();
     Must(h != NULL); // ICAPXaction::maybeLog calls only if there is a log
     al.icp.opcode = ICP_INVALID;
     al.url = h->log_uri.termedBuf();
     const Adaptation::Icap::ServiceRep  &s = service();
     al.icap.reqMethod = s.cfg().method;
 
-    al.cache.caddr = request_->client_addr;
+    al.cache.caddr = virgin_request_->client_addr;
 
-    al.request = request_;
+    al.request = virgin_request_;
     HTTPMSGLOCK(al.request);
     al.adapted_request = adapted_request_;
     HTTPMSGLOCK(al.adapted_request);
 
-    if (reply_) {
-        al.reply = reply_;
+    if (adapted_reply_) {
+        al.reply = adapted_reply_;
         HTTPMSGLOCK(al.reply);
     } else
         al.reply = NULL;
@@ -1302,30 +1303,34 @@
         al.cache.ssluser = h->ssluser.termedBuf();
 #endif
     al.cache.code = h->logType;
-    // XXX: should use icap-specific counters instead ?
-    al.http.clientRequestSz.payloadData = h->req_sz;
+
+    const HttpMsg *virgin_msg = dynamic_cast<HttpReply*>(virgin.header);
+    if (!virgin_msg)
+        virgin_msg = virgin_request_;
+    assert(virgin_msg != virgin.cause);
+    al.http.clientRequestSz.header = virgin_msg->hdr_sz;
+    al.http.clientRequestSz.payloadData = virgin_msg->body_pipe->producedSize();
 
     // leave al.icap.bodyBytesRead negative if no body
     if (replyHttpHeaderSize >= 0 || replyHttpBodySize >= 0) {
         const int64_t zero = 0; // to make max() argument types the same
-        al.icap.bodyBytesRead =
-            max(zero, replyHttpHeaderSize) + max(zero, replyHttpBodySize);
+        const uint64_t headerSize = max(zero, replyHttpHeaderSize);
+        const uint64_t bodySize =  max(zero, replyHttpBodySize);
+        al.icap.bodyBytesRead = headerSize + bodySize;
+        al.http.clientReplySz.header = headerSize;
+        al.http.clientReplySz.payloadData = bodySize;
     }
 
-    if (reply_) {
-        al.http.code = reply_->sline.status();
-        al.http.content_type = reply_->content_type.termedBuf();
-        if (replyHttpBodySize >= 0) {
-            // XXX: should use icap-specific counters instead ?
-            al.http.clientReplySz.payloadData = replyHttpBodySize;
-            al.http.clientReplySz.header =  reply_->hdr_sz;
+    if (adapted_reply_) {
+        al.http.code = adapted_reply_->sline.status();
+        al.http.content_type = adapted_reply_->content_type.termedBuf();
+        if (replyHttpBodySize >= 0)
             al.cache.highOffset = replyHttpBodySize;
-        }
         //don't set al.cache.objectSize because it hasn't exist yet
 
         MemBuf mb;
         mb.init();
-        reply_->header.packInto(&mb);
+        adapted_reply_->header.packInto(&mb);
         al.headers.reply = xstrdup(mb.buf);
         mb.clean();
     }
diff -u -r -N squid-4.0.14/src/adaptation/icap/ServiceRep.cc squid-4.0.15/src/adaptation/icap/ServiceRep.cc
--- squid-4.0.14/src/adaptation/icap/ServiceRep.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/adaptation/icap/ServiceRep.cc	2016-10-10 08:05:51.000000000 +1300
@@ -33,7 +33,6 @@
 
 Adaptation::Icap::ServiceRep::ServiceRep(const ServiceConfigPointer &svcCfg):
     AsyncJob("Adaptation::Icap::ServiceRep"), Adaptation::Service(svcCfg),
-    sslContext(NULL),
     theOptions(NULL), theOptionsFetcher(0), theLastUpdate(0),
     theBusyConns(0),
     theAllWaiters(0),
diff -u -r -N squid-4.0.14/src/adaptation/icap/ServiceRep.h squid-4.0.15/src/adaptation/icap/ServiceRep.h
--- squid-4.0.14/src/adaptation/icap/ServiceRep.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/adaptation/icap/ServiceRep.h	2016-10-10 08:05:51.000000000 +1300
@@ -110,7 +110,7 @@
     // receive either an ICAP OPTIONS response header or an abort message
     virtual void noteAdaptationAnswer(const Answer &answer);
 
-    Security::ContextPtr sslContext;
+    Security::ContextPointer sslContext;
     Security::SessionStatePointer sslSession;
 
 private:
diff -u -r -N squid-4.0.14/src/adaptation/icap/Xaction.cc squid-4.0.15/src/adaptation/icap/Xaction.cc
--- squid-4.0.14/src/adaptation/icap/Xaction.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/adaptation/icap/Xaction.cc	2016-10-10 08:05:51.000000000 +1300
@@ -64,7 +64,9 @@
     /* Security::PeerConnector API */
     virtual bool initialize(Security::SessionPointer &);
     virtual void noteNegotiationDone(ErrorState *error);
-    virtual Security::ContextPtr getSslContext() {return icapService->sslContext;}
+    virtual Security::ContextPointer getTlsContext() {
+        return icapService->sslContext;
+    }
 
 private:
     Adaptation::Icap::ServiceRep::Pointer icapService;
diff -u -r -N squid-4.0.14/src/anyp/PortCfg.cc squid-4.0.15/src/anyp/PortCfg.cc
--- squid-4.0.14/src/anyp/PortCfg.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/anyp/PortCfg.cc	2016-10-10 08:05:51.000000000 +1300
@@ -103,7 +103,7 @@
 #if 0
     // TODO: AYJ: 2015-01-15: for now SSL does not clone the context object.
     // cloning should only be done before the PortCfg is post-configure initialized and opened
-    Security::ContextPtr sslContext;
+    Security::ContextPointer sslContext;
 #endif
 
 #endif /*0*/
diff -u -r -N squid-4.0.14/src/auth/basic/DB/basic_db_auth.8 squid-4.0.15/src/auth/basic/DB/basic_db_auth.8
--- squid-4.0.14/src/auth/basic/DB/basic_db_auth.8	2016-09-09 03:31:37.000000000 +1200
+++ squid-4.0.15/src/auth/basic/DB/basic_db_auth.8	2016-10-10 11:57:47.000000000 +1300
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -46,7 +46,7 @@
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" If the F register is >0, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.nr rF 0
-.if \n(.g .if rF .nr rF 1
-.if (\n(rF:(\n(.g==0)) \{
-.    if \nF \{
-.        de IX
-.        tm Index:\\$1\t\\n%\t"\\$2"
+.if !\nF .nr F 0
+.if \nF>0 \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.        if !\nF==2 \{
-.            nr % 0
-.            nr F 2
-.        \}
+.    if !\nF==2 \{\
+.        nr % 0
+.        nr F 2
 .    \}
 .\}
-.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -133,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "BASIC_DB_AUTH 8"
-.TH BASIC_DB_AUTH 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH BASIC_DB_AUTH 8 "2016-10-09" "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
@@ -194,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"
@@ -233,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 \\fIs0\fR\|(7),
+squid (8), \s-1GPL\s0 (7),
 .PP
 The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq
 .PP
diff -u -r -N squid-4.0.14/src/auth/basic/POP3/basic_pop3_auth.8 squid-4.0.15/src/auth/basic/POP3/basic_pop3_auth.8
--- squid-4.0.14/src/auth/basic/POP3/basic_pop3_auth.8	2016-09-09 03:31:47.000000000 +1200
+++ squid-4.0.15/src/auth/basic/POP3/basic_pop3_auth.8	2016-10-10 11:58:16.000000000 +1300
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -46,7 +46,7 @@
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" If the F register is >0, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.nr rF 0
-.if \n(.g .if rF .nr rF 1
-.if (\n(rF:(\n(.g==0)) \{
-.    if \nF \{
-.        de IX
-.        tm Index:\\$1\t\\n%\t"\\$2"
+.if !\nF .nr F 0
+.if \nF>0 \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.        if !\nF==2 \{
-.            nr % 0
-.            nr F 2
-.        \}
+.    if !\nF==2 \{\
+.        nr % 0
+.        nr F 2
 .    \}
 .\}
-.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -133,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "BASIC_POP3_AUTH 8"
-.TH BASIC_POP3_AUTH 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH BASIC_POP3_AUTH 8 "2016-10-09" "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
@@ -202,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 \\fIs0\fR\|(7),
+squid (8), \s-1GPL\s0 (7),
 .PP
 The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq
 .PP
diff -u -r -N squid-4.0.14/src/base/RunnersRegistry.cc squid-4.0.15/src/base/RunnersRegistry.cc
--- squid-4.0.14/src/base/RunnersRegistry.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/base/RunnersRegistry.cc	2016-10-10 08:05:51.000000000 +1300
@@ -8,6 +8,7 @@
 
 #include "squid.h"
 #include "base/RunnersRegistry.h"
+#include "base/TextException.h"
 #include <set>
 
 /// a collection of unique runners, in no particular order
@@ -19,7 +20,7 @@
 
 /// creates the registered runners container if needed
 /// \return either registered runners (if they should exist) or nil (otherwise)
-static Runners *
+static inline Runners *
 FindRunners()
 {
     if (!TheRunners && !RunnersGone)
@@ -35,11 +36,21 @@
     // else ignore; IndependentRunner
 }
 
+static inline void
+RegisterRunner_(RegisteredRunner *rr)
+{
+    Runners *runners = FindRunners();
+    Must(runners);
+    runners->insert(rr);
+}
+
 bool
 RegisterRunner(RegisteredRunner *rr)
 {
-    if (Runners *runners = FindRunners()) {
-        runners->insert(rr);
+    Must(!dynamic_cast<IndependentRunner*>(rr));
+
+    if (FindRunners()) {
+        RegisterRunner_(rr);
         return true;
     }
 
@@ -88,6 +99,14 @@
     // else it is too late, finishShutdown() has been called
 }
 
+void
+IndependentRunner::registerRunner()
+{
+    if (FindRunners())
+        RegisterRunner_(this);
+    // else do nothing past finishShutdown
+}
+
 bool
 UseThisStatic(const void *)
 {
diff -u -r -N squid-4.0.14/src/base/RunnersRegistry.h squid-4.0.15/src/base/RunnersRegistry.h
--- squid-4.0.14/src/base/RunnersRegistry.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/base/RunnersRegistry.h	2016-10-10 08:05:51.000000000 +1300
@@ -57,6 +57,11 @@
 
     /* Reconfiguration events */
 
+    /// Called after receiving a reconfigure request and before parsing squid.conf.
+    /// Meant for modules that need to prepare for their configuration being changed
+    /// [outside their control]. The changes end with the syncConfig() event.
+    virtual void startReconfigure() {}
+
     /// Called after parsing squid.conf during reconfiguration.
     /// Meant for adjusting the module state based on configuration changes.
     virtual void syncConfig() {}
@@ -100,7 +105,7 @@
     virtual ~IndependentRunner() { unregisterRunner(); }
 
 protected:
-    void registerRunner() {RegisterRunner(this);}
+    void registerRunner();
     void unregisterRunner(); ///< unregisters self; safe to call multiple times
 };
 
diff -u -r -N squid-4.0.14/src/cache_cf.cc squid-4.0.15/src/cache_cf.cc
--- squid-4.0.14/src/cache_cf.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/cache_cf.cc	2016-10-10 08:05:51.000000000 +1300
@@ -613,7 +613,7 @@
 static void
 configDoConfigure(void)
 {
-    memset(&Config2, '\0', sizeof(SquidConfig2));
+    Config2.clear();
     /* init memory as early as possible */
     memConfigure();
     /* Sanity checks */
@@ -836,7 +836,7 @@
             if (pwd->pw_dir && *pwd->pw_dir) {
                 // putenv() leaks by design; avoid leaks when nothing changes
                 static SBuf lastDir;
-                if (lastDir.isEmpty() || !lastDir.cmp(pwd->pw_dir)) {
+                if (lastDir.isEmpty() || lastDir.cmp(pwd->pw_dir) != 0) {
                     lastDir = pwd->pw_dir;
                     int len = strlen(pwd->pw_dir) + 6;
                     char *env_str = (char *)xcalloc(len, 1);
@@ -880,7 +880,7 @@
 #endif
         }
 #if USE_OPENSSL
-        Ssl::useSquidUntrusted(Config.ssl_client.sslContext);
+        Ssl::useSquidUntrusted(Config.ssl_client.sslContext.get());
 #endif
     }
 
@@ -1487,7 +1487,7 @@
 free_acl_tos(acl_tos ** head)
 {
     delete *head;
-    head = NULL;
+    *head = NULL;
 }
 
 #if SO_MARK && USE_LIBCAP
@@ -1540,7 +1540,7 @@
 free_acl_nfmark(acl_nfmark ** head)
 {
     delete *head;
-    head = NULL;
+    *head = NULL;
 }
 #endif /* SO_MARK */
 
@@ -3903,8 +3903,8 @@
 configFreeMemory(void)
 {
     free_all();
+    Config.ssl_client.sslContext.reset();
 #if USE_OPENSSL
-    SSL_CTX_free(Config.ssl_client.sslContext);
     Ssl::unloadSquidUntrusted();
 #endif
 }
diff -u -r -N squid-4.0.14/src/CachePeer.cc squid-4.0.15/src/CachePeer.cc
--- squid-4.0.14/src/CachePeer.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/CachePeer.cc	2016-10-10 08:05:51.000000000 +1300
@@ -40,9 +40,6 @@
     connect_fail_limit(0),
     max_conn(0),
     domain(NULL),
-#if USE_OPENSSL
-    sslContext(NULL),
-#endif
     front_end_https(0),
     connection_auth(2 /* auto */)
 {
@@ -97,10 +94,5 @@
     PeerPoolMgr::Checkpoint(standby.mgr, "peer gone");
 
     xfree(domain);
-
-#if USE_OPENSSL
-    if (sslContext)
-        SSL_CTX_free(sslContext);
-#endif
 }
 
diff -u -r -N squid-4.0.14/src/CachePeer.h squid-4.0.15/src/CachePeer.h
--- squid-4.0.14/src/CachePeer.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/CachePeer.h	2016-10-10 08:05:51.000000000 +1300
@@ -183,7 +183,7 @@
 
     /// security settings for peer connection
     Security::PeerOptions secure;
-    Security::ContextPtr sslContext;
+    Security::ContextPointer sslContext;
     Security::SessionStatePointer sslSession;
 
     int front_end_https;
diff -u -r -N squid-4.0.14/src/cf.data.pre squid-4.0.15/src/cf.data.pre
--- squid-4.0.14/src/cf.data.pre	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/cf.data.pre	2016-10-10 08:05:51.000000000 +1300
@@ -4519,13 +4519,35 @@
 	ICAP transaction log lines will correspond to a single access
 	log line.
 
-	ICAP log uses logformat codes that make sense for an ICAP
-	transaction. Header-related codes are applied to the HTTP header
-	embedded in an ICAP server response, with the following caveats:
-	For REQMOD, there is no HTTP response header unless the ICAP
-	server performed request satisfaction. For RESPMOD, the HTTP
-	request header is the header sent to the ICAP server. For
-	OPTIONS, there are no HTTP headers.
+	ICAP log supports many access.log logformat %codes. In ICAP context,
+	HTTP message-related %codes are applied to the HTTP message embedded
+	in an ICAP message. Logformat "%http::>..." codes are used for HTTP
+	messages embedded in ICAP requests while "%http::<..." codes are used
+	for HTTP messages embedded in ICAP responses. For example:
+
+		http::>h	To-be-adapted HTTP message headers sent by Squid to
+				the ICAP service. For REQMOD transactions, these are
+				HTTP request headers. For RESPMOD, these are HTTP
+				response headers, but Squid currently cannot log them
+				(i.e., %http::>h will expand to "-" for RESPMOD).
+
+		http::<h	Adapted HTTP message headers sent by the ICAP
+				service to Squid (i.e., HTTP request headers in regular
+				REQMOD; HTTP response headers in RESPMOD and during
+				request satisfaction in REQMOD).
+
+	ICAP OPTIONS transactions do not embed HTTP messages.
+
+	Several logformat codes below deal with ICAP message bodies. An ICAP
+	message body, if any, typically includes a complete HTTP message
+	(required HTTP headers plus optional HTTP message body). When
+	computing HTTP message body size for these logformat codes, Squid
+	either includes or excludes chunked encoding overheads; see
+	code-specific documentation for details.
+
+	For Secure ICAP services, all size-related information is currently
+	computed before/after TLS encryption/decryption, as if TLS was not
+	in use at all.
 
 	The following format codes are also available for ICAP logs:
 
@@ -4539,19 +4561,16 @@
 		icap::rm	ICAP request method (REQMOD, RESPMOD, or 
 				OPTIONS). Similar to existing rm.
 
-		icap::>st	Bytes sent to the ICAP server (TCP payload
-				only; i.e., what Squid writes to the socket).
+		icap::>st	The total size of the ICAP request sent to the ICAP
+				server (ICAP headers + ICAP body), including chunking
+				metadata (if any).
+
+		icap::<st	The total size of the ICAP response received from the
+				ICAP server (ICAP headers + ICAP body), including
+				chunking metadata (if any).
 
-		icap::<st	Bytes received from the ICAP server (TCP
-				payload only; i.e., what Squid reads from
-				the socket).
-
-		icap::<bs	Number of message body bytes received from the
-				ICAP server. ICAP message body, if any, usually
-				includes encapsulated HTTP message headers and
-				possibly encapsulated HTTP message body. The
-				HTTP body part is dechunked before its size is
-				computed.
+		icap::<bs	The size of the ICAP response body received from the
+				ICAP server, excluding chunking metadata (if any).
 
 		icap::tr 	Transaction response time (in
 				milliseconds).  The timer starts when
@@ -4581,9 +4600,9 @@
 	The default ICAP log format, which can be used without an explicit
 	definition, is called icap_squid:
 
-logformat icap_squid %ts.%03tu %6icap::tr %>a %icap::to/%03icap::Hs %icap::<size %icap::rm %icap::ru% %un -/%icap::<A -
+logformat icap_squid %ts.%03tu %6icap::tr %>A %icap::to/%03icap::Hs %icap::<st %icap::rm %icap::ru %un -/%icap::<A -
 
-	See also: logformat, log_icap, and %adapt::<last_h 
+	See also: logformat and %adapt::<last_h
 DOC_END
 
 NAME: logfile_daemon
diff -u -r -N squid-4.0.14/src/cf_gen.cc squid-4.0.15/src/cf_gen.cc
--- squid-4.0.14/src/cf_gen.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/cf_gen.cc	2016-10-10 08:05:51.000000000 +1300
@@ -478,10 +478,10 @@
     fout << "static void" << std::endl <<
          "default_line(const char *s)" << std::endl <<
          "{" << std::endl <<
-         "    int len = strlen(s) +1;" << std::endl <<
-         "    char *tmp_line = xstrndup(s, len);" << std::endl <<
+         "    char *tmp_line = xstrdup(s);" << std::endl <<
+         "    int len = strlen(tmp_line);" << std::endl <<
          "    ProcessMacros(tmp_line, len);" << std::endl <<
-         "    xstrncpy(config_input_line, tmp_line, len);" << std::endl <<
+         "    xstrncpy(config_input_line, tmp_line, sizeof(config_input_line));" << std::endl <<
          "    config_lineno++;" << std::endl <<
          "    parse_line(tmp_line);" << std::endl <<
          "    xfree(tmp_line);" << std::endl <<
diff -u -r -N squid-4.0.14/src/client_side.cc squid-4.0.15/src/client_side.cc
--- squid-4.0.14/src/client_side.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/client_side.cc	2016-10-10 08:05:51.000000000 +1300
@@ -362,8 +362,6 @@
     aLogEntry->http.method = request->method;
     aLogEntry->http.version = request->http_ver;
     aLogEntry->hier = request->hier;
-    if (request->content_length > 0) // negative when no body or unknown length
-        aLogEntry->http.clientRequestSz.payloadData += request->content_length; // XXX: actually adaptedRequest payload size ??
     aLogEntry->cache.extuser = request->extacl_user.termedBuf();
 
     // Adapted request, if any, inherits and then collects all the stats, but
@@ -400,6 +398,9 @@
         al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ?
 
     al->http.clientRequestSz.header = req_sz;
+    // the virgin request is saved to al->request
+    if (al->request && al->request->body_pipe)
+        al->http.clientRequestSz.payloadData = al->request->body_pipe->producedSize();
     al->http.clientReplySz.header = out.headers_sz;
     // XXX: calculate without payload encoding or headers !!
     al->http.clientReplySz.payloadData = out.size - out.headers_sz; // pretend its all un-encoded data for now.
@@ -1508,16 +1509,16 @@
     // In bump-server-first mode, we have not necessarily seen the intended
     // server name at certificate-peeking time. Check for domain mismatch now,
     // when we can extract the intended name from the bumped HTTP request.
-    if (X509 *srvCert = sslServerBump->serverCert.get()) {
+    if (const Security::CertPointer &srvCert = sslServerBump->serverCert) {
         HttpRequest *request = http->request;
-        if (!Ssl::checkX509ServerValidity(srvCert, request->url.host())) {
+        if (!Ssl::checkX509ServerValidity(srvCert.get(), request->url.host())) {
             debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " <<
                    "does not match domainname " << request->url.host());
 
             bool allowDomainMismatch = false;
             if (Config.ssl_client.cert_error) {
                 ACLFilledChecklist check(Config.ssl_client.cert_error, request, dash_str);
-                check.sslErrors = new Ssl::CertErrors(Ssl::CertError(SQUID_X509_V_ERR_DOMAIN_MISMATCH, srvCert));
+                check.sslErrors = new Security::CertErrors(Security::CertError(SQUID_X509_V_ERR_DOMAIN_MISMATCH, srvCert));
                 allowDomainMismatch = (check.fastCheck() == ACCESS_ALLOWED);
                 delete check.sslErrors;
                 check.sslErrors = NULL;
@@ -1539,7 +1540,7 @@
                 err->src_addr = clientConnection->remote;
                 Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail(
                     SQUID_X509_V_ERR_DOMAIN_MISMATCH,
-                    srvCert, NULL);
+                    srvCert.get(), nullptr);
                 err->detail = errDetail;
                 // Save the original request for logging purposes.
                 if (!context->http->al->request) {
@@ -2448,7 +2449,7 @@
 
     // register to receive notice of Squid signal events
     // which may affect long persisting client connections
-    RegisterRunner(this);
+    registerRunner();
 }
 
 void
@@ -2579,9 +2580,9 @@
 
 /** Create SSL connection structure and update fd_table */
 static bool
-httpsCreate(const Comm::ConnectionPointer &conn, Security::ContextPtr sslContext)
+httpsCreate(const Comm::ConnectionPointer &conn, const Security::ContextPointer &ctx)
 {
-    if (Ssl::CreateServer(sslContext, conn, "client https start")) {
+    if (Ssl::CreateServer(ctx, conn, "client https start")) {
         debugs(33, 5, "will negotate SSL on " << conn);
         return true;
     }
@@ -2648,9 +2649,6 @@
 clientNegotiateSSL(int fd, void *data)
 {
     ConnStateData *conn = (ConnStateData *)data;
-    X509 *client_cert;
-    auto ssl = fd_table[fd].ssl.get();
-
     int ret;
     if ((ret = Squid_SSL_accept(conn, clientNegotiateSSL)) <= 0) {
         if (ret < 0) // An error
@@ -2658,16 +2656,21 @@
         return;
     }
 
-    if (Security::SessionIsResumed(fd_table[fd].ssl)) {
-        debugs(83, 2, "clientNegotiateSSL: Session " << SSL_get_session(ssl) <<
-               " reused on FD " << fd << " (" << fd_table[fd].ipaddr << ":" << (int)fd_table[fd].remote_port << ")");
+    Security::SessionPointer session(fd_table[fd].ssl);
+    if (Security::SessionIsResumed(session)) {
+        debugs(83, 2, "Session " << SSL_get_session(session.get()) <<
+               " reused on FD " << fd << " (" << fd_table[fd].ipaddr <<
+               ":" << (int)fd_table[fd].remote_port << ")");
     } else {
         if (Debug::Enabled(83, 4)) {
             /* Write out the SSL session details.. actually the call below, but
              * OpenSSL headers do strange typecasts confusing GCC.. */
             /* PEM_write_SSL_SESSION(debug_log, SSL_get_session(ssl)); */
 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00908000L
-            PEM_ASN1_write((i2d_of_void *)i2d_SSL_SESSION, PEM_STRING_SSL_SESSION, debug_log, (char *)SSL_get_session(ssl), NULL,NULL,0,NULL,NULL);
+            PEM_ASN1_write(reinterpret_cast<i2d_of_void *>(i2d_SSL_SESSION),
+                           PEM_STRING_SSL_SESSION, debug_log,
+                           reinterpret_cast<char *>(SSL_get_session(session.get())),
+                           nullptr, nullptr, 0, nullptr, nullptr);
 
 #elif (ALLOW_ALWAYS_SSL_SESSION_DETAIL == 1)
 
@@ -2678,47 +2681,48 @@
             * Because there are two possible usable cast, if you get an error here, try the other
             * commented line. */
 
-            PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION, debug_log, (char *)SSL_get_session(ssl), NULL,NULL,0,NULL,NULL);
-            /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION, debug_log, (char *)SSL_get_session(ssl), NULL,NULL,0,NULL,NULL); */
-
+            PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
+                           debug_log,
+                           reinterpret_cast<char *>(SSL_get_session(session.get())),
+                           nullptr, nullptr, 0, nullptr, nullptr);
+            /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
+                           debug_log,
+                           reinterpret_cast<char *>(SSL_get_session(session.get())),
+                           nullptr, nullptr, 0, nullptr, nullptr);
+             */
 #else
-
-            debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source." );
+            debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source.");
 
 #endif
             /* Note: This does not automatically fflush the log file.. */
         }
 
-        debugs(83, 2, "clientNegotiateSSL: New session " <<
-               SSL_get_session(ssl) << " on FD " << fd << " (" <<
-               fd_table[fd].ipaddr << ":" << (int)fd_table[fd].remote_port <<
-               ")");
+        debugs(83, 2, "New session " << SSL_get_session(session.get()) <<
+               " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" <<
+               fd_table[fd].remote_port << ")");
     }
 
     // Connection established. Retrieve TLS connection parameters for logging.
-    conn->clientConnection->tlsNegotiations()->retrieveNegotiatedInfo(ssl);
+    conn->clientConnection->tlsNegotiations()->retrieveNegotiatedInfo(session);
 
-    client_cert = SSL_get_peer_certificate(ssl);
+    X509 *client_cert = SSL_get_peer_certificate(session.get());
 
-    if (client_cert != NULL) {
-        debugs(83, 3, "clientNegotiateSSL: FD " << fd <<
-               " client certificate: subject: " <<
+    if (client_cert) {
+        debugs(83, 3, "FD " << fd << " client certificate: subject: " <<
                X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0));
 
-        debugs(83, 3, "clientNegotiateSSL: FD " << fd <<
-               " client certificate: issuer: " <<
+        debugs(83, 3, "FD " << fd << " client certificate: issuer: " <<
                X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0));
 
         X509_free(client_cert);
     } else {
-        debugs(83, 5, "clientNegotiateSSL: FD " << fd <<
-               " has no certificate.");
+        debugs(83, 5, "FD " << fd << " has no certificate.");
     }
 
 #if defined(TLSEXT_NAMETYPE_host_name)
     if (!conn->serverBump()) {
         // when in bumpClientFirst mode, get the server name from SNI
-        if (const char *server = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))
+        if (const char *server = SSL_get_servername(session.get(), TLSEXT_NAMETYPE_host_name))
             conn->resetSslCommonName(server);
     }
 #endif
@@ -2727,16 +2731,16 @@
 }
 
 /**
- * If Security::ContextPtr is given, starts reading the TLS handshake.
- * Otherwise, calls switchToHttps to generate a dynamic Security::ContextPtr.
+ * If Security::ContextPointer is given, starts reading the TLS handshake.
+ * Otherwise, calls switchToHttps to generate a dynamic Security::ContextPointer.
  */
 static void
-httpsEstablish(ConnStateData *connState, Security::ContextPtr sslContext)
+httpsEstablish(ConnStateData *connState, const Security::ContextPointer &ctx)
 {
     assert(connState);
     const Comm::ConnectionPointer &details = connState->clientConnection;
 
-    if (!sslContext || !httpsCreate(details, sslContext))
+    if (!ctx || !httpsCreate(details, ctx))
         return;
 
     typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
@@ -2837,7 +2841,7 @@
         acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, this);
         return;
     } else {
-        httpsEstablish(this, port->secure.staticContext.get());
+        httpsEstablish(this, port->secure.staticContext);
     }
 }
 
@@ -2876,17 +2880,19 @@
                     if (!ret)
                         debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
 
-                    SSL_CTX *sslContext = SSL_get_SSL_CTX(ssl);
-                    Ssl::configureUnconfiguredSslContext(sslContext, signAlgorithm, *port);
+                    Security::ContextPointer ctx;
+                    ctx.resetAndLock(SSL_get_SSL_CTX(ssl));
+                    Ssl::configureUnconfiguredSslContext(ctx, signAlgorithm, *port);
                 } else {
-                    auto ctx = Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str(), *port);
+                    Security::ContextPointer ctx(Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str(), *port));
                     getSslContextDone(ctx, true);
                 }
                 return;
             }
         }
     }
-    getSslContextDone(NULL);
+    Security::ContextPointer nil;
+    getSslContextDone(nil);
 }
 
 void ConnStateData::buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties)
@@ -2999,13 +3005,12 @@
         if (!(sslServerBump && (sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare))) {
             debugs(33, 5, "Finding SSL certificate for " << sslBumpCertKey << " in cache");
             Ssl::LocalContextStorage * ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
-            Security::ContextPtr dynCtx = nullptr;
             Security::ContextPointer *cachedCtx = ssl_ctx_cache ? ssl_ctx_cache->get(sslBumpCertKey.termedBuf()) : nullptr;
-            if (cachedCtx && (dynCtx = cachedCtx->get())) {
+            if (cachedCtx) {
                 debugs(33, 5, "SSL certificate for " << sslBumpCertKey << " found in cache");
-                if (Ssl::verifySslCertificate(dynCtx, certProperties)) {
+                if (Ssl::verifySslCertificate(*cachedCtx, certProperties)) {
                     debugs(33, 5, "Cached SSL certificate for " << sslBumpCertKey << " is valid");
-                    getSslContextDone(dynCtx);
+                    getSslContextDone(*cachedCtx);
                     return;
                 } else {
                     debugs(33, 5, "Cached SSL certificate for " << sslBumpCertKey << " is out of date. Delete this certificate from cache");
@@ -3042,25 +3047,28 @@
             if (!Ssl::configureSSL(ssl, certProperties, *port))
                 debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
 
-            SSL_CTX *sslContext = SSL_get_SSL_CTX(ssl);
-            Ssl::configureUnconfiguredSslContext(sslContext, certProperties.signAlgorithm, *port);
+            Security::ContextPointer ctx;
+            ctx.resetAndLock(SSL_get_SSL_CTX(ssl));
+            Ssl::configureUnconfiguredSslContext(ctx, certProperties.signAlgorithm, *port);
         } else {
-            auto dynCtx = Ssl::generateSslContext(certProperties, *port);
+            Security::ContextPointer dynCtx(Ssl::generateSslContext(certProperties, *port));
             getSslContextDone(dynCtx, true);
         }
         return;
     }
-    getSslContextDone(NULL);
+
+    Security::ContextPointer nil;
+    getSslContextDone(nil);
 }
 
 void
-ConnStateData::getSslContextDone(Security::ContextPtr sslContext, bool isNew)
+ConnStateData::getSslContextDone(Security::ContextPointer &ctx, bool isNew)
 {
     // Try to add generated ssl context to storage.
     if (port->generateHostCertificates && isNew) {
 
-        if (sslContext && (signAlgorithm == Ssl::algSignTrusted)) {
-            Ssl::chainCertificatesToSSLContext(sslContext, *port);
+        if (ctx && (signAlgorithm == Ssl::algSignTrusted)) {
+            Ssl::chainCertificatesToSSLContext(ctx, *port);
         } else if (signAlgorithm == Ssl::algSignTrusted) {
             debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain because SSL context chain is invalid!");
         }
@@ -3068,10 +3076,10 @@
 
         Ssl::LocalContextStorage *ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
         assert(sslBumpCertKey.size() > 0 && sslBumpCertKey[0] != '\0');
-        if (sslContext) {
-            if (!ssl_ctx_cache || !ssl_ctx_cache->add(sslBumpCertKey.termedBuf(), new Security::ContextPointer(sslContext))) {
+        if (ctx) {
+            if (!ssl_ctx_cache || !ssl_ctx_cache->add(sslBumpCertKey.termedBuf(), new Security::ContextPointer(ctx))) {
                 // If it is not in storage delete after using. Else storage deleted it.
-                fd_table[clientConnection->fd].dynamicSslContext = sslContext;
+                fd_table[clientConnection->fd].dynamicTlsContext = ctx;
             }
         } else {
             debugs(33, 2, HERE << "Failed to generate SSL cert for " << sslConnectHostOrIp);
@@ -3079,18 +3087,18 @@
     }
 
     // If generated ssl context = NULL, try to use static ssl context.
-    if (!sslContext) {
+    if (!ctx) {
         if (!port->secure.staticContext) {
             debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
             clientConnection->close();
             return;
         } else {
             debugs(33, 5, "Using static TLS context.");
-            sslContext = port->secure.staticContext.get();
+            ctx = port->secure.staticContext;
         }
     }
 
-    if (!httpsCreate(clientConnection, sslContext))
+    if (!httpsCreate(clientConnection, ctx))
         return;
 
     // bumped intercepted conns should already have Config.Timeout.request set
@@ -3311,8 +3319,8 @@
     }
 
     // will call httpsPeeked() with certificate and connection, eventually
-    auto unConfiguredCTX = Ssl::createSSLContext(port->signingCert, port->signPkey, *port);
-    fd_table[clientConnection->fd].dynamicSslContext = unConfiguredCTX;
+    Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->signingCert, port->signPkey, *port));
+    fd_table[clientConnection->fd].dynamicTlsContext = unConfiguredCTX;
 
     if (!httpsCreate(clientConnection, unConfiguredCTX))
         return;
diff -u -r -N squid-4.0.14/src/client_side.h squid-4.0.15/src/client_side.h
--- squid-4.0.14/src/client_side.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/client_side.h	2016-10-10 08:05:51.000000000 +1300
@@ -221,14 +221,14 @@
     /// \retval false otherwise
     bool spliceOnError(const err_type err);
 
-    /// Start to create dynamic Security::ContextPtr for host or uses static port SSL context.
+    /// Start to create dynamic Security::ContextPointer for host or uses static port SSL context.
     void getSslContextStart();
     /**
      * Done create dynamic ssl certificate.
      *
      * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
      */
-    void getSslContextDone(Security::ContextPtr sslContext, bool isNew = false);
+    void getSslContextDone(Security::ContextPointer &, bool isNew = false);
     /// Callback function. It is called when squid receive message from ssl_crtd.
     static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply);
     /// Proccess response from ssl_crtd.
diff -u -r -N squid-4.0.14/src/client_side_reply.cc squid-4.0.15/src/client_side_reply.cc
--- squid-4.0.14/src/client_side_reply.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/client_side_reply.cc	2016-10-10 08:05:51.000000000 +1300
@@ -266,7 +266,8 @@
 {
     const char *url = storeId();
     debugs(88, 3, "clientReplyContext::processExpired: '" << http->uri << "'");
-    assert(http->storeEntry()->lastmod >= 0);
+    const time_t lastmod = http->storeEntry()->lastModified();
+    assert(lastmod >= 0);
     /*
      * check if we are allowed to contact other servers
      * @?@: Instead of a 504 (Gateway Timeout) reply, we may want to return
@@ -323,7 +324,7 @@
     sc->setDelayId(DelayId::DelayClient(http));
 #endif
 
-    http->request->lastmod = old_entry->lastmod;
+    http->request->lastmod = lastmod;
 
     if (!http->request->header.has(Http::HdrType::IF_NONE_MATCH)) {
         ETag etag = {NULL, -1}; // TODO: make that a default ETag constructor
@@ -331,7 +332,7 @@
             http->request->etag = etag.str;
     }
 
-    debugs(88, 5, "clientReplyContext::processExpired : lastmod " << entry->lastmod );
+    debugs(88, 5, "lastmod " << entry->lastModified());
     http->storeEntry(entry);
     assert(http->out.offset == 0);
     assert(http->request->clientConnectionManager == http->getConn());
@@ -406,7 +407,7 @@
     if (deleting)
         return;
 
-    debugs(88, 3, "handleIMSReply: " << http->storeEntry()->url() << ", " << (long unsigned) result.length << " bytes" );
+    debugs(88, 3, http->storeEntry()->url() << ", " << (long unsigned) result.length << " bytes");
 
     if (http->storeEntry() == NULL)
         return;
@@ -421,7 +422,7 @@
 
     // request to origin was aborted
     if (EBIT_TEST(http->storeEntry()->flags, ENTRY_ABORTED)) {
-        debugs(88, 3, "handleIMSReply: request to origin aborted '" << http->storeEntry()->url() << "', sending old entry to client" );
+        debugs(88, 3, "request to origin aborted '" << http->storeEntry()->url() << "', sending old entry to client");
         http->logType = LOG_TCP_REFRESH_FAIL_OLD;
         sendClientOldEntry();
     }
@@ -438,13 +439,13 @@
 
         // if client sent IMS
 
-        if (http->request->flags.ims && !old_entry->modifiedSince(http->request)) {
+        if (http->request->flags.ims && !old_entry->modifiedSince(http->request->ims, http->request->imslen)) {
             // forward the 304 from origin
-            debugs(88, 3, "handleIMSReply: origin replied 304, revalidating existing entry and forwarding 304 to client");
+            debugs(88, 3, "origin replied 304, revalidating existing entry and forwarding 304 to client");
             sendClientUpstreamResponse();
         } else {
             // send existing entry, it's still valid
-            debugs(88, 3, "handleIMSReply: origin replied 304, revalidating existing entry and sending " <<
+            debugs(88, 3, "origin replied 304, revalidating existing entry and sending " <<
                    old_rep->sline.status() << " to client");
             sendClientOldEntry();
         }
@@ -452,26 +453,37 @@
 
     // origin replied with a non-error code
     else if (status > Http::scNone && status < Http::scInternalServerError) {
-        // forward response from origin
-        http->logType = LOG_TCP_REFRESH_MODIFIED;
-        debugs(88, 3, "handleIMSReply: origin replied " << status << ", replacing existing entry and forwarding to client");
+        const HttpReply *new_rep = http->storeEntry()->getReply();
+        // RFC 7234 section 4: a cache MUST use the most recent response
+        // (as determined by the Date header field)
+        if (new_rep->olderThan(old_rep)) {
+            http->logType.err.ignored = true;
+            debugs(88, 3, "origin replied " << status <<
+                   " but with an older date header, sending old entry (" <<
+                   old_rep->sline.status() << ") to client");
+            sendClientOldEntry();
+        } else {
+            http->logType = LOG_TCP_REFRESH_MODIFIED;
+            debugs(88, 3, "origin replied " << status <<
+                   ", replacing existing entry and forwarding to client");
 
-        if (collapsedRevalidation)
-            http->storeEntry()->clearPublicKeyScope();
+            if (collapsedRevalidation)
+                http->storeEntry()->clearPublicKeyScope();
 
-        sendClientUpstreamResponse();
+            sendClientUpstreamResponse();
+        }
     }
 
     // origin replied with an error
     else if (http->request->flags.failOnValidationError) {
         http->logType = LOG_TCP_REFRESH_FAIL_ERR;
-        debugs(88, 3, "handleIMSReply: origin replied with error " << status <<
+        debugs(88, 3, "origin replied with error " << status <<
                ", forwarding to client due to fail_on_validation_err");
         sendClientUpstreamResponse();
     } else {
         // ignore and let client have old entry
         http->logType = LOG_TCP_REFRESH_FAIL_OLD;
-        debugs(88, 3, "handleIMSReply: origin replied with error " <<
+        debugs(88, 3, "origin replied with error " <<
                status << ", sending old entry (" << old_rep->sline.status() << ") to client");
         sendClientOldEntry();
     }
@@ -614,11 +626,12 @@
          */
         r->flags.needValidation = true;
 
-        if (e->lastmod < 0) {
-            debugs(88, 3, "validate HIT object? NO. Missing Last-Modified header. Do MISS.");
+        if (e->lastModified() < 0) {
+            debugs(88, 3, "validate HIT object? NO. Can't calculate entry modification time. Do MISS.");
             /*
-             * Previous reply didn't have a Last-Modified header,
-             * we cannot revalidate it.
+             * We cannot revalidate entries without knowing their
+             * modification time.
+             * XXX: BUG 1890 objects without Date do not get one added.
              */
             http->logType = LOG_TCP_MISS;
             processMiss();
@@ -807,7 +820,7 @@
 
     if (r.flags.ims) {
         // handle If-Modified-Since requests from the client
-        if (e->modifiedSince(&r)) {
+        if (e->modifiedSince(r.ims, r.imslen)) {
             http->logType = LOG_TCP_IMS_HIT;
             sendMoreData(result);
             return;
diff -u -r -N squid-4.0.14/src/client_side_request.cc squid-4.0.15/src/client_side_request.cc
--- squid-4.0.14/src/client_side_request.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/client_side_request.cc	2016-10-10 08:05:51.000000000 +1300
@@ -1787,8 +1787,9 @@
 
     if (calloutContext->error) {
         // XXX: prformance regression. c_str() reallocates
-        SBuf storeUri(request->storeId());
-        StoreEntry *e = storeCreateEntry(storeUri.c_str(), storeUri.c_str(), request->flags, request->method);
+        SBuf storeUriBuf(request->storeId());
+        const char *storeUri = storeUriBuf.c_str();
+        StoreEntry *e = storeCreateEntry(storeUri, storeUri, request->flags, request->method);
 #if USE_OPENSSL
         if (sslBumpNeeded()) {
             // We have to serve an error, so bump the client first.
diff -u -r -N squid-4.0.14/src/comm.cc squid-4.0.15/src/comm.cc
--- squid-4.0.14/src/comm.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/comm.cc	2016-10-10 08:05:51.000000000 +1300
@@ -839,13 +839,7 @@
 {
     fde *F = &fd_table[params.fd];
     F->ssl.reset();
-
-#if USE_OPENSSL
-    if (F->dynamicSslContext) {
-        SSL_CTX_free(F->dynamicSslContext);
-        F->dynamicSslContext = NULL;
-    }
-#endif
+    F->dynamicTlsContext.reset();
     fd_close(params.fd);        /* update fdstat */
     close(params.fd);
 
diff -u -r -N squid-4.0.14/src/dns/forward.h squid-4.0.15/src/dns/forward.h
--- squid-4.0.14/src/dns/forward.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/dns/forward.h	2016-10-10 08:05:51.000000000 +1300
@@ -9,23 +9,19 @@
 #ifndef _SQUID_SRC_DNS_FORWARD_H
 #define _SQUID_SRC_DNS_FORWARD_H
 
-namespace Ip
-{
-class Address;
-}
+#include "ip/forward.h"
 
 class rfc1035_rr;
 
 typedef void IDNSCB(void *, const rfc1035_rr *, int, const char *);
 
-// generic DNS API
+/// generic DNS API
 namespace Dns
 {
 
 class LookupDetails;
 
 void Init(void);
-void Shutdown(void);
 
 } // namespace Dns
 
diff -u -r -N squid-4.0.14/src/dns_internal.cc squid-4.0.15/src/dns_internal.cc
--- squid-4.0.14/src/dns_internal.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/dns_internal.cc	2016-10-10 08:05:51.000000000 +1300
@@ -10,6 +10,7 @@
 
 #include "squid.h"
 #include "base/InstanceId.h"
+#include "base/RunnersRegistry.h"
 #include "comm.h"
 #include "comm/Connection.h"
 #include "comm/ConnOpener.h"
@@ -209,6 +210,22 @@
     nsvc *vc;
 };
 
+namespace Dns
+{
+
+/// manage DNS internal component
+class ConfigRr : public RegisteredRunner
+{
+public:
+    /* RegisteredRunner API */
+    virtual void startReconfigure() override;
+    virtual void endingShutdown() override;
+};
+
+RunnerRegistrationEntry(ConfigRr);
+
+} // namespace Dns
+
 struct _sp {
     char domain[NS_MAXDNAME];
     int queries;
@@ -903,7 +920,7 @@
 {
     delete queue;
     delete msg;
-    if (ns < nns) // XXX: Dns::Shutdown may have freed nameservers[]
+    if (ns < nns) // XXX: idnsShutdownAndFreeState may have freed nameservers[]
         nameservers[ns].vc = NULL;
 }
 
@@ -962,6 +979,13 @@
 static void
 idnsSendQuery(idns_query * q)
 {
+    // XXX: DNS sockets get closed during reconfigure produces a race between
+    // any already active connections (or ones received between closing DNS
+    // sockets and server listening sockets) and the reconfigure completing
+    // (Runner syncConfig() being run). Transactions which loose this race will
+    // produce DNS timeouts (or whatever the caller set) as their queries never
+    // get queued to be re-tried after the DNS socekts are re-opened.
+
     if (DnsSocketA < 0 && DnsSocketB < 0) {
         debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
         return;
@@ -1641,12 +1665,14 @@
     Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
 }
 
-void
-Dns::Shutdown(void)
+static void
+idnsShutdownAndFreeState(const char *reason)
 {
     if (DnsSocketA < 0 && DnsSocketB < 0)
         return;
 
+    debugs(78, 2, reason << ": Closing DNS sockets");
+
     if (DnsSocketA >= 0 ) {
         comm_close(DnsSocketA);
         DnsSocketA = -1;
@@ -1669,6 +1695,18 @@
     idnsFreeSearchpath();
 }
 
+void
+Dns::ConfigRr::endingShutdown()
+{
+    idnsShutdownAndFreeState("Shutdown");
+}
+
+void
+Dns::ConfigRr::startReconfigure()
+{
+    idnsShutdownAndFreeState("Reconfigure");
+}
+
 static int
 idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
 {
diff -u -r -N squid-4.0.14/src/Downloader.cc squid-4.0.15/src/Downloader.cc
--- squid-4.0.14/src/Downloader.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/Downloader.cc	2016-10-10 08:05:51.000000000 +1300
@@ -73,6 +73,17 @@
 
 Downloader::~Downloader()
 {
+    debugs(33, 6, this);
+}
+
+void
+Downloader::swanSong()
+{
+    debugs(33, 6, this);
+    if (context_) {
+        context_->finished();
+        context_ = nullptr;
+    }
 }
 
 bool
@@ -234,12 +245,6 @@
 Downloader::downloadFinished()
 {
     debugs(33, 7, this);
-    // We cannot delay http destruction until refcounting deletes
-    // DownloaderContext. The http object destruction will cause
-    // clientStream cleanup and will release the refcount to context_
-    // object hold by clientStream structures.
-    context_->finished();
-    context_ = nullptr;
     Must(done());
 }
 
@@ -256,12 +261,10 @@
     ScheduleCallHere(callback_);
     callback_ = nullptr;
 
-    // Calling deleteThis method here to finish Downloader
-    // may result to squid crash.
-    // This method called by handleReply method which maybe called
-    // by ClientHttpRequest::doCallouts. The doCallouts after this object
-    // deleted, may operate on non valid objects.
-    // Schedule an async call here just to force squid to delete this object.
+    // We cannot deleteThis() because we may be called synchronously from
+    // doCallouts() via handleReply() (XXX), and doCallouts() may crash if we
+    // disappear. Instead, schedule an async call now so that later, when the
+    // call firing code discovers a done() job, it deletes us.
     CallJobHere(33, 7, CbcPointer<Downloader>(this), Downloader, downloadFinished);
 }
 
diff -u -r -N squid-4.0.14/src/Downloader.h squid-4.0.15/src/Downloader.h
--- squid-4.0.14/src/Downloader.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/Downloader.h	2016-10-10 08:05:51.000000000 +1300
@@ -47,6 +47,7 @@
 
     Downloader(SBuf &url, AsyncCall::Pointer &aCallback, unsigned int level = 0);
     virtual ~Downloader();
+    virtual void swanSong();
 
     /// delays destruction to protect doCallouts()
     void downloadFinished();
diff -u -r -N squid-4.0.14/src/errorpage.cc squid-4.0.15/src/errorpage.cc
--- squid-4.0.14/src/errorpage.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/errorpage.cc	2016-10-10 08:05:51.000000000 +1300
@@ -361,7 +361,6 @@
 bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
 {
     while (pos < hdr.size()) {
-        char *dt = lang;
 
         /* skip any initial whitespace. */
         while (pos < hdr.size() && xisspace(hdr[pos]))
@@ -375,6 +374,7 @@
          *    with preference given to an exact match.
          */
         bool invalid_byte = false;
+        char *dt = lang;
         while (pos < hdr.size() && hdr[pos] != ';' && hdr[pos] != ',' && !xisspace(hdr[pos]) && dt < (lang + (langLen -1)) ) {
             if (!invalid_byte) {
 #if USE_HTTP_VIOLATIONS
@@ -394,7 +394,6 @@
             ++pos;
         }
         *dt = '\0'; // nul-terminated the filename content string before system use.
-        ++dt;
 
         // if we terminated the tag on garbage or ';' we need to skip to the next ',' or end of header.
         while (pos < hdr.size() && hdr[pos] != ',')
@@ -403,7 +402,7 @@
         if (pos < hdr.size() && hdr[pos] == ',')
             ++pos;
 
-        debugs(4, 9, HERE << "STATE: dt='" << dt << "', lang='" << lang << "', pos=" << pos << ", buf='" << ((pos < hdr.size()) ? hdr.substr(pos,hdr.size()) : "") << "'");
+        debugs(4, 9, "STATE: lang=" << lang << ", pos=" << pos << ", buf='" << ((pos < hdr.size()) ? hdr.substr(pos,hdr.size()) : "") << "'");
 
         /* if we found anything we might use, try it. */
         if (*lang != '\0' && !invalid_byte)
diff -u -r -N squid-4.0.14/src/fde.h squid-4.0.15/src/fde.h
--- squid-4.0.14/src/fde.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/fde.h	2016-10-10 08:05:51.000000000 +1300
@@ -120,7 +120,7 @@
     READ_HANDLER *read_method;
     WRITE_HANDLER *write_method;
     Security::SessionPointer ssl;
-    Security::ContextPtr dynamicSslContext; ///< cached and then freed when fd is closed
+    Security::ContextPointer dynamicTlsContext; ///< cached and then freed when fd is closed
 #if _SQUID_WINDOWS_
     struct {
         long handle;
@@ -168,7 +168,7 @@
         read_method = NULL;
         write_method = NULL;
         ssl.reset();
-        dynamicSslContext = NULL;
+        dynamicTlsContext.reset();
 #if _SQUID_WINDOWS_
         win32.handle = (long)NULL;
 #endif
diff -u -r -N squid-4.0.14/src/format/Format.cc squid-4.0.15/src/format/Format.cc
--- squid-4.0.14/src/format/Format.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/format/Format.cc	2016-10-10 08:05:51.000000000 +1300
@@ -21,6 +21,7 @@
 #include "HttpRequest.h"
 #include "MemBuf.h"
 #include "rfc1738.h"
+#include "security/CertError.h"
 #include "security/NegotiationHistory.h"
 #include "SquidTime.h"
 #include "Store.h"
@@ -322,13 +323,45 @@
 
 #if USE_OPENSSL
 static char *
-sslErrorName(Ssl::ssl_error_t err, char *buf, size_t size)
+sslErrorName(Security::ErrorCode err, char *buf, size_t size)
 {
     snprintf(buf, size, "SSL_ERR=%d", err);
     return buf;
 }
 #endif
 
+/// XXX: Misnamed. TODO: Split <h (and this function) to distinguish received
+/// headers from sent headers rather than failing to distinguish requests from responses.
+/// \retval HttpReply sent to the HTTP client (access.log and default context).
+/// \retval HttpReply received (encapsulated) from the ICAP server (icap.log context).
+/// \retval HttpRequest received (encapsulated) from the ICAP server (icap.log context).
+static const HttpMsg *
+actualReplyHeader(const AccessLogEntry::Pointer &al)
+{
+    const HttpMsg *msg = al->reply;
+#if USE_ADAPTATION
+    // al->icap.reqMethod is methodNone in access.log context
+    if (!msg && al->icap.reqMethod == Adaptation::methodReqmod)
+        msg = al->adapted_request;
+#endif
+    return msg;
+}
+
+/// XXX: Misnamed. See actualReplyHeader().
+/// \return HttpRequest or HttpReply for %http::>h.
+static const HttpMsg *
+actualRequestHeader(const AccessLogEntry::Pointer &al)
+{
+#if USE_ADAPTATION
+    // al->icap.reqMethod is methodNone in access.log context
+    if (al->icap.reqMethod == Adaptation::methodRespmod) {
+        // XXX: for now AccessLogEntry lacks virgin response headers
+        return nullptr;
+    }
+#endif
+    return al->request;
+}
+
 void
 Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logSequenceNumber) const
 {
@@ -377,6 +410,9 @@
             if (al->request) {
                 outint = al->request->client_addr.port();
                 doint = 1;
+            } else if (al->tcpClient) {
+                outint = al->tcpClient->remote.port();
+                doint = 1;
             }
             break;
 
@@ -592,9 +628,8 @@
             break;
 
         case LFT_REQUEST_HEADER:
-
-            if (al->request)
-                sb = al->request->header.getByName(fmt->data.header.header);
+            if (const HttpMsg *msg = actualRequestHeader(al))
+                sb = msg->header.getByName(fmt->data.header.header);
 
             out = sb.termedBuf();
 
@@ -613,15 +648,15 @@
 
             break;
 
-        case LFT_REPLY_HEADER:
-            if (al->reply)
-                sb = al->reply->header.getByName(fmt->data.header.header);
+        case LFT_REPLY_HEADER: {
+            if (const HttpMsg *msg = actualReplyHeader(al))
+                sb = msg->header.getByName(fmt->data.header.header);
 
             out = sb.termedBuf();
 
             quote = 1;
-
-            break;
+        }
+        break;
 
 #if USE_ADAPTATION
         case LFT_ADAPTATION_SUM_XACT_TIMES:
@@ -803,8 +838,8 @@
             break;
 #endif
         case LFT_REQUEST_HEADER_ELEM:
-            if (al->request)
-                sb = al->request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
+            if (const HttpMsg *msg = actualRequestHeader(al))
+                sb = msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
 
             out = sb.termedBuf();
 
@@ -822,18 +857,27 @@
 
             break;
 
-        case LFT_REPLY_HEADER_ELEM:
-            if (al->reply)
-                sb = al->reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
+        case LFT_REPLY_HEADER_ELEM: {
+            if (const HttpMsg *msg = actualReplyHeader(al))
+                sb = msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
 
             out = sb.termedBuf();
 
             quote = 1;
-
-            break;
+        }
+        break;
 
         case LFT_REQUEST_ALL_HEADERS:
-            out = al->headers.request;
+#if USE_ADAPTATION
+            if (al->icap.reqMethod == Adaptation::methodRespmod) {
+                // XXX: since AccessLogEntry::Headers lacks virgin response
+                // headers, do nothing for now
+                out = nullptr;
+            } else
+#endif
+            {
+                out = al->headers.request;
+            }
 
             quote = 1;
 
@@ -848,6 +892,10 @@
 
         case LFT_REPLY_ALL_HEADERS:
             out = al->headers.reply;
+#if USE_ADAPTATION
+            if (!out && al->icap.reqMethod == Adaptation::methodReqmod)
+                out = al->headers.adapted_request;
+#endif
 
             quote = 1;
 
@@ -1261,7 +1309,7 @@
             if (al->request && al->request->clientConnectionManager.valid()) {
                 if (Ssl::ServerBump * srvBump = al->request->clientConnectionManager->serverBump()) {
                     const char *separator = fmt->data.string ? fmt->data.string : ":";
-                    for (Ssl::CertErrors const *sslError = srvBump->sslErrors(); sslError != NULL;  sslError = sslError->next) {
+                    for (const Security::CertErrors *sslError = srvBump->sslErrors(); sslError != nullptr; sslError = sslError->next) {
                         if (sb.size())
                             sb.append(separator);
                         if (const char *errorName = Ssl::GetErrorName(sslError->element.code))
diff -u -r -N squid-4.0.14/src/fs/rock/RockHeaderUpdater.cc squid-4.0.15/src/fs/rock/RockHeaderUpdater.cc
--- squid-4.0.14/src/fs/rock/RockHeaderUpdater.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/fs/rock/RockHeaderUpdater.cc	2016-10-10 08:05:51.000000000 +1300
@@ -184,6 +184,7 @@
         Must(freshSwapHeader);
         writer->write(freshSwapHeader, freshSwapHeaderSize, 0, nullptr);
         offset += freshSwapHeaderSize;
+        xfree(freshSwapHeader);
     }
 
     {
diff -u -r -N squid-4.0.14/src/fs/rock/RockSwapDir.cc squid-4.0.15/src/fs/rock/RockSwapDir.cc
--- squid-4.0.14/src/fs/rock/RockSwapDir.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/fs/rock/RockSwapDir.cc	2016-10-10 08:05:51.000000000 +1300
@@ -122,7 +122,7 @@
     e.lastref = basics.lastref;
     e.timestamp = basics.timestamp;
     e.expires = basics.expires;
-    e.lastmod = basics.lastmod;
+    e.lastModified(basics.lastmod);
     e.refcount = basics.refcount;
     e.flags = basics.flags;
 
diff -u -r -N squid-4.0.14/src/fs/ufs/RebuildState.cc squid-4.0.15/src/fs/ufs/RebuildState.cc
--- squid-4.0.14/src/fs/ufs/RebuildState.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/fs/ufs/RebuildState.cc	2016-10-10 08:05:51.000000000 +1300
@@ -91,9 +91,11 @@
 Fs::Ufs::RebuildState::RebuildStep(void *data)
 {
     RebuildState *rb = (RebuildState *)data;
-    rb->rebuildStep();
+    if (!reconfiguring)
+        rb->rebuildStep();
 
-    if (!rb->isDone())
+    // delay storeRebuildComplete() when reconfiguring to protect storeCleanup()
+    if (!rb->isDone() || reconfiguring)
         eventAdd("storeRebuild", RebuildStep, rb, 0.01, 1);
     else {
         -- StoreController::store_dirs_rebuilding;
@@ -217,7 +219,7 @@
                                     tmpe.expires,
                                     tmpe.timestamp,
                                     tmpe.lastref,
-                                    tmpe.lastmod,
+                                    tmpe.lastModified(),
                                     tmpe.refcount,  /* refcount */
                                     tmpe.flags,     /* flags */
                                     (int) flags.clean));
@@ -344,7 +346,7 @@
             currentEntry()->lastref = swapData.timestamp;
             currentEntry()->timestamp = swapData.timestamp;
             currentEntry()->expires = swapData.expires;
-            currentEntry()->lastmod = swapData.lastmod;
+            currentEntry()->lastModified(swapData.lastmod);
             currentEntry()->flags = swapData.flags;
             currentEntry()->refcount += swapData.refcount;
             sd->dereference(*currentEntry());
diff -u -r -N squid-4.0.14/src/fs/ufs/UFSStoreState.cc squid-4.0.15/src/fs/ufs/UFSStoreState.cc
--- squid-4.0.14/src/fs/ufs/UFSStoreState.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/fs/ufs/UFSStoreState.cc	2016-10-10 08:05:51.000000000 +1300
@@ -405,7 +405,7 @@
     if (flags.write_draining)
         return;
 
-    if (!theFile->canWrite())
+    if (!theFile || !theFile->canWrite())
         return;
 
     flags.write_draining = true;
diff -u -r -N squid-4.0.14/src/fs/ufs/UFSStoreState.h squid-4.0.15/src/fs/ufs/UFSStoreState.h
--- squid-4.0.14/src/fs/ufs/UFSStoreState.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/fs/ufs/UFSStoreState.h	2016-10-10 08:05:51.000000000 +1300
@@ -59,6 +59,8 @@
         ~_queued_read() {
             cbdataReferenceDone(callback_data);
         }
+        _queued_read(const _queued_read &qr) = delete;
+        _queued_read &operator =(const _queued_read &qr) = delete;
 
         char *buf;
         size_t size;
@@ -88,6 +90,8 @@
             if (free_func && buf)
                 free_func(const_cast<char *>(buf));
         }
+        _queued_write(const _queued_write &qr) = delete;
+        _queued_write &operator =(const _queued_write &qr) = delete;
 
         char const *buf;
         size_t size;
diff -u -r -N squid-4.0.14/src/fs/ufs/UFSSwapDir.cc squid-4.0.15/src/fs/ufs/UFSSwapDir.cc
--- squid-4.0.14/src/fs/ufs/UFSSwapDir.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/fs/ufs/UFSSwapDir.cc	2016-10-10 08:05:51.000000000 +1300
@@ -88,7 +88,7 @@
     s.timestamp = e.timestamp;
     s.lastref = e.lastref;
     s.expires = e.expires;
-    s.lastmod = e.lastmod;
+    s.lastmod = e.lastModified();
     s.swap_file_sz = e.swap_file_sz;
     s.refcount = e.refcount;
     s.flags = e.flags;
@@ -317,7 +317,8 @@
     currentIOOptions(new ConfigOptionVector()),
     ioType(xstrdup(anIOType)),
     cur_size(0),
-    n_disk_objects(0)
+    n_disk_objects(0),
+    rebuilding_(false)
 {
     /* modulename is only set to disk modules that are built, by configure,
      * so the Find call should never return NULL here.
@@ -725,6 +726,15 @@
 void
 Fs::Ufs::UFSSwapDir::openLog()
 {
+    assert(NumberOfUFSDirs || !UFSDirToGlobalDirMapping);
+    ++NumberOfUFSDirs;
+    assert(NumberOfUFSDirs <= Config.cacheSwap.n_configured);
+
+    if (rebuilding_) { // we did not close the temporary log used for rebuilding
+        assert(swaplog_fd >= 0);
+        return;
+    }
+
     char *logPath;
     logPath = logFile();
     swaplog_fd = file_open(logPath, O_WRONLY | O_CREAT | O_BINARY);
@@ -736,13 +746,6 @@
     }
 
     debugs(50, 3, HERE << "Cache Dir #" << index << " log opened on FD " << swaplog_fd);
-
-    if (0 == NumberOfUFSDirs)
-        assert(NULL == UFSDirToGlobalDirMapping);
-
-    ++NumberOfUFSDirs;
-
-    assert(NumberOfUFSDirs <= Config.cacheSwap.n_configured);
 }
 
 void
@@ -751,18 +754,19 @@
     if (swaplog_fd < 0) /* not open */
         return;
 
+    --NumberOfUFSDirs;
+    assert(NumberOfUFSDirs >= 0);
+    if (!NumberOfUFSDirs)
+        safe_free(UFSDirToGlobalDirMapping);
+
+    if (rebuilding_) // we cannot close the temporary log used for rebuilding
+        return;
+
     file_close(swaplog_fd);
 
     debugs(47, 3, "Cache Dir #" << index << " log closed on FD " << swaplog_fd);
 
     swaplog_fd = -1;
-
-    --NumberOfUFSDirs;
-
-    assert(NumberOfUFSDirs >= 0);
-
-    if (0 == NumberOfUFSDirs)
-        safe_free(UFSDirToGlobalDirMapping);
 }
 
 bool
@@ -804,7 +808,7 @@
     e->lastref = lastref;
     e->timestamp = timestamp;
     e->expires = expires;
-    e->lastmod = lastmod;
+    e->lastModified(lastmod);
     e->refcount = refcount;
     e->flags = newFlags;
     EBIT_CLR(e->flags, RELEASE_REQUEST);
@@ -842,6 +846,9 @@
 void
 Fs::Ufs::UFSSwapDir::closeTmpSwapLog()
 {
+    assert(rebuilding_);
+    rebuilding_ = false;
+
     char *swaplog_path = xstrdup(logFile(NULL)); // where the swaplog should be
     char *tmp_path = xstrdup(logFile(".new")); // the temporary file we have generated
     int fd;
@@ -868,6 +875,8 @@
 FILE *
 Fs::Ufs::UFSSwapDir::openTmpSwapLog(int *clean_flag, int *zero_flag)
 {
+    assert(!rebuilding_);
+
     char *swaplog_path = xstrdup(logFile(NULL));
     char *clean_path = xstrdup(logFile(".last-clean"));
     char *new_path = xstrdup(logFile(".new"));
@@ -902,6 +911,7 @@
     }
 
     swaplog_fd = fd;
+    rebuilding_ = true;
 
     {
         const StoreSwapLogHeader header;
@@ -1060,18 +1070,17 @@
     cleanLog = NULL;
 }
 
-void
-Fs::Ufs::UFSSwapDir::CleanEvent(void *)
+/// safely cleans a few unused files if possible
+int
+Fs::Ufs::UFSSwapDir::HandleCleanEvent()
 {
     static int swap_index = 0;
     int i;
     int j = 0;
     int n = 0;
-    /*
-     * Assert that there are UFS cache_dirs configured, otherwise
-     * we should never be called.
-     */
-    assert(NumberOfUFSDirs);
+
+    if (!NumberOfUFSDirs)
+        return 0; // probably in the middle of reconfiguration
 
     if (NULL == UFSDirToGlobalDirMapping) {
         SwapDir *sd;
@@ -1115,6 +1124,13 @@
         ++swap_index;
     }
 
+    return n;
+}
+
+void
+Fs::Ufs::UFSSwapDir::CleanEvent(void *)
+{
+    const int n = HandleCleanEvent();
     eventAdd("storeDirClean", CleanEvent, NULL,
              15.0 * exp(-0.25 * n), 1);
 }
@@ -1284,13 +1300,18 @@
 void
 Fs::Ufs::UFSSwapDir::logEntry(const StoreEntry & e, int op) const
 {
+    if (swaplog_fd < 0) {
+        debugs(36, 5, "cannot log " << e << " in the middle of reconfiguration");
+        return;
+    }
+
     StoreSwapLogData *s = new StoreSwapLogData;
     s->op = (char) op;
     s->swap_filen = e.swap_filen;
     s->timestamp = e.timestamp;
     s->lastref = e.lastref;
     s->expires = e.expires;
-    s->lastmod = e.lastmod;
+    s->lastmod = e.lastModified();
     s->swap_file_sz = e.swap_file_sz;
     s->refcount = e.refcount;
     s->flags = e.flags;
diff -u -r -N squid-4.0.14/src/fs/ufs/UFSSwapDir.h squid-4.0.15/src/fs/ufs/UFSSwapDir.h
--- squid-4.0.14/src/fs/ufs/UFSSwapDir.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/fs/ufs/UFSSwapDir.h	2016-10-10 08:05:51.000000000 +1300
@@ -126,6 +126,7 @@
     bool pathIsDirectory(const char *path)const;
     int swaplog_fd;
     static EVH CleanEvent;
+    static int HandleCleanEvent();
     /** Verify that the the CacheDir exists
      *
      * If this returns < 0, then Squid exits, complains about swap
@@ -145,6 +146,7 @@
     char const *ioType;
     uint64_t cur_size; ///< currently used space in the storage area
     uint64_t n_disk_objects; ///< total number of objects stored
+    bool rebuilding_; ///< whether RebuildState is writing the new swap.state
 };
 
 } //namespace Ufs
diff -u -r -N squid-4.0.14/src/htcp.cc squid-4.0.15/src/htcp.cc
--- squid-4.0.14/src/htcp.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/htcp.cc	2016-10-10 08:05:51.000000000 +1300
@@ -848,8 +848,8 @@
         if (e && e->expires > -1)
             hdr.putTime(Http::HdrType::EXPIRES, e->expires);
 
-        if (e && e->lastmod > -1)
-            hdr.putTime(Http::HdrType::LAST_MODIFIED, e->lastmod);
+        if (e && e->lastModified() > -1)
+            hdr.putTime(Http::HdrType::LAST_MODIFIED, e->lastModified());
 
         hdr.packInto(&mb);
 
diff -u -r -N squid-4.0.14/src/http/one/RequestParser.cc squid-4.0.15/src/http/one/RequestParser.cc
--- squid-4.0.14/src/http/one/RequestParser.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/http/one/RequestParser.cc	2016-10-10 08:05:51.000000000 +1300
@@ -185,14 +185,36 @@
 bool
 Http::One::RequestParser::parseHttpVersionField(Http1::Tokenizer &tok)
 {
+    static const SBuf http1p0("HTTP/1.0");
+    static const SBuf http1p1("HTTP/1.1");
     const auto savedTok = tok;
 
-    SBuf digit;
-    // Searching for Http1magic precludes detecting HTTP/2+ versions.
-    // Rewrite if we ever _need_ to return 505 (Version Not Supported) errors.
-    if (tok.suffix(digit, CharacterSet::DIGIT) && tok.skipSuffix(Http1magic)) {
-        msgProtocol_ = Http::ProtocolVersion(1, (*digit.rawContent() - '0'));
+    // Optimization: Expect (and quickly parse) HTTP/1.1 or HTTP/1.0 in
+    // the vast majority of cases.
+    if (tok.skipSuffix(http1p1)) {
+        msgProtocol_ = Http::ProtocolVersion(1, 1);
         return true;
+    } else if (tok.skipSuffix(http1p0)) {
+        msgProtocol_ = Http::ProtocolVersion(1, 0);
+        return true;
+    } else {
+        // RFC 7230 section 2.6:
+        // HTTP-version  = HTTP-name "/" DIGIT "." DIGIT
+        static const CharacterSet period("Decimal point", ".");
+        static const SBuf proto("HTTP/");
+        SBuf majorDigit;
+        SBuf minorDigit;
+        if (tok.suffix(minorDigit, CharacterSet::DIGIT) &&
+                tok.skipOneTrailing(period) &&
+                tok.suffix(majorDigit, CharacterSet::DIGIT) &&
+                tok.skipSuffix(proto)) {
+            const bool multiDigits = majorDigit.length() > 1 || minorDigit.length() > 1;
+            // use '0.0' for unsupported multiple digit version numbers
+            const unsigned int major = multiDigits ? 0 : (*majorDigit.rawContent() - '0');
+            const unsigned int minor = multiDigits ? 0 : (*minorDigit.rawContent() - '0');
+            msgProtocol_ = Http::ProtocolVersion(major, minor);
+            return true;
+        }
     }
 
     // A GET request might use HTTP/0.9 syntax
diff -u -r -N squid-4.0.14/src/http/Stream.cc squid-4.0.15/src/http/Stream.cc
--- squid-4.0.14/src/http/Stream.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/http/Stream.cc	2016-10-10 08:05:51.000000000 +1300
@@ -382,7 +382,7 @@
 
     /* got modification time? */
     if (spec.time >= 0)
-        return http->storeEntry()->lastmod <= spec.time;
+        return !http->storeEntry()->modifiedSince(spec.time);
 
     assert(0);          /* should not happen */
     return false;
diff -u -r -N squid-4.0.14/src/http/url_rewriters/LFS/url_lfs_rewrite.8 squid-4.0.15/src/http/url_rewriters/LFS/url_lfs_rewrite.8
--- squid-4.0.14/src/http/url_rewriters/LFS/url_lfs_rewrite.8	2016-09-09 03:32:18.000000000 +1200
+++ squid-4.0.15/src/http/url_rewriters/LFS/url_lfs_rewrite.8	2016-10-10 12:00:01.000000000 +1300
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -46,7 +46,7 @@
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" If the F register is >0, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.nr rF 0
-.if \n(.g .if rF .nr rF 1
-.if (\n(rF:(\n(.g==0)) \{
-.    if \nF \{
-.        de IX
-.        tm Index:\\$1\t\\n%\t"\\$2"
+.if !\nF .nr F 0
+.if \nF>0 \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.        if !\nF==2 \{
-.            nr % 0
-.            nr F 2
-.        \}
+.    if !\nF==2 \{\
+.        nr % 0
+.        nr F 2
 .    \}
 .\}
-.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -133,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "URL_LFS_REWRITE 8"
-.TH URL_LFS_REWRITE 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH URL_LFS_REWRITE 8 "2016-10-09" "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
@@ -238,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 \\fIs0\fR\|(7),
+squid (8), \s-1GPL\s0 (7),
 .PP
 The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq
 .PP
diff -u -r -N squid-4.0.14/src/http.cc squid-4.0.15/src/http.cc
--- squid-4.0.14/src/http.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/http.cc	2016-10-10 08:05:51.000000000 +1300
@@ -90,7 +90,8 @@
     lastChunk(0),
     httpChunkDecoder(NULL),
     payloadSeen(0),
-    payloadTruncated(0)
+    payloadTruncated(0),
+    sawDateGoBack(false)
 {
     debugs(11,5,HERE << "HttpStateData " << this << " created");
     ignoreCacheControl = false;
@@ -168,6 +169,14 @@
     mustStop("HttpStateData::httpTimeout");
 }
 
+static StoreEntry *
+findPreviouslyCachedEntry(StoreEntry *newEntry) {
+    assert(newEntry->mem_obj);
+    return newEntry->mem_obj->request ?
+           storeGetPublicByRequest(newEntry->mem_obj->request) :
+           storeGetPublic(newEntry->mem_obj->storeId(), newEntry->mem_obj->method);
+}
+
 /// Remove an existing public store entry if the incoming response (to be
 /// stored in a currently private entry) is going to invalidate it.
 static void
@@ -175,7 +184,6 @@
 {
     int remove = 0;
     int forbidden = 0;
-    StoreEntry *pe;
 
     // If the incoming response already goes into a public entry, then there is
     // nothing to remove. This protects ready-for-collapsing entries as well.
@@ -234,12 +242,7 @@
     if (!remove && !forbidden)
         return;
 
-    assert(e->mem_obj);
-
-    if (e->mem_obj->request)
-        pe = storeGetPublicByRequest(e->mem_obj->request);
-    else
-        pe = storeGetPublic(e->mem_obj->storeId(), e->mem_obj->method);
+    StoreEntry *pe = findPreviouslyCachedEntry(e);
 
     if (pe != NULL) {
         assert(e != pe);
@@ -330,6 +333,13 @@
         return 0;
     }
 
+    // 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;
+    }
+
     // Check for Surrogate/1.0 protocol conditions
     // NP: reverse-proxy traffic our parent server has instructed us never to cache
     if (surrogateNoStore) {
@@ -916,7 +926,10 @@
     /* Check if object is cacheable or not based on reply code */
     debugs(11, 3, "HTTP CODE: " << rep->sline.status());
 
-    if (neighbors_do_private_keys)
+    if (const StoreEntry *oldEntry = findPreviouslyCachedEntry(entry))
+        sawDateGoBack = rep->olderThan(oldEntry->getReply());
+
+    if (neighbors_do_private_keys && !sawDateGoBack)
         httpMaybeRemovePublic(entry, rep->sline.status());
 
     bool varyFailure = false;
diff -u -r -N squid-4.0.14/src/http.h squid-4.0.15/src/http.h
--- squid-4.0.14/src/http.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/http.h	2016-10-10 08:05:51.000000000 +1300
@@ -129,6 +129,10 @@
     int64_t payloadSeen;
     /// positive when we read more than we wanted
     int64_t payloadTruncated;
+
+    /// Whether we received a Date header older than that of a matching
+    /// cached response.
+    bool sawDateGoBack;
 };
 
 int httpCachable(const HttpRequestMethod&);
diff -u -r -N squid-4.0.14/src/HttpHdrCc.cc squid-4.0.15/src/HttpHdrCc.cc
--- squid-4.0.14/src/HttpHdrCc.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/HttpHdrCc.cc	2016-10-10 08:05:51.000000000 +1300
@@ -306,7 +306,7 @@
 {
     extern const HttpHeaderStat *dump_stat; /* argh! */
     const int id = static_cast<int>(val);
-    const bool valid_id = id < HttpHdrCcType::CC_ENUM_END;
+    const bool valid_id = id >= 0 && id < static_cast<int>(HttpHdrCcType::CC_ENUM_END);
     const char *name = valid_id ? CcAttrs[id].name : "INVALID";
 
     if (count || valid_id)
diff -u -r -N squid-4.0.14/src/HttpHdrCc.cci squid-4.0.15/src/HttpHdrCc.cci
--- squid-4.0.14/src/HttpHdrCc.cci	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/HttpHdrCc.cci	2016-10-10 08:05:51.000000000 +1300
@@ -15,16 +15,16 @@
 HttpHdrCc::isSet(HttpHdrCcType id) const
 {
     assert(id < HttpHdrCcType::CC_ENUM_END);
-    return EBIT_TEST(mask,id);
+    return EBIT_TEST(mask, static_cast<long>(id));
 }
 
 void
 HttpHdrCc::setMask(HttpHdrCcType id, bool newval)
 {
     if (newval)
-        EBIT_SET(mask,id);
+        EBIT_SET(mask,static_cast<long>(id));
     else
-        EBIT_CLR(mask,id);
+        EBIT_CLR(mask, static_cast<long>(id));
 }
 
 /// set a data member to a new value, and set the corresponding mask-bit.
diff -u -r -N squid-4.0.14/src/HttpHeader.cc squid-4.0.15/src/HttpHeader.cc
--- squid-4.0.14/src/HttpHeader.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/HttpHeader.cc	2016-10-10 08:05:51.000000000 +1300
@@ -882,7 +882,7 @@
     /* Sorry, an unknown header name. Do linear search */
     bool found = false;
     while ((e = getEntry(&pos))) {
-        if (e->id == Http::HdrType::OTHER && e->name.caseCmp(name) == 0) {
+        if (e->id == Http::HdrType::OTHER && e->name.size() == static_cast<String::size_type>(namelen) && e->name.caseCmp(name, namelen) == 0) {
             found = true;
             strListAdd(&result, e->value.termedBuf(), ',');
         }
diff -u -r -N squid-4.0.14/src/HttpMsg.cc squid-4.0.15/src/HttpMsg.cc
--- squid-4.0.14/src/HttpMsg.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/HttpMsg.cc	2016-10-10 08:05:51.000000000 +1300
@@ -314,6 +314,8 @@
         return false;
     }
 
+    // XXX: we are just parsing HTTP headers, not the whole message prefix here
+    hdr_sz = hp.messageHeaderSize();
     pstate = psParsed;
     hdrCacheInit();
     return true;
diff -u -r -N squid-4.0.14/src/HttpReply.cc squid-4.0.15/src/HttpReply.cc
--- squid-4.0.14/src/HttpReply.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/HttpReply.cc	2016-10-10 08:05:51.000000000 +1300
@@ -627,3 +627,11 @@
     return newValue;
 }
 
+bool
+HttpReply::olderThan(const HttpReply *them) const
+{
+    if (!them || !them->date || !date)
+        return false;
+    return date < them->date;
+}
+
diff -u -r -N squid-4.0.14/src/HttpReply.h squid-4.0.15/src/HttpReply.h
--- squid-4.0.14/src/HttpReply.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/HttpReply.h	2016-10-10 08:05:51.000000000 +1300
@@ -112,6 +112,10 @@
 
     virtual void hdrCacheInit();
 
+    /// whether our Date header value is smaller than theirs
+    /// \returns false if any information is missing
+    bool olderThan(const HttpReply *them) const;
+
 private:
     /** initialize */
     void init();
diff -u -r -N squid-4.0.14/src/icmp/Makefile.am squid-4.0.15/src/icmp/Makefile.am
--- squid-4.0.14/src/icmp/Makefile.am	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/icmp/Makefile.am	2016-10-10 08:05:51.000000000 +1300
@@ -67,6 +67,7 @@
 	$(top_builddir)/src/ip/libip.la \
 	$(top_builddir)/src/base/libbase.la \
 	$(COMPAT_LIB) \
+	$(SSLLIB) \
 	$(XTRA_LIBS)
 
 CLEANFILES += $(COPIED_SOURCE)
diff -u -r -N squid-4.0.14/src/icmp/Makefile.in squid-4.0.15/src/icmp/Makefile.in
--- squid-4.0.14/src/icmp/Makefile.in	2016-09-09 02:14:53.000000000 +1200
+++ squid-4.0.15/src/icmp/Makefile.in	2016-10-10 08:17:03.000000000 +1300
@@ -191,7 +191,7 @@
 am__DEPENDENCIES_3 =
 pinger_DEPENDENCIES = libicmpcore.la $(top_builddir)/src/ip/libip.la \
 	$(top_builddir)/src/base/libbase.la $(am__DEPENDENCIES_2) \
-	$(am__DEPENDENCIES_3)
+	$(am__DEPENDENCIES_3) $(am__DEPENDENCIES_3)
 pinger_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
 	$(CXXFLAGS) $(pinger_LDFLAGS) $(LDFLAGS) -o $@
@@ -792,6 +792,7 @@
 	$(top_builddir)/src/ip/libip.la \
 	$(top_builddir)/src/base/libbase.la \
 	$(COMPAT_LIB) \
+	$(SSLLIB) \
 	$(XTRA_LIBS)
 
 all: all-am
diff -u -r -N squid-4.0.14/src/ip/Intercept.cc squid-4.0.15/src/ip/Intercept.cc
--- squid-4.0.14/src/ip/Intercept.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ip/Intercept.cc	2016-10-10 08:05:51.000000000 +1300
@@ -208,16 +208,22 @@
         debugs(89, warningLevel, "IPF (IPFilter v4) NAT does not support IPv6. Please upgrade to IPFilter v5.1");
         warningLevel = (warningLevel + 1) % 10;
         return false;
+    }
+    newConn->local.getInAddr(natLookup.nl_inip);
+    newConn->remote.getInAddr(natLookup.nl_outip);
 #else
         natLookup.nl_v = 6;
-    } else {
+        newConn->local.getInAddr(natLookup.nl_inipaddr.in6);
+        newConn->remote.getInAddr(natLookup.nl_outipaddr.in6);
+    }
+    else {
         natLookup.nl_v = 4;
-#endif
+        newConn->local.getInAddr(natLookup.nl_inipaddr.in4);
+        newConn->remote.getInAddr(natLookup.nl_outipaddr.in4);
     }
+#endif
     natLookup.nl_inport = htons(newConn->local.port());
-    newConn->local.getInAddr(natLookup.nl_inip);
     natLookup.nl_outport = htons(newConn->remote.port());
-    newConn->remote.getInAddr(natLookup.nl_outip);
     // ... and the TCP flag
     natLookup.nl_flags = IPN_TCP;
 
@@ -284,7 +290,14 @@
         debugs(89, 9, HERE << "address: " << newConn);
         return false;
     } else {
+#if IPFILTER_VERSION < 5000003
         newConn->local = natLookup.nl_realip;
+#else
+        if (newConn->remote.isIPv6())
+            newConn->local = natLookup.nl_realipaddr.in6;
+        else
+            newConn->local = natLookup.nl_realipaddr.in4;
+#endif
         newConn->local.port(ntohs(natLookup.nl_realport));
         debugs(89, 5, HERE << "address NAT: " << newConn);
         return true;
diff -u -r -N squid-4.0.14/src/ipc/StoreMap.cc squid-4.0.15/src/ipc/StoreMap.cc
--- squid-4.0.14/src/ipc/StoreMap.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ipc/StoreMap.cc	2016-10-10 08:05:51.000000000 +1300
@@ -751,7 +751,7 @@
     basics.timestamp = from.timestamp;
     basics.lastref = from.lastref;
     basics.expires = from.expires;
-    basics.lastmod = from.lastmod;
+    basics.lastmod = from.lastModified();
     basics.swap_file_sz = from.swap_file_sz;
     basics.refcount = from.refcount;
     basics.flags = from.flags;
diff -u -r -N squid-4.0.14/src/log/DB/log_db_daemon.8 squid-4.0.15/src/log/DB/log_db_daemon.8
--- squid-4.0.14/src/log/DB/log_db_daemon.8	2016-09-09 03:32:27.000000000 +1200
+++ squid-4.0.15/src/log/DB/log_db_daemon.8	2016-10-10 12:00:28.000000000 +1300
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -46,7 +46,7 @@
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" If the F register is >0, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.nr rF 0
-.if \n(.g .if rF .nr rF 1
-.if (\n(rF:(\n(.g==0)) \{
-.    if \nF \{
-.        de IX
-.        tm Index:\\$1\t\\n%\t"\\$2"
+.if !\nF .nr F 0
+.if \nF>0 \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.        if !\nF==2 \{
-.            nr % 0
-.            nr F 2
-.        \}
+.    if !\nF==2 \{\
+.        nr % 0
+.        nr F 2
 .    \}
 .\}
-.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -133,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "LOG_DB_DAEMON 8"
-.TH LOG_DB_DAEMON 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH LOG_DB_DAEMON 8 "2016-10-09" "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.14/src/LogTags.cc squid-4.0.15/src/LogTags.cc
--- squid-4.0.14/src/LogTags.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/LogTags.cc	2016-10-10 08:05:51.000000000 +1300
@@ -55,6 +55,9 @@
     else
         pos += snprintf(buf, sizeof(buf), "NONE");
 
+    if (err.ignored)
+        pos += snprintf(buf+pos,sizeof(buf)-pos, "_IGNORED");
+
     // error tags
     if (err.timedout)
         pos += snprintf(buf+pos,sizeof(buf)-pos, "_TIMEDOUT");
diff -u -r -N squid-4.0.14/src/LogTags.h squid-4.0.15/src/LogTags.h
--- squid-4.0.14/src/LogTags.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/LogTags.h	2016-10-10 08:05:51.000000000 +1300
@@ -49,6 +49,8 @@
 {
 public:
     LogTags(LogTags_ot t) : oldType(t) {assert(oldType < LOG_TYPE_MAX);}
+    // XXX: this operator does not reset flags
+    // TODO: either replace with a category-only setter or remove
     LogTags &operator =(const LogTags_ot &t) {assert(t < LOG_TYPE_MAX); oldType = t; return *this;}
 
     /// compute the status access.log field
@@ -57,12 +59,16 @@
     /// determine if the log tag code indicates a cache HIT
     bool isTcpHit() const;
 
-    /// error states terminating the transaction
-    struct Errors {
-        Errors() : timedout(false), aborted(false) {}
+    /// Things that may happen to a transaction while it is being
+    /// processed according to its LOG_* category. Logged as _SUFFIX(es).
+    /// Unlike LOG_* categories, these flags may not be mutually exclusive.
+    class Errors {
+    public:
+        Errors() : ignored(false), timedout(false), aborted(false) {}
 
-        bool timedout; ///< tag: TIMEDOUT - terminated due to a lifetime or I/O timeout
-        bool aborted;  ///< tag: ABORTED  - other abnormal termination (e.g., I/O error)
+        bool ignored; ///< _IGNORED: the response was not used for anything
+        bool timedout; ///< _TIMEDOUT: terminated due to a lifetime or I/O timeout
+        bool aborted;  ///< _ABORTED: other abnormal termination (e.g., I/O error)
     } err;
 
 private:
diff -u -r -N squid-4.0.14/src/main.cc squid-4.0.15/src/main.cc
--- squid-4.0.14/src/main.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/main.cc	2016-10-10 08:05:51.000000000 +1300
@@ -851,13 +851,14 @@
     debugs(1, DBG_IMPORTANT, "Reconfiguring Squid Cache (version " << version_string << ")...");
     reconfiguring = 1;
 
+    RunRegisteredHere(RegisteredRunner::startReconfigure);
+
     // Initiate asynchronous closing sequence
     serverConnectionsClose();
     icpClosePorts();
 #if USE_HTCP
     htcpClosePorts();
 #endif
-    Dns::Shutdown();
 #if USE_SSL_CRTD
     Ssl::Helper::GetInstance()->Shutdown();
 #endif
@@ -2006,7 +2007,6 @@
 #endif
 
     debugs(1, DBG_IMPORTANT, "Shutting down...");
-    Dns::Shutdown();
 #if USE_SSL_CRTD
     Ssl::Helper::GetInstance()->Shutdown();
 #endif
diff -u -r -N squid-4.0.14/src/Makefile.am squid-4.0.15/src/Makefile.am
--- squid-4.0.14/src/Makefile.am	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/Makefile.am	2016-10-10 08:05:51.000000000 +1300
@@ -547,11 +547,11 @@
 	fs/libfs.la \
 	DiskIO/libdiskio.la \
 	comm/libcomm.la \
+	anyp/libanyp.la \
 	security/libsecurity.la \
 	$(SSL_LIBS) \
 	ipc/libipc.la \
 	mgr/libmgr.la \
-	anyp/libanyp.la \
 	parser/libparser.la \
 	eui/libeui.la \
 	icmp/libicmp.la \
diff -u -r -N squid-4.0.14/src/Makefile.in squid-4.0.15/src/Makefile.in
--- squid-4.0.14/src/Makefile.in	2016-09-09 02:14:18.000000000 +1200
+++ squid-4.0.15/src/Makefile.in	2016-10-10 08:11:22.000000000 +1300
@@ -416,11 +416,11 @@
 	clients/libclients.la servers/libservers.la ftp/libftp.la \
 	helper/libhelper.la http/libhttp.la dns/libdns.la \
 	base/libbase.la libsquid.la ip/libip.la fs/libfs.la \
-	DiskIO/libdiskio.la comm/libcomm.la security/libsecurity.la \
-	$(SSL_LIBS) ipc/libipc.la mgr/libmgr.la anyp/libanyp.la \
-	parser/libparser.la eui/libeui.la icmp/libicmp.la \
-	log/liblog.la format/libformat.la sbuf/libsbuf.la \
-	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	DiskIO/libdiskio.la comm/libcomm.la anyp/libanyp.la \
+	security/libsecurity.la $(SSL_LIBS) ipc/libipc.la \
+	mgr/libmgr.la parser/libparser.la eui/libeui.la \
+	icmp/libicmp.la log/liblog.la format/libformat.la \
+	sbuf/libsbuf.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_4) $(am__DEPENDENCIES_5) mem/libmem.la \
@@ -2947,13 +2947,14 @@
 	clients/libclients.la servers/libservers.la ftp/libftp.la \
 	helper/libhelper.la http/libhttp.la dns/libdns.la \
 	base/libbase.la libsquid.la ip/libip.la fs/libfs.la \
-	DiskIO/libdiskio.la comm/libcomm.la security/libsecurity.la \
-	$(SSL_LIBS) ipc/libipc.la mgr/libmgr.la anyp/libanyp.la \
-	parser/libparser.la eui/libeui.la icmp/libicmp.la \
-	log/liblog.la format/libformat.la sbuf/libsbuf.la $(XTRA_OBJS) \
-	$(REPL_OBJS) $(NETTLELIB) $(CRYPTLIB) $(REGEXLIB) \
-	$(ADAPTATION_LIBS) $(ESI_LIBS) $(SNMP_LIBS) mem/libmem.la \
-	store/libstore.la $(top_builddir)/lib/libmisccontainers.la \
+	DiskIO/libdiskio.la comm/libcomm.la anyp/libanyp.la \
+	security/libsecurity.la $(SSL_LIBS) ipc/libipc.la \
+	mgr/libmgr.la parser/libparser.la eui/libeui.la \
+	icmp/libicmp.la log/liblog.la format/libformat.la \
+	sbuf/libsbuf.la $(XTRA_OBJS) $(REPL_OBJS) $(NETTLELIB) \
+	$(CRYPTLIB) $(REGEXLIB) $(ADAPTATION_LIBS) $(ESI_LIBS) \
+	$(SNMP_LIBS) mem/libmem.la store/libstore.la \
+	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la $(ATOMICLIB) $(SSLLIB) \
 	$(EPOLL_LIBS) $(MINGW_LIBS) $(KRB5LIBS) $(COMPAT_LIB) \
diff -u -r -N squid-4.0.14/src/MemStore.cc squid-4.0.15/src/MemStore.cc
--- squid-4.0.14/src/MemStore.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/MemStore.cc	2016-10-10 08:05:51.000000000 +1300
@@ -456,7 +456,7 @@
     e.lastref = basics.lastref;
     e.timestamp = basics.timestamp;
     e.expires = basics.expires;
-    e.lastmod = basics.lastmod;
+    e.lastModified(basics.lastmod);
     e.refcount = basics.refcount;
     e.flags = basics.flags;
 
diff -u -r -N squid-4.0.14/src/pconn.cc squid-4.0.15/src/pconn.cc
--- squid-4.0.14/src/pconn.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/pconn.cc	2016-10-10 08:05:51.000000000 +1300
@@ -42,7 +42,7 @@
 
     theList_ = new Comm::ConnectionPointer[capacity_];
 
-    RegisterRunner(this);
+    registerRunner();
 
 // TODO: re-attach to MemPools. WAS: theList = (?? *)pconn_fds_pool->alloc();
 }
diff -u -r -N squid-4.0.14/src/peer_digest.cc squid-4.0.15/src/peer_digest.cc
--- squid-4.0.14/src/peer_digest.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/peer_digest.cc	2016-10-10 08:05:51.000000000 +1300
@@ -370,7 +370,7 @@
     /* set lastmod to trigger IMS request if possible */
 
     if (old_e)
-        e->lastmod = old_e->lastmod;
+        e->lastModified(old_e->lastModified());
 
     /* push towards peer cache */
     debugs(72, 3, "peerDigestRequest: forwarding to fwdStart...");
@@ -918,8 +918,8 @@
     debugs(72, 3, "peerDigestFetchFinish: expires: " <<
            (long int) fetch->expires << " (" << std::showpos <<
            (int) (fetch->expires - squid_curtime) << "), lmt: " <<
-           std::noshowpos << (long int) fetch->entry->lastmod << " (" <<
-           std::showpos << (int) (fetch->entry->lastmod - squid_curtime) <<
+           std::noshowpos << (long int) fetch->entry->lastModified() << " (" <<
+           std::showpos << (int) (fetch->entry->lastModified() - squid_curtime) <<
            ")");
 
 }
diff -u -r -N squid-4.0.14/src/redirect.cc squid-4.0.15/src/redirect.cc
--- squid-4.0.14/src/redirect.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/redirect.cc	2016-10-10 08:05:51.000000000 +1300
@@ -395,11 +395,13 @@
     }
 
     if (Config.redirector_extras) {
+        delete redirectorExtrasFmt;
         redirectorExtrasFmt = new ::Format::Format("url_rewrite_extras");
         (void)redirectorExtrasFmt->parse(Config.redirector_extras);
     }
 
     if (Config.storeId_extras) {
+        delete storeIdExtrasFmt;
         storeIdExtrasFmt = new ::Format::Format("store_id_extras");
         (void)storeIdExtrasFmt->parse(Config.storeId_extras);
     }
@@ -414,9 +416,6 @@
      * When and if needed for more helpers a separated shutdown
      * method will be added for each of them.
      */
-    if (!storeIds && !redirectors)
-        return;
-
     if (redirectors)
         helperShutdown(redirectors);
 
diff -u -r -N squid-4.0.14/src/refresh.cc squid-4.0.15/src/refresh.cc
--- squid-4.0.14/src/refresh.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/refresh.cc	2016-10-10 08:05:51.000000000 +1300
@@ -174,13 +174,8 @@
     }
 
     // 3. If there is a Last-Modified header, try the last-modified factor algorithm.
-    if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) {
-
-        /* lastmod_delta is the difference between the last-modified date of the response
-         * and the time we cached it. It's how "old" the response was when we got it.
-         */
-        time_t lastmod_delta = entry->timestamp - entry->lastmod;
-
+    const time_t lastmod_delta = entry->timestamp - entry->lastModified();
+    if (lastmod_delta > 0) {
         /* stale_age is the age of the response when it became/becomes stale according to
          * the last-modified factor algorithm. It's how long we can consider the response
          * fresh from the time we cached it.
@@ -540,8 +535,8 @@
         /* Does not need refresh. This is certainly cachable */
         return true;
 
-    if (entry->lastmod < 0)
-        /* Last modified is needed to do a refresh */
+    if (entry->lastModified() < 0)
+        /* We should know entry's modification time to do a refresh */
         return false;
 
     if (entry->mem_obj == NULL)
diff -u -r -N squid-4.0.14/src/sbuf/MemBlob.h squid-4.0.15/src/sbuf/MemBlob.h
--- squid-4.0.14/src/sbuf/MemBlob.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/sbuf/MemBlob.h	2016-10-10 08:05:51.000000000 +1300
@@ -72,7 +72,7 @@
      */
     bool canAppend(const size_type off, const size_type n) const {
         // TODO: ignore offset (and adjust size) when the blob is not shared?
-        return isAppendOffset(off) && willFit(n);
+        return (isAppendOffset(off) && willFit(n)) || !n;
     }
 
     /** adjusts internal object state as if exactly n bytes were append()ed
diff -u -r -N squid-4.0.14/src/sbuf/SBuf.cc squid-4.0.15/src/sbuf/SBuf.cc
--- squid-4.0.14/src/sbuf/SBuf.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/sbuf/SBuf.cc	2016-10-10 08:05:51.000000000 +1300
@@ -827,27 +827,6 @@
     return npos;
 }
 
-/*
- * TODO: borrow a sscanf implementation from Linux or similar?
- * we'd really need a vsnscanf(3)... ? As an alternative, a
- * light-regexp-like domain-specific syntax might be an idea.
- */
-int
-SBuf::scanf(const char *format, ...)
-{
-    // with the format or an arg might be a dangerous char*
-    // that gets invalidated by c_str()
-    const Locker blobKeeper(this, buf());
-
-    va_list arg;
-    int rv;
-    ++stats.scanf;
-    va_start(arg, format);
-    rv = vsscanf(c_str(), format, arg);
-    va_end(arg);
-    return rv;
-}
-
 void
 SBuf::toLower()
 {
diff -u -r -N squid-4.0.14/src/sbuf/SBuf.h squid-4.0.15/src/sbuf/SBuf.h
--- squid-4.0.14/src/sbuf/SBuf.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/sbuf/SBuf.h	2016-10-10 08:05:51.000000000 +1300
@@ -583,14 +583,6 @@
      */
     size_type findLastNotOf(const CharacterSet &set, size_type endPos = npos) const;
 
-    /** sscanf-alike
-     *
-     * sscanf re-implementation. Non-const, and not \0-clean.
-     * \return same as sscanf
-     * \see man sscanf(3)
-     */
-    int scanf(const char *format, ...);
-
     /// converts all characters to lower case; \see man tolower(3)
     void toLower();
 
diff -u -r -N squid-4.0.14/src/sbuf/Stats.cc squid-4.0.15/src/sbuf/Stats.cc
--- squid-4.0.14/src/sbuf/Stats.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/sbuf/Stats.cc	2016-10-10 08:05:51.000000000 +1300
@@ -17,7 +17,7 @@
     : alloc(0), allocCopy(0), allocFromCString(0),
       assignFast(0), clear(0), append(0), moves(0), toStream(0), setChar(0),
       getChar(0), compareSlow(0), compareFast(0), copyOut(0),
-      rawAccess(0), nulTerminate(0), chop(0), trim(0), find(0), scanf(0),
+      rawAccess(0), nulTerminate(0), chop(0), trim(0), find(0),
       caseChange(0), cowFast(0), cowSlow(0), live(0)
 {}
 
@@ -42,7 +42,6 @@
     chop += ss.chop;
     trim += ss.trim;
     find += ss.find;
-    scanf += ss.scanf;
     caseChange += ss.caseChange;
     cowFast += ss.cowFast;
     cowSlow += ss.cowSlow;
@@ -75,7 +74,6 @@
        "\nchop operations: " << chop <<
        "\ntrim operations: " << trim <<
        "\nfind: " << find <<
-       "\nscanf: " << scanf <<
        "\ncase-change ops: " << caseChange <<
        "\nCOW not actually requiring a copy: " << cowFast <<
        "\nCOW: " << cowSlow <<
diff -u -r -N squid-4.0.14/src/sbuf/Stats.h squid-4.0.15/src/sbuf/Stats.h
--- squid-4.0.14/src/sbuf/Stats.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/sbuf/Stats.h	2016-10-10 08:05:51.000000000 +1300
@@ -39,7 +39,6 @@
     uint64_t chop;  ///<number of chop operations
     uint64_t trim;  ///<number of trim operations
     uint64_t find;  ///<number of find operations
-    uint64_t scanf;  ///<number of scanf operations
     uint64_t caseChange; ///<number of toUpper and toLower operations
     uint64_t cowFast; ///<number of cow operations not actually requiring a copy
     uint64_t cowSlow; ///<number of cow operations requiring a copy
diff -u -r -N squid-4.0.14/src/security/BlindPeerConnector.cc squid-4.0.15/src/security/BlindPeerConnector.cc
--- squid-4.0.14/src/security/BlindPeerConnector.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/BlindPeerConnector.cc	2016-10-10 08:05:51.000000000 +1300
@@ -19,13 +19,12 @@
 
 CBDATA_NAMESPACED_CLASS_INIT(Security, BlindPeerConnector);
 
-Security::ContextPtr
-Security::BlindPeerConnector::getSslContext()
+Security::ContextPointer
+Security::BlindPeerConnector::getTlsContext()
 {
     if (const CachePeer *peer = serverConnection()->getPeer()) {
         assert(peer->secure.encryptTransport);
-        Security::ContextPtr sslContext(peer->sslContext);
-        return sslContext;
+        return peer->sslContext;
     }
     return ::Config.ssl_client.sslContext;
 }
diff -u -r -N squid-4.0.14/src/security/BlindPeerConnector.h squid-4.0.15/src/security/BlindPeerConnector.h
--- squid-4.0.14/src/security/BlindPeerConnector.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/BlindPeerConnector.h	2016-10-10 08:05:51.000000000 +1300
@@ -39,8 +39,8 @@
     /// \returns true on successful initialization
     virtual bool initialize(Security::SessionPointer &);
 
-    /// Return the configured Security::ContextPtr object
-    virtual Security::ContextPtr getSslContext();
+    /// Return the configured TLS context object
+    virtual Security::ContextPointer getTlsContext();
 
     /// On error calls peerConnectFailed().
     /// On success store the used TLS session for later use.
diff -u -r -N squid-4.0.14/src/security/CertError.h squid-4.0.15/src/security/CertError.h
--- squid-4.0.14/src/security/CertError.h	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.15/src/security/CertError.h	2016-10-10 08:05:51.000000000 +1300
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SRC_SECURITY_CERTERROR_H
+#define SQUID_SRC_SECURITY_CERTERROR_H
+
+#include "security/forward.h"
+
+namespace Security
+{
+
+/// An X.509 certificate-related error.
+/// Pairs an error code with the certificate experiencing the error.
+class CertError
+{
+public:
+    CertError(int anErr, const Security::CertPointer &aCert, int aDepth = -1) :
+        code(anErr), cert(aCert), depth(aDepth)
+    {}
+
+    bool operator == (const CertError &ce) const {
+        // We expect to be used in contexts where identical certificates have
+        // identical pointers.
+        return code == ce.code && depth == ce.depth && cert == ce.cert;
+    }
+
+    bool operator != (const CertError &ce) const {
+        return !(*this == ce);
+    }
+
+public:
+    Security::ErrorCode code; ///< certificate error code
+    Security::CertPointer cert; ///< certificate with the above error code
+
+    /**
+     * Absolute cert position in the final certificate chain that may include
+     * intermediate certificates. Chain positions start with zero and increase
+     * towards the root certificate. Negative if unknown.
+     */
+    int depth;
+};
+
+} // namespace Security
+
+#endif /* SQUID_SRC_SECURITY_CERTERROR_H */
+
diff -u -r -N squid-4.0.14/src/security/cert_validators/fake/security_fake_certverify.8 squid-4.0.15/src/security/cert_validators/fake/security_fake_certverify.8
--- squid-4.0.14/src/security/cert_validators/fake/security_fake_certverify.8	2016-09-09 03:32:45.000000000 +1200
+++ squid-4.0.15/src/security/cert_validators/fake/security_fake_certverify.8	2016-10-10 12:01:21.000000000 +1300
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -46,7 +46,7 @@
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" If the F register is >0, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.nr rF 0
-.if \n(.g .if rF .nr rF 1
-.if (\n(rF:(\n(.g==0)) \{
-.    if \nF \{
-.        de IX
-.        tm Index:\\$1\t\\n%\t"\\$2"
+.if !\nF .nr F 0
+.if \nF>0 \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.        if !\nF==2 \{
-.            nr % 0
-.            nr F 2
-.        \}
+.    if !\nF==2 \{\
+.        nr % 0
+.        nr F 2
 .    \}
 .\}
-.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -133,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "SECURITY_FAKE_CERTVERIFY 8"
-.TH SECURITY_FAKE_CERTVERIFY 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH SECURITY_FAKE_CERTVERIFY 8 "2016-10-09" "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.14/src/security/Context.h squid-4.0.15/src/security/Context.h
--- squid-4.0.14/src/security/Context.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/Context.h	2016-10-10 08:05:51.000000000 +1300
@@ -24,27 +24,16 @@
 
 namespace Security {
 
-/* IMPORTANT:
- * Due to circular dependency issues between ssl/libsslsquid.la and
- * security/libsecurity.la the code within src/ssl/ is restricted to
- * only using Security::ContextPtr, it MUST NOT use ContextPointer
- *
- * Code outside of src/ssl/ should always use Security::ContextPointer
- * when storing a reference to a context.
- */
 #if USE_OPENSSL
-typedef SSL_CTX* ContextPtr;
 CtoCpp1(SSL_CTX_free, SSL_CTX *);
 typedef LockingPointer<SSL_CTX, SSL_CTX_free_cpp, CRYPTO_LOCK_SSL_CTX> ContextPointer;
 
 #elif USE_GNUTLS
-typedef gnutls_certificate_credentials_t ContextPtr;
 CtoCpp1(gnutls_certificate_free_credentials, gnutls_certificate_credentials_t);
 typedef Security::LockingPointer<struct gnutls_certificate_credentials_st, gnutls_certificate_free_credentials_cpp, -1> ContextPointer;
 
 #else
 // use void* so we can check against nullptr
-typedef void* ContextPtr;
 typedef Security::LockingPointer<void, nullptr, -1> ContextPointer;
 
 #endif
diff -u -r -N squid-4.0.14/src/security/forward.h squid-4.0.15/src/security/forward.h
--- squid-4.0.14/src/security/forward.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/forward.h	2016-10-10 08:05:51.000000000 +1300
@@ -9,6 +9,7 @@
 #ifndef SQUID_SRC_SECURITY_FORWARD_H
 #define SQUID_SRC_SECURITY_FORWARD_H
 
+#include "base/CbDataList.h"
 #include "security/Context.h"
 #include "security/Session.h"
 
@@ -18,6 +19,7 @@
 #endif
 #endif
 #include <list>
+#include <unordered_set>
 
 #if USE_OPENSSL
 // Macro to be used to define the C++ wrapper functor of the sk_*_pop_free
@@ -42,6 +44,10 @@
 namespace Security
 {
 
+class CertError;
+/// Holds a list of X.509 certificate errors
+typedef CbDataList<Security::CertError> CertErrors;
+
 #if USE_OPENSSL
 CtoCpp1(X509_free, X509 *)
 typedef Security::LockingPointer<X509, X509_free_cpp, CRYPTO_LOCK_X509> CertPointer;
@@ -74,6 +80,14 @@
 #endif
 
 class EncryptorAnswer;
+
+/// Squid defined error code (<0), an error code returned by X.509 API, or SSL_ERROR_NONE
+typedef int ErrorCode;
+
+/// set of Squid defined TLS error codes
+/// \note using std::unordered_set ensures values are unique, with fast lookup
+typedef std::unordered_set<Security::ErrorCode> Errors;
+
 class KeyData;
 class PeerConnector;
 class PeerOptions;
diff -u -r -N squid-4.0.14/src/security/Handshake.cc squid-4.0.15/src/security/Handshake.cc
--- squid-4.0.14/src/security/Handshake.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/Handshake.cc	2016-10-10 08:05:51.000000000 +1300
@@ -542,9 +542,9 @@
     auto x509Start = reinterpret_cast<const unsigned char *>(raw.rawContent());
     auto x509Pos = x509Start;
     X509 *x509 = d2i_X509(nullptr, &x509Pos, raw.length());
+    pCert.resetWithoutLocking(x509);
     Must(x509); // successfully parsed
     Must(x509Pos == x509Start + raw.length()); // no leftovers
-    pCert.resetAndLock(x509);
 #endif
 }
 
diff -u -r -N squid-4.0.14/src/security/LockingPointer.h squid-4.0.15/src/security/LockingPointer.h
--- squid-4.0.14/src/security/LockingPointer.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/LockingPointer.h	2016-10-10 08:05:51.000000000 +1300
@@ -66,7 +66,7 @@
     ~LockingPointer() { unlock(); }
 
     // copy semantics are okay only when adding a lock reference
-    explicit LockingPointer(const SelfType &o) : raw(nullptr) {
+    LockingPointer(const SelfType &o) : raw(nullptr) {
         resetAndLock(o.get());
     }
     const SelfType &operator =(const SelfType &o) {
@@ -85,6 +85,10 @@
 
     bool operator !() const { return !raw; }
     explicit operator bool() const { return raw; }
+    bool operator ==(const SelfType &o) const { return (o.get() == raw); }
+    bool operator !=(const SelfType &o) const { return (o.get() != raw); }
+
+    T *operator ->() const { return raw; }
 
     /// Returns raw and possibly nullptr pointer
     T *get() const { return raw; }
diff -u -r -N squid-4.0.14/src/security/Makefile.am squid-4.0.15/src/security/Makefile.am
--- squid-4.0.14/src/security/Makefile.am	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/Makefile.am	2016-10-10 08:05:51.000000000 +1300
@@ -15,6 +15,7 @@
 libsecurity_la_SOURCES= \
 	BlindPeerConnector.cc \
 	BlindPeerConnector.h \
+	CertError.h \
 	Context.h \
 	EncryptorAnswer.cc \
 	EncryptorAnswer.h \
diff -u -r -N squid-4.0.14/src/security/Makefile.in squid-4.0.15/src/security/Makefile.in
--- squid-4.0.14/src/security/Makefile.in	2016-09-09 02:15:01.000000000 +1200
+++ squid-4.0.15/src/security/Makefile.in	2016-10-10 08:18:19.000000000 +1300
@@ -760,6 +760,7 @@
 libsecurity_la_SOURCES = \
 	BlindPeerConnector.cc \
 	BlindPeerConnector.h \
+	CertError.h \
 	Context.h \
 	EncryptorAnswer.cc \
 	EncryptorAnswer.h \
diff -u -r -N squid-4.0.14/src/security/NegotiationHistory.cc squid-4.0.15/src/security/NegotiationHistory.cc
--- squid-4.0.14/src/security/NegotiationHistory.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/NegotiationHistory.cc	2016-10-10 08:05:51.000000000 +1300
@@ -65,18 +65,18 @@
 #endif
 
 void
-Security::NegotiationHistory::retrieveNegotiatedInfo(Security::SessionPtr ssl)
+Security::NegotiationHistory::retrieveNegotiatedInfo(const Security::SessionPointer &session)
 {
 #if USE_OPENSSL
-    if ((cipher = SSL_get_current_cipher(ssl)) != NULL) {
+    if ((cipher = SSL_get_current_cipher(session.get()))) {
         // Set the negotiated version only if the cipher negotiated
         // else probably the negotiation is not completed and version
         // is not the final negotiated version
-        version_ = toProtocolVersion(ssl->version);
+        version_ = toProtocolVersion(session->version);
     }
 
     if (Debug::Enabled(83, 5)) {
-        BIO *b = SSL_get_rbio(ssl);
+        BIO *b = SSL_get_rbio(session.get());
         Ssl::Bio *bio = static_cast<Ssl::Bio *>(b->ptr);
         debugs(83, 5, "SSL connection info on FD " << bio->fd() <<
                " SSL version " << version_ <<
diff -u -r -N squid-4.0.14/src/security/NegotiationHistory.h squid-4.0.15/src/security/NegotiationHistory.h
--- squid-4.0.14/src/security/NegotiationHistory.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/NegotiationHistory.h	2016-10-10 08:05:51.000000000 +1300
@@ -21,7 +21,7 @@
     NegotiationHistory();
 
     /// Extract negotiation information from TLS object
-    void retrieveNegotiatedInfo(Security::SessionPtr);
+    void retrieveNegotiatedInfo(const Security::SessionPointer &);
 
     /// Extract information from parser stored in TlsDetails  object
     void retrieveParsedInfo(Security::TlsDetails::Pointer const &details);
diff -u -r -N squid-4.0.14/src/security/PeerConnector.cc squid-4.0.15/src/security/PeerConnector.cc
--- squid-4.0.14/src/security/PeerConnector.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/PeerConnector.cc	2016-10-10 08:05:51.000000000 +1300
@@ -100,10 +100,10 @@
 Security::PeerConnector::initialize(Security::SessionPointer &serverSession)
 {
 #if USE_OPENSSL
-    Security::ContextPtr sslContext(getSslContext());
-    assert(sslContext);
+    Security::ContextPointer ctx(getTlsContext());
+    assert(ctx);
 
-    if (!Ssl::CreateClient(sslContext, serverConnection(), "server https start")) {
+    if (!Ssl::CreateClient(ctx, serverConnection(), "server https start")) {
         ErrorState *anErr = new ErrorState(ERR_SOCKET_FAILURE, Http::scInternalServerError, request.getRaw());
         anErr->xerrno = errno;
         debugs(83, DBG_IMPORTANT, "Error allocating TLS handle: " << ERR_error_string(ERR_get_error(), NULL));
@@ -151,14 +151,15 @@
 void
 Security::PeerConnector::recordNegotiationDetails()
 {
-#if USE_OPENSSL
     const int fd = serverConnection()->fd;
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
+    Security::SessionPointer session(fd_table[fd].ssl);
 
     // retrieve TLS server negotiated information if any
-    serverConnection()->tlsNegotiations()->retrieveNegotiatedInfo(ssl);
+    serverConnection()->tlsNegotiations()->retrieveNegotiatedInfo(session);
+
+#if USE_OPENSSL
     // retrieve TLS parsed extra info
-    BIO *b = SSL_get_rbio(ssl);
+    BIO *b = SSL_get_rbio(session.get());
     Ssl::ServerBio *bio = static_cast<Ssl::ServerBio *>(b->ptr);
     if (const Security::TlsDetails::Pointer &details = bio->receivedHelloDetails())
         serverConnection()->tlsNegotiations()->retrieveParsedInfo(details);
@@ -199,20 +200,19 @@
 #if USE_OPENSSL
     if (Ssl::TheConfig.ssl_crt_validator && useCertValidator_) {
         const int fd = serverConnection()->fd;
-        Security::SessionPtr ssl = fd_table[fd].ssl.get();
+        Security::SessionPointer session(fd_table[fd].ssl);
 
         Ssl::CertValidationRequest validationRequest;
         // WARNING: Currently we do not use any locking for any of the
         // members of the Ssl::CertValidationRequest class. In this code the
         // Ssl::CertValidationRequest object used only to pass data to
         // Ssl::CertValidationHelper::submit method.
-        validationRequest.ssl = ssl;
-        validationRequest.domainName = request->url.host();
-        if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
+        validationRequest.ssl = session.get();
+        SBuf *dName = (SBuf *)SSL_get_ex_data(session.get(), ssl_ex_index_server);
+        validationRequest.domainName = dName->c_str();
+        if (Security::CertErrors *errs = static_cast<Security::CertErrors *>(SSL_get_ex_data(session.get(), ssl_ex_index_ssl_errors)))
             // validationRequest disappears on return so no need to cbdataReference
             validationRequest.errors = errs;
-        else
-            validationRequest.errors = NULL;
         try {
             debugs(83, 5, "Sending SSL certificate for validation to ssl_crtvd.");
             AsyncCall::Pointer call = asyncCall(83,5, "Security::PeerConnector::sslCrtvdHandleReply", Ssl::CertValidationHelper::CbDialer(this, &Security::PeerConnector::sslCrtvdHandleReply, nullptr));
@@ -250,13 +250,17 @@
         return;
     }
 
-    debugs(83,5, request->url.host() << " cert validation result: " << validationResponse->resultCode);
+    if (Debug::Enabled(83, 5)) {
+        Security::SessionPointer ssl(fd_table[serverConnection()->fd].ssl);
+        SBuf *server = static_cast<SBuf *>(SSL_get_ex_data(ssl.get(), ssl_ex_index_server));
+        debugs(83,5, *server << " cert validation result: " << validationResponse->resultCode);
+    }
 
     if (validationResponse->resultCode == ::Helper::Error) {
-        if (Ssl::CertErrors *errs = sslCrtvdCheckForErrors(*validationResponse, errDetails)) {
-            Security::SessionPtr ssl = fd_table[serverConnection()->fd].ssl.get();
-            Ssl::CertErrors *oldErrs = static_cast<Ssl::CertErrors*>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors));
-            SSL_set_ex_data(ssl, ssl_ex_index_ssl_errors,  (void *)errs);
+        if (Security::CertErrors *errs = sslCrtvdCheckForErrors(*validationResponse, errDetails)) {
+            Security::SessionPointer session(fd_table[serverConnection()->fd].ssl);
+            Security::CertErrors *oldErrs = static_cast<Security::CertErrors*>(SSL_get_ex_data(session.get(), ssl_ex_index_ssl_errors));
+            SSL_set_ex_data(session.get(), ssl_ex_index_ssl_errors,  (void *)errs);
             delete oldErrs;
         }
     } else if (validationResponse->resultCode != ::Helper::Okay)
@@ -287,19 +291,18 @@
 #if USE_OPENSSL
 /// Checks errors in the cert. validator response against sslproxy_cert_error.
 /// The first honored error, if any, is returned via errDetails parameter.
-/// The method returns all seen errors except SSL_ERROR_NONE as Ssl::CertErrors.
-Ssl::CertErrors *
+/// The method returns all seen errors except SSL_ERROR_NONE as Security::CertErrors.
+Security::CertErrors *
 Security::PeerConnector::sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &resp, Ssl::ErrorDetail *& errDetails)
 {
-    Ssl::CertErrors *errs = NULL;
-
     ACLFilledChecklist *check = NULL;
     if (acl_access *acl = ::Config.ssl_client.cert_error) {
         check = new ACLFilledChecklist(acl, request.getRaw(), dash_str);
         check->al = al;
     }
 
-    Security::SessionPtr ssl = fd_table[serverConnection()->fd].ssl.get();
+    Security::CertErrors *errs = nullptr;
+    Security::SessionPointer session(fd_table[serverConnection()->fd].ssl);
     typedef Ssl::CertValidationResponse::RecvdErrors::const_iterator SVCRECI;
     for (SVCRECI i = resp.errors.begin(); i != resp.errors.end(); ++i) {
         debugs(83, 7, "Error item: " << i->error_no << " " << i->error_reason);
@@ -309,7 +312,7 @@
         if (!errDetails) {
             bool allowed = false;
             if (check) {
-                check->sslErrors = new Ssl::CertErrors(Ssl::CertError(i->error_no, i->cert.get(), i->error_depth));
+                check->sslErrors = new Security::CertErrors(Security::CertError(i->error_no, i->cert, i->error_depth));
                 if (check->fastCheck() == ACCESS_ALLOWED)
                     allowed = true;
             }
@@ -321,7 +324,7 @@
             } else {
                 debugs(83, 5, "confirming SSL error " << i->error_no);
                 X509 *brokenCert = i->cert.get();
-                Security::CertPointer peerCert(SSL_get_peer_certificate(ssl));
+                Security::CertPointer peerCert(SSL_get_peer_certificate(session.get()));
                 const char *aReason = i->error_reason.empty() ? NULL : i->error_reason.c_str();
                 errDetails = new Ssl::ErrorDetail(i->error_no, peerCert.get(), brokenCert, aReason);
             }
@@ -332,9 +335,9 @@
         }
 
         if (!errs)
-            errs = new Ssl::CertErrors(Ssl::CertError(i->error_no, i->cert.get(), i->error_depth));
+            errs = new Security::CertErrors(Security::CertError(i->error_no, i->cert, i->error_depth));
         else
-            errs->push_back_unique(Ssl::CertError(i->error_no, i->cert.get(), i->error_depth));
+            errs->push_back_unique(Security::CertError(i->error_no, i->cert, i->error_depth));
     }
     if (check)
         delete check;
@@ -358,8 +361,8 @@
 #if USE_OPENSSL
     const int fd = serverConnection()->fd;
     unsigned long ssl_lib_error = SSL_ERROR_NONE;
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
-    const int ssl_error = SSL_get_error(ssl, ret);
+    Security::SessionPointer session(fd_table[fd].ssl);
+    const int ssl_error = SSL_get_error(session.get(), ret);
 
     switch (ssl_error) {
     case SSL_ERROR_WANT_READ:
@@ -391,8 +394,8 @@
 {
     const int fd = serverConnection()->fd;
 #if USE_OPENSSL
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
+    Security::SessionPointer session(fd_table[fd].ssl);
+    BIO *b = SSL_get_rbio(session.get());
     Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
     if (srvBio->holdRead()) {
         if (srvBio->gotHello()) {
@@ -450,8 +453,8 @@
         anErr = new ErrorState(ERR_SECURE_CONNECT_FAIL, Http::scServiceUnavailable, NULL);
     anErr->xerrno = sysErrNo;
 
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
-    Ssl::ErrorDetail *errFromFailure = static_cast<Ssl::ErrorDetail *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail));
+    Security::SessionPointer session(fd_table[fd].ssl);
+    Ssl::ErrorDetail *errFromFailure = static_cast<Ssl::ErrorDetail *>(SSL_get_ex_data(session.get(), ssl_ex_index_ssl_error_detail));
     if (errFromFailure != NULL) {
         // The errFromFailure is attached to the ssl object
         // and will be released when ssl object destroyed.
@@ -459,7 +462,7 @@
         anErr->detail = new Ssl::ErrorDetail(*errFromFailure);
     } else {
         // server_cert can be NULL here
-        X509 *server_cert = SSL_get_peer_certificate(ssl);
+        X509 *server_cert = SSL_get_peer_certificate(session.get());
         anErr->detail = new Ssl::ErrorDetail(SQUID_ERR_SSL_HANDSHAKE, server_cert, NULL);
         X509_free(server_cert);
     }
@@ -567,7 +570,7 @@
                                       "Security::PeerConnector::certDownloadingDone",
                                       PeerConnectorCertDownloaderDialer(&Security::PeerConnector::certDownloadingDone, this));
 
-    const Downloader *csd = dynamic_cast<const Downloader*>(request->downloader.valid());
+    const Downloader *csd = (request ? dynamic_cast<const Downloader*>(request->downloader.valid()) : nullptr);
     Downloader *dl = new Downloader(url, certCallback, csd ? csd->nestedLevel() + 1 : 1);
     AsyncJob::Start(dl);
 }
@@ -580,8 +583,8 @@
 
     // get ServerBio from SSL object
     const int fd = serverConnection()->fd;
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
+    Security::SessionPointer session(fd_table[fd].ssl);
+    BIO *b = SSL_get_rbio(session.get());
     Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
 
     // Parse Certificate. Assume that it is in DER format.
@@ -599,7 +602,7 @@
         if (const char *issuerUri = Ssl::uriOfIssuerIfMissing(cert,  certsList)) {
             urlsOfMissingCerts.push(SBuf(issuerUri));
         }
-        Ssl::SSL_add_untrusted_cert(ssl, cert);
+        Ssl::SSL_add_untrusted_cert(session.get(), cert);
     }
 
     // Check if there are URIs to download from and if yes start downloading
@@ -621,13 +624,13 @@
     // certificate located in an SSL site which requires to download a
     // a missing certificate (... from an SSL site which requires to ...).
 
-    const Downloader *csd = request->downloader.get();
+    const Downloader *csd = (request ? request->downloader.get() : nullptr);
     if (csd && csd->nestedLevel() >= MaxNestedDownloads)
         return false;
 
     const int fd = serverConnection()->fd;
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
+    Security::SessionPointer session(fd_table[fd].ssl);
+    BIO *b = SSL_get_rbio(session.get());
     Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
     const Security::CertList &certs = srvBio->serverCertificatesIfAny();
 
diff -u -r -N squid-4.0.14/src/security/PeerConnector.h squid-4.0.15/src/security/PeerConnector.h
--- squid-4.0.14/src/security/PeerConnector.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/PeerConnector.h	2016-10-10 08:05:51.000000000 +1300
@@ -155,9 +155,9 @@
     /// \param error if not NULL the SSL negotiation was aborted with an error
     virtual void noteNegotiationDone(ErrorState *error) {}
 
-    /// Must implemented by the kid classes to return the Security::ContextPtr object to use
+    /// Must implemented by the kid classes to return the TLS context object to use
     /// for building the encryption context objects.
-    virtual Security::ContextPtr getSslContext() = 0;
+    virtual Security::ContextPointer getTlsContext() = 0;
 
     /// mimics FwdState to minimize changes to FwdState::initiate/negotiateSsl
     Comm::ConnectionPointer const &serverConnection() const { return serverConn; }
@@ -188,7 +188,7 @@
     void sslCrtvdHandleReply(Ssl::CertValidationResponsePointer);
 
     /// Check SSL errors returned from cert validator against sslproxy_cert_error access list
-    Ssl::CertErrors *sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &, Ssl::ErrorDetail *&);
+    Security::CertErrors *sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &, Ssl::ErrorDetail *&);
 #endif
 
     /// A wrapper function for negotiateSsl for use with Comm::SetSelect
diff -u -r -N squid-4.0.14/src/security/PeerOptions.cc squid-4.0.15/src/security/PeerOptions.cc
--- squid-4.0.14/src/security/PeerOptions.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/PeerOptions.cc	2016-10-10 08:05:51.000000000 +1300
@@ -215,44 +215,46 @@
     }
 }
 
-Security::ContextPtr
+Security::ContextPointer
 Security::PeerOptions::createBlankContext() const
 {
-    Security::ContextPtr t = nullptr;
-
+    Security::ContextPointer ctx;
 #if USE_OPENSSL
     Ssl::Initialize();
 
 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
-    t = SSL_CTX_new(TLS_client_method());
+    SSL_CTX *t = SSL_CTX_new(TLS_client_method());
 #else
-    t = SSL_CTX_new(SSLv23_client_method());
+    SSL_CTX *t = SSL_CTX_new(SSLv23_client_method());
 #endif
     if (!t) {
         const auto x = ERR_error_string(ERR_get_error(), nullptr);
         fatalf("Failed to allocate TLS client context: %s\n", x);
     }
+    ctx.resetWithoutLocking(t);
 
 #elif USE_GNUTLS
     // Initialize for X.509 certificate exchange
+    gnutls_certificate_credentials_t t;
     if (const int x = gnutls_certificate_allocate_credentials(&t)) {
         fatalf("Failed to allocate TLS client context: error=%d\n", x);
     }
+    ctx.resetWithoutLocking(t);
 
 #else
     debugs(83, 1, "WARNING: Failed to allocate TLS client context: No TLS library");
 
 #endif
 
-    return t;
+    return ctx;
 }
 
-Security::ContextPtr
+Security::ContextPointer
 Security::PeerOptions::createClientContext(bool setOptions)
 {
     updateTlsVersionLimits();
 
-    Security::ContextPtr t = createBlankContext();
+    Security::ContextPointer t(createBlankContext());
     if (t) {
 #if USE_OPENSSL
         // XXX: temporary performance regression. c_str() data copies and prevents this being a const method
@@ -554,13 +556,13 @@
 #endif
 
 void
-Security::PeerOptions::updateContextNpn(Security::ContextPtr &ctx)
+Security::PeerOptions::updateContextNpn(Security::ContextPointer &ctx)
 {
     if (!flags.tlsNpn)
         return;
 
 #if USE_OPENSSL && defined(TLSEXT_TYPE_next_proto_neg)
-    SSL_CTX_set_next_proto_select_cb(ctx, &ssl_next_proto_cb, nullptr);
+    SSL_CTX_set_next_proto_select_cb(ctx.get(), &ssl_next_proto_cb, nullptr);
 #endif
 
     // NOTE: GnuTLS does not support the obsolete NPN extension.
@@ -568,14 +570,14 @@
 }
 
 static const char *
-loadSystemTrustedCa(Security::ContextPtr &ctx)
+loadSystemTrustedCa(Security::ContextPointer &ctx)
 {
 #if USE_OPENSSL
-    if (SSL_CTX_set_default_verify_paths(ctx) == 0)
+    if (SSL_CTX_set_default_verify_paths(ctx.get()) == 0)
         return ERR_error_string(ERR_get_error(), nullptr);
 
 #elif USE_GNUTLS
-    auto x = gnutls_certificate_set_x509_system_trust(ctx);
+    auto x = gnutls_certificate_set_x509_system_trust(ctx.get());
     if (x < 0)
         return gnutls_strerror(x);
 
@@ -584,7 +586,7 @@
 }
 
 void
-Security::PeerOptions::updateContextCa(Security::ContextPtr &ctx)
+Security::PeerOptions::updateContextCa(Security::ContextPointer &ctx)
 {
     debugs(83, 8, "Setting CA certificate locations.");
 #if USE_OPENSSL
@@ -592,12 +594,12 @@
 #endif
     for (auto i : caFiles) {
 #if USE_OPENSSL
-        if (!SSL_CTX_load_verify_locations(ctx, i.c_str(), path)) {
+        if (!SSL_CTX_load_verify_locations(ctx.get(), i.c_str(), path)) {
             const int ssl_error = ERR_get_error();
             debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL));
         }
 #elif USE_GNUTLS
-        if (gnutls_certificate_set_x509_trust_file(ctx, i.c_str(), GNUTLS_X509_FMT_PEM) < 0) {
+        if (gnutls_certificate_set_x509_trust_file(ctx.get(), i.c_str(), GNUTLS_X509_FMT_PEM) < 0) {
             debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location: " << i);
         }
 #endif
@@ -612,11 +614,11 @@
 }
 
 void
-Security::PeerOptions::updateContextCrl(Security::ContextPtr &ctx)
+Security::PeerOptions::updateContextCrl(Security::ContextPointer &ctx)
 {
 #if USE_OPENSSL
     bool verifyCrl = false;
-    X509_STORE *st = SSL_CTX_get_cert_store(ctx);
+    X509_STORE *st = SSL_CTX_get_cert_store(ctx.get());
     if (parsedCrl.size()) {
         for (auto &i : parsedCrl) {
             if (!X509_STORE_add_crl(st, i.get()))
diff -u -r -N squid-4.0.14/src/security/PeerOptions.h squid-4.0.15/src/security/PeerOptions.h
--- squid-4.0.14/src/security/PeerOptions.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/PeerOptions.h	2016-10-10 08:05:51.000000000 +1300
@@ -33,22 +33,22 @@
     virtual void clear() {*this = PeerOptions();}
 
     /// generate an unset security context object
-    virtual Security::ContextPtr createBlankContext() const;
+    virtual Security::ContextPointer createBlankContext() const;
 
     /// generate a security client-context from these configured options
-    Security::ContextPtr createClientContext(bool setOptions);
+    Security::ContextPointer createClientContext(bool setOptions);
 
     /// sync the context options with tls-min-version=N configuration
     void updateTlsVersionLimits();
 
     /// setup the NPN extension details for the given context
-    void updateContextNpn(Security::ContextPtr &);
+    void updateContextNpn(Security::ContextPointer &);
 
     /// setup the CA details for the given context
-    void updateContextCa(Security::ContextPtr &);
+    void updateContextCa(Security::ContextPointer &);
 
     /// setup the CRL details for the given context
-    void updateContextCrl(Security::ContextPtr &);
+    void updateContextCrl(Security::ContextPointer &);
 
     /// output squid.conf syntax with 'pfx' prefix on parameters for the stored settings
     virtual void dumpCfg(Packable *, const char *pfx) const;
diff -u -r -N squid-4.0.14/src/security/ServerOptions.cc squid-4.0.15/src/security/ServerOptions.cc
--- squid-4.0.14/src/security/ServerOptions.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/ServerOptions.cc	2016-10-10 08:05:51.000000000 +1300
@@ -85,36 +85,38 @@
         p->appendf(" %sdh=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(dh));
 }
 
-Security::ContextPtr
+Security::ContextPointer
 Security::ServerOptions::createBlankContext() const
 {
-    Security::ContextPtr t = nullptr;
-
+    Security::ContextPointer ctx;
 #if USE_OPENSSL
     Ssl::Initialize();
 
 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
-    t = SSL_CTX_new(TLS_server_method());
+    SSL_CTX *t = SSL_CTX_new(TLS_server_method());
 #else
-    t = SSL_CTX_new(SSLv23_server_method());
+    SSL_CTX *t = SSL_CTX_new(SSLv23_server_method());
 #endif
     if (!t) {
         const auto x = ERR_error_string(ERR_get_error(), nullptr);
         debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: " << x);
     }
+    ctx.resetWithoutLocking(t);
 
 #elif USE_GNUTLS
     // Initialize for X.509 certificate exchange
+    gnutls_certificate_credentials_t t;
     if (const int x = gnutls_certificate_allocate_credentials(&t)) {
         debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: error=" << x);
     }
+    ctx.resetWithoutLocking(t);
 
 #else
     debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: No TLS library");
 
 #endif
 
-    return t;
+    return ctx;
 }
 
 bool
@@ -166,7 +168,7 @@
 }
 
 void
-Security::ServerOptions::updateContextEecdh(Security::ContextPtr &ctx)
+Security::ServerOptions::updateContextEecdh(Security::ContextPointer &ctx)
 {
     // set Elliptic Curve details into the server context
     if (!eecdhCurve.isEmpty()) {
@@ -186,7 +188,7 @@
             return;
         }
 
-        if (!SSL_CTX_set_tmp_ecdh(ctx, ecdh)) {
+        if (!SSL_CTX_set_tmp_ecdh(ctx.get(), ecdh)) {
             auto ssl_error = ERR_get_error();
             debugs(83, DBG_CRITICAL, "ERROR: Unable to set Ephemeral ECDH: " << ERR_error_string(ssl_error, NULL));
         }
@@ -201,7 +203,7 @@
     // set DH parameters into the server context
 #if USE_OPENSSL
     if (parsedDhParams.get()) {
-        SSL_CTX_set_tmp_dh(ctx, parsedDhParams.get());
+        SSL_CTX_set_tmp_dh(ctx.get(), parsedDhParams.get());
     }
 #endif
 }
diff -u -r -N squid-4.0.14/src/security/ServerOptions.h squid-4.0.15/src/security/ServerOptions.h
--- squid-4.0.14/src/security/ServerOptions.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/ServerOptions.h	2016-10-10 08:05:51.000000000 +1300
@@ -29,7 +29,7 @@
     /* Security::PeerOptions API */
     virtual void parse(const char *);
     virtual void clear() {*this = ServerOptions();}
-    virtual Security::ContextPtr createBlankContext() const;
+    virtual Security::ContextPointer createBlankContext() const;
     virtual void dumpCfg(Packable *, const char *pfx) const;
 
     /// generate a security server-context from these configured options
@@ -38,7 +38,7 @@
     bool createStaticServerContext(AnyP::PortCfg &);
 
     /// update the context with DH, EDH, EECDH settings
-    void updateContextEecdh(Security::ContextPtr &);
+    void updateContextEecdh(Security::ContextPointer &);
 
 public:
     /// TLS context to use for HTTPS accelerator or static SSL-Bump
diff -u -r -N squid-4.0.14/src/security/Session.cc squid-4.0.15/src/security/Session.cc
--- squid-4.0.14/src/security/Session.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/Session.cc	2016-10-10 08:05:51.000000000 +1300
@@ -110,8 +110,8 @@
     }
 
     for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
-        if (s->secure.staticContext.get())
-            Ssl::SetSessionCallbacks(s->secure.staticContext.get());
+        if (s->secure.staticContext)
+            Ssl::SetSessionCallbacks(s->secure.staticContext);
     }
 #endif
 }
diff -u -r -N squid-4.0.14/src/security/Session.h squid-4.0.15/src/security/Session.h
--- squid-4.0.14/src/security/Session.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/security/Session.h	2016-10-10 08:05:51.000000000 +1300
@@ -29,14 +29,12 @@
 namespace Security {
 
 #if USE_OPENSSL
-typedef SSL* SessionPtr;
 CtoCpp1(SSL_free, SSL *);
 typedef LockingPointer<SSL, Security::SSL_free_cpp, CRYPTO_LOCK_SSL> SessionPointer;
 
 typedef std::unique_ptr<SSL_SESSION, HardFun<void, SSL_SESSION*, &SSL_SESSION_free>> SessionStatePointer;
 
 #elif USE_GNUTLS
-typedef gnutls_session_t SessionPtr;
 // Locks can be implemented attaching locks counter to gnutls_session_t
 // objects using the gnutls_session_set_ptr()/gnutls_session_get_ptr ()
 // library functions
@@ -49,8 +47,7 @@
 
 #else
 // use void* so we can check against NULL
-typedef void* SessionPtr;
-CtoCpp1(xfree, SessionPtr);
+CtoCpp1(xfree, void *);
 typedef LockingPointer<void, xfree_cpp, -1> SessionPointer;
 
 typedef std::unique_ptr<int> SessionStatePointer;
diff -u -r -N squid-4.0.14/src/SquidConfig.h squid-4.0.15/src/SquidConfig.h
--- squid-4.0.14/src/SquidConfig.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/SquidConfig.h	2016-10-10 08:05:51.000000000 +1300
@@ -505,7 +505,7 @@
     external_acl *externalAclHelperList;
 
     struct {
-        Security::ContextPtr sslContext;
+        Security::ContextPointer sslContext;
 #if USE_OPENSSL
         char *foreignIntermediateCertsPath;
         acl_access *cert_error;
@@ -547,11 +547,15 @@
 class SquidConfig2
 {
 public:
+    void clear() {
+        *this = SquidConfig2();
+    }
+
     struct {
-        int enable_purge;
+        int enable_purge = 0;
     } onoff;
-    uid_t effectiveUserID;
-    gid_t effectiveGroupID;
+    uid_t effectiveUserID = 0;
+    gid_t effectiveGroupID = 0;
 };
 
 extern SquidConfig2 Config2;
diff -u -r -N squid-4.0.14/src/SquidNew.cc squid-4.0.15/src/SquidNew.cc
--- squid-4.0.14/src/SquidNew.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/SquidNew.cc	2016-10-10 08:05:51.000000000 +1300
@@ -10,7 +10,7 @@
 
 #include "squid.h"
 
-#if !defined(__clang__)
+#if !defined(__clang__) && !defined(__SUNPRO_CC)
 
 #include <new>
 
diff -u -r -N squid-4.0.14/src/ssl/cert_validate_message.cc squid-4.0.15/src/ssl/cert_validate_message.cc
--- squid-4.0.14/src/ssl/cert_validate_message.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/cert_validate_message.cc	2016-10-10 08:05:51.000000000 +1300
@@ -10,6 +10,7 @@
 #include "acl/FilledChecklist.h"
 #include "globals.h"
 #include "helper.h"
+#include "security/CertError.h"
 #include "ssl/cert_validate_message.h"
 #include "ssl/ErrorDetail.h"
 #include "ssl/support.h"
@@ -48,7 +49,7 @@
 
     if (vcert.errors) {
         int i = 0;
-        for (const Ssl::CertErrors *err = vcert.errors; err; err = err->next, ++i) {
+        for (const Security::CertErrors *err = vcert.errors; err; err = err->next, ++i) {
             body +="\n";
             body = body + param_error_name + xitoa(i) + "=" + GetErrorName(err->element.code) + "\n";
             int errorCertPos = -1;
diff -u -r -N squid-4.0.14/src/ssl/cert_validate_message.h squid-4.0.15/src/ssl/cert_validate_message.h
--- squid-4.0.14/src/ssl/cert_validate_message.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/cert_validate_message.h	2016-10-10 08:05:51.000000000 +1300
@@ -27,7 +27,7 @@
 {
 public:
     SSL *ssl;
-    CertErrors *errors; ///< The list of errors detected
+    Security::CertErrors *errors; ///< The list of errors detected
     std::string domainName; ///< The server name
     CertValidationRequest() : ssl(NULL), errors(NULL) {}
 };
@@ -53,7 +53,7 @@
         RecvdError & operator =(const RecvdError &);
         void setCert(X509 *);  ///< Sets cert to the given certificate
         int id; ///<  The id of the error
-        ssl_error_t error_no; ///< The OpenSSL error code
+        Security::ErrorCode error_no; ///< The OpenSSL error code
         std::string error_reason; ///< A string describing the error
         Security::CertPointer cert; ///< The broken certificate
         int error_depth; ///< The error depth
diff -u -r -N squid-4.0.14/src/ssl/ErrorDetail.cc squid-4.0.15/src/ssl/ErrorDetail.cc
--- squid-4.0.14/src/ssl/ErrorDetail.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/ErrorDetail.cc	2016-10-10 08:05:51.000000000 +1300
@@ -15,13 +15,13 @@
 #include <map>
 
 struct SslErrorEntry {
-    Ssl::ssl_error_t value;
+    Security::ErrorCode value;
     const char *name;
 };
 
 static const char *SslErrorDetailDefaultStr = "SSL handshake error (%err_name)";
 //Use std::map to optimize search
-typedef std::map<Ssl::ssl_error_t, const SslErrorEntry *> SslErrors;
+typedef std::map<Security::ErrorCode, const SslErrorEntry *> SslErrors;
 SslErrors TheSslErrors;
 
 static SslErrorEntry TheSslErrorArray[] = {
@@ -290,20 +290,20 @@
 
 struct SslErrorAlias {
     const char *name;
-    const Ssl::ssl_error_t *errors;
+    const Security::ErrorCode *errors;
 };
 
-static const Ssl::ssl_error_t hasExpired[] = {X509_V_ERR_CERT_HAS_EXPIRED, SSL_ERROR_NONE};
-static const Ssl::ssl_error_t notYetValid[] = {X509_V_ERR_CERT_NOT_YET_VALID, SSL_ERROR_NONE};
-static const Ssl::ssl_error_t domainMismatch[] = {SQUID_X509_V_ERR_DOMAIN_MISMATCH, SSL_ERROR_NONE};
-static const Ssl::ssl_error_t certUntrusted[] = {X509_V_ERR_INVALID_CA,
-                                                 X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
-                                                 X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
-                                                 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
-                                                 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
-                                                 X509_V_ERR_CERT_UNTRUSTED, SSL_ERROR_NONE
-                                                };
-static const Ssl::ssl_error_t certSelfSigned[] = {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, SSL_ERROR_NONE};
+static const Security::ErrorCode hasExpired[] = {X509_V_ERR_CERT_HAS_EXPIRED, SSL_ERROR_NONE};
+static const Security::ErrorCode notYetValid[] = {X509_V_ERR_CERT_NOT_YET_VALID, SSL_ERROR_NONE};
+static const Security::ErrorCode domainMismatch[] = {SQUID_X509_V_ERR_DOMAIN_MISMATCH, SSL_ERROR_NONE};
+static const Security::ErrorCode certUntrusted[] = {X509_V_ERR_INVALID_CA,
+                                                    X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
+                                                    X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
+                                                    X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
+                                                    X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
+                                                    X509_V_ERR_CERT_UNTRUSTED, SSL_ERROR_NONE
+                                                   };
+static const Security::ErrorCode certSelfSigned[] = {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, SSL_ERROR_NONE};
 
 // The list of error name shortcuts  for use with ssl_error acls.
 // The keys without the "ssl::" scope prefix allow shorter error
@@ -324,7 +324,7 @@
 };
 
 // Use std::map to optimize search.
-typedef std::map<std::string, const Ssl::ssl_error_t *> SslErrorShortcuts;
+typedef std::map<std::string, const Security::ErrorCode *> SslErrorShortcuts;
 SslErrorShortcuts TheSslErrorShortcuts;
 
 static void loadSslErrorMap()
@@ -342,7 +342,7 @@
         TheSslErrorShortcuts[TheSslErrorShortcutsArray[i].name] = TheSslErrorShortcutsArray[i].errors;
 }
 
-Ssl::ssl_error_t Ssl::GetErrorCode(const char *name)
+Security::ErrorCode Ssl::GetErrorCode(const char *name)
 {
     //TODO: use a std::map?
     for (int i = 0; TheSslErrorArray[i].name != NULL; ++i) {
@@ -352,20 +352,24 @@
     return SSL_ERROR_NONE;
 }
 
-Ssl::Errors *
-Ssl::ParseErrorString(const char *name)
+bool
+Ssl::ParseErrorString(const char *name, Security::Errors &errors)
 {
     assert(name);
 
-    const Ssl::ssl_error_t ssl_error = GetErrorCode(name);
-    if (ssl_error != SSL_ERROR_NONE)
-        return new Ssl::Errors(ssl_error);
+    const Security::ErrorCode ssl_error = GetErrorCode(name);
+    if (ssl_error != SSL_ERROR_NONE) {
+        errors.emplace(ssl_error);
+        return true;
+    }
 
     if (xisdigit(*name)) {
         const long int value = strtol(name, NULL, 0);
-        if (SQUID_SSL_ERROR_MIN <= value && value <= SQUID_SSL_ERROR_MAX)
-            return new Ssl::Errors(value);
-        fatalf("Too small or too bug SSL error code '%s'", name);
+        if (SQUID_SSL_ERROR_MIN <= value && value <= SQUID_SSL_ERROR_MAX) {
+            errors.emplace(value);
+            return true;
+        }
+        fatalf("Too small or too big TLS error code '%s'", name);
     }
 
     if (TheSslErrorShortcuts.empty())
@@ -375,18 +379,17 @@
     if (it != TheSslErrorShortcuts.end()) {
         // Should not be empty...
         assert(it->second[0] != SSL_ERROR_NONE);
-        Ssl::Errors *errors = new Ssl::Errors(it->second[0]);
-        for (int i =1; it->second[i] != SSL_ERROR_NONE; ++i) {
-            errors->push_back_unique(it->second[i]);
+        for (int i = 0; it->second[i] != SSL_ERROR_NONE; ++i) {
+            errors.emplace(it->second[i]);
         }
-        return errors;
+        return true;
     }
 
-    fatalf("Unknown SSL error name '%s'", name);
-    return NULL; // not reached
+    fatalf("Unknown TLS error name '%s'", name);
+    return false; // not reached
 }
 
-const char *Ssl::GetErrorName(Ssl::ssl_error_t value)
+const char *Ssl::GetErrorName(Security::ErrorCode value)
 {
     if (TheSslErrors.empty())
         loadSslErrorMap();
@@ -409,7 +412,7 @@
 }
 
 const char *
-Ssl::GetErrorDescr(Ssl::ssl_error_t value)
+Ssl::GetErrorDescr(Security::ErrorCode value)
 {
     return ErrorDetailsManager::GetInstance().getDefaultErrorDescr(value);
 }
@@ -625,7 +628,7 @@
     return errDetailStr;
 }
 
-Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no, X509 *cert, X509 *broken, const char *aReason): error_no (err_no), lib_error_no(SSL_ERROR_NONE), errReason(aReason)
+Ssl::ErrorDetail::ErrorDetail( Security::ErrorCode err_no, X509 *cert, X509 *broken, const char *aReason): error_no (err_no), lib_error_no(SSL_ERROR_NONE), errReason(aReason)
 {
     if (cert)
         peer_cert.resetAndLock(cert);
diff -u -r -N squid-4.0.14/src/ssl/ErrorDetail.h squid-4.0.15/src/ssl/ErrorDetail.h
--- squid-4.0.14/src/ssl/ErrorDetail.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/ErrorDetail.h	2016-10-10 08:05:51.000000000 +1300
@@ -17,42 +17,25 @@
 namespace Ssl
 {
 /**
-  \ingroup ServerProtocolSSLAPI
- * Converts user-friendly error "name" into an Ssl::Errors list.
- * The resulting list may have one or more elements, and needs to be
- * released by the caller.
+ * Converts user-friendly error "name" into an Security::ErrorCode
+ * and adds it to the provided container (using emplace).
  * This function can handle numeric error numbers as well as names.
  */
-Ssl::Errors *ParseErrorString(const char *name);
+bool ParseErrorString(const char *name, Security::Errors &);
 
-/**
-   \ingroup ServerProtocolSSLAPI
-  * The ssl_error_t code of the error described by  "name".
-  */
-ssl_error_t GetErrorCode(const char *name);
-
-/**
-   \ingroup ServerProtocolSSLAPI
- * The string representation of the SSL error "value"
- */
-const char *GetErrorName(ssl_error_t value);
+/// The Security::ErrorCode code of the error described by  "name".
+Security::ErrorCode GetErrorCode(const char *name);
 
-/**
-   \ingroup ServerProtocolSSLAPI
- * A short description of the SSL error "value"
- */
-const char *GetErrorDescr(ssl_error_t value);
+/// The string representation of the TLS error "value"
+const char *GetErrorName(Security::ErrorCode value);
 
-/**
-   \ingroup ServerProtocolSSLAPI
-   * Return true if the SSL error is optional and may not supported
-   * by current squid version
- */
+/// A short description of the TLS error "value"
+const char *GetErrorDescr(Security::ErrorCode value);
 
+/// \return true if the TLS error is optional and may not be supported by current squid version
 bool ErrorIsOptional(const char *name);
 
 /**
-   \ingroup ServerProtocolSSLAPI
  * Used to pass SSL error details to the error pages returned to the
  * end user.
  */
@@ -60,14 +43,14 @@
 {
 public:
     // if broken certificate is nil, the peer certificate is broken
-    ErrorDetail(ssl_error_t err_no, X509 *peer, X509 *broken, const char *aReason = NULL);
+    ErrorDetail(Security::ErrorCode err_no, X509 *peer, X509 *broken, const char *aReason = NULL);
     ErrorDetail(ErrorDetail const &);
     const String &toString() const;  ///< An error detail string to embed in squid error pages
     void useRequest(HttpRequest *aRequest) { if (aRequest != NULL) request = aRequest;}
     /// The error name to embed in squid error pages
     const char *errorName() const {return err_code();}
     /// The error no
-    ssl_error_t errorNo() const {return error_no;}
+    Security::ErrorCode errorNo() const {return error_no;}
     ///Sets the low-level error returned by OpenSSL ERR_get_error()
     void setLibError(unsigned long lib_err_no) {lib_error_no = lib_err_no;}
     /// the peer certificate
@@ -100,7 +83,7 @@
     void buildDetail() const;
 
     mutable String errDetailStr; ///< Caches the error detail message
-    ssl_error_t error_no;   ///< The error code
+    Security::ErrorCode error_no;   ///< The error code
     unsigned long lib_error_no; ///< low-level error returned by OpenSSL ERR_get_error(3SSL)
     Security::CertPointer peer_cert; ///< A pointer to the peer certificate
     Security::CertPointer broken_cert; ///< A pointer to the broken certificate (peer or intermediate)
diff -u -r -N squid-4.0.14/src/ssl/ErrorDetailManager.cc squid-4.0.15/src/ssl/ErrorDetailManager.cc
--- squid-4.0.14/src/ssl/ErrorDetailManager.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/ErrorDetailManager.cc	2016-10-10 08:05:51.000000000 +1300
@@ -43,7 +43,7 @@
 
 /******************/
 bool
-Ssl::ErrorDetailsList::getRecord(Ssl::ssl_error_t value, ErrorDetailEntry &entry)
+Ssl::ErrorDetailsList::getRecord(Security::ErrorCode value, ErrorDetailEntry &entry)
 {
     const ErrorDetails::const_iterator it = theList.find(value);
     if (it != theList.end()) {
@@ -57,7 +57,7 @@
 }
 
 const char *
-Ssl::ErrorDetailsList::getErrorDescr(Ssl::ssl_error_t value)
+Ssl::ErrorDetailsList::getErrorDescr(Security::ErrorCode value)
 {
     const ErrorDetails::const_iterator it = theList.find(value);
     if (it != theList.end()) {
@@ -68,7 +68,7 @@
 }
 
 const char *
-Ssl::ErrorDetailsList::getErrorDetail(Ssl::ssl_error_t value)
+Ssl::ErrorDetailsList::getErrorDetail(Security::ErrorCode value)
 {
     const ErrorDetails::const_iterator it = theList.find(value);
     if (it != theList.end()) {
@@ -123,7 +123,7 @@
 }
 
 bool
-Ssl::ErrorDetailsManager::getErrorDetail(Ssl::ssl_error_t value, const HttpRequest::Pointer &request, ErrorDetailEntry &entry)
+Ssl::ErrorDetailsManager::getErrorDetail(Security::ErrorCode value, const HttpRequest::Pointer &request, ErrorDetailEntry &entry)
 {
 #if USE_ERR_LOCALES
     String hdr;
@@ -164,13 +164,13 @@
 }
 
 const char *
-Ssl::ErrorDetailsManager::getDefaultErrorDescr(Ssl::ssl_error_t value)
+Ssl::ErrorDetailsManager::getDefaultErrorDescr(Security::ErrorCode value)
 {
     return theDefaultErrorDetails->getErrorDescr(value);
 }
 
 const char *
-Ssl::ErrorDetailsManager::getDefaultErrorDetail(Ssl::ssl_error_t value)
+Ssl::ErrorDetailsManager::getDefaultErrorDetail(Security::ErrorCode value)
 {
     return theDefaultErrorDetails->getErrorDetail(value);
 }
@@ -225,7 +225,7 @@
                 return false;
             }
 
-            Ssl::ssl_error_t ssl_error = Ssl::GetErrorCode(errorName.termedBuf());
+            Security::ErrorCode ssl_error = Ssl::GetErrorCode(errorName.termedBuf());
             if (ssl_error != SSL_ERROR_NONE) {
 
                 if (theDetails->getErrorDetail(ssl_error)) {
diff -u -r -N squid-4.0.14/src/ssl/ErrorDetailManager.h squid-4.0.15/src/ssl/ErrorDetailManager.h
--- squid-4.0.14/src/ssl/ErrorDetailManager.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/ErrorDetailManager.h	2016-10-10 08:05:51.000000000 +1300
@@ -25,7 +25,7 @@
 class ErrorDetailEntry
 {
 public:
-    Ssl::ssl_error_t error_no; ///< The SSL error code
+    Security::ErrorCode error_no; ///< The SSL error code
     String name; ///< a name for the error
     String detail; ///< for error page %D macro expansion; may contain macros
     String descr;  ///< short error description (for use in debug messages or error pages)
@@ -43,12 +43,12 @@
      * Retrieves the error details  for a given error to "entry" object
      * \return true on success, false otherwise
      */
-    bool getRecord(Ssl::ssl_error_t value, ErrorDetailEntry &entry);
-    const char *getErrorDescr(Ssl::ssl_error_t value); ///< an error description for an error if exist in list.
-    const char *getErrorDetail(Ssl::ssl_error_t value); ///< an error details for an error if exist in list.
+    bool getRecord(Security::ErrorCode value, ErrorDetailEntry &entry);
+    const char *getErrorDescr(Security::ErrorCode value); ///< an error description for an error if exist in list.
+    const char *getErrorDetail(Security::ErrorCode value); ///< an error details for an error if exist in list.
 
     String errLanguage; ///< The language of the error-details.txt template, if any
-    typedef std::map<Ssl::ssl_error_t, ErrorDetailEntry> ErrorDetails;
+    typedef std::map<Security::ErrorCode, ErrorDetailEntry> ErrorDetails;
     ErrorDetails theList; ///< The list of error details entries
 };
 
@@ -73,9 +73,9 @@
      * \param entry where to store error details
      * \return true on success, false otherwise
      */
-    bool getErrorDetail(Ssl::ssl_error_t value, const HttpRequest::Pointer &request, ErrorDetailEntry &entry);
-    const char *getDefaultErrorDescr(Ssl::ssl_error_t value); ///< the default error description for a given error
-    const char *getDefaultErrorDetail(Ssl::ssl_error_t value); ///< the default error details for a given error
+    bool getErrorDetail(Security::ErrorCode value, const HttpRequest::Pointer &request, ErrorDetailEntry &entry);
+    const char *getDefaultErrorDescr(Security::ErrorCode value); ///< the default error description for a given error
+    const char *getDefaultErrorDetail(Security::ErrorCode value); ///< the default error details for a given error
 
 private:
     /// Return cached error details list for a given language if exist
diff -u -r -N squid-4.0.14/src/ssl/PeekingPeerConnector.cc squid-4.0.15/src/ssl/PeekingPeerConnector.cc
--- squid-4.0.14/src/ssl/PeekingPeerConnector.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/PeekingPeerConnector.cc	2016-10-10 08:05:51.000000000 +1300
@@ -63,8 +63,8 @@
     acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpStare));
     acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpClientFirst));
     acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpServerFirst));
-    Security::SessionPtr ssl = fd_table[serverConn->fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
+    Security::SessionPointer session(fd_table[serverConn->fd].ssl);
+    BIO *b = SSL_get_rbio(session.get());
     Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
     if (!srvBio->canSplice())
         acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpSplice));
@@ -76,8 +76,8 @@
 void
 Ssl::PeekingPeerConnector::checkForPeekAndSpliceMatched(const Ssl::BumpMode action)
 {
-    Security::SessionPtr ssl = fd_table[serverConn->fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
+    Security::SessionPointer session(fd_table[serverConn->fd].ssl);
+    BIO *b = SSL_get_rbio(session.get());
     Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
     debugs(83,5, "Will check for peek and splice on FD " << serverConn->fd);
 
@@ -126,10 +126,9 @@
     return Ssl::bumpSplice;
 }
 
-Security::ContextPtr
-Ssl::PeekingPeerConnector::getSslContext()
+Security::ContextPointer
+Ssl::PeekingPeerConnector::getTlsContext()
 {
-    // XXX: locate a per-server context in Security:: instead
     return ::Config.ssl_client.sslContext;
 }
 
@@ -217,10 +216,8 @@
 void
 Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState *error)
 {
-    Security::SessionPtr ssl = fd_table[serverConnection()->fd].ssl.get();
-
     // Check the list error with
-    if (!request->clientConnectionManager.valid() || ! ssl)
+    if (!request->clientConnectionManager.valid() || !fd_table[serverConnection()->fd].ssl)
         return;
 
     // remember the server certificate from the ErrorDetail object
@@ -263,8 +260,8 @@
 Ssl::PeekingPeerConnector::noteWantWrite()
 {
     const int fd = serverConnection()->fd;
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
+    Security::SessionPointer session(fd_table[fd].ssl);
+    BIO *b = SSL_get_rbio(session.get());
     Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
 
     if ((srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
@@ -280,8 +277,8 @@
 Ssl::PeekingPeerConnector::noteNegotiationError(const int result, const int ssl_error, const int ssl_lib_error)
 {
     const int fd = serverConnection()->fd;
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
+    Security::SessionPointer session(fd_table[fd].ssl);
+    BIO *b = SSL_get_rbio(session.get());
     Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
 
     // In Peek mode, the ClientHello message sent to the server. If the
@@ -307,10 +304,10 @@
     // thus hiding them.
     // Abort if no certificate found probably because of malformed or
     // unsupported server Hello message (TODO: make configurable).
-    if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) &&
+    if (!SSL_get_ex_data(session.get(), ssl_ex_index_ssl_error_detail) &&
             (srvBio->bumpMode() == Ssl::bumpPeek  || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
-        Security::CertPointer serverCert(SSL_get_peer_certificate(ssl));
-        if (serverCert.get()) {
+        Security::CertPointer serverCert(SSL_get_peer_certificate(session.get()));
+        if (serverCert) {
             debugs(81, 3, "Error ("  << ERR_error_string(ssl_lib_error, NULL) <<  ") but, hold write on SSL connection on FD " << fd);
             checkForPeekAndSplice();
             return;
@@ -329,9 +326,9 @@
 
     if (ConnStateData *csd = request->clientConnectionManager.valid()) {
         const int fd = serverConnection()->fd;
-        Security::SessionPtr ssl = fd_table[fd].ssl.get();
-        Security::CertPointer serverCert(SSL_get_peer_certificate(ssl));
-        if (!serverCert.get())
+        Security::SessionPointer session(fd_table[fd].ssl);
+        Security::CertPointer serverCert(SSL_get_peer_certificate(session.get()));
+        if (!serverCert)
             return;
 
         serverCertificateHandled = true;
@@ -352,10 +349,10 @@
             serverCert.resetAndLock(serverBump->serverCert.get());
         else {
             const int fd = serverConnection()->fd;
-            Security::SessionPtr ssl = fd_table[fd].ssl.get();
-            serverCert.resetWithoutLocking(SSL_get_peer_certificate(ssl));
+            Security::SessionPointer session(fd_table[fd].ssl);
+            serverCert.resetWithoutLocking(SSL_get_peer_certificate(session.get()));
         }
-        if (serverCert.get()) {
+        if (serverCert) {
             csd->resetSslCommonName(Ssl::CommonHostName(serverCert.get()));
             debugs(83, 5, "HTTPS server CN: " << csd->sslCommonName() <<
                    " bumped: " << *serverConnection());
diff -u -r -N squid-4.0.14/src/ssl/PeekingPeerConnector.h squid-4.0.15/src/ssl/PeekingPeerConnector.h
--- squid-4.0.14/src/ssl/PeekingPeerConnector.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/PeekingPeerConnector.h	2016-10-10 08:05:51.000000000 +1300
@@ -38,7 +38,7 @@
 
     /* Security::PeerConnector API */
     virtual bool initialize(Security::SessionPointer &);
-    virtual Security::ContextPtr getSslContext();
+    virtual Security::ContextPointer getTlsContext();
     virtual void noteWantWrite();
     virtual void noteNegotiationError(const int result, const int ssl_error, const int ssl_lib_error);
     virtual void noteNegotiationDone(ErrorState *error);
diff -u -r -N squid-4.0.14/src/ssl/ServerBump.cc squid-4.0.15/src/ssl/ServerBump.cc
--- squid-4.0.14/src/ssl/ServerBump.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/ServerBump.cc	2016-10-10 08:05:51.000000000 +1300
@@ -33,8 +33,9 @@
         entry->lock("Ssl::ServerBump");
     } else {
         // XXX: Performance regression. c_str() reallocates
-        SBuf uri(request->effectiveRequestUri());
-        entry = storeCreateEntry(uri.c_str(), uri.c_str(), request->flags, request->method);
+        SBuf uriBuf(request->effectiveRequestUri());
+        const char *uri = uriBuf.c_str();
+        entry = storeCreateEntry(uri, uri, request->flags, request->method);
     }
     // We do not need to be a client because the error contents will be used
     // later, but an entry without any client will trim all its contents away.
@@ -60,13 +61,13 @@
     serverSSL.resetAndLock(ssl);
 }
 
-const Ssl::CertErrors *
+const Security::CertErrors *
 Ssl::ServerBump::sslErrors() const
 {
     if (!serverSSL.get())
         return NULL;
 
-    const Ssl::CertErrors *errs = static_cast<const Ssl::CertErrors*>(SSL_get_ex_data(serverSSL.get(), ssl_ex_index_ssl_errors));
+    const Security::CertErrors *errs = static_cast<const Security::CertErrors*>(SSL_get_ex_data(serverSSL.get(), ssl_ex_index_ssl_errors));
     return errs;
 }
 
diff -u -r -N squid-4.0.14/src/ssl/ServerBump.h squid-4.0.15/src/ssl/ServerBump.h
--- squid-4.0.14/src/ssl/ServerBump.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/ServerBump.h	2016-10-10 08:05:51.000000000 +1300
@@ -33,7 +33,7 @@
     explicit ServerBump(HttpRequest *fakeRequest, StoreEntry *e = NULL, Ssl::BumpMode mode = Ssl::bumpServerFirst);
     ~ServerBump();
     void attachServerSSL(SSL *); ///< Sets the server SSL object
-    const Ssl::CertErrors *sslErrors() const; ///< SSL [certificate validation] errors
+    const Security::CertErrors *sslErrors() const; ///< SSL [certificate validation] errors
 
     /// faked, minimal request; required by Client API
     HttpRequest::Pointer request;
diff -u -r -N squid-4.0.14/src/ssl/support.cc squid-4.0.15/src/ssl/support.cc
--- squid-4.0.14/src/ssl/support.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/support.cc	2016-10-10 08:05:51.000000000 +1300
@@ -22,6 +22,7 @@
 #include "fde.h"
 #include "globals.h"
 #include "ipc/MemMap.h"
+#include "security/CertError.h"
 #include "SquidConfig.h"
 #include "SquidTime.h"
 #include "ssl/bio.h"
@@ -230,19 +231,19 @@
 ssl_verify_cb(int ok, X509_STORE_CTX * ctx)
 {
     // preserve original ctx->error before SSL_ calls can overwrite it
-    Ssl::ssl_error_t error_no = ok ? SSL_ERROR_NONE : ctx->error;
+    Security::ErrorCode error_no = ok ? SSL_ERROR_NONE : ctx->error;
 
     char buffer[256] = "";
     SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
-    Security::ContextPtr sslctx = SSL_get_SSL_CTX(ssl);
+    SSL_CTX *sslctx = SSL_get_SSL_CTX(ssl);
     SBuf *server = (SBuf *)SSL_get_ex_data(ssl, ssl_ex_index_server);
     void *dont_verify_domain = SSL_CTX_get_ex_data(sslctx, ssl_ctx_ex_index_dont_verify_domain);
     ACLChecklist *check = (ACLChecklist*)SSL_get_ex_data(ssl, ssl_ex_index_cert_error_check);
     X509 *peeked_cert = (X509 *)SSL_get_ex_data(ssl, ssl_ex_index_ssl_peeked_cert);
-    X509 *peer_cert = ctx->cert;
+    Security::CertPointer peer_cert;
+    peer_cert.resetAndLock(ctx->cert);
 
-    X509_NAME_oneline(X509_get_subject_name(peer_cert), buffer,
-                      sizeof(buffer));
+    X509_NAME_oneline(X509_get_subject_name(peer_cert.get()), buffer, sizeof(buffer));
 
     // detect infinite loops
     uint32_t *validationCounter = static_cast<uint32_t *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_validation_counter));
@@ -265,8 +266,8 @@
         debugs(83, 5, "SSL Certificate signature OK: " << buffer);
 
         // Check for domain mismatch only if the current certificate is the peer certificate.
-        if (!dont_verify_domain && server && peer_cert == X509_STORE_CTX_get_current_cert(ctx)) {
-            if (!Ssl::checkX509ServerValidity(peer_cert, server->c_str())) {
+        if (!dont_verify_domain && server && peer_cert.get() == X509_STORE_CTX_get_current_cert(ctx)) {
+            if (!Ssl::checkX509ServerValidity(peer_cert.get(), server->c_str())) {
                 debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " << buffer << " does not match domainname " << server);
                 ok = 0;
                 error_no = SQUID_X509_V_ERR_DOMAIN_MISMATCH;
@@ -276,7 +277,7 @@
 
     if (ok && peeked_cert) {
         // Check whether the already peeked certificate matches the new one.
-        if (X509_cmp(peer_cert, peeked_cert) != 0) {
+        if (X509_cmp(peer_cert.get(), peeked_cert) != 0) {
             debugs(83, 2, "SQUID_X509_V_ERR_CERT_CHANGE: Certificate " << buffer << " does not match peeked certificate");
             ok = 0;
             error_no =  SQUID_X509_V_ERR_CERT_CHANGE;
@@ -284,21 +285,22 @@
     }
 
     if (!ok) {
-        X509 *broken_cert =  X509_STORE_CTX_get_current_cert(ctx);
+        Security::CertPointer broken_cert;
+        broken_cert.resetAndLock(X509_STORE_CTX_get_current_cert(ctx));
         if (!broken_cert)
             broken_cert = peer_cert;
 
-        Ssl::CertErrors *errs = static_cast<Ssl::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors));
+        Security::CertErrors *errs = static_cast<Security::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors));
         const int depth = X509_STORE_CTX_get_error_depth(ctx);
         if (!errs) {
-            errs = new Ssl::CertErrors(Ssl::CertError(error_no, broken_cert, depth));
+            errs = new Security::CertErrors(Security::CertError(error_no, broken_cert, depth));
             if (!SSL_set_ex_data(ssl, ssl_ex_index_ssl_errors,  (void *)errs)) {
                 debugs(83, 2, "Failed to set ssl error_no in ssl_verify_cb: Certificate " << buffer);
                 delete errs;
                 errs = NULL;
             }
         } else // remember another error number
-            errs->push_back_unique(Ssl::CertError(error_no, broken_cert, depth));
+            errs->push_back_unique(Security::CertError(error_no, broken_cert, depth));
 
         if (const char *err_descr = Ssl::GetErrorDescr(error_no))
             debugs(83, 5, err_descr << ": " << buffer);
@@ -311,8 +313,8 @@
             if (check) {
                 ACLFilledChecklist *filledCheck = Filled(check);
                 assert(!filledCheck->sslErrors);
-                filledCheck->sslErrors = new Ssl::CertErrors(Ssl::CertError(error_no, broken_cert));
-                filledCheck->serverCert.resetAndLock(peer_cert);
+                filledCheck->sslErrors = new Security::CertErrors(Security::CertError(error_no, broken_cert));
+                filledCheck->serverCert = peer_cert;
                 if (check->fastCheck() == ACCESS_ALLOWED) {
                     debugs(83, 3, "bypassing SSL error " << error_no << " in " << buffer);
                     ok = 1;
@@ -343,17 +345,15 @@
     if (!ok && !SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) ) {
 
         // Find the broken certificate. It may be intermediate.
-        X509 *broken_cert = peer_cert; // reasonable default if search fails
+        Security::CertPointer broken_cert(peer_cert); // reasonable default if search fails
         // Our SQUID_X509_V_ERR_DOMAIN_MISMATCH implies peer_cert is at fault.
         if (error_no != SQUID_X509_V_ERR_DOMAIN_MISMATCH) {
-            if (X509 *last_used_cert = X509_STORE_CTX_get_current_cert(ctx))
-                broken_cert = last_used_cert;
+            if (auto *last_used_cert = X509_STORE_CTX_get_current_cert(ctx))
+                broken_cert.resetAndLock(last_used_cert);
         }
 
-        Ssl::ErrorDetail *errDetail =
-            new Ssl::ErrorDetail(error_no, peer_cert, broken_cert);
-
-        if (!SSL_set_ex_data(ssl, ssl_ex_index_ssl_error_detail,  errDetail)) {
+        auto *errDetail = new Ssl::ErrorDetail(error_no, peer_cert.get(), broken_cert.get());
+        if (!SSL_set_ex_data(ssl, ssl_ex_index_ssl_error_detail, errDetail)) {
             debugs(83, 2, "Failed to set Ssl::ErrorDetail in ssl_verify_cb: Certificate " << buffer);
             delete errDetail;
         }
@@ -394,7 +394,7 @@
 ssl_free_SslErrors(void *, void *ptr, CRYPTO_EX_DATA *,
                    int, long, void *)
 {
-    Ssl::CertErrors *errs = static_cast <Ssl::CertErrors*>(ptr);
+    Security::CertErrors *errs = static_cast <Security::CertErrors*>(ptr);
     delete errs;
 }
 
@@ -492,32 +492,32 @@
 #endif
 
 static bool
-configureSslContext(Security::ContextPtr sslContext, AnyP::PortCfg &port)
+configureSslContext(Security::ContextPointer &ctx, AnyP::PortCfg &port)
 {
     int ssl_error;
-    SSL_CTX_set_options(sslContext, port.secure.parsedOptions);
+    SSL_CTX_set_options(ctx.get(), port.secure.parsedOptions);
 
 #if defined(SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
-    SSL_CTX_set_info_callback(sslContext, ssl_info_cb);
+    SSL_CTX_set_info_callback(ctx.get(), ssl_info_cb);
 #endif
 
     if (port.sslContextSessionId)
-        SSL_CTX_set_session_id_context(sslContext, (const unsigned char *)port.sslContextSessionId, strlen(port.sslContextSessionId));
+        SSL_CTX_set_session_id_context(ctx.get(), (const unsigned char *)port.sslContextSessionId, strlen(port.sslContextSessionId));
 
     if (port.secure.parsedFlags & SSL_FLAG_NO_SESSION_REUSE) {
-        SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
+        SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_OFF);
     }
 
     if (Config.SSL.unclean_shutdown) {
         debugs(83, 5, "Enabling quiet SSL shutdowns (RFC violation).");
 
-        SSL_CTX_set_quiet_shutdown(sslContext, 1);
+        SSL_CTX_set_quiet_shutdown(ctx.get(), 1);
     }
 
     if (!port.secure.sslCipher.isEmpty()) {
         debugs(83, 5, "Using chiper suite " << port.secure.sslCipher << ".");
 
-        if (!SSL_CTX_set_cipher_list(sslContext, port.secure.sslCipher.c_str())) {
+        if (!SSL_CTX_set_cipher_list(ctx.get(), port.secure.sslCipher.c_str())) {
             ssl_error = ERR_get_error();
             debugs(83, DBG_CRITICAL, "ERROR: Failed to set SSL cipher suite '" << port.secure.sslCipher << "': " << ERR_error_string(ssl_error, NULL));
             return false;
@@ -525,15 +525,15 @@
     }
 
     debugs(83, 9, "Setting RSA key generation callback.");
-    SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
+    SSL_CTX_set_tmp_rsa_callback(ctx.get(), ssl_temp_rsa_cb);
 
-    port.secure.updateContextEecdh(sslContext);
-    port.secure.updateContextCa(sslContext);
+    port.secure.updateContextEecdh(ctx);
+    port.secure.updateContextCa(ctx);
 
     if (port.clientCA.get()) {
         ERR_clear_error();
         if (STACK_OF(X509_NAME) *clientca = SSL_dup_CA_list(port.clientCA.get())) {
-            SSL_CTX_set_client_CA_list(sslContext, clientca);
+            SSL_CTX_set_client_CA_list(ctx.get(), clientca);
         } else {
             ssl_error = ERR_get_error();
             debugs(83, DBG_CRITICAL, "ERROR: Failed to dupe the client CA list: " << ERR_error_string(ssl_error, NULL));
@@ -542,29 +542,29 @@
 
         if (port.secure.parsedFlags & SSL_FLAG_DELAYED_AUTH) {
             debugs(83, 9, "Not requesting client certificates until acl processing requires one");
-            SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
+            SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_NONE, NULL);
         } else {
             debugs(83, 9, "Requiring client certificates.");
-            SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
+            SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
         }
 
-        port.secure.updateContextCrl(sslContext);
+        port.secure.updateContextCrl(ctx);
 
     } else {
         debugs(83, 9, "Not requiring any client certificates");
-        SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
+        SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_NONE, NULL);
     }
 
     if (port.secure.parsedFlags & SSL_FLAG_DONT_VERIFY_DOMAIN)
-        SSL_CTX_set_ex_data(sslContext, ssl_ctx_ex_index_dont_verify_domain, (void *) -1);
+        SSL_CTX_set_ex_data(ctx.get(), ssl_ctx_ex_index_dont_verify_domain, (void *) -1);
 
-    Ssl::SetSessionCallbacks(sslContext);
+    Ssl::SetSessionCallbacks(ctx);
 
     return true;
 }
 
 bool
-Ssl::InitServerContext(const Security::ContextPointer &ctx, AnyP::PortCfg &port)
+Ssl::InitServerContext(Security::ContextPointer &ctx, AnyP::PortCfg &port)
 {
     if (!ctx)
         return false;
@@ -583,7 +583,7 @@
         return false;
     }
 
-    Ssl::addChainToSslContext(ctx.get(), port.certsToChain.get());
+    Ssl::addChainToSslContext(ctx, port.certsToChain.get());
 
     /* Alternate code;
         debugs(83, DBG_IMPORTANT, "Using certificate in " << certfile);
@@ -613,7 +613,7 @@
         }
     */
 
-    if (!configureSslContext(ctx.get(), port)) {
+    if (!configureSslContext(ctx, port)) {
         debugs(83, DBG_CRITICAL, "ERROR: Configuring static SSL context");
         return false;
     }
@@ -622,22 +622,22 @@
 }
 
 bool
-Ssl::InitClientContext(Security::ContextPtr &sslContext, Security::PeerOptions &peer, long options, long fl)
+Ssl::InitClientContext(Security::ContextPointer &ctx, Security::PeerOptions &peer, long options, long fl)
 {
-    if (!sslContext)
+    if (!ctx)
         return false;
 
-    SSL_CTX_set_options(sslContext, options);
+    SSL_CTX_set_options(ctx.get(), options);
 
 #if defined(SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
-    SSL_CTX_set_info_callback(sslContext, ssl_info_cb);
+    SSL_CTX_set_info_callback(ctx.get(), ssl_info_cb);
 #endif
 
     if (!peer.sslCipher.isEmpty()) {
         debugs(83, 5, "Using chiper suite " << peer.sslCipher << ".");
 
         const char *cipher = peer.sslCipher.c_str();
-        if (!SSL_CTX_set_cipher_list(sslContext, cipher)) {
+        if (!SSL_CTX_set_cipher_list(ctx.get(), cipher)) {
             const int ssl_error = ERR_get_error();
             fatalf("Failed to set SSL cipher suite '%s': %s\n",
                    cipher, ERR_error_string(ssl_error, NULL));
@@ -651,7 +651,7 @@
             debugs(83, DBG_IMPORTANT, "Using certificate in " << keys.certFile);
 
             const char *certfile = keys.certFile.c_str();
-            if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) {
+            if (!SSL_CTX_use_certificate_chain_file(ctx.get(), certfile)) {
                 const int ssl_error = ERR_get_error();
                 fatalf("Failed to acquire SSL certificate '%s': %s\n",
                        certfile, ERR_error_string(ssl_error, NULL));
@@ -659,9 +659,9 @@
 
             debugs(83, DBG_IMPORTANT, "Using private key in " << keys.privateKeyFile);
             const char *keyfile = keys.privateKeyFile.c_str();
-            ssl_ask_password(sslContext, keyfile);
+            ssl_ask_password(ctx.get(), keyfile);
 
-            if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) {
+            if (!SSL_CTX_use_PrivateKey_file(ctx.get(), keyfile, SSL_FILETYPE_PEM)) {
                 const int ssl_error = ERR_get_error();
                 fatalf("Failed to acquire SSL private key '%s': %s\n",
                        keyfile, ERR_error_string(ssl_error, NULL));
@@ -669,7 +669,7 @@
 
             debugs(83, 5, "Comparing private and public SSL keys.");
 
-            if (!SSL_CTX_check_private_key(sslContext)) {
+            if (!SSL_CTX_check_private_key(ctx.get())) {
                 const int ssl_error = ERR_get_error();
                 fatalf("SSL private key '%s' does not match public key '%s': %s\n",
                        certfile, keyfile, ERR_error_string(ssl_error, NULL));
@@ -678,14 +678,14 @@
     }
 
     debugs(83, 9, "Setting RSA key generation callback.");
-    SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
+    SSL_CTX_set_tmp_rsa_callback(ctx.get(), ssl_temp_rsa_cb);
 
     if (fl & SSL_FLAG_DONT_VERIFY_PEER) {
         debugs(83, 2, "NOTICE: Peer certificates are not verified for validity!");
-        SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
+        SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_NONE, NULL);
     } else {
         debugs(83, 9, "Setting certificate verification callback.");
-        SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
+        SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
     }
 
     return true;
@@ -707,6 +707,9 @@
 #endif
 
     int i = SSL_read(ssl, buf, len);
+    if (i > 0) {
+        (void)VALGRIND_MAKE_MEM_DEFINED(buf, i);
+    }
 
     if (i > 0 && SSL_pending(ssl) > 0) {
         debugs(83, 2, "SSL FD " << fd << " is pending");
@@ -925,71 +928,66 @@
 }
 
 /// Create SSL context and apply ssl certificate and private key to it.
-Security::ContextPtr
+Security::ContextPointer
 Ssl::createSSLContext(Security::CertPointer & x509, Ssl::EVP_PKEY_Pointer & pkey, AnyP::PortCfg &port)
 {
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
-    Security::ContextPointer sslContext(SSL_CTX_new(TLS_server_method()));
-#else
-    Security::ContextPointer sslContext(SSL_CTX_new(SSLv23_server_method()));
-#endif
+    Security::ContextPointer ctx(port.secure.createBlankContext());
 
-    if (!SSL_CTX_use_certificate(sslContext.get(), x509.get()))
-        return NULL;
+    if (!SSL_CTX_use_certificate(ctx.get(), x509.get()))
+        return Security::ContextPointer();
 
-    if (!SSL_CTX_use_PrivateKey(sslContext.get(), pkey.get()))
-        return NULL;
+    if (!SSL_CTX_use_PrivateKey(ctx.get(), pkey.get()))
+        return Security::ContextPointer();
 
-    if (!configureSslContext(sslContext.get(), port))
-        return NULL;
+    if (!configureSslContext(ctx, port))
+        return Security::ContextPointer();
 
-    return sslContext.release();
+    return ctx;
 }
 
-Security::ContextPtr
+Security::ContextPointer
 Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port)
 {
     Security::CertPointer cert;
     Ssl::EVP_PKEY_Pointer pkey;
     if (!readCertAndPrivateKeyFromMemory(cert, pkey, data) || !cert || !pkey)
-        return nullptr;
+        return Security::ContextPointer();
 
     return createSSLContext(cert, pkey, port);
 }
 
-Security::ContextPtr
+Security::ContextPointer
 Ssl::generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port)
 {
     Security::CertPointer cert;
     Ssl::EVP_PKEY_Pointer pkey;
     if (!generateSslCertificate(cert, pkey, properties) || !cert || !pkey)
-        return nullptr;
+        return Security::ContextPointer();
 
     return createSSLContext(cert, pkey, port);
 }
 
 void
-Ssl::chainCertificatesToSSLContext(SSL_CTX *sslContext, AnyP::PortCfg &port)
+Ssl::chainCertificatesToSSLContext(Security::ContextPointer &ctx, AnyP::PortCfg &port)
 {
-    assert(sslContext != NULL);
+    assert(ctx);
     // Add signing certificate to the certificates chain
     X509 *signingCert = port.signingCert.get();
-    if (SSL_CTX_add_extra_chain_cert(sslContext, signingCert)) {
+    if (SSL_CTX_add_extra_chain_cert(ctx.get(), signingCert)) {
         // increase the certificate lock
         CRYPTO_add(&(signingCert->references),1,CRYPTO_LOCK_X509);
     } else {
         const int ssl_error = ERR_get_error();
         debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain: " << ERR_error_string(ssl_error, NULL));
     }
-    Ssl::addChainToSslContext(sslContext, port.certsToChain.get());
+    Ssl::addChainToSslContext(ctx, port.certsToChain.get());
 }
 
 void
-Ssl::configureUnconfiguredSslContext(SSL_CTX *sslContext, Ssl::CertSignAlgorithm signAlgorithm,AnyP::PortCfg &port)
+Ssl::configureUnconfiguredSslContext(Security::ContextPointer &ctx, Ssl::CertSignAlgorithm signAlgorithm,AnyP::PortCfg &port)
 {
-    if (sslContext && signAlgorithm == Ssl::algSignTrusted) {
-        Ssl::chainCertificatesToSSLContext(sslContext, port);
-    }
+    if (ctx && signAlgorithm == Ssl::algSignTrusted)
+        Ssl::chainCertificatesToSSLContext(ctx, port);
 }
 
 bool
@@ -1035,19 +1033,20 @@
     return true;
 }
 
-bool Ssl::verifySslCertificate(Security::ContextPtr sslContext, CertificateProperties const &properties)
+bool
+Ssl::verifySslCertificate(Security::ContextPointer &ctx, CertificateProperties const &properties)
 {
     // SSL_get_certificate is buggy in openssl versions 1.0.1d and 1.0.1e
-    // Try to retrieve certificate directly from Security::ContextPtr object
+    // Try to retrieve certificate directly from Security::ContextPointer object
 #if SQUID_USE_SSLGETCERTIFICATE_HACK
-    X509 ***pCert = (X509 ***)sslContext->cert;
+    X509 ***pCert = (X509 ***)ctx->cert;
     X509 * cert = pCert && *pCert ? **pCert : NULL;
 #elif SQUID_SSLGETCERTIFICATE_BUGGY
     X509 * cert = NULL;
     assert(0);
 #else
     // Temporary ssl for getting X509 certificate from SSL_CTX.
-    Security::SessionPointer ssl(SSL_new(sslContext));
+    Security::SessionPointer ssl(SSL_new(ctx.get()));
     X509 * cert = SSL_get_certificate(ssl.get());
 #endif
     if (!cert)
@@ -1080,14 +1079,15 @@
 #endif
 }
 
-void Ssl::addChainToSslContext(Security::ContextPtr sslContext, STACK_OF(X509) *chain)
+void
+Ssl::addChainToSslContext(Security::ContextPointer &ctx, STACK_OF(X509) *chain)
 {
     if (!chain)
         return;
 
     for (int i = 0; i < sk_X509_num(chain); ++i) {
         X509 *cert = sk_X509_value(chain, i);
-        if (SSL_CTX_add_extra_chain_cert(sslContext, cert)) {
+        if (SSL_CTX_add_extra_chain_cert(ctx.get(), cert)) {
             // increase the certificate lock
             CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509);
         } else {
@@ -1402,7 +1402,7 @@
 }
 
 static bool
-SslCreate(Security::ContextPtr sslContext, const Comm::ConnectionPointer &conn, Ssl::Bio::Type type, const char *squidCtx)
+SslCreate(const Security::ContextPointer &ctx, const Comm::ConnectionPointer &conn, Ssl::Bio::Type type, const char *squidCtx)
 {
     if (!Comm::IsConnOpen(conn)) {
         debugs(83, DBG_IMPORTANT, "Gone connection");
@@ -1411,7 +1411,7 @@
 
     const char *errAction = NULL;
     int errCode = 0;
-    if (auto ssl = SSL_new(sslContext)) {
+    if (auto ssl = SSL_new(ctx.get())) {
         const int fd = conn->fd;
         // without BIO, we would call SSL_set_fd(ssl, fd) instead
         if (BIO *bio = Ssl::Bio::Create(fd, type)) {
@@ -1437,46 +1437,15 @@
 }
 
 bool
-Ssl::CreateClient(Security::ContextPtr sslContext, const Comm::ConnectionPointer &c, const char *squidCtx)
-{
-    return SslCreate(sslContext, c, Ssl::Bio::BIO_TO_SERVER, squidCtx);
-}
-
-bool
-Ssl::CreateServer(Security::ContextPtr sslContext, const Comm::ConnectionPointer &c, const char *squidCtx)
-{
-    return SslCreate(sslContext, c, Ssl::Bio::BIO_TO_CLIENT, squidCtx);
-}
-
-Ssl::CertError::CertError(ssl_error_t anErr, X509 *aCert, int aDepth): code(anErr), depth(aDepth)
-{
-    cert.resetAndLock(aCert);
-}
-
-Ssl::CertError::CertError(CertError const &err): code(err.code), depth(err.depth)
-{
-    cert.resetAndLock(err.cert.get());
-}
-
-Ssl::CertError &
-Ssl::CertError::operator = (const CertError &old)
-{
-    code = old.code;
-    depth = old.depth;
-    cert.resetAndLock(old.cert.get());
-    return *this;
-}
-
-bool
-Ssl::CertError::operator == (const CertError &ce) const
+Ssl::CreateClient(const Security::ContextPointer &ctx, const Comm::ConnectionPointer &c, const char *squidCtx)
 {
-    return code == ce.code && cert.get() == ce.cert.get() && depth == ce.depth;
+    return SslCreate(ctx, c, Ssl::Bio::BIO_TO_SERVER, squidCtx);
 }
 
 bool
-Ssl::CertError::operator != (const CertError &ce) const
+Ssl::CreateServer(const Security::ContextPointer &ctx, const Comm::ConnectionPointer &c, const char *squidCtx)
 {
-    return code != ce.code || cert.get() != ce.cert.get() || depth != ce.depth;
+    return SslCreate(ctx, c, Ssl::Bio::BIO_TO_CLIENT, squidCtx);
 }
 
 static int
@@ -1568,13 +1537,13 @@
 }
 
 void
-Ssl::SetSessionCallbacks(Security::ContextPtr ctx)
+Ssl::SetSessionCallbacks(Security::ContextPointer &ctx)
 {
     if (Ssl::SessionCache) {
-        SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL);
-        SSL_CTX_sess_set_new_cb(ctx, store_session_cb);
-        SSL_CTX_sess_set_remove_cb(ctx, remove_session_cb);
-        SSL_CTX_sess_set_get_cb(ctx, get_session_cb);
+        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);
     }
 }
 
diff -u -r -N squid-4.0.14/src/ssl/support.h squid-4.0.15/src/ssl/support.h
--- squid-4.0.14/src/ssl/support.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/ssl/support.h	2016-10-10 08:05:51.000000000 +1300
@@ -69,55 +69,27 @@
 /// call before generating any SSL context
 void Initialize();
 
-/// Squid defined error code (<0),  an error code returned by SSL X509 api, or SSL_ERROR_NONE
-typedef int ssl_error_t;
-
-typedef CbDataList<Ssl::ssl_error_t> Errors;
-
 class ErrorDetail;
 class CertValidationResponse;
 typedef RefCount<CertValidationResponse> CertValidationResponsePointer;
 
 /// Creates SSL Client connection structure and initializes SSL I/O (Comm and BIO).
 /// On errors, emits DBG_IMPORTANT with details and returns false.
-bool CreateClient(Security::ContextPtr sslContext, const Comm::ConnectionPointer &, const char *squidCtx);
+bool CreateClient(const Security::ContextPointer &, const Comm::ConnectionPointer &, const char *squidCtx);
 
 /// Creates SSL Server connection structure and initializes SSL I/O (Comm and BIO).
 /// On errors, emits DBG_IMPORTANT with details and returns false.
-bool CreateServer(Security::ContextPtr sslContext, const Comm::ConnectionPointer &, const char *squidCtx);
-
-/// An SSL certificate-related error.
-/// Pairs an error code with the certificate experiencing the error.
-class CertError
-{
-public:
-    ssl_error_t code; ///< certificate error code
-    Security::CertPointer cert; ///< certificate with the above error code
-    /**
-     * Absolute cert position in the final certificate chain that may include
-     * intermediate certificates. Chain positions start with zero and increase
-     * towards the root certificate. Negative if unknown.
-     */
-    int depth;
-    CertError(ssl_error_t anErr, X509 *aCert, int depth = -1);
-    CertError(CertError const &err);
-    CertError & operator = (const CertError &old);
-    bool operator == (const CertError &ce) const;
-    bool operator != (const CertError &ce) const;
-};
-
-/// Holds a list of certificate SSL errors
-typedef CbDataList<Ssl::CertError> CertErrors;
+bool CreateServer(const Security::ContextPointer &, const Comm::ConnectionPointer &, const char *squidCtx);
 
-void SetSessionCallbacks(Security::ContextPtr);
+void SetSessionCallbacks(Security::ContextPointer &);
 extern Ipc::MemMap *SessionCache;
 extern const char *SessionCacheName;
 
 /// initialize a TLS server context with OpenSSL specific settings
-bool InitServerContext(const Security::ContextPointer &, AnyP::PortCfg &);
+bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &);
 
 /// initialize a TLS client context with OpenSSL specific settings
-bool InitClientContext(Security::ContextPtr &, Security::PeerOptions &, long options, long flags);
+bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, long options, long flags);
 
 } //namespace Ssl
 
@@ -257,7 +229,7 @@
   \ingroup ServerProtocolSSLAPI
   * Decide on the kind of certificate and generate a CA- or self-signed one
 */
-Security::ContextPtr generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port);
+Security::ContextPointer generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port);
 
 /**
   \ingroup ServerProtocolSSLAPI
@@ -266,32 +238,32 @@
   \param properties Check if the context certificate matches the given properties
   \return true if the contexts certificate is valid, false otherwise
  */
-bool verifySslCertificate(Security::ContextPtr sslContext,  CertificateProperties const &properties);
+bool verifySslCertificate(Security::ContextPointer &, CertificateProperties const &);
 
 /**
   \ingroup ServerProtocolSSLAPI
   * Read private key and certificate from memory and generate SSL context
   * using their.
  */
-Security::ContextPtr generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port);
+Security::ContextPointer generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port);
 
 /**
   \ingroup ServerProtocolSSLAPI
   * Create an SSL context using the provided certificate and key
  */
-Security::ContextPtr createSSLContext(Security::CertPointer & x509, Ssl::EVP_PKEY_Pointer & pkey, AnyP::PortCfg &port);
+Security::ContextPointer createSSLContext(Security::CertPointer & x509, Ssl::EVP_PKEY_Pointer & pkey, AnyP::PortCfg &port);
 
 /**
  \ingroup ServerProtocolSSLAPI
  * Chain signing certificate and chained certificates to an SSL Context
  */
-void chainCertificatesToSSLContext(SSL_CTX *sslContext, AnyP::PortCfg &port);
+void chainCertificatesToSSLContext(Security::ContextPointer &, AnyP::PortCfg &);
 
 /**
  \ingroup ServerProtocolSSLAPI
  * Configure a previously unconfigured SSL context object.
  */
-void configureUnconfiguredSslContext(SSL_CTX *sslContext, Ssl::CertSignAlgorithm signAlgorithm,AnyP::PortCfg &port);
+void configureUnconfiguredSslContext(Security::ContextPointer &, Ssl::CertSignAlgorithm signAlgorithm, AnyP::PortCfg &);
 
 /**
   \ingroup ServerProtocolSSLAPI
@@ -311,7 +283,7 @@
   \ingroup ServerProtocolSSLAPI
   * Adds the certificates in certList to the certificate chain of the SSL context
  */
-void addChainToSslContext(Security::ContextPtr sslContext, STACK_OF(X509) *certList);
+void addChainToSslContext(Security::ContextPointer &, STACK_OF(X509) *certList);
 
 /**
   \ingroup ServerProtocolSSLAPI
diff -u -r -N squid-4.0.14/src/stat.cc squid-4.0.15/src/stat.cc
--- squid-4.0.14/src/stat.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/stat.cc	2016-10-10 08:05:51.000000000 +1300
@@ -79,7 +79,6 @@
 
 /* LOCALS */
 static const char *describeStatuses(const StoreEntry *);
-static const char *describeTimestamps(const StoreEntry *);
 static void statAvgTick(void *notused);
 static void statAvgDump(StoreEntry *, int minutes, int hours);
 #if STAT_GRAPHS
@@ -330,18 +329,6 @@
     return buf;
 }
 
-static const char *
-describeTimestamps(const StoreEntry * entry)
-{
-    LOCAL_ARRAY(char, buf, 256);
-    snprintf(buf, 256, "LV:%-9d LU:%-9d LM:%-9d EX:%-9d",
-             (int) entry->timestamp,
-             (int) entry->lastref,
-             (int) entry->lastmod,
-             (int) entry->expires);
-    return buf;
-}
-
 static void
 statStoreEntry(MemBuf * mb, StoreEntry * e)
 {
@@ -349,7 +336,7 @@
     mb->appendf("KEY %s\n", e->getMD5Text());
     mb->appendf("\t%s\n", describeStatuses(e));
     mb->appendf("\t%s\n", storeEntryFlags(e));
-    mb->appendf("\t%s\n", describeTimestamps(e));
+    mb->appendf("\t%s\n", e->describeTimestamps());
     mb->appendf("\t%d locks, %d clients, %d refs\n", (int) e->locks(), storePendingNClients(e), (int) e->refcount);
     mb->appendf("\tSwap Dir %d, File %#08X\n", e->swap_dirn, e->swap_filen);
 
diff -u -r -N squid-4.0.14/src/store/Disks.cc squid-4.0.15/src/store/Disks.cc
--- squid-4.0.14/src/store/Disks.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/store/Disks.cc	2016-10-10 08:05:51.000000000 +1300
@@ -582,7 +582,7 @@
 
     // Check for store_dirs_rebuilding because fatal() often calls us in early
     // initialization phases, before store log is initialized and ready. Also,
-    // some stores probably do not support log cleanup during Store rebuilding.
+    // some stores do not support log cleanup during Store rebuilding.
     if (StoreController::store_dirs_rebuilding) {
         debugs(20, DBG_IMPORTANT, "Not currently OK to rewrite swap log.");
         debugs(20, DBG_IMPORTANT, "storeDirWriteCleanLogs: Operation aborted.");
diff -u -r -N squid-4.0.14/src/store/id_rewriters/file/storeid_file_rewrite.8 squid-4.0.15/src/store/id_rewriters/file/storeid_file_rewrite.8
--- squid-4.0.14/src/store/id_rewriters/file/storeid_file_rewrite.8	2016-09-09 03:31:21.000000000 +1200
+++ squid-4.0.15/src/store/id_rewriters/file/storeid_file_rewrite.8	2016-10-10 11:56:34.000000000 +1300
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -46,7 +46,7 @@
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" If the F register is >0, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.nr rF 0
-.if \n(.g .if rF .nr rF 1
-.if (\n(rF:(\n(.g==0)) \{
-.    if \nF \{
-.        de IX
-.        tm Index:\\$1\t\\n%\t"\\$2"
+.if !\nF .nr F 0
+.if \nF>0 \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.        if !\nF==2 \{
-.            nr % 0
-.            nr F 2
-.        \}
+.    if !\nF==2 \{\
+.        nr % 0
+.        nr F 2
 .    \}
 .\}
-.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -133,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "STOREID_FILE_REWRITE 8"
-.TH STOREID_FILE_REWRITE 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH STOREID_FILE_REWRITE 8 "2016-10-09" "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
@@ -213,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 \\fIs0\fR\|(7),
+squid (8), \s-1GPL\s0 (7),
 .PP
 The Squid wiki http://wiki.squid\-cache.org/Features/StoreID
 .PP
diff -u -r -N squid-4.0.14/src/store.cc squid-4.0.15/src/store.cc
--- squid-4.0.14/src/store.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/store.cc	2016-10-10 08:05:51.000000000 +1300
@@ -331,7 +331,7 @@
     timestamp(-1),
     lastref(-1),
     expires(-1),
-    lastmod(-1),
+    lastModified_(-1),
     swap_file_sz(0),
     refcount(0),
     flags(0),
@@ -1564,12 +1564,17 @@
     else
         exp = reply->expires;
 
-    if (lastmod == reply->last_modified && timestamp == served_date && expires == exp)
-        return false;
+    if (timestamp == served_date && expires == exp) {
+        // if the reply lacks LMT, then we now know that our effective
+        // LMT (i.e., timestamp) will stay the same, otherwise, old and
+        // new modification times must match
+        if (reply->last_modified < 0 || reply->last_modified == lastModified())
+            return false; // nothing has changed
+    }
 
     expires = exp;
 
-    lastmod = reply->last_modified;
+    lastModified_ = reply->last_modified;
 
     timestamp = served_date;
 
@@ -1604,7 +1609,7 @@
     debugs(20, l, "StoreEntry->timestamp: " << timestamp);
     debugs(20, l, "StoreEntry->lastref: " << lastref);
     debugs(20, l, "StoreEntry->expires: " << expires);
-    debugs(20, l, "StoreEntry->lastmod: " << lastmod);
+    debugs(20, l, "StoreEntry->lastModified_: " << lastModified_);
     debugs(20, l, "StoreEntry->swap_file_sz: " << swap_file_sz);
     debugs(20, l, "StoreEntry->refcount: " << refcount);
     debugs(20, l, "StoreEntry->flags: " << storeEntryFlags(this));
@@ -1742,7 +1747,7 @@
     mem_obj->reset();
     HttpReply *rep = (HttpReply *) getReply();       // bypass const
     rep->reset();
-    expires = lastmod = timestamp = -1;
+    expires = lastModified_ = timestamp = -1;
 }
 
 /*
@@ -1949,13 +1954,10 @@
 }
 
 bool
-StoreEntry::modifiedSince(HttpRequest * request) const
+StoreEntry::modifiedSince(const time_t ims, const int imslen) const
 {
     int object_length;
-    time_t mod_time = lastmod;
-
-    if (mod_time < 0)
-        mod_time = timestamp;
+    const time_t mod_time = lastModified();
 
     debugs(88, 3, "modifiedSince: '" << url() << "'");
 
@@ -1970,16 +1972,16 @@
     if (object_length < 0)
         object_length = contentLen();
 
-    if (mod_time > request->ims) {
+    if (mod_time > ims) {
         debugs(88, 3, "--> YES: entry newer than client");
         return true;
-    } else if (mod_time < request->ims) {
+    } else if (mod_time < ims) {
         debugs(88, 3, "-->  NO: entry older than client");
         return false;
-    } else if (request->imslen < 0) {
+    } else if (imslen < 0) {
         debugs(88, 3, "-->  NO: same LMT, no client length");
         return false;
-    } else if (request->imslen == object_length) {
+    } else if (imslen == object_length) {
         debugs(88, 3, "-->  NO: same LMT, same length");
         return false;
     } else {
@@ -2069,6 +2071,18 @@
     return true;
 }
 
+const char *
+StoreEntry::describeTimestamps() const
+{
+    LOCAL_ARRAY(char, buf, 256);
+    snprintf(buf, 256, "LV:%-9d LU:%-9d LM:%-9d EX:%-9d",
+             static_cast<int>(timestamp),
+             static_cast<int>(lastref),
+             static_cast<int>(lastModified_),
+             static_cast<int>(expires));
+    return buf;
+}
+
 std::ostream &operator <<(std::ostream &os, const StoreEntry &e)
 {
     os << "e:";
diff -u -r -N squid-4.0.14/src/Store.h squid-4.0.15/src/Store.h
--- squid-4.0.14/src/Store.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/Store.h	2016-10-10 08:05:51.000000000 +1300
@@ -131,7 +131,16 @@
     void delayAwareRead(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer callback);
 
     void setNoDelay (bool const);
-    bool modifiedSince(HttpRequest * request) const;
+    void lastModified(const time_t when) { lastModified_ = when; }
+    /// \returns entry's 'effective' modification time
+    time_t lastModified() const {
+        // may still return -1 if timestamp is not set
+        return lastModified_ < 0 ? timestamp : lastModified_;
+    }
+    /// \returns a formatted string with entry's timestamps
+    const char *describeTimestamps() const;
+    // TODO: consider removing currently unsupported imslen parameter
+    bool modifiedSince(const time_t ims, const int imslen = -1) const;
     /// has ETag matching at least one of the If-Match etags
     bool hasIfMatchEtag(const HttpRequest &request) const;
     /// has ETag matching at least one of the If-None-Match etags
@@ -148,7 +157,9 @@
     time_t timestamp;
     time_t lastref;
     time_t expires;
-    time_t lastmod;
+private:
+    time_t lastModified_; ///< received Last-Modified value or -1; use lastModified()
+public:
     uint64_t swap_file_sz;
     uint16_t refcount;
     uint16_t flags;
diff -u -r -N squid-4.0.14/src/store_rebuild.cc squid-4.0.15/src/store_rebuild.cc
--- squid-4.0.14/src/store_rebuild.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/store_rebuild.cc	2016-10-10 08:05:51.000000000 +1300
@@ -256,7 +256,7 @@
             what->timestamp = tmp->timestamp;
             what->lastref = tmp->lastref;
             what->expires = tmp->expires;
-            what->lastmod = tmp->lastmod;
+            what->lastModified(tmp->lastmod);
             what->swap_file_sz = tmp->swap_file_sz;
             what->refcount = tmp->refcount;
             what->flags = tmp->flags;
diff -u -r -N squid-4.0.14/src/tests/stub_client_side.cc squid-4.0.15/src/tests/stub_client_side.cc
--- squid-4.0.14/src/tests/stub_client_side.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/tests/stub_client_side.cc	2016-10-10 08:05:51.000000000 +1300
@@ -42,7 +42,7 @@
 #if USE_OPENSSL
 void ConnStateData::httpsPeeked(Comm::ConnectionPointer) STUB
 void ConnStateData::getSslContextStart() STUB
-void ConnStateData::getSslContextDone(Security::ContextPtr, bool) STUB
+void ConnStateData::getSslContextDone(Security::ContextPointer &, bool) STUB
 void ConnStateData::sslCrtdHandleReplyWrapper(void *, const Helper::Reply &) STUB
 void ConnStateData::sslCrtdHandleReply(const Helper::Reply &) STUB
 void ConnStateData::switchToHttps(HttpRequest *, Ssl::BumpMode) STUB
diff -u -r -N squid-4.0.14/src/tests/stub_libsecurity.cc squid-4.0.15/src/tests/stub_libsecurity.cc
--- squid-4.0.14/src/tests/stub_libsecurity.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/tests/stub_libsecurity.cc	2016-10-10 08:05:51.000000000 +1300
@@ -19,7 +19,7 @@
 namespace Security
 {
 bool BlindPeerConnector::initialize(Security::SessionPointer &) STUB_RETVAL(false)
-Security::ContextPtr BlindPeerConnector::getSslContext() STUB_RETVAL(nullptr)
+Security::ContextPointer BlindPeerConnector::getTlsContext() STUB_RETVAL(Security::ContextPointer())
 void BlindPeerConnector::noteNegotiationDone(ErrorState *) STUB
 }
 
@@ -33,7 +33,7 @@
 
 #include "security/NegotiationHistory.h"
 Security::NegotiationHistory::NegotiationHistory() STUB
-void Security::NegotiationHistory::retrieveNegotiatedInfo(Security::SessionPtr) STUB
+void Security::NegotiationHistory::retrieveNegotiatedInfo(const Security::SessionPointer &) STUB
 void Security::NegotiationHistory::retrieveParsedInfo(Security::TlsDetails::Pointer const &) STUB
 const char *Security::NegotiationHistory::cipherName() const STUB
 const char *Security::NegotiationHistory::printTlsVersion(AnyP::ProtocolVersion const &v) const STUB
@@ -60,7 +60,7 @@
 void PeerConnector::noteWantRead() STUB
 void PeerConnector::noteWantWrite() STUB
 void PeerConnector::noteNegotiationError(const int, const int, const int) STUB
-//    virtual Security::ContextPtr getSslContext() = 0;
+//    virtual Security::ContextPointer getTlsContext() = 0;
 void PeerConnector::bail(ErrorState *) STUB
 void PeerConnector::callBack() STUB
 void PeerConnector::recordNegotiationDetails() STUB
@@ -69,11 +69,11 @@
 #include "security/PeerOptions.h"
 Security::PeerOptions Security::ProxyOutgoingConfig;
 void Security::PeerOptions::parse(char const*) STUB
-Security::ContextPtr Security::PeerOptions::createClientContext(bool) STUB_RETVAL(NULL)
+Security::ContextPointer Security::PeerOptions::createClientContext(bool) STUB_RETVAL(Security::ContextPointer())
 void Security::PeerOptions::updateTlsVersionLimits() STUB
-Security::ContextPtr Security::PeerOptions::createBlankContext() const STUB
-void Security::PeerOptions::updateContextCa(Security::ContextPtr &) STUB
-void Security::PeerOptions::updateContextCrl(Security::ContextPtr &) STUB
+Security::ContextPointer Security::PeerOptions::createBlankContext() const STUB_RETVAL(Security::ContextPointer())
+void Security::PeerOptions::updateContextCa(Security::ContextPointer &) STUB
+void Security::PeerOptions::updateContextCrl(Security::ContextPointer &) STUB
 void Security::PeerOptions::dumpCfg(Packable*, char const*) const STUB
 long Security::PeerOptions::parseOptions() STUB_RETVAL(0)
 long Security::PeerOptions::parseFlags() STUB_RETVAL(0)
@@ -83,9 +83,9 @@
 //Security::ServerOptions::ServerOptions(const Security::ServerOptions &) STUB
 void Security::ServerOptions::parse(const char *) STUB
 void Security::ServerOptions::dumpCfg(Packable *, const char *) const STUB
-Security::ContextPtr Security::ServerOptions::createBlankContext() const STUB
+Security::ContextPointer Security::ServerOptions::createBlankContext() const STUB_RETVAL(Security::ContextPointer())
 bool Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &) STUB_RETVAL(false)
-void Security::ServerOptions::updateContextEecdh(Security::ContextPtr &) STUB
+void Security::ServerOptions::updateContextEecdh(Security::ContextPointer &) STUB
 
 #include "security/Session.h"
 namespace Security {
diff -u -r -N squid-4.0.14/src/tests/stub_libsslsquid.cc squid-4.0.15/src/tests/stub_libsslsquid.cc
--- squid-4.0.14/src/tests/stub_libsslsquid.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/tests/stub_libsslsquid.cc	2016-10-10 08:05:51.000000000 +1300
@@ -41,22 +41,17 @@
 //Ssl::GlobalContextStorage Ssl::TheGlobalContextStorage;
 
 #include "ssl/ErrorDetail.h"
-Ssl::ssl_error_t parseErrorString(const char *name) STUB_RETVAL(0)
-//const char *Ssl::getErrorName(ssl_error_t value) STUB_RETVAL(NULL)
-Ssl::ErrorDetail::ErrorDetail(ssl_error_t err_no, X509 *, X509 *, const char *) STUB
+Security::ErrorCode parseErrorString(const char *name) STUB_RETVAL(0)
+//const char *Ssl::getErrorName(Security::ErrorCode value) STUB_RETVAL(NULL)
+Ssl::ErrorDetail::ErrorDetail(Security::ErrorCode, X509 *, X509 *, const char *) STUB
 Ssl::ErrorDetail::ErrorDetail(ErrorDetail const &) STUB
 const String & Ssl::ErrorDetail::toString() const STUB_RETSTATREF(String)
 
 #include "ssl/support.h"
 namespace Ssl
 {
-//CertError::CertError(ssl_error_t anErr, X509 *aCert) STUB
-//CertError::CertError(CertError const &err) STUB
-CertError & CertError::operator = (const CertError &old) STUB_RETVAL(*this)
-bool CertError::operator == (const CertError &ce) const STUB_RETVAL(false)
-bool CertError::operator != (const CertError &ce) const STUB_RETVAL(false)
-bool InitServerContext(const Security::ContextPointer &, AnyP::PortCfg &) STUB_RETVAL(false)
-bool InitClientContext(Security::ContextPtr &, Security::PeerOptions &, long, const char *) STUB_RETVAL(false)
+bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &) STUB_RETVAL(false)
+bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, long, const char *) STUB_RETVAL(false)
 } // namespace Ssl
 int ssl_read_method(int, char *, int) STUB_RETVAL(0)
 int ssl_write_method(int, const char *, int) STUB_RETVAL(0)
@@ -73,10 +68,10 @@
 //GETX509ATTRIBUTE GetX509Fingerprint;
 const char *BumpModeStr[] = {""};
 bool generateUntrustedCert(Security::CertPointer & untrustedCert, EVP_PKEY_Pointer & untrustedPkey, Security::CertPointer const & cert, EVP_PKEY_Pointer const & pkey) STUB_RETVAL(false)
-Security::ContextPtr generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port) STUB_RETVAL(NULL)
-bool verifySslCertificate(Security::ContextPtr sslContext,  CertificateProperties const &properties) STUB_RETVAL(false)
-Security::ContextPtr generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port) STUB_RETVAL(NULL)
-void addChainToSslContext(Security::ContextPtr sslContext, STACK_OF(X509) *certList) STUB
+Security::ContextPointer generateSslContext(CertificateProperties const &, AnyP::PortCfg &) STUB_RETVAL(Security::ContextPointer())
+bool verifySslCertificate(Security::ContextPointer &, CertificateProperties const &) STUB_RETVAL(false)
+Security::ContextPointer generateSslContextUsingPkeyAndCertFromMemory(const char *, AnyP::PortCfg &) STUB_RETVAL(Security::ContextPointer())
+void addChainToSslContext(Security::ContextPointer &, STACK_OF(X509) *) STUB
 void readCertChainAndPrivateKeyFromFiles(Security::CertPointer & cert, EVP_PKEY_Pointer & pkey, X509_STACK_Pointer & chain, char const * certFilename, char const * keyFilename) STUB
 int matchX509CommonNames(X509 *peer_cert, void *check_data, int (*check_func)(void *check_data,  ASN1_STRING *cn_data)) STUB_RETVAL(0)
 bool checkX509ServerValidity(X509 *cert, const char *server) STUB_RETVAL(false)
diff -u -r -N squid-4.0.14/src/tests/stub_SBuf.cc squid-4.0.15/src/tests/stub_SBuf.cc
--- squid-4.0.14/src/tests/stub_SBuf.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/tests/stub_SBuf.cc	2016-10-10 08:05:51.000000000 +1300
@@ -63,7 +63,6 @@
 SBuf::size_type SBuf::rfind(const SBuf &str, size_type endPos) const STUB_RETVAL(SBuf::npos)
 SBuf::size_type SBuf::findFirstOf(const CharacterSet &set, size_type startPos) const STUB_RETVAL(SBuf::npos)
 SBuf::size_type SBuf::findFirstNotOf(const CharacterSet &set, size_type startPos) const STUB_RETVAL(SBuf::npos)
-int SBuf::scanf(const char *format, ...) STUB_RETVAL(-1)
 void SBuf::toLower() STUB
 void SBuf::toUpper() STUB
 
diff -u -r -N squid-4.0.14/src/tests/stub_store.cc squid-4.0.15/src/tests/stub_store.cc
--- squid-4.0.14/src/tests/stub_store.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/tests/stub_store.cc	2016-10-10 08:05:51.000000000 +1300
@@ -68,7 +68,7 @@
 int StoreEntry::checkTooSmall() STUB_RETVAL(0)
 void StoreEntry::delayAwareRead(const Comm::ConnectionPointer&, char *buf, int len, AsyncCall::Pointer callback) STUB
 void StoreEntry::setNoDelay (bool const) STUB
-bool StoreEntry::modifiedSince(HttpRequest * request) const STUB_RETVAL(false)
+bool StoreEntry::modifiedSince(const time_t, const int) const STUB_RETVAL(false)
 bool StoreEntry::hasIfMatchEtag(const HttpRequest &request) const STUB_RETVAL(false)
 bool StoreEntry::hasIfNoneMatchEtag(const HttpRequest &request) const STUB_RETVAL(false)
 Store::Disk &StoreEntry::disk() const STUB_RETREF(Store::Disk)
diff -u -r -N squid-4.0.14/src/tests/testHttp1Parser.cc squid-4.0.15/src/tests/testHttp1Parser.cc
--- squid-4.0.14/src/tests/testHttp1Parser.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/tests/testHttp1Parser.cc	2016-10-10 08:05:51.000000000 +1300
@@ -39,8 +39,6 @@
     Config.maxRequestHeaderSize = 1024; // XXX: unit test the RequestParser handling of this limit
 }
 
-#if __cplusplus >= 201103L
-
 struct resultSet {
     bool parsed;
     bool needsMore;
@@ -119,7 +117,6 @@
         CPPUNIT_ASSERT_EQUAL(expect.parserState, output.parsingStage_);
     CPPUNIT_ASSERT_EQUAL(expect.suffixSz, output.buf_.length());
 }
-#endif /* __cplusplus >= 200103L */
 
 void
 testHttp1Parser::testParserConstruct()
@@ -235,7 +232,7 @@
         input.clear();
     }
 
-    // RFC 7230 : future version full-request
+    // RFC 7230 : future 1.x version full-request
     {
         input.append("GET / HTTP/1.2\r\n", 16);
         struct resultSet expect = {
@@ -253,25 +250,45 @@
         input.clear();
     }
 
-    // RFC 7230 : future versions do not use request-line syntax
+    // RFC 7230 : future versions do not use 1.x message syntax.
+    // However, it is still valid syntax for the single-digit forms
+    // to appear. The parser we are testing should accept them.
     {
         input.append("GET / HTTP/2.0\r\n", 16);
         struct resultSet expectA = {
-            .parsed = false,
+            .parsed = true,
             .needsMore = false,
-            .parserState = Http1::HTTP_PARSE_MIME,
-            .status = Http::scBadRequest,
-            .suffixSz = input.length(),
-            .method = HttpRequestMethod(),
+            .parserState = Http1::HTTP_PARSE_DONE,
+            .status = Http::scOkay,
+            .suffixSz = 0,
+            .method = HttpRequestMethod(Http::METHOD_GET),
             .uri = "/",
-            .version = AnyP::ProtocolVersion()
+            .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,2,0)
         };
         output.clear();
         testResults(__LINE__, input, output, expectA);
         input.clear();
 
-        input.append("GET / HTTP/10.12\r\n", 18);
+        input.append("GET / HTTP/9.9\r\n", 16);
         struct resultSet expectB = {
+            .parsed = true,
+            .needsMore = false,
+            .parserState = Http1::HTTP_PARSE_DONE,
+            .status = Http::scOkay,
+            .suffixSz = 0,
+            .method = HttpRequestMethod(Http::METHOD_GET),
+            .uri = "/",
+            .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,9,9)
+        };
+        output.clear();
+        testResults(__LINE__, input, output, expectB);
+        input.clear();
+    }
+
+    // RFC 7230 : future versions >= 10.0 are invalid syntax
+    {
+        input.append("GET / HTTP/10.12\r\n", 18);
+        struct resultSet expect = {
             .parsed = false,
             .needsMore = false,
             .parserState = Http1::HTTP_PARSE_MIME,
@@ -282,7 +299,7 @@
             .version = AnyP::ProtocolVersion()
         };
         output.clear();
-        testResults(__LINE__, input, output, expectB);
+        testResults(__LINE__, input, output, expect);
         input.clear();
     }
 
diff -u -r -N squid-4.0.14/src/tests/testSBuf.cc squid-4.0.15/src/tests/testSBuf.cc
--- squid-4.0.14/src/tests/testSBuf.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/tests/testSBuf.cc	2016-10-10 08:05:51.000000000 +1300
@@ -754,22 +754,6 @@
 }
 
 void
-testSBuf::testScanf()
-{
-    SBuf s1;
-    char s[128];
-    int i;
-    float f;
-    int rv;
-    s1.assign("string , 123 , 123.50");
-    rv=s1.scanf("%s , %d , %f",s,&i,&f);
-    CPPUNIT_ASSERT_EQUAL(3,rv);
-    CPPUNIT_ASSERT_EQUAL(0,strcmp(s,"string"));
-    CPPUNIT_ASSERT_EQUAL(123,i);
-    CPPUNIT_ASSERT_EQUAL(static_cast<float>(123.5),f);
-}
-
-void
 testSBuf::testCopy()
 {
     char buf[40]; //shorter than literal()
diff -u -r -N squid-4.0.14/src/tests/testSBuf.h squid-4.0.15/src/tests/testSBuf.h
--- squid-4.0.14/src/tests/testSBuf.h	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/tests/testSBuf.h	2016-10-10 08:05:51.000000000 +1300
@@ -45,7 +45,6 @@
     CPPUNIT_TEST( testFindFirstOf );
     CPPUNIT_TEST( testFindFirstNotOf );
     CPPUNIT_TEST( testPrintf );
-    CPPUNIT_TEST( testScanf );
     CPPUNIT_TEST( testCopy );
     CPPUNIT_TEST( testStringOps );
     CPPUNIT_TEST( testGrow );
@@ -67,7 +66,6 @@
     void testAppendStdString();
     void testAppendf();
     void testPrintf();
-    void testScanf();
     void testSubscriptOp();
     void testSubscriptOpFail();
     void testDumpStats();
diff -u -r -N squid-4.0.14/src/tests/testStoreController.cc squid-4.0.15/src/tests/testStoreController.cc
--- squid-4.0.14/src/tests/testStoreController.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/tests/testStoreController.cc	2016-10-10 08:05:51.000000000 +1300
@@ -111,7 +111,7 @@
     e->lastref = squid_curtime;
     e->timestamp = squid_curtime;
     e->expires = squid_curtime;
-    e->lastmod = squid_curtime;
+    e->lastModified(squid_curtime);
     e->refcount = 1;
     EBIT_CLR(e->flags, RELEASE_REQUEST);
     EBIT_CLR(e->flags, KEY_PRIVATE);
diff -u -r -N squid-4.0.14/src/tests/testStoreHashIndex.cc squid-4.0.15/src/tests/testStoreHashIndex.cc
--- squid-4.0.14/src/tests/testStoreHashIndex.cc	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/src/tests/testStoreHashIndex.cc	2016-10-10 08:05:51.000000000 +1300
@@ -89,7 +89,7 @@
     e->lastref = squid_curtime;
     e->timestamp = squid_curtime;
     e->expires = squid_curtime;
-    e->lastmod = squid_curtime;
+    e->lastModified(squid_curtime);
     e->refcount = 1;
     EBIT_CLR(e->flags, RELEASE_REQUEST);
     EBIT_CLR(e->flags, KEY_PRIVATE);
diff -u -r -N squid-4.0.14/test-suite/stub_SBuf.cc squid-4.0.15/test-suite/stub_SBuf.cc
--- squid-4.0.14/test-suite/stub_SBuf.cc	2016-09-09 03:32:58.000000000 +1200
+++ squid-4.0.15/test-suite/stub_SBuf.cc	2016-10-10 12:02:05.000000000 +1300
@@ -63,7 +63,6 @@
 SBuf::size_type SBuf::rfind(const SBuf &str, size_type endPos) const STUB_RETVAL(SBuf::npos)
 SBuf::size_type SBuf::findFirstOf(const CharacterSet &set, size_type startPos) const STUB_RETVAL(SBuf::npos)
 SBuf::size_type SBuf::findFirstNotOf(const CharacterSet &set, size_type startPos) const STUB_RETVAL(SBuf::npos)
-int SBuf::scanf(const char *format, ...) STUB_RETVAL(-1)
 void SBuf::toLower() STUB
 void SBuf::toUpper() STUB
 
diff -u -r -N squid-4.0.14/tools/helper-mux/helper-mux.8 squid-4.0.15/tools/helper-mux/helper-mux.8
--- squid-4.0.14/tools/helper-mux/helper-mux.8	2016-09-09 03:33:04.000000000 +1200
+++ squid-4.0.15/tools/helper-mux/helper-mux.8	2016-10-10 12:02:23.000000000 +1300
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -46,7 +46,7 @@
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" If the F register is >0, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.nr rF 0
-.if \n(.g .if rF .nr rF 1
-.if (\n(rF:(\n(.g==0)) \{
-.    if \nF \{
-.        de IX
-.        tm Index:\\$1\t\\n%\t"\\$2"
+.if !\nF .nr F 0
+.if \nF>0 \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.        if !\nF==2 \{
-.            nr % 0
-.            nr F 2
-.        \}
+.    if !\nF==2 \{\
+.        nr % 0
+.        nr F 2
 .    \}
 .\}
-.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -133,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "HELPER-MUX 8"
-.TH HELPER-MUX 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH HELPER-MUX 8 "2016-10-09" "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.14/tools/systemd/squid.service squid-4.0.15/tools/systemd/squid.service
--- squid-4.0.14/tools/systemd/squid.service	2016-09-09 02:12:03.000000000 +1200
+++ squid-4.0.15/tools/systemd/squid.service	2016-10-10 08:05:51.000000000 +1300
@@ -13,6 +13,7 @@
 [Service]
 Type=forking
 PIDFile=/var/run/squid.pid
+ExecStartPre=/usr/sbin/squid --foreground -z
 ExecStart=/usr/sbin/squid -sYC
 ExecReload=/bin/kill -HUP $MAINPID
 KillMode=mixed
