diff -u -r -N squid-4.0.19/acinclude/lib-checks.m4 squid-4.0.20/acinclude/lib-checks.m4
--- squid-4.0.19/acinclude/lib-checks.m4	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/acinclude/lib-checks.m4	2017-06-02 00:49:17.000000000 +1200
@@ -46,6 +46,61 @@
   SQUID_STATE_ROLLBACK(iphlpapi)
 ])
 
+dnl Checks whether the -lssl library provides OpenSSL TLS_*_method() definitions
+AC_DEFUN([SQUID_CHECK_OPENSSL_TLS_METHODS],[
+  AH_TEMPLATE(HAVE_OPENSSL_TLS_METHOD, "Define to 1 if the TLS_method() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_OPENSSL_TLS_CLIENT_METHOD, "Define to 1 if the TLS_client_method() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_OPENSSL_TLS_SERVER_METHOD, "Define to 1 if the TLS_server_method() OpenSSL API function exists")
+  SQUID_STATE_SAVE(check_openssl_TLS_METHODS)
+  LIBS="$LIBS $SSLLIB"
+  AC_CHECK_LIB(ssl, TLS_method, AC_DEFINE(HAVE_OPENSSL_TLS_METHOD, 1))
+  AC_CHECK_LIB(ssl, TLS_client_method, AC_DEFINE(HAVE_OPENSSL_TLS_CLIENT_METHOD, 1))
+  AC_CHECK_LIB(ssl, TLS_server_method, AC_DEFINE(HAVE_OPENSSL_TLS_SERVER_METHOD, 1))
+  SQUID_STATE_ROLLBACK(check_openssl_TLS_METHODS)
+])
+
+dnl Checks whether the -lcrypto library provides various OpenSSL API functions
+AC_DEFUN([SQUID_CHECK_LIBCRYPTO_API],[
+  AH_TEMPLATE(HAVE_LIBCRYPTO_EVP_PKEY_GET0_RSA, "Define to 1 if the EVP_PKEY_get0_RSA() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBCRYPTO_BIO_METH_NEW, "Define to 1 if the BIO_meth_new() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBCRYPTO_BIO_GET_INIT, "Define to 1 if the BIO_get_init() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBCRYPTO_ASN1_STRING_GET0_DATA, "Define to 1 if the ASN1_STRING_get0_data() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_CERT, "Define to 1 if the X509_STORE_CTX_get0_cert() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBCRYPTO_X509_VERIFY_PARAM_GET_DEPTH, "Define to 1 if the X509_VERIFY_PARAM_get_depth() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_UNTRUSTED, "Define to 1 if the X509_STORE_CTX_get0_untrusted() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBCRYPTO_X509_STORE_CTX_SET0_UNTRUSTED, "Define to 1 if the X509_STORE_CTX_set0_untrusted() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBCRYPTO_X509_UP_REF, "Define to 1 if the X509_up_ref() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBCRYPTO_X509_CRL_UP_REF, "Define to 1 if the X509_CRL_up_ref() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBCRYPTO_DH_UP_REF, "Define to 1 if the DH_up_ref() OpenSSL API function exists")
+  SQUID_STATE_SAVE(check_openssl_libcrypto_api)
+  LIBS="$LIBS $SSLLIB"
+  AC_CHECK_LIB(crypto, EVP_PKEY_get0_RSA, AC_DEFINE(HAVE_LIBCRYPTO_EVP_PKEY_GET0_RSA, 1))
+  AC_CHECK_LIB(crypto, BIO_meth_new, AC_DEFINE(HAVE_LIBCRYPTO_BIO_METH_NEW, 1))
+  AC_CHECK_LIB(crypto, BIO_get_init, AC_DEFINE(HAVE_LIBCRYPTO_BIO_GET_INIT, 1))
+  AC_CHECK_LIB(crypto, ASN1_STRING_get0_data, AC_DEFINE(HAVE_LIBCRYPTO_ASN1_STRING_GET0_DATA, 1))
+  AC_CHECK_LIB(crypto, X509_STORE_CTX_get0_cert, AC_DEFINE(HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_CERT, 1))
+  AC_CHECK_LIB(crypto, X509_VERIFY_PARAM_get_depth, AC_DEFINE(HAVE_LIBCRYPTO_X509_VERIFY_PARAM_GET_DEPTH, 1))
+  AC_CHECK_LIB(crypto, X509_STORE_CTX_get0_untrusted, AC_DEFINE(HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_UNTRUSTED, 1))
+  AC_CHECK_LIB(crypto, X509_STORE_CTX_set0_untrusted, AC_DEFINE(HAVE_LIBCRYPTO_X509_STORE_CTX_SET0_UNTRUSTED, 1))
+  AC_CHECK_LIB(crypto, X509_up_ref, AC_DEFINE(HAVE_LIBCRYPTO_X509_UP_REF, 1))
+  AC_CHECK_LIB(crypto, X509_CRL_up_ref, AC_DEFINE(HAVE_LIBCRYPTO_X509_CRL_UP_REF, 1))
+  AC_CHECK_LIB(crypto, DH_up_ref, AC_DEFINE(HAVE_LIBCRYPTO_DH_UP_REF, 1))
+  SQUID_STATE_ROLLBACK(check_openssl_libcrypto_api)
+])
+
+dnl Checks whether the -lssl library provides various OpenSSL API functions
+AC_DEFUN([SQUID_CHECK_LIBSSL_API],[
+  AH_TEMPLATE(HAVE_LIBSSL_SSL_CIPHER_FIND, "Define to 1 if the SSL_CIPHER_find() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK, "Define to 1 if the SSL_CTX_set_tmp_rsa_callback() OpenSSL API function exists")
+  AH_TEMPLATE(HAVE_LIBSSL_SSL_SESSION_GET_ID, "Define to 1 if the SSL_SESSION_get_id() OpenSSL API function exists")
+  SQUID_STATE_SAVE(check_openssl_libssl_api)
+  LIBS="$LIBS $SSLLIB"
+  AC_CHECK_LIB(ssl, SSL_CIPHER_find, AC_DEFINE(HAVE_LIBSSL_SSL_CIPHER_FIND, 1))
+  AC_CHECK_LIB(ssl, SSL_CTX_set_tmp_rsa_callback, AC_DEFINE(HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK, 1))
+  AC_CHECK_LIB(ssl, SSL_SESSION_get_id, AC_DEFINE(HAVE_LIBSSL_SSL_SESSION_GET_ID, 1))
+  SQUID_STATE_ROLLBACK(check_openssl_libssl_api)
+])
+
 dnl Checks whether the OpenSSL SSL_get_certificate crashes squid and if a
 dnl workaround can be used instead of using the SSL_get_certificate
 AC_DEFUN([SQUID_CHECK_OPENSSL_GETCERTIFICATE_WORKS],[
@@ -66,7 +121,7 @@
     ],
     [
     SSLeay_add_ssl_algorithms();
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#if HAVE_OPENSSL_TLS_METHOD
     SSL_CTX *sslContext = SSL_CTX_new(TLS_method());
 #else
     SSL_CTX *sslContext = SSL_CTX_new(SSLv23_method());
@@ -97,7 +152,7 @@
     ],
     [
     SSLeay_add_ssl_algorithms();
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#if HAVE_OPENSSL_TLS_METHOD
     SSL_CTX *sslContext = SSL_CTX_new(TLS_method());
 #else
     SSL_CTX *sslContext = SSL_CTX_new(SSLv23_method());
@@ -153,8 +208,54 @@
   [])
 
 SQUID_STATE_ROLLBACK(check_const_SSL_METHOD)
-]
-)
+])
+
+dnl Checks whether the CRYPTO_EX_DATA duplication callback for SSL_get_ex_new_index() has a const argument
+AC_DEFUN([SQUID_CHECK_OPENSSL_CONST_CRYPTO_EX_DATA],[
+  AH_TEMPLATE(SQUID_USE_CONST_CRYPTO_EX_DATA_DUP, "Define to 1 if the SSL_get_new_ex_index() dup callback accepts 'const CRYPTO_EX_DATA *'")
+  SQUID_STATE_SAVE(check_const_CRYPTO_EX_DATA)
+  AC_MSG_CHECKING(whether SSL_get_new_ex_index() dup callback accepts 'const CRYPTO_EX_DATA *'")
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+#include <openssl/ssl.h>
+
+int const_dup_func(CRYPTO_EX_DATA *, const CRYPTO_EX_DATA *, void *, int, long, void *) {
+    return 0;
+}
+    ],[
+return SSL_get_ex_new_index(0, (void*)"foo", NULL, &const_dup_func, NULL);
+    ])
+  ],[
+   AC_DEFINE(SQUID_USE_CONST_CRYPTO_EX_DATA_DUP, 1)
+   AC_MSG_RESULT([yes])
+  ],[
+   AC_MSG_RESULT([no])
+  ])
+  SQUID_STATE_ROLLBACK(check_const_CRYPTO_EX_DATA)
+])
+
+dnl Checks whether the callback for SSL_CTX_sess_set_get_cb() accepts a const ID argument
+AC_DEFUN([SQUID_CHECK_OPENSSL_CONST_SSL_SESSION_CB_ARG],[
+  AH_TEMPLATE(SQUID_USE_CONST_SSL_SESSION_CBID, "Define to 1 if the SSL_CTX_sess_set_get_cb() callback accepts a const ID argument")
+  SQUID_STATE_SAVE(check_const_SSL_CTX_sess_set_get_cb)
+  AC_MSG_CHECKING(whether SSL_CTX_sess_set_get_cb() callback accepts a const ID argument")
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+#include <openssl/ssl.h>
+
+SSL_SESSION *get_session_cb(SSL *, const unsigned char *ID, int, int *) {
+    return NULL;
+}
+    ],[
+SSL_CTX_sess_set_get_cb(NULL, get_session_cb);
+return 0;
+    ])
+  ],[
+   AC_DEFINE(SQUID_USE_CONST_SSL_SESSION_CBID, 1)
+   AC_MSG_RESULT([yes])
+  ],[
+   AC_MSG_RESULT([no])
+  ])
+  SQUID_STATE_ROLLBACK(check_const_SSL_CTX_sess_set_get_cb)
+])
 
 dnl Try to handle TXT_DB related  problems:
 dnl 1) The type of TXT_DB::data member changed in openSSL-1.0.1 version
diff -u -r -N squid-4.0.19/ChangeLog squid-4.0.20/ChangeLog
--- squid-4.0.19/ChangeLog	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/ChangeLog	2017-06-02 00:49:17.000000000 +1200
@@ -1,3 +1,23 @@
+Changes to squid-4.0.20 (01 Jun 2017):
+
+	- Bug #4692: SslBump breaks intercepted IPv6 connections
+	- Bug #4682: ignoring http_access deny when client-first bumping mode is used
+	- Bug #4662: build errors with LibreSSL 2.4.4
+	- Bug #4659: sslproxy_foreign_intermediate_certs does not work
+	- Bug #4321: ssl_bump terminate does not terminate at step1
+	- Add 'has' ACL
+	- Do not forward HTTP requests to dead idle peers
+	- Do not unconditionally revive dead peers after a DNS refresh
+	- Make PID file check/creation atomic to avoid associated race conditions
+	- Count failures and use peer-specific connect timeouts when tunneling
+	- SSL-Bump: Fix crashes when server-first bumping mode is used with openSSL-1.1.0
+	- eCAP: Fix empty header handling in Ecap::HeaderRep::hasAny()
+	- SSL-Bump: Second adaptation missing for CONNECTs
+	- ext_session_acl: cope with new logformat inputs
+	- ... and some documentation updates
+	- ... and some code stability fixes
+	- ... and all fixes from 3.5.25
+
 Changes to squid-4.0.19 (02 Apr 2017):
 
 	- Bug 4674: delay_parameters for class 3 and 4 assertion failed
@@ -285,6 +305,19 @@
 	- ... and many documentation changes
 	- ... and much code cleanup and polishing
 
+Changes to squid-3.5.26 (01 Jun 2017):
+
+	- Bug 4711: SubjectAlternativeNames is missing in some generated certificates
+	- Bug 4695: squidpurge: GCC 7 build errors
+	- Bug 4682: ignoring http_access deny when client-first bumping mode is used
+	- Bug 4682: Fix ssl_bump "bump" action documentation
+	- Bug 4653: %st lies about tunneled traffic volumes
+	- Bug 4589: ssl_crtd: returning zero on failure
+	- Bug 3772: message from FTP server gets mangled
+	- Bug 3102: FTP directory listing drops fist character of file names
+	- Add OpenSSL library details to -v output
+	- ... and some documentatino updates
+
 Changes to squid-3.5.25 (02 Apr 2017):
 
 	- Bug 4688: various typo error(s) in man page(s)
diff -u -r -N squid-4.0.19/compat/xstring.h squid-4.0.20/compat/xstring.h
--- squid-4.0.19/compat/xstring.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/compat/xstring.h	2017-06-02 00:49:17.000000000 +1200
@@ -41,7 +41,10 @@
 char *xstrncpy(char *dst, const char *src, size_t n);
 
 /**
- * xstrndup() - same as strndup(3).  Used for portability.
+ * xstrndup() - Somewhat similar(XXX) to strndup(3): Allocates up to n bytes,
+ * while strndup(3) copies up to n bytes and allocates up to n+1 bytes
+ * to fit the terminating character. Assumes s is 0-terminated (another XXX).
+ *
  * Never returns NULL; fatal on error.
  *
  * Sets errno to EINVAL if a NULL pointer or negative
diff -u -r -N squid-4.0.19/configure squid-4.0.20/configure
--- squid-4.0.19/configure	2017-04-02 19:46:37.000000000 +1200
+++ squid-4.0.20/configure	2017-06-02 01:01:44.000000000 +1200
@@ -1,7 +1,7 @@
 #! /bin/sh
 # From configure.ac Revision.
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.0.19.
+# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.0.20.
 #
 # 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.19'
-PACKAGE_STRING='Squid Web Proxy 4.0.19'
+PACKAGE_VERSION='4.0.20'
+PACKAGE_STRING='Squid Web Proxy 4.0.20'
 PACKAGE_BUGREPORT='http://bugs.squid-cache.org/'
 PACKAGE_URL=''
 
@@ -1647,7 +1647,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures Squid Web Proxy 4.0.19 to adapt to many kinds of systems.
+\`configure' configures Squid Web Proxy 4.0.20 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1718,7 +1718,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Squid Web Proxy 4.0.19:";;
+     short | recursive ) echo "Configuration of Squid Web Proxy 4.0.20:";;
    esac
   cat <<\_ACEOF
 
@@ -2147,7 +2147,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Squid Web Proxy configure 4.0.19
+Squid Web Proxy configure 4.0.20
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -3251,7 +3251,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Squid Web Proxy $as_me 4.0.19, which was
+It was created by Squid Web Proxy $as_me 4.0.20, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -4118,7 +4118,7 @@
 
 # Define the identity of the package.
  PACKAGE='squid'
- VERSION='4.0.19'
+ VERSION='4.0.20'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -4674,6 +4674,16 @@
 
 
 
+
+
+
+
+
+
+
+
+
+
 ## Copyright (C) 1996-2017 The Squid Software Foundation and contributors
 ##
 ## Squid software is distributed under GPLv2+ license and includes
@@ -23910,7 +23920,962 @@
 $as_echo "#define USE_OPENSSL 1" >>confdefs.h
 
 
+    # check for API functions
+
+
+
+
+
+
+
+
+
+
+
+
+
+# save state, key is check_openssl_libcrypto_api
+check_openssl_libcrypto_api_CFLAGS="${CFLAGS}"
+check_openssl_libcrypto_api_CXXFLAGS="${CXXFLAGS}"
+check_openssl_libcrypto_api_LDFLAGS="${LDFLAGS}"
+check_openssl_libcrypto_api_LIBS="${LIBS}"
+check_openssl_libcrypto_api_CC="${CC}"
+check_openssl_libcrypto_api_CXX="${CXX}"
+check_openssl_libcrypto_api_CPPFLAGS="${CPPFLAGS}"
+check_openssl_libcrypto_api_squid_saved_vars=""
+for squid_util_var_tosave in $check_openssl_libcrypto_api_squid_saved_vars
+do
+    squid_util_var_tosave2="check_openssl_libcrypto_api_${squid_util_var_tosave}"
+    eval "${squid_util_var_tosave2}=\"${squid_util_var_tosave}\""
+done
+
+  LIBS="$LIBS $SSLLIB"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_PKEY_get0_RSA in -lcrypto" >&5
+$as_echo_n "checking for EVP_PKEY_get0_RSA in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_EVP_PKEY_get0_RSA+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char EVP_PKEY_get0_RSA ();
+int
+main ()
+{
+return EVP_PKEY_get0_RSA ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_EVP_PKEY_get0_RSA=yes
+else
+  ac_cv_lib_crypto_EVP_PKEY_get0_RSA=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_EVP_PKEY_get0_RSA" >&5
+$as_echo "$ac_cv_lib_crypto_EVP_PKEY_get0_RSA" >&6; }
+if test "x$ac_cv_lib_crypto_EVP_PKEY_get0_RSA" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_EVP_PKEY_GET0_RSA 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BIO_meth_new in -lcrypto" >&5
+$as_echo_n "checking for BIO_meth_new in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_BIO_meth_new+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char BIO_meth_new ();
+int
+main ()
+{
+return BIO_meth_new ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_BIO_meth_new=yes
+else
+  ac_cv_lib_crypto_BIO_meth_new=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_BIO_meth_new" >&5
+$as_echo "$ac_cv_lib_crypto_BIO_meth_new" >&6; }
+if test "x$ac_cv_lib_crypto_BIO_meth_new" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_BIO_METH_NEW 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BIO_get_init in -lcrypto" >&5
+$as_echo_n "checking for BIO_get_init in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_BIO_get_init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char BIO_get_init ();
+int
+main ()
+{
+return BIO_get_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_BIO_get_init=yes
+else
+  ac_cv_lib_crypto_BIO_get_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_BIO_get_init" >&5
+$as_echo "$ac_cv_lib_crypto_BIO_get_init" >&6; }
+if test "x$ac_cv_lib_crypto_BIO_get_init" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_BIO_GET_INIT 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ASN1_STRING_get0_data in -lcrypto" >&5
+$as_echo_n "checking for ASN1_STRING_get0_data in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_ASN1_STRING_get0_data+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ASN1_STRING_get0_data ();
+int
+main ()
+{
+return ASN1_STRING_get0_data ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_ASN1_STRING_get0_data=yes
+else
+  ac_cv_lib_crypto_ASN1_STRING_get0_data=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_ASN1_STRING_get0_data" >&5
+$as_echo "$ac_cv_lib_crypto_ASN1_STRING_get0_data" >&6; }
+if test "x$ac_cv_lib_crypto_ASN1_STRING_get0_data" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_ASN1_STRING_GET0_DATA 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X509_STORE_CTX_get0_cert in -lcrypto" >&5
+$as_echo_n "checking for X509_STORE_CTX_get0_cert in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_X509_STORE_CTX_get0_cert+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char X509_STORE_CTX_get0_cert ();
+int
+main ()
+{
+return X509_STORE_CTX_get0_cert ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_X509_STORE_CTX_get0_cert=yes
+else
+  ac_cv_lib_crypto_X509_STORE_CTX_get0_cert=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_X509_STORE_CTX_get0_cert" >&5
+$as_echo "$ac_cv_lib_crypto_X509_STORE_CTX_get0_cert" >&6; }
+if test "x$ac_cv_lib_crypto_X509_STORE_CTX_get0_cert" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_CERT 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X509_VERIFY_PARAM_get_depth in -lcrypto" >&5
+$as_echo_n "checking for X509_VERIFY_PARAM_get_depth in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_X509_VERIFY_PARAM_get_depth+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char X509_VERIFY_PARAM_get_depth ();
+int
+main ()
+{
+return X509_VERIFY_PARAM_get_depth ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_X509_VERIFY_PARAM_get_depth=yes
+else
+  ac_cv_lib_crypto_X509_VERIFY_PARAM_get_depth=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_X509_VERIFY_PARAM_get_depth" >&5
+$as_echo "$ac_cv_lib_crypto_X509_VERIFY_PARAM_get_depth" >&6; }
+if test "x$ac_cv_lib_crypto_X509_VERIFY_PARAM_get_depth" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_X509_VERIFY_PARAM_GET_DEPTH 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X509_STORE_CTX_get0_untrusted in -lcrypto" >&5
+$as_echo_n "checking for X509_STORE_CTX_get0_untrusted in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_X509_STORE_CTX_get0_untrusted+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char X509_STORE_CTX_get0_untrusted ();
+int
+main ()
+{
+return X509_STORE_CTX_get0_untrusted ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_X509_STORE_CTX_get0_untrusted=yes
+else
+  ac_cv_lib_crypto_X509_STORE_CTX_get0_untrusted=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_X509_STORE_CTX_get0_untrusted" >&5
+$as_echo "$ac_cv_lib_crypto_X509_STORE_CTX_get0_untrusted" >&6; }
+if test "x$ac_cv_lib_crypto_X509_STORE_CTX_get0_untrusted" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_UNTRUSTED 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X509_STORE_CTX_set0_untrusted in -lcrypto" >&5
+$as_echo_n "checking for X509_STORE_CTX_set0_untrusted in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_X509_STORE_CTX_set0_untrusted+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char X509_STORE_CTX_set0_untrusted ();
+int
+main ()
+{
+return X509_STORE_CTX_set0_untrusted ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_X509_STORE_CTX_set0_untrusted=yes
+else
+  ac_cv_lib_crypto_X509_STORE_CTX_set0_untrusted=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_X509_STORE_CTX_set0_untrusted" >&5
+$as_echo "$ac_cv_lib_crypto_X509_STORE_CTX_set0_untrusted" >&6; }
+if test "x$ac_cv_lib_crypto_X509_STORE_CTX_set0_untrusted" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_X509_STORE_CTX_SET0_UNTRUSTED 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X509_up_ref in -lcrypto" >&5
+$as_echo_n "checking for X509_up_ref in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_X509_up_ref+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char X509_up_ref ();
+int
+main ()
+{
+return X509_up_ref ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_X509_up_ref=yes
+else
+  ac_cv_lib_crypto_X509_up_ref=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_X509_up_ref" >&5
+$as_echo "$ac_cv_lib_crypto_X509_up_ref" >&6; }
+if test "x$ac_cv_lib_crypto_X509_up_ref" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_X509_UP_REF 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X509_CRL_up_ref in -lcrypto" >&5
+$as_echo_n "checking for X509_CRL_up_ref in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_X509_CRL_up_ref+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char X509_CRL_up_ref ();
+int
+main ()
+{
+return X509_CRL_up_ref ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_X509_CRL_up_ref=yes
+else
+  ac_cv_lib_crypto_X509_CRL_up_ref=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_X509_CRL_up_ref" >&5
+$as_echo "$ac_cv_lib_crypto_X509_CRL_up_ref" >&6; }
+if test "x$ac_cv_lib_crypto_X509_CRL_up_ref" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_X509_CRL_UP_REF 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DH_up_ref in -lcrypto" >&5
+$as_echo_n "checking for DH_up_ref in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_DH_up_ref+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char DH_up_ref ();
+int
+main ()
+{
+return DH_up_ref ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_DH_up_ref=yes
+else
+  ac_cv_lib_crypto_DH_up_ref=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_DH_up_ref" >&5
+$as_echo "$ac_cv_lib_crypto_DH_up_ref" >&6; }
+if test "x$ac_cv_lib_crypto_DH_up_ref" = xyes; then :
+  $as_echo "#define HAVE_LIBCRYPTO_DH_UP_REF 1" >>confdefs.h
+
+fi
+
+
+# rollback state, key is check_openssl_libcrypto_api
+CFLAGS="${check_openssl_libcrypto_api_CFLAGS}"
+CXXFLAGS="${check_openssl_libcrypto_api_CXXFLAGS}"
+LDFLAGS="${check_openssl_libcrypto_api_LDFLAGS}"
+LIBS="${check_openssl_libcrypto_api_LIBS}"
+CC="${check_openssl_libcrypto_api_CC}"
+CXX="${check_openssl_libcrypto_api_CXX}"
+CPPFLAGS="${check_openssl_libcrypto_api_CPPFLAGS}"
+for squid_util_var_tosave in $check_openssl_libcrypto_api_squid_saved_vars
+do
+    squid_util_var_tosave2="\$check_openssl_libcrypto_api_${squid_util_var_tosave}"
+    eval "$squid_util_var_tosave=\"${squid_util_var_tosave2}\""
+done
+
+# commit state, key is check_openssl_libcrypto_api
+unset check_openssl_libcrypto_api_CFLAGS
+unset check_openssl_libcrypto_api_CXXFLAGS
+unset check_openssl_libcrypto_api_LDFLAGS
+unset check_openssl_libcrypto_api_LIBS
+unset check_openssl_libcrypto_api_CC
+unset check_openssl_libcrypto_api_CXX
+unset check_openssl_libcrypto_api_CPPFLAGS
+for squid_util_var_tosave in $check_openssl_libcrypto_api_squid_saved_vars
+do
+    unset ${squid_util_var_tosave}
+done
+
+
+
+
+
+
+
+
+# save state, key is check_openssl_libssl_api
+check_openssl_libssl_api_CFLAGS="${CFLAGS}"
+check_openssl_libssl_api_CXXFLAGS="${CXXFLAGS}"
+check_openssl_libssl_api_LDFLAGS="${LDFLAGS}"
+check_openssl_libssl_api_LIBS="${LIBS}"
+check_openssl_libssl_api_CC="${CC}"
+check_openssl_libssl_api_CXX="${CXX}"
+check_openssl_libssl_api_CPPFLAGS="${CPPFLAGS}"
+check_openssl_libssl_api_squid_saved_vars=""
+for squid_util_var_tosave in $check_openssl_libssl_api_squid_saved_vars
+do
+    squid_util_var_tosave2="check_openssl_libssl_api_${squid_util_var_tosave}"
+    eval "${squid_util_var_tosave2}=\"${squid_util_var_tosave}\""
+done
+
+  LIBS="$LIBS $SSLLIB"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_CIPHER_find in -lssl" >&5
+$as_echo_n "checking for SSL_CIPHER_find in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_SSL_CIPHER_find+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char SSL_CIPHER_find ();
+int
+main ()
+{
+return SSL_CIPHER_find ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_ssl_SSL_CIPHER_find=yes
+else
+  ac_cv_lib_ssl_SSL_CIPHER_find=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_CIPHER_find" >&5
+$as_echo "$ac_cv_lib_ssl_SSL_CIPHER_find" >&6; }
+if test "x$ac_cv_lib_ssl_SSL_CIPHER_find" = xyes; then :
+  $as_echo "#define HAVE_LIBSSL_SSL_CIPHER_FIND 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_CTX_set_tmp_rsa_callback in -lssl" >&5
+$as_echo_n "checking for SSL_CTX_set_tmp_rsa_callback in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_SSL_CTX_set_tmp_rsa_callback+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char SSL_CTX_set_tmp_rsa_callback ();
+int
+main ()
+{
+return SSL_CTX_set_tmp_rsa_callback ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_ssl_SSL_CTX_set_tmp_rsa_callback=yes
+else
+  ac_cv_lib_ssl_SSL_CTX_set_tmp_rsa_callback=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_CTX_set_tmp_rsa_callback" >&5
+$as_echo "$ac_cv_lib_ssl_SSL_CTX_set_tmp_rsa_callback" >&6; }
+if test "x$ac_cv_lib_ssl_SSL_CTX_set_tmp_rsa_callback" = xyes; then :
+  $as_echo "#define HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_SESSION_get_id in -lssl" >&5
+$as_echo_n "checking for SSL_SESSION_get_id in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_SSL_SESSION_get_id+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char SSL_SESSION_get_id ();
+int
+main ()
+{
+return SSL_SESSION_get_id ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_ssl_SSL_SESSION_get_id=yes
+else
+  ac_cv_lib_ssl_SSL_SESSION_get_id=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_SESSION_get_id" >&5
+$as_echo "$ac_cv_lib_ssl_SSL_SESSION_get_id" >&6; }
+if test "x$ac_cv_lib_ssl_SSL_SESSION_get_id" = xyes; then :
+  $as_echo "#define HAVE_LIBSSL_SSL_SESSION_GET_ID 1" >>confdefs.h
+
+fi
+
+
+# rollback state, key is check_openssl_libssl_api
+CFLAGS="${check_openssl_libssl_api_CFLAGS}"
+CXXFLAGS="${check_openssl_libssl_api_CXXFLAGS}"
+LDFLAGS="${check_openssl_libssl_api_LDFLAGS}"
+LIBS="${check_openssl_libssl_api_LIBS}"
+CC="${check_openssl_libssl_api_CC}"
+CXX="${check_openssl_libssl_api_CXX}"
+CPPFLAGS="${check_openssl_libssl_api_CPPFLAGS}"
+for squid_util_var_tosave in $check_openssl_libssl_api_squid_saved_vars
+do
+    squid_util_var_tosave2="\$check_openssl_libssl_api_${squid_util_var_tosave}"
+    eval "$squid_util_var_tosave=\"${squid_util_var_tosave2}\""
+done
+
+# commit state, key is check_openssl_libssl_api
+unset check_openssl_libssl_api_CFLAGS
+unset check_openssl_libssl_api_CXXFLAGS
+unset check_openssl_libssl_api_LDFLAGS
+unset check_openssl_libssl_api_LIBS
+unset check_openssl_libssl_api_CC
+unset check_openssl_libssl_api_CXX
+unset check_openssl_libssl_api_CPPFLAGS
+for squid_util_var_tosave in $check_openssl_libssl_api_squid_saved_vars
+do
+    unset ${squid_util_var_tosave}
+done
+
+
+
+
+
+
+
+
+# save state, key is check_openssl_TLS_METHODS
+check_openssl_TLS_METHODS_CFLAGS="${CFLAGS}"
+check_openssl_TLS_METHODS_CXXFLAGS="${CXXFLAGS}"
+check_openssl_TLS_METHODS_LDFLAGS="${LDFLAGS}"
+check_openssl_TLS_METHODS_LIBS="${LIBS}"
+check_openssl_TLS_METHODS_CC="${CC}"
+check_openssl_TLS_METHODS_CXX="${CXX}"
+check_openssl_TLS_METHODS_CPPFLAGS="${CPPFLAGS}"
+check_openssl_TLS_METHODS_squid_saved_vars=""
+for squid_util_var_tosave in $check_openssl_TLS_METHODS_squid_saved_vars
+do
+    squid_util_var_tosave2="check_openssl_TLS_METHODS_${squid_util_var_tosave}"
+    eval "${squid_util_var_tosave2}=\"${squid_util_var_tosave}\""
+done
+
+  LIBS="$LIBS $SSLLIB"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TLS_method in -lssl" >&5
+$as_echo_n "checking for TLS_method in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_TLS_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char TLS_method ();
+int
+main ()
+{
+return TLS_method ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_ssl_TLS_method=yes
+else
+  ac_cv_lib_ssl_TLS_method=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_TLS_method" >&5
+$as_echo "$ac_cv_lib_ssl_TLS_method" >&6; }
+if test "x$ac_cv_lib_ssl_TLS_method" = xyes; then :
+  $as_echo "#define HAVE_OPENSSL_TLS_METHOD 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TLS_client_method in -lssl" >&5
+$as_echo_n "checking for TLS_client_method in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_TLS_client_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char TLS_client_method ();
+int
+main ()
+{
+return TLS_client_method ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_ssl_TLS_client_method=yes
+else
+  ac_cv_lib_ssl_TLS_client_method=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_TLS_client_method" >&5
+$as_echo "$ac_cv_lib_ssl_TLS_client_method" >&6; }
+if test "x$ac_cv_lib_ssl_TLS_client_method" = xyes; then :
+  $as_echo "#define HAVE_OPENSSL_TLS_CLIENT_METHOD 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TLS_server_method in -lssl" >&5
+$as_echo_n "checking for TLS_server_method in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_TLS_server_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char TLS_server_method ();
+int
+main ()
+{
+return TLS_server_method ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_ssl_TLS_server_method=yes
+else
+  ac_cv_lib_ssl_TLS_server_method=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_TLS_server_method" >&5
+$as_echo "$ac_cv_lib_ssl_TLS_server_method" >&6; }
+if test "x$ac_cv_lib_ssl_TLS_server_method" = xyes; then :
+  $as_echo "#define HAVE_OPENSSL_TLS_SERVER_METHOD 1" >>confdefs.h
+
+fi
+
+
+# rollback state, key is check_openssl_TLS_METHODS
+CFLAGS="${check_openssl_TLS_METHODS_CFLAGS}"
+CXXFLAGS="${check_openssl_TLS_METHODS_CXXFLAGS}"
+LDFLAGS="${check_openssl_TLS_METHODS_LDFLAGS}"
+LIBS="${check_openssl_TLS_METHODS_LIBS}"
+CC="${check_openssl_TLS_METHODS_CC}"
+CXX="${check_openssl_TLS_METHODS_CXX}"
+CPPFLAGS="${check_openssl_TLS_METHODS_CPPFLAGS}"
+for squid_util_var_tosave in $check_openssl_TLS_METHODS_squid_saved_vars
+do
+    squid_util_var_tosave2="\$check_openssl_TLS_METHODS_${squid_util_var_tosave}"
+    eval "$squid_util_var_tosave=\"${squid_util_var_tosave2}\""
+done
+
+# commit state, key is check_openssl_TLS_METHODS
+unset check_openssl_TLS_METHODS_CFLAGS
+unset check_openssl_TLS_METHODS_CXXFLAGS
+unset check_openssl_TLS_METHODS_LDFLAGS
+unset check_openssl_TLS_METHODS_LIBS
+unset check_openssl_TLS_METHODS_CC
+unset check_openssl_TLS_METHODS_CXX
+unset check_openssl_TLS_METHODS_CPPFLAGS
+for squid_util_var_tosave in $check_openssl_TLS_METHODS_squid_saved_vars
+do
+    unset ${squid_util_var_tosave}
+done
+
+
+
+
+# save state, key is check_SSL_CTX_get0_certificate
+check_SSL_CTX_get0_certificate_CFLAGS="${CFLAGS}"
+check_SSL_CTX_get0_certificate_CXXFLAGS="${CXXFLAGS}"
+check_SSL_CTX_get0_certificate_LDFLAGS="${LDFLAGS}"
+check_SSL_CTX_get0_certificate_LIBS="${LIBS}"
+check_SSL_CTX_get0_certificate_CC="${CC}"
+check_SSL_CTX_get0_certificate_CXX="${CXX}"
+check_SSL_CTX_get0_certificate_CPPFLAGS="${CPPFLAGS}"
+check_SSL_CTX_get0_certificate_squid_saved_vars=""
+for squid_util_var_tosave in $check_SSL_CTX_get0_certificate_squid_saved_vars
+do
+    squid_util_var_tosave2="check_SSL_CTX_get0_certificate_${squid_util_var_tosave}"
+    eval "${squid_util_var_tosave2}=\"${squid_util_var_tosave}\""
+done
+
+    LIBS="$LIBS $SSLLIB"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_CTX_get0_certificate in -lssl" >&5
+$as_echo_n "checking for SSL_CTX_get0_certificate in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_SSL_CTX_get0_certificate+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char SSL_CTX_get0_certificate ();
+int
+main ()
+{
+return SSL_CTX_get0_certificate ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_ssl_SSL_CTX_get0_certificate=yes
+else
+  ac_cv_lib_ssl_SSL_CTX_get0_certificate=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_CTX_get0_certificate" >&5
+$as_echo "$ac_cv_lib_ssl_SSL_CTX_get0_certificate" >&6; }
+if test "x$ac_cv_lib_ssl_SSL_CTX_get0_certificate" = xyes; then :
+
+
+$as_echo "#define HAVE_SSL_CTX_GET0_CERTIFICATE 1" >>confdefs.h
+
+
+else
+
+          missing_SSL_CTX_get0_certificate=yes
+
+fi
+
+
+# rollback state, key is check_SSL_CTX_get0_certificate
+CFLAGS="${check_SSL_CTX_get0_certificate_CFLAGS}"
+CXXFLAGS="${check_SSL_CTX_get0_certificate_CXXFLAGS}"
+LDFLAGS="${check_SSL_CTX_get0_certificate_LDFLAGS}"
+LIBS="${check_SSL_CTX_get0_certificate_LIBS}"
+CC="${check_SSL_CTX_get0_certificate_CC}"
+CXX="${check_SSL_CTX_get0_certificate_CXX}"
+CPPFLAGS="${check_SSL_CTX_get0_certificate_CPPFLAGS}"
+for squid_util_var_tosave in $check_SSL_CTX_get0_certificate_squid_saved_vars
+do
+    squid_util_var_tosave2="\$check_SSL_CTX_get0_certificate_${squid_util_var_tosave}"
+    eval "$squid_util_var_tosave=\"${squid_util_var_tosave2}\""
+done
+
+# commit state, key is check_SSL_CTX_get0_certificate
+unset check_SSL_CTX_get0_certificate_CFLAGS
+unset check_SSL_CTX_get0_certificate_CXXFLAGS
+unset check_SSL_CTX_get0_certificate_LDFLAGS
+unset check_SSL_CTX_get0_certificate_LIBS
+unset check_SSL_CTX_get0_certificate_CC
+unset check_SSL_CTX_get0_certificate_CXX
+unset check_SSL_CTX_get0_certificate_CPPFLAGS
+for squid_util_var_tosave in $check_SSL_CTX_get0_certificate_squid_saved_vars
+do
+    unset ${squid_util_var_tosave}
+done
+
+
+
     # check for other specific broken implementations
+    if test "x$missing_SSL_CTX_get0_certificate" = "xyes"; then
 
 
 
@@ -23957,7 +24922,7 @@
 {
 
     SSLeay_add_ssl_algorithms();
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#if HAVE_OPENSSL_TLS_METHOD
     SSL_CTX *sslContext = SSL_CTX_new(TLS_method());
 #else
     SSL_CTX *sslContext = SSL_CTX_new(SSLv23_method());
@@ -24011,7 +24976,7 @@
 {
 
     SSLeay_add_ssl_algorithms();
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#if HAVE_OPENSSL_TLS_METHOD
     SSL_CTX *sslContext = SSL_CTX_new(TLS_method());
 #else
     SSL_CTX *sslContext = SSL_CTX_new(SSLv23_method());
@@ -24075,6 +25040,7 @@
 
 
 
+    fi
 
 
 
@@ -24164,6 +25130,174 @@
 
 
 
+# save state, key is check_const_CRYPTO_EX_DATA
+check_const_CRYPTO_EX_DATA_CFLAGS="${CFLAGS}"
+check_const_CRYPTO_EX_DATA_CXXFLAGS="${CXXFLAGS}"
+check_const_CRYPTO_EX_DATA_LDFLAGS="${LDFLAGS}"
+check_const_CRYPTO_EX_DATA_LIBS="${LIBS}"
+check_const_CRYPTO_EX_DATA_CC="${CC}"
+check_const_CRYPTO_EX_DATA_CXX="${CXX}"
+check_const_CRYPTO_EX_DATA_CPPFLAGS="${CPPFLAGS}"
+check_const_CRYPTO_EX_DATA_squid_saved_vars=""
+for squid_util_var_tosave in $check_const_CRYPTO_EX_DATA_squid_saved_vars
+do
+    squid_util_var_tosave2="check_const_CRYPTO_EX_DATA_${squid_util_var_tosave}"
+    eval "${squid_util_var_tosave2}=\"${squid_util_var_tosave}\""
+done
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether SSL_get_new_ex_index() dup callback accepts 'const CRYPTO_EX_DATA *'\"" >&5
+$as_echo_n "checking whether SSL_get_new_ex_index() dup callback accepts 'const CRYPTO_EX_DATA *'\"... " >&6; }
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <openssl/ssl.h>
+
+int const_dup_func(CRYPTO_EX_DATA *, const CRYPTO_EX_DATA *, void *, int, long, void *) {
+    return 0;
+}
+
+int
+main ()
+{
+
+return SSL_get_ex_new_index(0, (void*)"foo", NULL, &const_dup_func, NULL);
+
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+   $as_echo "#define SQUID_USE_CONST_CRYPTO_EX_DATA_DUP 1" >>confdefs.h
+
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# rollback state, key is check_const_CRYPTO_EX_DATA
+CFLAGS="${check_const_CRYPTO_EX_DATA_CFLAGS}"
+CXXFLAGS="${check_const_CRYPTO_EX_DATA_CXXFLAGS}"
+LDFLAGS="${check_const_CRYPTO_EX_DATA_LDFLAGS}"
+LIBS="${check_const_CRYPTO_EX_DATA_LIBS}"
+CC="${check_const_CRYPTO_EX_DATA_CC}"
+CXX="${check_const_CRYPTO_EX_DATA_CXX}"
+CPPFLAGS="${check_const_CRYPTO_EX_DATA_CPPFLAGS}"
+for squid_util_var_tosave in $check_const_CRYPTO_EX_DATA_squid_saved_vars
+do
+    squid_util_var_tosave2="\$check_const_CRYPTO_EX_DATA_${squid_util_var_tosave}"
+    eval "$squid_util_var_tosave=\"${squid_util_var_tosave2}\""
+done
+
+# commit state, key is check_const_CRYPTO_EX_DATA
+unset check_const_CRYPTO_EX_DATA_CFLAGS
+unset check_const_CRYPTO_EX_DATA_CXXFLAGS
+unset check_const_CRYPTO_EX_DATA_LDFLAGS
+unset check_const_CRYPTO_EX_DATA_LIBS
+unset check_const_CRYPTO_EX_DATA_CC
+unset check_const_CRYPTO_EX_DATA_CXX
+unset check_const_CRYPTO_EX_DATA_CPPFLAGS
+for squid_util_var_tosave in $check_const_CRYPTO_EX_DATA_squid_saved_vars
+do
+    unset ${squid_util_var_tosave}
+done
+
+
+
+
+
+
+# save state, key is check_const_SSL_CTX_sess_set_get_cb
+check_const_SSL_CTX_sess_set_get_cb_CFLAGS="${CFLAGS}"
+check_const_SSL_CTX_sess_set_get_cb_CXXFLAGS="${CXXFLAGS}"
+check_const_SSL_CTX_sess_set_get_cb_LDFLAGS="${LDFLAGS}"
+check_const_SSL_CTX_sess_set_get_cb_LIBS="${LIBS}"
+check_const_SSL_CTX_sess_set_get_cb_CC="${CC}"
+check_const_SSL_CTX_sess_set_get_cb_CXX="${CXX}"
+check_const_SSL_CTX_sess_set_get_cb_CPPFLAGS="${CPPFLAGS}"
+check_const_SSL_CTX_sess_set_get_cb_squid_saved_vars=""
+for squid_util_var_tosave in $check_const_SSL_CTX_sess_set_get_cb_squid_saved_vars
+do
+    squid_util_var_tosave2="check_const_SSL_CTX_sess_set_get_cb_${squid_util_var_tosave}"
+    eval "${squid_util_var_tosave2}=\"${squid_util_var_tosave}\""
+done
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether SSL_CTX_sess_set_get_cb() callback accepts a const ID argument\"" >&5
+$as_echo_n "checking whether SSL_CTX_sess_set_get_cb() callback accepts a const ID argument\"... " >&6; }
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <openssl/ssl.h>
+
+SSL_SESSION *get_session_cb(SSL *, const unsigned char *ID, int, int *) {
+    return NULL;
+}
+
+int
+main ()
+{
+
+SSL_CTX_sess_set_get_cb(NULL, get_session_cb);
+return 0;
+
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+   $as_echo "#define SQUID_USE_CONST_SSL_SESSION_CBID 1" >>confdefs.h
+
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# rollback state, key is check_const_SSL_CTX_sess_set_get_cb
+CFLAGS="${check_const_SSL_CTX_sess_set_get_cb_CFLAGS}"
+CXXFLAGS="${check_const_SSL_CTX_sess_set_get_cb_CXXFLAGS}"
+LDFLAGS="${check_const_SSL_CTX_sess_set_get_cb_LDFLAGS}"
+LIBS="${check_const_SSL_CTX_sess_set_get_cb_LIBS}"
+CC="${check_const_SSL_CTX_sess_set_get_cb_CC}"
+CXX="${check_const_SSL_CTX_sess_set_get_cb_CXX}"
+CPPFLAGS="${check_const_SSL_CTX_sess_set_get_cb_CPPFLAGS}"
+for squid_util_var_tosave in $check_const_SSL_CTX_sess_set_get_cb_squid_saved_vars
+do
+    squid_util_var_tosave2="\$check_const_SSL_CTX_sess_set_get_cb_${squid_util_var_tosave}"
+    eval "$squid_util_var_tosave=\"${squid_util_var_tosave2}\""
+done
+
+# commit state, key is check_const_SSL_CTX_sess_set_get_cb
+unset check_const_SSL_CTX_sess_set_get_cb_CFLAGS
+unset check_const_SSL_CTX_sess_set_get_cb_CXXFLAGS
+unset check_const_SSL_CTX_sess_set_get_cb_LDFLAGS
+unset check_const_SSL_CTX_sess_set_get_cb_LIBS
+unset check_const_SSL_CTX_sess_set_get_cb_CC
+unset check_const_SSL_CTX_sess_set_get_cb_CXX
+unset check_const_SSL_CTX_sess_set_get_cb_CPPFLAGS
+for squid_util_var_tosave in $check_const_SSL_CTX_sess_set_get_cb_squid_saved_vars
+do
+    unset ${squid_util_var_tosave}
+done
+
+
+
+
+
 
 
 
@@ -34652,15 +35786,23 @@
 
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-#include </usr/include/db.h>
+#include <db.h>
+int
+main ()
+{
 
+      DB *db = dbopen("/tmp", O_CREAT | O_RDWR, 0666, DB_BTREE, NULL);
+
+  ;
+  return 0;
+}
 _ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "dbopen" >/dev/null 2>&1; then :
-  BUILD_HELPER="time_quota"
-fi
-rm -f conftest*
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+      BUILD_HELPER="time_quota"
 
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 fi
 
@@ -42514,7 +43656,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by Squid Web Proxy $as_me 4.0.19, which was
+This file was extended by Squid Web Proxy $as_me 4.0.20, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -42580,7 +43722,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-Squid Web Proxy config.status 4.0.19
+Squid Web Proxy config.status 4.0.20
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -u -r -N squid-4.0.19/configure.ac squid-4.0.20/configure.ac
--- squid-4.0.19/configure.ac	2017-04-02 19:46:37.000000000 +1200
+++ squid-4.0.20/configure.ac	2017-06-02 01:01:44.000000000 +1200
@@ -5,7 +5,7 @@
 ## Please see the COPYING and CONTRIBUTORS files for details.
 ##
 
-AC_INIT([Squid Web Proxy],[4.0.19],[http://bugs.squid-cache.org/],[squid])
+AC_INIT([Squid Web Proxy],[4.0.20],[http://bugs.squid-cache.org/],[squid])
 AC_PREREQ(2.61)
 AC_CONFIG_HEADERS([include/autoconf.h])
 AC_CONFIG_AUX_DIR(cfgaux)
@@ -1347,9 +1347,26 @@
     SSLLIB="$LIBOPENSSL_PATH $LIBOPENSSL_LIBS $SSLLIB"
     AC_DEFINE(USE_OPENSSL,1,[OpenSSL support is available])
 
+    # check for API functions
+    SQUID_CHECK_LIBCRYPTO_API
+    SQUID_CHECK_LIBSSL_API
+    SQUID_CHECK_OPENSSL_TLS_METHODS
+    SQUID_STATE_SAVE(check_SSL_CTX_get0_certificate)
+    LIBS="$LIBS $SSLLIB"
+    AC_CHECK_LIB(ssl, SSL_CTX_get0_certificate, [
+      AC_DEFINE(HAVE_SSL_CTX_GET0_CERTIFICATE, 1, [SSL_CTX_get0_certificate is available])
+      ], [
+          missing_SSL_CTX_get0_certificate=yes
+      ])
+    SQUID_STATE_ROLLBACK(check_SSL_CTX_get0_certificate)
+
     # check for other specific broken implementations
-    SQUID_CHECK_OPENSSL_GETCERTIFICATE_WORKS
+    if test "x$missing_SSL_CTX_get0_certificate" = "xyes"; then
+      SQUID_CHECK_OPENSSL_GETCERTIFICATE_WORKS
+    fi
     SQUID_CHECK_OPENSSL_CONST_SSL_METHOD
+    SQUID_CHECK_OPENSSL_CONST_CRYPTO_EX_DATA
+    SQUID_CHECK_OPENSSL_CONST_SSL_SESSION_CB_ARG
     SQUID_CHECK_OPENSSL_TXTDB
     SQUID_CHECK_OPENSSL_HELLO_OVERWRITE_HACK
   fi
diff -u -r -N squid-4.0.19/doc/release-notes/release-4.html squid-4.0.20/doc/release-notes/release-4.html
--- squid-4.0.19/doc/release-notes/release-4.html	2017-04-02 23:47:27.000000000 +1200
+++ squid-4.0.20/doc/release-notes/release-4.html	2017-06-02 09:49:09.000000000 +1200
@@ -2,10 +2,10 @@
 <HTML>
 <HEAD>
  <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.72">
- <TITLE>Squid 4.0.19 release notes</TITLE>
+ <TITLE>Squid 4.0.20 release notes</TITLE>
 </HEAD>
 <BODY>
-<H1>Squid 4.0.19 release notes</H1>
+<H1>Squid 4.0.20 release notes</H1>
 
 <H2>Squid Developers</H2>
 <HR>
@@ -62,7 +62,7 @@
 <HR>
 <H2><A NAME="s1">1.</A> <A HREF="#toc1">Notice</A></H2>
 
-<P>The Squid Team are pleased to announce the release of Squid-4.0.19 for testing.</P>
+<P>The Squid Team are pleased to announce the release of Squid-4.0.20 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>
@@ -340,6 +340,8 @@
 <P>New <EM>connections_encrypted</EM> type for matching transactions
 where all HTTP messages were received over TLS transport connections,
 including messages received from ICAP servers.</P>
+<P>New <EM>has</EM> type for matching whether or not Squid is able to provide
+certain sets of transaction state. For example HTTP reply headers.</P>
 
 <DT><B>auth_param</B><DD>
 <P>New parameter <EM>queue-size=</EM> to set the maximum number
diff -u -r -N squid-4.0.19/include/autoconf.h.in squid-4.0.20/include/autoconf.h.in
--- squid-4.0.19/include/autoconf.h.in	2017-04-02 19:44:46.000000000 +1200
+++ squid-4.0.20/include/autoconf.h.in	2017-06-02 00:51:15.000000000 +1200
@@ -492,6 +492,43 @@
 /* Define to 1 if you have the `cap' library (-lcap). */
 #undef HAVE_LIBCAP
 
+/* "Define to 1 if the ASN1_STRING_get0_data() OpenSSL API function exists" */
+#undef HAVE_LIBCRYPTO_ASN1_STRING_GET0_DATA
+
+/* "Define to 1 if the BIO_get_init() OpenSSL API function exists" */
+#undef HAVE_LIBCRYPTO_BIO_GET_INIT
+
+/* "Define to 1 if the BIO_meth_new() OpenSSL API function exists" */
+#undef HAVE_LIBCRYPTO_BIO_METH_NEW
+
+/* "Define to 1 if the DH_up_ref() OpenSSL API function exists" */
+#undef HAVE_LIBCRYPTO_DH_UP_REF
+
+/* "Define to 1 if the EVP_PKEY_get0_RSA() OpenSSL API function exists" */
+#undef HAVE_LIBCRYPTO_EVP_PKEY_GET0_RSA
+
+/* "Define to 1 if the X509_CRL_up_ref() OpenSSL API function exists" */
+#undef HAVE_LIBCRYPTO_X509_CRL_UP_REF
+
+/* "Define to 1 if the X509_STORE_CTX_get0_cert() OpenSSL API function exists"
+   */
+#undef HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_CERT
+
+/* "Define to 1 if the X509_STORE_CTX_get0_untrusted() OpenSSL API function
+   exists" */
+#undef HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_UNTRUSTED
+
+/* "Define to 1 if the X509_STORE_CTX_set0_untrusted() OpenSSL API function
+   exists" */
+#undef HAVE_LIBCRYPTO_X509_STORE_CTX_SET0_UNTRUSTED
+
+/* "Define to 1 if the X509_up_ref() OpenSSL API function exists" */
+#undef HAVE_LIBCRYPTO_X509_UP_REF
+
+/* "Define to 1 if the X509_VERIFY_PARAM_get_depth() OpenSSL API function
+   exists" */
+#undef HAVE_LIBCRYPTO_X509_VERIFY_PARAM_GET_DEPTH
+
 /* Define to 1 if you have the <libc.h> header file. */
 #undef HAVE_LIBC_H
 
@@ -521,6 +558,16 @@
    <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h> header file. */
 #undef HAVE_LIBNETFILTER_CONNTRACK_LIBNETFILTER_CONNTRACK_TCP_H
 
+/* "Define to 1 if the SSL_CIPHER_find() OpenSSL API function exists" */
+#undef HAVE_LIBSSL_SSL_CIPHER_FIND
+
+/* "Define to 1 if the SSL_CTX_set_tmp_rsa_callback() OpenSSL API function
+   exists" */
+#undef HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
+
+/* "Define to 1 if the SSL_SESSION_get_id() OpenSSL API function exists" */
+#undef HAVE_LIBSSL_SSL_SESSION_GET_ID
+
 /* Define to 1 if you have the libxml2 library */
 #undef HAVE_LIBXML2
 
@@ -717,6 +764,15 @@
 /* Define to 1 if you have the <openssl/ssl.h> header file. */
 #undef HAVE_OPENSSL_SSL_H
 
+/* "Define to 1 if the TLS_client_method() OpenSSL API function exists" */
+#undef HAVE_OPENSSL_TLS_CLIENT_METHOD
+
+/* "Define to 1 if the TLS_method() OpenSSL API function exists" */
+#undef HAVE_OPENSSL_TLS_METHOD
+
+/* "Define to 1 if the TLS_server_method() OpenSSL API function exists" */
+#undef HAVE_OPENSSL_TLS_SERVER_METHOD
+
 /* Define to 1 if you have the <openssl/txt_db.h> header file. */
 #undef HAVE_OPENSSL_TXT_DB_H
 
@@ -887,6 +943,9 @@
 /* SPNEGO support */
 #undef HAVE_SPNEGO
 
+/* SSL_CTX_get0_certificate is available */
+#undef HAVE_SSL_CTX_GET0_CERTIFICATE
+
 /* Define if sockaddr_storage has field ss_len */
 #undef HAVE_SS_LEN_IN_SS
 
@@ -1312,10 +1371,18 @@
 /* TCP send buffer size */
 #undef SQUID_TCP_SO_SNDBUF
 
+/* "Define to 1 if the SSL_get_new_ex_index() dup callback accepts 'const
+   CRYPTO_EX_DATA *'" */
+#undef SQUID_USE_CONST_CRYPTO_EX_DATA_DUP
+
 /* "Define to 1 if the SSL_CTX_new and similar openSSL API functions require
    'const SSL_METHOD *'" */
 #undef SQUID_USE_CONST_SSL_METHOD
 
+/* "Define to 1 if the SSL_CTX_sess_set_get_cb() callback accepts a const ID
+   argument" */
+#undef SQUID_USE_CONST_SSL_SESSION_CBID
+
 /* "Define to 1 if hello message can be overwritten in SSL struct" */
 #undef SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK
 
diff -u -r -N squid-4.0.19/include/version.h squid-4.0.20/include/version.h
--- squid-4.0.19/include/version.h	2017-04-02 19:46:37.000000000 +1200
+++ squid-4.0.20/include/version.h	2017-06-02 01:01:44.000000000 +1200
@@ -7,7 +7,7 @@
  */
 
 #ifndef SQUID_RELEASE_TIME
-#define SQUID_RELEASE_TIME 1491119016
+#define SQUID_RELEASE_TIME 1496321346
 #endif
 
 /*
diff -u -r -N squid-4.0.19/RELEASENOTES.html squid-4.0.20/RELEASENOTES.html
--- squid-4.0.19/RELEASENOTES.html	2017-04-02 23:47:27.000000000 +1200
+++ squid-4.0.20/RELEASENOTES.html	2017-06-02 09:49:09.000000000 +1200
@@ -2,10 +2,10 @@
 <HTML>
 <HEAD>
  <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.72">
- <TITLE>Squid 4.0.19 release notes</TITLE>
+ <TITLE>Squid 4.0.20 release notes</TITLE>
 </HEAD>
 <BODY>
-<H1>Squid 4.0.19 release notes</H1>
+<H1>Squid 4.0.20 release notes</H1>
 
 <H2>Squid Developers</H2>
 <HR>
@@ -62,7 +62,7 @@
 <HR>
 <H2><A NAME="s1">1.</A> <A HREF="#toc1">Notice</A></H2>
 
-<P>The Squid Team are pleased to announce the release of Squid-4.0.19 for testing.</P>
+<P>The Squid Team are pleased to announce the release of Squid-4.0.20 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>
@@ -340,6 +340,8 @@
 <P>New <EM>connections_encrypted</EM> type for matching transactions
 where all HTTP messages were received over TLS transport connections,
 including messages received from ICAP servers.</P>
+<P>New <EM>has</EM> type for matching whether or not Squid is able to provide
+certain sets of transaction state. For example HTTP reply headers.</P>
 
 <DT><B>auth_param</B><DD>
 <P>New parameter <EM>queue-size=</EM> to set the maximum number
diff -u -r -N squid-4.0.19/src/acl/external/delayer/ext_delayer_acl.8 squid-4.0.20/src/acl/external/delayer/ext_delayer_acl.8
--- squid-4.0.19/src/acl/external/delayer/ext_delayer_acl.8	2017-04-02 23:48:24.000000000 +1200
+++ squid-4.0.20/src/acl/external/delayer/ext_delayer_acl.8	2017-06-02 09:52:23.000000000 +1200
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_DELAYER_ACL 8"
-.TH EXT_DELAYER_ACL 8 "2017-04-02" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH EXT_DELAYER_ACL 8 "2017-06-01" "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.19/src/acl/external/file_userip/ext_file_userip_acl.8 squid-4.0.20/src/acl/external/file_userip/ext_file_userip_acl.8
--- squid-4.0.19/src/acl/external/file_userip/ext_file_userip_acl.8	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/acl/external/file_userip/ext_file_userip_acl.8	2017-06-02 00:49:17.000000000 +1200
@@ -68,7 +68,7 @@
 .B ALL 
 and 
 .B NONE 
-, which mean \"any user on this IP address may authenticate\" or \"no user on this IP address may authenticate\".
+, which mean \(dqany user on this IP address may authenticate\(dq or \(dqno user on this IP address may authenticate\(dq.
 .
 .SH AUTHOR
 This program was written by
diff -u -r -N squid-4.0.19/src/acl/external/session/ext_session_acl.cc squid-4.0.20/src/acl/external/session/ext_session_acl.cc
--- squid-4.0.19/src/acl/external/session/ext_session_acl.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/acl/external/session/ext_session_acl.cc	2017-06-02 00:49:17.000000000 +1200
@@ -210,6 +210,11 @@
                 action = -1;
                 detail_len = (size_t)(lastdetail-detail);
                 *lastdetail = '\0';
+            } else if (!default_action && strcmp(lastdetail, " -") == 0) {
+                // no action; LOGIN/LOGOUT not supplied
+                // but truncate the '-' %DATA value given by Squid-4 and later
+                detail_len = (size_t)(lastdetail-detail);
+                *lastdetail = '\0';
             }
         }
         if (action == -1) {
diff -u -r -N squid-4.0.19/src/acl/external/SQL_session/ext_sql_session_acl.8 squid-4.0.20/src/acl/external/SQL_session/ext_sql_session_acl.8
--- squid-4.0.19/src/acl/external/SQL_session/ext_sql_session_acl.8	2017-04-02 23:48:36.000000000 +1200
+++ squid-4.0.20/src/acl/external/SQL_session/ext_sql_session_acl.8	2017-06-02 09:52:58.000000000 +1200
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_SQL_SESSION_ACL 8"
-.TH EXT_SQL_SESSION_ACL 8 "2017-04-02" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH EXT_SQL_SESSION_ACL 8 "2017-06-01" "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.19/src/acl/external/time_quota/required.m4 squid-4.0.20/src/acl/external/time_quota/required.m4
--- squid-4.0.19/src/acl/external/time_quota/required.m4	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/acl/external/time_quota/required.m4	2017-06-02 00:49:17.000000000 +1200
@@ -7,6 +7,10 @@
 
 AC_CHECK_HEADERS(db_185.h,[BUILD_HELPER="time_quota"],[
   AC_CHECK_HEADERS(db.h,[
-    AC_EGREP_HEADER([dbopen],[/usr/include/db.h],[BUILD_HELPER="time_quota"])
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <db.h>]],[[
+      DB *db = dbopen("/tmp", O_CREAT | O_RDWR, 0666, DB_BTREE, NULL);
+    ]])],[
+      BUILD_HELPER="time_quota"
+    ],[])
   ])
 ])
diff -u -r -N squid-4.0.19/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 squid-4.0.20/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8
--- squid-4.0.19/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8	2017-04-02 23:48:41.000000000 +1200
+++ squid-4.0.20/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8	2017-06-02 09:53:11.000000000 +1200
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "EXT_WBINFO_GROUP_ACL 8"
-.TH EXT_WBINFO_GROUP_ACL 8 "2017-04-02" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH EXT_WBINFO_GROUP_ACL 8 "2017-06-01" "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.19/src/acl/FilledChecklist.h squid-4.0.20/src/acl/FilledChecklist.h
--- squid-4.0.19/src/acl/FilledChecklist.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/acl/FilledChecklist.h	2017-06-02 00:49:17.000000000 +1200
@@ -35,7 +35,7 @@
 
 public:
     ACLFilledChecklist();
-    ACLFilledChecklist(const acl_access *, HttpRequest *, const char *ident);
+    ACLFilledChecklist(const acl_access *, HttpRequest *, const char *ident = nullptr);
     ~ACLFilledChecklist();
 
 public:
diff -u -r -N squid-4.0.19/src/acl/HasComponent.cc squid-4.0.20/src/acl/HasComponent.cc
--- squid-4.0.19/src/acl/HasComponent.cc	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.20/src/acl/HasComponent.cc	2017-06-02 00:49:17.000000000 +1200
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "acl/HasComponent.h"
+#include "acl/HasComponentData.h"
+
+int
+ACLHasComponentStrategy::match(ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &flags)
+{
+    ACLHasComponentData *cdata = dynamic_cast<ACLHasComponentData*>(data);
+    assert(cdata);
+    return cdata->match(checklist);
+}
+
+ACLHasComponentStrategy *
+ACLHasComponentStrategy::Instance()
+{
+    return &Instance_;
+}
+
+ACLHasComponentStrategy ACLHasComponentStrategy::Instance_;
+
diff -u -r -N squid-4.0.19/src/acl/HasComponentData.cc squid-4.0.20/src/acl/HasComponentData.cc
--- squid-4.0.19/src/acl/HasComponentData.cc	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.20/src/acl/HasComponentData.cc	2017-06-02 00:49:17.000000000 +1200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "acl/HasComponentData.h"
+#include "cache_cf.h"
+#include "ConfigParser.h"
+#include "sbuf/Algorithms.h"
+
+const SBuf ACLHasComponentData::RequestStr("request");
+const SBuf ACLHasComponentData::ResponseStr("response");
+const SBuf ACLHasComponentData::AleStr("ALE");
+
+ACLHasComponentData::ACLHasComponentData()
+    : componentMethods(coEnd, nullptr)
+{ }
+
+void
+ACLHasComponentData::parse()
+{
+    const char *tok = ConfigParser::NextToken();
+    if (!tok) {
+        debugs(28, DBG_CRITICAL, "FATAL: \"has\" acl argument missing");
+        self_destruct();
+        return;
+    }
+    if (ConfigParser::PeekAtToken()) {
+        debugs(28, DBG_CRITICAL, "FATAL: multiple components not supported for \"has\" acl");
+        self_destruct();
+        return;
+    }
+    parseComponent(tok);
+}
+
+bool
+ACLHasComponentData::match(ACLChecklist *checklist)
+{
+    for (const auto method: componentMethods)
+        if (method && (checklist->*method)())
+            return true;
+    return false;
+}
+
+SBufList
+ACLHasComponentData::dump() const
+{
+    SBufList sl;
+    if (componentMethods.at(coRequest))
+        sl.push_back(RequestStr);
+    if (componentMethods.at(coResponse))
+        sl.push_back(ResponseStr);
+    if (componentMethods.at(coAle))
+        sl.push_back(AleStr);
+    return sl;
+}
+
+void
+ACLHasComponentData::parseComponent(const char *token)
+{
+    if (RequestStr.cmp(token) == 0)
+        componentMethods[coRequest] = &ACLChecklist::hasRequest;
+    else if (ResponseStr.cmp(token) == 0)
+        componentMethods[coResponse] = &ACLChecklist::hasReply;
+    else if (AleStr.cmp(token) == 0)
+        componentMethods[coAle] = &ACLChecklist::hasAle;
+    else {
+        debugs(28, DBG_CRITICAL, "FATAL: unsupported component '" << token << "' for 'has' acl");
+        self_destruct();
+    }
+}
+
+ACLData<ACLChecklist *> *
+ACLHasComponentData::clone() const
+{
+    return new ACLHasComponentData(*this);
+}
+
diff -u -r -N squid-4.0.19/src/acl/HasComponentData.h squid-4.0.20/src/acl/HasComponentData.h
--- squid-4.0.19/src/acl/HasComponentData.h	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.20/src/acl/HasComponentData.h	2017-06-02 00:49:17.000000000 +1200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_ACLHASCOMPONENTDATA_H
+#define SQUID_ACLHASCOMPONENTDATA_H
+
+#include "acl/Checklist.h"
+#include "acl/Data.h"
+
+/// \ingroup ACLAPI
+class ACLHasComponentData : public ACLData<ACLChecklist *>
+{
+    MEMPROXY_CLASS(ACLHasComponentData);
+
+public:
+    ACLHasComponentData();
+
+    /* ACLData<M> API */
+    virtual bool match(ACLChecklist *) override;
+    virtual SBufList dump() const override;
+    virtual void parse() override;
+    virtual bool empty() const override { return false; }
+    virtual ACLData<ACLChecklist *> *clone() const override;
+
+private:
+    enum ComponentKind { coRequest = 0, coResponse, coAle, coEnd };
+    void parseComponent(const char *token);
+
+    static const SBuf RequestStr;
+    static const SBuf ResponseStr;
+    static const SBuf AleStr;
+
+    typedef bool (ACLChecklist::*ComponentCheck)() const;
+    /// component check callbacks, ordered by component kind ID
+    std::vector<ComponentCheck> componentMethods;
+};
+
+#endif
+
diff -u -r -N squid-4.0.19/src/acl/HasComponent.h squid-4.0.20/src/acl/HasComponent.h
--- squid-4.0.19/src/acl/HasComponent.h	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.20/src/acl/HasComponent.h	2017-06-02 00:49:17.000000000 +1200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_ACLHASCOMPONENT_H
+#define SQUID_ACLHASCOMPONENT_H
+
+#include "acl/Strategised.h"
+#include "acl/Strategy.h"
+
+/// \ingroup ACLAPI
+class ACLHasComponentStrategy : public ACLStrategy<ACLChecklist *>
+{
+public:
+    static ACLHasComponentStrategy *Instance();
+    ACLHasComponentStrategy(ACLHasComponentStrategy const &) = delete;
+    ACLHasComponentStrategy& operator=(ACLHasComponentStrategy const &) = delete;
+    virtual int match(ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
+
+private:
+    static ACLHasComponentStrategy Instance_;
+    ACLHasComponentStrategy() { }
+};
+
+/// \ingroup ACLAPI
+class ACLHasComponent
+{
+private:
+    static ACL::Prototype RegistryProtoype;
+    static ACLStrategised<ACLChecklist *> RegistryEntry_;
+};
+
+#endif
+
diff -u -r -N squid-4.0.19/src/acl/HttpHeaderData.cc squid-4.0.20/src/acl/HttpHeaderData.cc
--- squid-4.0.19/src/acl/HttpHeaderData.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/acl/HttpHeaderData.cc	2017-06-02 00:49:17.000000000 +1200
@@ -48,7 +48,7 @@
             return false;
         value = hdr->getStrOrList(hdrId);
     } else {
-        if (!hdr->getByNameIfPresent(hdrName, value))
+        if (!hdr->hasNamed(hdrName, &value))
             return false;
     }
 
diff -u -r -N squid-4.0.19/src/acl/Makefile.am squid-4.0.20/src/acl/Makefile.am
--- squid-4.0.19/src/acl/Makefile.am	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/acl/Makefile.am	2017-06-02 00:49:17.000000000 +1200
@@ -69,6 +69,10 @@
 	DomainData.h \
 	ExtUser.cc \
 	ExtUser.h \
+	HasComponent.cc \
+	HasComponent.h \
+	HasComponentData.cc \
+	HasComponentData.h \
 	HierCodeData.cc \
 	HierCodeData.h \
 	HierCode.cc \
diff -u -r -N squid-4.0.19/src/acl/Makefile.in squid-4.0.20/src/acl/Makefile.in
--- squid-4.0.19/src/acl/Makefile.in	2017-04-02 19:45:35.000000000 +1200
+++ squid-4.0.20/src/acl/Makefile.in	2017-06-02 00:54:27.000000000 +1200
@@ -173,8 +173,9 @@
 	ConnectionsEncrypted.h DestinationAsn.h DestinationDomain.cc \
 	DestinationDomain.h DestinationIp.cc DestinationIp.h \
 	DomainData.cc DomainData.h ExtUser.cc ExtUser.h \
-	HierCodeData.cc HierCodeData.h HierCode.cc HierCode.h \
-	HttpHeaderData.cc HttpHeaderData.h HttpRepHeader.cc \
+	HasComponent.cc HasComponent.h HasComponentData.cc \
+	HasComponentData.h HierCodeData.cc HierCodeData.h HierCode.cc \
+	HierCode.h HttpHeaderData.cc HttpHeaderData.h HttpRepHeader.cc \
 	HttpRepHeader.h HttpReqHeader.cc HttpReqHeader.h HttpStatus.cc \
 	HttpStatus.h Ip.cc Ip.h LocalIp.cc LocalIp.h LocalPort.cc \
 	LocalPort.h MaxConnection.cc MaxConnection.h Method.cc \
@@ -208,12 +209,12 @@
 am_libacls_la_OBJECTS = IntRange.lo RegexData.lo StringData.lo Time.lo \
 	TimeData.lo AllOf.lo AnyOf.lo Asn.lo Browser.lo \
 	ConnectionsEncrypted.lo DestinationDomain.lo DestinationIp.lo \
-	DomainData.lo ExtUser.lo HierCodeData.lo HierCode.lo \
-	HttpHeaderData.lo HttpRepHeader.lo HttpReqHeader.lo \
-	HttpStatus.lo Ip.lo LocalIp.lo LocalPort.lo MaxConnection.lo \
-	Method.lo MethodData.lo MyPortName.lo Note.lo NoteData.lo \
-	PeerName.lo Protocol.lo ProtocolData.lo Random.lo Referer.lo \
-	ReplyMimeType.lo RequestMimeType.lo SourceDomain.lo \
+	DomainData.lo ExtUser.lo HasComponent.lo HasComponentData.lo \
+	HierCodeData.lo HierCode.lo HttpHeaderData.lo HttpRepHeader.lo \
+	HttpReqHeader.lo HttpStatus.lo Ip.lo LocalIp.lo LocalPort.lo \
+	MaxConnection.lo Method.lo MethodData.lo MyPortName.lo Note.lo \
+	NoteData.lo PeerName.lo Protocol.lo ProtocolData.lo Random.lo \
+	Referer.lo ReplyMimeType.lo RequestMimeType.lo SourceDomain.lo \
 	SourceIp.lo SquidError.lo SquidErrorData.lo Tag.lo Url.lo \
 	UrlLogin.lo UrlPath.lo UrlPort.lo UserData.lo Gadgets.lo \
 	AclSizeLimit.lo $(am__objects_2) $(am__objects_4) \
@@ -848,8 +849,9 @@
 	ConnectionsEncrypted.h DestinationAsn.h DestinationDomain.cc \
 	DestinationDomain.h DestinationIp.cc DestinationIp.h \
 	DomainData.cc DomainData.h ExtUser.cc ExtUser.h \
-	HierCodeData.cc HierCodeData.h HierCode.cc HierCode.h \
-	HttpHeaderData.cc HttpHeaderData.h HttpRepHeader.cc \
+	HasComponent.cc HasComponent.h HasComponentData.cc \
+	HasComponentData.h HierCodeData.cc HierCodeData.h HierCode.cc \
+	HierCode.h HttpHeaderData.cc HttpHeaderData.h HttpRepHeader.cc \
 	HttpRepHeader.h HttpReqHeader.cc HttpReqHeader.h HttpStatus.cc \
 	HttpStatus.h Ip.cc Ip.h LocalIp.cc LocalIp.h LocalPort.cc \
 	LocalPort.h MaxConnection.cc MaxConnection.h Method.cc \
@@ -986,6 +988,8 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ExtUser.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FilledChecklist.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Gadgets.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HasComponent.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HasComponentData.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HierCode.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HierCodeData.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpHeaderData.Plo@am__quote@
diff -u -r -N squid-4.0.19/src/AclRegs.cc squid-4.0.20/src/AclRegs.cc
--- squid-4.0.19/src/AclRegs.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/AclRegs.cc	2017-06-02 00:49:17.000000000 +1200
@@ -41,6 +41,8 @@
 #endif
 #include "acl/FilledChecklist.h"
 #include "acl/Gadgets.h"
+#include "acl/HasComponent.h"
+#include "acl/HasComponentData.h"
 #include "acl/HierCode.h"
 #include "acl/HierCodeData.h"
 #include "acl/HttpHeaderData.h"
@@ -235,3 +237,6 @@
 ACL::Prototype Acl::ConnectionsEncrypted::RegistryProtoype(&Acl::ConnectionsEncrypted::RegistryEntry_, "connections_encrypted");
 Acl::ConnectionsEncrypted Acl::ConnectionsEncrypted::RegistryEntry_("connections_encrypted");
 
+ACL::Prototype ACLHasComponent::RegistryProtoype(&ACLHasComponent::RegistryEntry_, "has");
+ACLStrategised<ACLChecklist *> ACLHasComponent::RegistryEntry_(new ACLHasComponentData, ACLHasComponentStrategy::Instance(), "has");
+
diff -u -r -N squid-4.0.19/src/adaptation/ecap/MessageRep.cc squid-4.0.20/src/adaptation/ecap/MessageRep.cc
--- squid-4.0.19/src/adaptation/ecap/MessageRep.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/adaptation/ecap/MessageRep.cc	2017-06-02 00:49:17.000000000 +1200
@@ -33,10 +33,9 @@
 Adaptation::Ecap::HeaderRep::hasAny(const Name &name) const
 {
     const Http::HdrType squidId = TranslateHeaderId(name);
-    // XXX: optimize to remove getByName: we do not need the value here
     return squidId == Http::HdrType::OTHER ?
-           theHeader.getByName(name.image().c_str()).size() > 0:
-           (bool)theHeader.has(squidId);
+           theHeader.hasNamed(name.image().c_str(), name.image().size()) :
+           static_cast<bool>(theHeader.has(squidId));
 }
 
 Adaptation::Ecap::HeaderRep::Value
diff -u -r -N squid-4.0.19/src/auth/basic/DB/basic_db_auth.8 squid-4.0.20/src/auth/basic/DB/basic_db_auth.8
--- squid-4.0.19/src/auth/basic/DB/basic_db_auth.8	2017-04-02 23:49:15.000000000 +1200
+++ squid-4.0.20/src/auth/basic/DB/basic_db_auth.8	2017-06-02 09:55:21.000000000 +1200
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "BASIC_DB_AUTH 8"
-.TH BASIC_DB_AUTH 8 "2017-04-02" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH BASIC_DB_AUTH 8 "2017-06-01" "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.19/src/auth/basic/LDAP/basic_ldap_auth.8 squid-4.0.20/src/auth/basic/LDAP/basic_ldap_auth.8
--- squid-4.0.19/src/auth/basic/LDAP/basic_ldap_auth.8	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/auth/basic/LDAP/basic_ldap_auth.8	2017-06-02 00:49:17.000000000 +1200
@@ -5,9 +5,9 @@
 .
 .SH SYNOPSIS
 .if !'po4a'hide' .B basic_ldap_auth
-.if !'po4a'hide' .B \-b\ \"
+.if !'po4a'hide' .B \-b\ \(dq
 base DN
-.if !'po4a'hide' .B \"\ [\-u
+.if !'po4a'hide' .B \(dq\ [\-u
 attribute
 .if !'po4a'hide' .B ]\ [
 options
@@ -20,11 +20,11 @@
 .if !'po4a'hide' .B ]...
 .br
 .if !'po4a'hide' .B basic_ldap_auth
-.if !'po4a'hide' .B \-b\ \"
+.if !'po4a'hide' .B \-b\ \(dq
 base DN
-.if !'po4a'hide' .B \"\ \-f\ \"
+.if !'po4a'hide' .B \(dq\ \-f\ \(dq
 LDAP search filter
-.if !'po4a'hide' .B \"\ [
+.if !'po4a'hide' .B \(dq\ [
 options
 .if !'po4a'hide' .B ]\ [
 LDAP server name
@@ -74,7 +74,7 @@
 The search filter can contain up to 15 occurrences of
 .B %s
 which will be replaced by the username, as in
-.B "\"uid\=%s\""
+.B "\(dquid\=%s\(dq"
 for RFC2037 directories. For a detailed description of LDAP search
 filter syntax see RFC2254.
 .br
diff -u -r -N squid-4.0.19/src/auth/basic/POP3/basic_pop3_auth.8 squid-4.0.20/src/auth/basic/POP3/basic_pop3_auth.8
--- squid-4.0.19/src/auth/basic/POP3/basic_pop3_auth.8	2017-04-02 23:49:25.000000000 +1200
+++ squid-4.0.20/src/auth/basic/POP3/basic_pop3_auth.8	2017-06-02 09:56:01.000000000 +1200
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "BASIC_POP3_AUTH 8"
-.TH BASIC_POP3_AUTH 8 "2017-04-02" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH BASIC_POP3_AUTH 8 "2017-06-01" "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.19/src/auth/basic/RADIUS/basic_radius_auth.8 squid-4.0.20/src/auth/basic/RADIUS/basic_radius_auth.8
--- squid-4.0.19/src/auth/basic/RADIUS/basic_radius_auth.8	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/auth/basic/RADIUS/basic_radius_auth.8	2017-06-02 00:49:17.000000000 +1200
@@ -9,9 +9,9 @@
 config file
 .br
 .if !'po4a'hide' .B basic_radius_auth
-.if !'po4a'hide' .B "\-h \""
+.if !'po4a'hide' .B "\-h \(dq"
 server name
-.if !'po4a'hide' .B "\" [\-p "
+.if !'po4a'hide' .B "\(dq [\-p "
 port
 .if !'po4a'hide' .B "] [\-i "
 identifier
diff -u -r -N squid-4.0.19/src/base/File.cc squid-4.0.20/src/base/File.cc
--- squid-4.0.19/src/base/File.cc	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.20/src/base/File.cc	2017-06-02 00:49:17.000000000 +1200
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "base/File.h"
+#include "Debug.h"
+#include "sbuf/Stream.h"
+#include "tools.h"
+#include "xusleep.h"
+
+#include <utility>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* FileOpeningConfig */
+
+FileOpeningConfig
+FileOpeningConfig::ReadOnly()
+{
+    FileOpeningConfig cfg;
+
+    /* I/O */
+#if _SQUID_WINDOWS_
+    cfg.desiredAccess = GENERIC_READ;
+    cfg.shareMode = FILE_SHARE_READ;
+#else
+    cfg.openFlags = O_RDONLY;
+#endif
+
+    /* locking (if enabled later) */
+#if _SQUID_WINDOWS_
+    cfg.lockFlags = 0; // no named constant for a shared lock
+#elif _SQUID_SOLARIS_
+    cfg.lockType = F_RDLCK;
+#else
+    cfg.flockMode = LOCK_SH | LOCK_NB;
+#endif
+
+    return cfg;
+}
+
+FileOpeningConfig
+FileOpeningConfig::ReadWrite()
+{
+    FileOpeningConfig cfg;
+
+    /* I/O */
+#if _SQUID_WINDOWS_
+    cfg.desiredAccess = GENERIC_READ | GENERIC_WRITE;
+    cfg.shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+#else
+    cfg.openFlags = O_RDWR;
+#endif
+
+    /* locking (if enabled later) */
+#if _SQUID_WINDOWS_
+    cfg.lockFlags = LOCKFILE_EXCLUSIVE_LOCK;
+#elif _SQUID_SOLARIS_
+    cfg.lockType = F_WRLCK;
+#else
+    cfg.flockMode = LOCK_EX | LOCK_NB;
+#endif
+
+    return cfg;
+}
+
+FileOpeningConfig &
+FileOpeningConfig::locked(unsigned int attempts)
+{
+    lockAttempts = attempts;
+    // for simplicity, correct locking flags are preset in constructing methods
+    return *this;
+}
+
+FileOpeningConfig &
+FileOpeningConfig::createdIfMissing()
+{
+#if _SQUID_WINDOWS_
+    Must((desiredAccess & GENERIC_WRITE) == GENERIC_WRITE);
+    creationDisposition = OPEN_ALWAYS;
+#else
+    Must((openFlags & O_RDWR) == O_RDWR);
+    openFlags |= O_CREAT;
+    creationMask = (S_IXUSR | S_IXGRP|S_IWGRP | S_IXOTH|S_IWOTH); // unwanted bits
+#endif
+    return *this;
+}
+
+/* File */
+
+#if _SQUID_SOLARIS_
+// XXX: fcntl() locks are incompatible with complex applications that may lock
+// multiple open descriptors corresponding to the same underlying file. There is
+// nothing better on Solaris, but do not be tempted to use this elsewhere. For
+// more info, see http://bugs.squid-cache.org/show_bug.cgi?id=4212#c14
+/// fcntl(... struct flock) convenience wrapper
+int
+fcntlLock(const int fd, const short lockType)
+{
+    // the exact composition and order of flock data members is unknown!
+    struct flock fl;
+    memset(&fl, 0, sizeof(fl));
+    fl.l_type = lockType;
+    fl.l_whence = SEEK_SET; // with zero l_len and l_start, means "whole file"
+    return ::fcntl(fd, F_SETLK, &fl);
+}
+#endif // _SQUID_SOLARIS_
+
+File *
+File::Optional(const SBuf &filename, const FileOpeningConfig &cfg)
+{
+    try {
+        return new File(filename, cfg);
+    }
+    catch (const std::exception &ex) {
+        debugs(54, 5, "will not lock: " << ex.what());
+    }
+    return nullptr;
+}
+
+File::File(const SBuf &aName, const FileOpeningConfig &cfg):
+    name_(aName)
+{
+    debugs(54, 7, "constructing, this=" << this << ' ' << name_);
+    // close the file during post-open constructor exceptions
+    try {
+        open(cfg);
+        lock(cfg);
+    }
+    catch (...)
+    {
+        close();
+        throw;
+    }
+}
+
+File::~File()
+{
+    debugs(54, 7, "destructing, this=" << this << ' ' << name_);
+    close();
+}
+
+File::File(File &&other)
+{
+    *this = std::move(other);
+}
+
+File &
+File::operator = (File &&other)
+{
+    std::swap(fd_, other.fd_);
+    return *this;
+}
+
+/// opens (or creates) the file
+void
+File::open(const FileOpeningConfig &cfg)
+{
+#if _SQUID_WINDOWS_
+    fd_ = CreateFile(TEXT(name_.c_str()), desiredAccess, shareMode, nullptr, creationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
+    if (fd_ == InvalidHandle) {
+        const auto savedError = GetLastError();
+        throw TexcHere(sysCallFailure("CreateFile", WindowsErrorMessage(savedError).c_str()));
+    }
+#else
+    mode_t oldCreationMask = 0;
+    const auto filename = name_.c_str(); // avoid complex operations inside enter_suid()
+    enter_suid();
+    if (cfg.creationMask)
+        oldCreationMask = umask(cfg.creationMask); // XXX: Why here? Should not this be set for the whole Squid?
+    fd_ = ::open(filename, cfg.openFlags, cfg.openMode);
+    const auto savedErrno = errno;
+    if (cfg.creationMask)
+        umask(oldCreationMask);
+    leave_suid();
+    if (fd_ < 0)
+        throw TexcHere(sysCallError("open", savedErrno));
+#endif
+}
+
+void
+File::close()
+{
+    if (!isOpen())
+        return;
+#if _SQUID_WINDOWS_
+    if (!CloseHandle(fd_)) {
+        const auto savedError = GetLastError();
+        debugs(54, DBG_IMPORTANT, sysCallFailure("CloseHandle", WindowsErrorMessage(savedError)));
+    }
+#else
+    if (::close(fd_) != 0) {
+        const auto savedErrno = errno;
+        debugs(54, DBG_IMPORTANT, sysCallError("close", savedErrno));
+    }
+#endif
+    // closing the file handler implicitly removes all associated locks
+}
+
+void
+File::truncate()
+{
+#if _SQUID_WINDOWS_
+    if (!SetFilePointer(fd_, 0, nullptr, FILE_BEGIN)) {
+        const auto savedError = GetLastError();
+        throw TexcHere(sysCallFailure("SetFilePointer", WindowsErrorMessage(savedError).c_str()));
+    }
+
+    if (!SetEndOfFile(fd_)) {
+        const auto savedError = GetLastError();
+        throw TexcHere(sysCallFailure("SetEndOfFile", WindowsErrorMessage(savedError).c_str()));
+    }
+#else
+    if (::lseek(fd_, SEEK_SET, 0) < 0) {
+        const auto savedErrno = errno;
+        throw TexcHere(sysCallError("lseek", savedErrno));
+    }
+
+    if (::ftruncate(fd_, 0) != 0) {
+        const auto savedErrno = errno;
+        throw TexcHere(sysCallError("ftruncate", savedErrno));
+    }
+#endif
+}
+
+SBuf
+File::readSmall(const SBuf::size_type minBytes, const SBuf::size_type maxBytes)
+{
+    SBuf buf;
+    const auto readLimit = maxBytes + 1; // to detect excessively large files that we do not handle
+#if _SQUID_WINDOWS_
+    DWORD result = 0;
+    if (!ReadFile(fd_, buf.rawSpace(readLimit), readLimit, &result, nullptr)) {
+        const auto savedError = GetLastError();
+        throw TexcHere(sysCallFailure("ReadFile", WindowsErrorMessage(savedError).c_str()));
+    }
+#else
+    const auto result = ::read(fd_, buf.rawSpace(readLimit), readLimit);
+    if (result < 0) {
+        const auto savedErrno = errno;
+        throw TexcHere(sysCallError("read", savedErrno));
+    }
+#endif
+    const auto bytesRead = static_cast<size_t>(result);
+    assert(bytesRead <= readLimit);
+    Must(!buf.length());
+    buf.forceSize(bytesRead);
+
+    if (buf.length() < minBytes) {
+        const auto failure = buf.length() ? "premature eof" : "empty file";
+        throw TexcHere(sysCallFailure("read", failure));
+    }
+
+    if (buf.length() > maxBytes) {
+        const auto failure = "unreasonably large file";
+        throw TexcHere(sysCallFailure("read", failure));
+    }
+
+    Must(minBytes <= buf.length() && buf.length() <= maxBytes);
+    return buf;
+}
+
+void
+File::writeAll(const SBuf &data)
+{
+#if _SQUID_WINDOWS_
+    DWORD nBytesWritten = 0;
+    if (!WriteFile(fd_, data.rawContent(), data.length(), &nBytesWritten, nullptr)) {
+        const auto savedError = GetLastError();
+        throw TexcHere(sysCallFailure("WriteFile", WindowsErrorMessage(savedError).c_str()));
+    }
+    const auto bytesWritten = static_cast<size_t>(nBytesWritten);
+#else
+    const auto result = ::write(fd_, data.rawContent(), data.length());
+    if (result < 0) {
+        const auto savedErrno = errno;
+        throw TexcHere(sysCallError("write", savedErrno));
+    }
+    const auto bytesWritten = static_cast<size_t>(result);
+#endif
+    if (bytesWritten != data.length())
+        throw TexcHere(sysCallFailure("write", "partial write"));
+}
+
+void
+File::synchronize()
+{
+#if _SQUID_WINDOWS_
+    if (!FlushFileBuffers(fd_)) {
+        const auto savedError = GetLastError();
+        throw TexcHere(sysCallFailure("FlushFileBuffers", WindowsErrorMessage(savedError).c_str()));
+    }
+#else
+    if (::fsync(fd_) != 0) {
+        const auto savedErrno = errno;
+        throw TexcHere(sysCallError("fsync", savedErrno));
+    }
+#endif
+}
+
+/// calls lockOnce() as many times as necessary (including zero)
+void
+File::lock(const FileOpeningConfig &cfg)
+{
+    unsigned int attemptsLeft = cfg.lockAttempts;
+    while (attemptsLeft) {
+        try {
+            --attemptsLeft;
+            return lockOnce(cfg);
+        } catch (const std::exception &ex) {
+            if (!attemptsLeft)
+                throw;
+            debugs(54, 4, "sleeping and then trying up to " << attemptsLeft <<
+                   " more time(s) after a failure: " << ex.what());
+        }
+        Must(attemptsLeft); // the catch statement handles the last attempt
+        xusleep(cfg.RetryGapUsec);
+    }
+    debugs(54, 9, "disabled");
+}
+
+/// locks, blocking or returning immediately depending on the lock waiting mode
+void
+File::lockOnce(const FileOpeningConfig &cfg)
+{
+#if _SQUID_WINDOWS_
+    if (!LockFileEx(fd_, cfg.lockFlags, 0, 0, 1, 0)) {
+        const auto savedError = GetLastError();
+        throw TexcHere(sysCallFailure("LockFileEx", WindowsErrorMessage(savedError).c_str()));
+    }
+#elif _SQUID_SOLARIS_
+    if (fcntlLock(fd_, cfg.lockType) != 0) {
+        const auto savedErrno = errno;
+        throw TexcHere(sysCallError("fcntl(flock)", savedErrno));
+    }
+#else
+    if (::flock(fd_, cfg.flockMode) != 0) {
+        const auto savedErrno = errno;
+        throw TexcHere(sysCallError("flock", savedErrno));
+    }
+#endif
+    debugs(54, 3, "succeeded for " << name_);
+}
+
+/// \returns a description a system call-related failure
+SBuf
+File::sysCallFailure(const char *callName, const char *error) const
+{
+    return ToSBuf("failed to ", callName, ' ', name_, ": ", error);
+}
+
+/// \returns a description of an errno-based system call failure
+SBuf
+File::sysCallError(const char *callName, const int savedErrno) const
+{
+    return sysCallFailure(callName, xstrerr(savedErrno));
+}
+
diff -u -r -N squid-4.0.19/src/base/File.h squid-4.0.20/src/base/File.h
--- squid-4.0.19/src/base/File.h	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.20/src/base/File.h	2017-06-02 00:49:17.000000000 +1200
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_BASE_FILE_H
+#define SQUID_BASE_FILE_H
+
+#include "sbuf/SBuf.h"
+
+/// How should a file be opened/created? Should it be locked?
+class FileOpeningConfig
+{
+public:
+    static FileOpeningConfig ReadOnly(); // shared reading
+    static FileOpeningConfig ReadWrite(); // exclusive creation and/or reading/writing
+
+    /* adjustment methods; named to work well with the File::Be::X shorthand */
+
+    /// protect concurrent accesses by attempting to obtain an appropriate lock
+    FileOpeningConfig &locked(unsigned int attempts = 5);
+
+    /// when opening a file for writing, create it if it does not exist
+    FileOpeningConfig &createdIfMissing();
+
+    /// enter_suid() to open the file; leaves suid ASAP after that
+    FileOpeningConfig &openedByRoot() { openByRoot = true; return *this; }
+
+    /* add more mode adjustment methods as needed */
+
+private:
+    friend class File;
+
+    /* file opening parameters */
+#if _SQUID_WINDOWS_
+    DWORD desiredAccess = 0; ///< 2nd CreateFile() parameter
+    DWORD shareMode = 0; ///< 3rd CreateFile() parameter
+    DWORD creationDisposition = OPEN_EXISTING; ///< 5th CreateFile() parameter
+#else
+    mode_t creationMask = 0; ///< umask() parameter; the default is S_IWGRP|S_IWOTH
+    int openFlags = 0; ///< opening flags; 2nd open(2) parameter
+    mode_t openMode = 0644; ///< access mode; 3rd open(2) parameter
+#endif
+
+    /* file locking (disabled unless lock(n) sets positive lockAttempts) */
+#if _SQUID_WINDOWS_
+    DWORD lockFlags = 0; ///< 2nd LockFileEx() parameter
+#elif _SQUID_SOLARIS_
+    int lockType = F_UNLCK; ///< flock::type member for fcntl(F_SETLK)
+#else
+    int flockMode = LOCK_UN; ///< 2nd flock(2) parameter
+#endif
+    static const unsigned int RetryGapUsec = 500000; /// pause before each lock retry
+    unsigned int lockAttempts = 0; ///< how many times to try locking
+    bool openByRoot = false;
+};
+
+/// a portable locking-aware exception-friendly file (with RAII API)
+class File
+{
+public:
+    typedef FileOpeningConfig Be; ///< convenient shorthand for File() callers
+
+    /// \returns nil if File() throws or a new File object (otherwise)
+    static File *Optional(const SBuf &aName, const FileOpeningConfig &cfg);
+
+    File(const SBuf &aFilename, const FileOpeningConfig &cfg); ///< opens
+    ~File(); ///< closes
+
+    /* can move but cannot copy */
+    File(const File &) = delete;
+    File &operator = (const File &) = delete;
+    File(File &&other);
+    File &operator = (File &&other);
+
+    const SBuf &name() const { return name_; }
+
+    /* system call wrappers */
+
+    /// makes the file size (and the current I/O offset) zero
+    void truncate();
+    SBuf readSmall(SBuf::size_type minBytes, SBuf::size_type maxBytes); ///< read(2) for small files
+    void writeAll(const SBuf &data); ///< write(2) with a "wrote everything" check
+    void synchronize(); ///< fsync(2)
+
+protected:
+    bool isOpen() const {
+#if _SQUID_WINDOWS_
+        return fd_ != InvalidHandle;
+#else
+        return fd_ >= 0;
+#endif
+    }
+
+    void open(const FileOpeningConfig &cfg);
+    void lock(const FileOpeningConfig &cfg);
+    void lockOnce(const FileOpeningConfig &cfg);
+    void close();
+
+    /// \returns a description a system call-related failure
+    SBuf sysCallFailure(const char *callName, const char *error) const;
+    /// \returns a description of an errno-based system call failure
+    SBuf sysCallError(const char *callName, const int savedErrno) const;
+
+private:
+    SBuf name_; ///< location on disk
+
+    // Windows-specific HANDLE is needed because LockFileEx() does not take POSIX FDs.
+#if _SQUID_WINDOWS_
+    typedef HANDLE Handle;
+    static const Handle InvalidHandle = INVALID_HANDLE_VALUE;
+#else
+    typedef int Handle;
+    static const Handle InvalidHandle = -1;
+#endif
+    Handle fd_ = InvalidHandle; ///< OS-specific file handle
+};
+
+#endif
+
diff -u -r -N squid-4.0.19/src/base/Makefile.am squid-4.0.20/src/base/Makefile.am
--- squid-4.0.19/src/base/Makefile.am	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/base/Makefile.am	2017-06-02 00:49:17.000000000 +1200
@@ -25,6 +25,8 @@
 	CharacterSet.h \
 	CharacterSet.cc \
 	EnumIterator.h \
+	File.h \
+	File.cc \
 	HardFun.h \
 	InstanceId.h \
 	Lock.h \
diff -u -r -N squid-4.0.19/src/base/Makefile.in squid-4.0.20/src/base/Makefile.in
--- squid-4.0.19/src/base/Makefile.in	2017-04-02 19:46:02.000000000 +1200
+++ squid-4.0.20/src/base/Makefile.in	2017-06-02 00:58:40.000000000 +1200
@@ -164,7 +164,7 @@
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 libbase_la_LIBADD =
 am_libbase_la_OBJECTS = AsyncCall.lo AsyncJob.lo AsyncCallQueue.lo \
-	CharacterSet.lo RegexPattern.lo RunnersRegistry.lo \
+	CharacterSet.lo File.lo RegexPattern.lo RunnersRegistry.lo \
 	TextException.lo
 libbase_la_OBJECTS = $(am_libbase_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -729,6 +729,8 @@
 	CharacterSet.h \
 	CharacterSet.cc \
 	EnumIterator.h \
+	File.h \
+	File.cc \
 	HardFun.h \
 	InstanceId.h \
 	Lock.h \
@@ -813,6 +815,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AsyncCallQueue.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AsyncJob.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CharacterSet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/File.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RegexPattern.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RunnersRegistry.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TextException.Plo@am__quote@
diff -u -r -N squid-4.0.19/src/base/TextException.cc squid-4.0.20/src/base/TextException.cc
--- squid-4.0.19/src/base/TextException.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/base/TextException.cc	2017-06-02 00:49:17.000000000 +1200
@@ -9,6 +9,7 @@
 #include "squid.h"
 #include "base/TextException.h"
 #include "Debug.h"
+#include "sbuf/SBuf.h"
 #include "util.h"
 
 TextException::TextException()
@@ -28,6 +29,10 @@
     message(aMsg?xstrdup(aMsg):NULL), theFileName(aFileName), theLineNo(aLineNo), theId(anId)
 {}
 
+TextException::TextException(SBuf msg, const char *aFileName, int aLineNo, unsigned int anId):
+    TextException(msg.c_str(), aFileName, aLineNo, anId)
+{}
+
 TextException::~TextException() throw()
 {
     if (message) xfree(message);
diff -u -r -N squid-4.0.19/src/base/TextException.h squid-4.0.20/src/base/TextException.h
--- squid-4.0.19/src/base/TextException.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/base/TextException.h	2017-06-02 00:49:17.000000000 +1200
@@ -13,6 +13,8 @@
 
 #include <exception>
 
+class SBuf;
+
 static unsigned int FileNameHashCached(const char *fname);
 
 // simple exception to report custom errors
@@ -24,6 +26,7 @@
 public:
     TextException();
     TextException(const char *aMessage, const char *aFileName = 0, int aLineNo = -1, unsigned int anId =0);
+    TextException(SBuf aMessage, const char *aFileName = 0, int aLineNo = -1, unsigned int anId =0);
     TextException(const TextException& right);
     virtual ~TextException() throw();
 
diff -u -r -N squid-4.0.19/src/cache_cf.cc squid-4.0.20/src/cache_cf.cc
--- squid-4.0.19/src/cache_cf.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/cache_cf.cc	2017-06-02 00:49:17.000000000 +1200
@@ -2205,7 +2205,7 @@
         } else if (!strcmp(token, "auth-no-keytab")) {
             p->options.auth_no_keytab = 1;
         } else if (!strncmp(token, "connect-timeout=", 16)) {
-            p->connect_timeout = xatoi(token + 16);
+            p->connect_timeout_raw = xatoi(token + 16);
         } else if (!strncmp(token, "connect-fail-limit=", 19)) {
             p->connect_fail_limit = xatoi(token + 19);
 #if USE_CACHE_DIGESTS
diff -u -r -N squid-4.0.19/src/CachePeer.cc squid-4.0.20/src/CachePeer.cc
--- squid-4.0.19/src/CachePeer.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/CachePeer.cc	2017-06-02 00:49:17.000000000 +1200
@@ -31,12 +31,13 @@
     digest_url(NULL),
 #endif
     tcp_up(0),
+    reprobe(false),
     n_addresses(0),
     rr_count(0),
     next(NULL),
     testing_now(false),
     login(NULL),
-    connect_timeout(0),
+    connect_timeout_raw(0),
     connect_fail_limit(0),
     max_conn(0),
     domain(NULL),
diff -u -r -N squid-4.0.19/src/CachePeer.h squid-4.0.20/src/CachePeer.h
--- squid-4.0.19/src/CachePeer.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/CachePeer.h	2017-06-02 00:49:17.000000000 +1200
@@ -144,6 +144,8 @@
 #endif
 
     int tcp_up;         /* 0 if a connect() fails */
+    /// whether to do another TCP probe after current TCP probes
+    bool reprobe;
 
     Ip::Address addresses[10];
     int n_addresses;
@@ -170,7 +172,7 @@
     } sourcehash;
 
     char *login;        /* Proxy authorization */
-    time_t connect_timeout;
+    time_t connect_timeout_raw; ///< connect_timeout; use peerConnectTimeout() instead!
     int connect_fail_limit;
     int max_conn;
     struct {
diff -u -r -N squid-4.0.19/src/cf.data.pre squid-4.0.20/src/cf.data.pre
--- squid-4.0.19/src/cf.data.pre	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/cf.data.pre	2017-06-02 00:49:17.000000000 +1200
@@ -1242,6 +1242,33 @@
 	  # adaptation_meta because it starts matching immediately after
 	  # the service has been selected for adaptation.
 
+	acl aclname has component
+	  # matches a transaction "component" [fast]
+	  #
+	  # Supported transaction components are:
+	  #  request: transaction has a request header (at least)
+	  #  response: transaction has a response header (at least)
+	  #  ALE: transaction has an internally-generated Access Log Entry
+	  #       structure; bugs notwithstanding, all transaction have it
+	  #
+	  # For example, the following configuration helps when dealing with HTTP
+	  # clients that close connections without sending a request header:
+	  #
+	  #  acl hasRequest has request
+	  #  acl logMe note important_transaction
+	  #  # avoid "logMe ACL is used in context without an HTTP request" warnings
+	  #  access_log ... logformat=detailed hasRequest logMe
+	  #  # log request-less transactions, instead of ignoring them
+	  #  access_log ... logformat=brief !hasRequest
+	  #
+	  # Multiple components are not supported for one "acl" rule, but
+	  # can be specified (and are ORed) using multiple same-name rules:
+	  #
+	  #  # OK, this strange logging daemon needs request or response,
+	  #  # but can work without either a request or a response:
+	  #  acl hasWhatMyLoggingDaemonNeeds has request
+	  #  acl hasWhatMyLoggingDaemonNeeds has response
+
 IF USE_OPENSSL
 	acl aclname ssl_error errorname
 	  # match against SSL certificate validation error [fast]
@@ -2753,8 +2780,11 @@
 		This is the default action.
 
 	    bump
-		Establish a secure connection with the server and, using a
-		mimicked server certificate, with the client.
+		When used on step SslBump1, establishes a secure connection
+		with the client first, then connect to the server.
+		When used on step SslBump2 or SslBump3, establishes a secure
+		connection with the server and, using a mimicked server
+		certificate, with the client.
 
 	    peek
 		Receive client (step SslBump1) or server (step SslBump2)
@@ -4308,13 +4338,14 @@
 				For CONNECT requests that initiated bumping of
 				a connection and for any request received on
 				an already bumped connection, Squid logs the
-				corresponding SslBump mode ("server-first" or
-				"client-first"). See the ssl_bump option for
-				more information about these modes.
+				corresponding SslBump mode ("splice", "bump",
+				"peek", "stare", "terminate", "server-first"
+				or "client-first"). See the ssl_bump option 
+				for more information about these modes.
 
 				A "none" token is logged for requests that
 				triggered "ssl_bump" ACL evaluation matching
-				either a "none" rule or no rules at all.
+				a "none" rule.
 
 				In all other cases, a single dash ("-") is
 				logged.
diff -u -r -N squid-4.0.19/src/clients/FtpGateway.cc squid-4.0.20/src/clients/FtpGateway.cc
--- squid-4.0.19/src/clients/FtpGateway.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/clients/FtpGateway.cc	2017-06-02 00:49:17.000000000 +1200
@@ -619,10 +619,17 @@
                 while (strchr(w_space, *copyFrom))
                     ++copyFrom;
             } else {
-                /* XXX assumes a single space between date and filename
+                /* Handle the following four formats:
+                 * "MMM DD  YYYY Name"
+                 * "MMM DD  YYYYName"
+                 * "MMM DD YYYY  Name"
+                 * "MMM DD YYYY Name"
+                 * Assuming a single space between date and filename
                  * suggested by:  Nathan.Bailey@cc.monash.edu.au and
                  * Mike Battersby <mike@starbug.bofh.asn.au> */
-                copyFrom += strlen(tbuf) + 1;
+                copyFrom += strlen(tbuf);
+                if (strchr(w_space, *copyFrom))
+                    ++copyFrom;
             }
 
             p->name = xstrdup(copyFrom);
@@ -1507,7 +1514,7 @@
         /* Reset cwd_message to only include the last message */
         ftpState->cwd_message.reset("");
         for (wordlist *w = ftpState->ctrl.message; w; w = w->next) {
-            ftpState->cwd_message.append(' ');
+            ftpState->cwd_message.append('\n');
             ftpState->cwd_message.append(w->key);
         }
         ftpState->ctrl.message = NULL;
diff -u -r -N squid-4.0.19/src/client_side.cc squid-4.0.20/src/client_side.cc
--- squid-4.0.19/src/client_side.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/client_side.cc	2017-06-02 00:49:17.000000000 +1200
@@ -2727,8 +2727,6 @@
 
 /**
  * A callback function to use with the ACLFilledChecklist callback.
- * In the case of ACCESS_ALLOWED answer initializes a bumped SSL connection,
- * else reverts the connection to tunnel mode.
  */
 static void
 httpsSslBumpAccessCheckDone(allow_t answer, void *data)
@@ -2739,15 +2737,19 @@
     if (!connState->isOpen())
         return;
 
-    // Require both a match and a positive bump mode to work around exceptional
-    // cases where ACL code may return ACCESS_ALLOWED with zero answer.kind.
-    if (answer == ACCESS_ALLOWED && answer.kind != Ssl::bumpNone) {
-        debugs(33, 2, "sslBump needed for " << connState->clientConnection << " method " << answer.kind);
+    if (answer == ACCESS_ALLOWED) {
+        debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
         connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
     } else {
-        debugs(33, 2, HERE << "sslBump not needed for " << connState->clientConnection);
-        connState->sslBumpMode = Ssl::bumpNone;
+        debugs(33, 3, "sslBump not needed for " << connState->clientConnection);
+        connState->sslBumpMode = Ssl::bumpSplice;
+    }
+
+    if (connState->sslBumpMode == Ssl::bumpTerminate) {
+        connState->clientConnection->close();
+        return;
     }
+
     if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf))
         connState->clientConnection->close();
 }
@@ -3145,8 +3147,9 @@
 
     parsingTlsHandshake = false;
 
-    if (mayTunnelUnsupportedProto())
-        preservedClientData = inBuf;
+    // client data may be needed for splicing and for
+    // tunneling unsupportedProtocol after an error
+    preservedClientData = inBuf;
 
     // Even if the parser failed, each TLS detail should either be set
     // correctly or still be "unknown"; copying unknown detail is a no-op.
@@ -3167,7 +3170,8 @@
         Must(context && context->http);
         HttpRequest::Pointer request = context->http->request;
         debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump.");
-        sslBumpMode = Ssl::bumpNone;
+        sslBumpMode = Ssl::bumpSplice;
+        context->http->al->ssl.bumpMode = Ssl::bumpSplice;
         if (!clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_PROTOCOL_UNKNOWN))
             clientConnection->close();
         return;
@@ -3203,6 +3207,9 @@
 
     connState->serverBump()->act.step2 = bumpAction;
     connState->sslBumpMode = bumpAction;
+    Http::StreamPointer context = connState->pipeline.front();
+    if (ClientHttpRequest *http = (context ? context->http : nullptr))
+        http->al->ssl.bumpMode = bumpAction;
 
     if (bumpAction == Ssl::bumpTerminate) {
         connState->clientConnection->close();
@@ -3228,9 +3235,23 @@
     transferProtocol = Http::ProtocolVersion();
     assert(!pipeline.empty());
     Http::StreamPointer context = pipeline.front();
+    Must(context);
+    Must(context->http);
     ClientHttpRequest *http = context->http;
-    tunnelStart(http);
-    return true;
+    HttpRequest::Pointer request = http->request;
+    context->finished();
+    if (transparent()) {
+        // For transparent connections, make a new fake CONNECT request, now
+        // with SNI as target. doCallout() checks, adaptations may need that.
+        return fakeAConnectRequest("splice", preservedClientData);
+    } else {
+        // For non transparent connections  make a new tunneled CONNECT, which
+        // also sets the HttpRequest::flags::forceTunnel flag to avoid
+        // respond with "Connection Established" to the client.
+        // This fake CONNECT request required to allow use of SNI in
+        // doCallout() checks and adaptations.
+        return initiateTunneledRequest(request, Http::METHOD_CONNECT, "splice", preservedClientData);
+    }
 }
 
 void
@@ -3338,7 +3359,8 @@
 
     if (pinning.serverConnection != nullptr) {
         static char ip[MAX_IPSTRLEN];
-        connectHost.assign(pinning.serverConnection->remote.toStr(ip, sizeof(ip)));
+        pinning.serverConnection->remote.toHostStr(ip, sizeof(ip));
+        connectHost.assign(ip);
         connectPort = pinning.serverConnection->remote.port();
     } else if (cause && cause->method == Http::METHOD_CONNECT) {
         // We are inside a (not fully established) CONNECT request
@@ -3375,7 +3397,8 @@
 #endif
     {
         static char ip[MAX_IPSTRLEN];
-        connectHost.assign(clientConnection->local.toStr(ip, sizeof(ip)));
+        clientConnection->local.toHostStr(ip, sizeof(ip));
+        connectHost.assign(ip);
     }
 
     ClientHttpRequest *http = buildFakeRequest(Http::METHOD_CONNECT, connectHost, connectPort, payload);
diff -u -r -N squid-4.0.19/src/client_side_request.cc squid-4.0.20/src/client_side_request.cc
--- squid-4.0.19/src/client_side_request.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/client_side_request.cc	2017-06-02 00:49:17.000000000 +1200
@@ -193,7 +193,7 @@
 {
     assert(request);
     return request->cache_control &&
-           request->cache_control->onlyIfCached();
+           request->cache_control->hasOnlyIfCached();
 }
 
 /**
@@ -1415,17 +1415,29 @@
         return false;
     }
 
+    const Ssl::BumpMode bumpMode = http->getConn()->sslBumpMode;
     if (http->request->flags.forceTunnel) {
         debugs(85, 5, "not needed; already decided to tunnel " << http->getConn());
+        if (bumpMode != Ssl::bumpEnd)
+            http->al->ssl.bumpMode = bumpMode; // inherited from bumped connection
         return false;
     }
 
     // If SSL connection tunneling or bumping decision has been made, obey it.
-    const Ssl::BumpMode bumpMode = http->getConn()->sslBumpMode;
     if (bumpMode != Ssl::bumpEnd) {
         debugs(85, 5, HERE << "SslBump already decided (" << bumpMode <<
                "), " << "ignoring ssl_bump for " << http->getConn());
-        if (!http->getConn()->serverBump())
+
+        // We need the following "if" for transparently bumped TLS connection,
+        // because in this case we are running ssl_bump access list before
+        // the doCallouts runs. It can be removed after the bug #4340 fixed.
+        // We do not want to proceed to bumping steps:
+        //  - if the TLS connection with the client is already established
+        //    because we are accepting normal HTTP requests on TLS port,
+        //    or because of the client-first bumping mode
+        //  - When the bumping is already started
+        if (!http->getConn()->switchedToHttps() &&
+                !http->getConn()->serverBump())
             http->sslBumpNeed(bumpMode); // for processRequest() to bump if needed and not already bumped
         http->al->ssl.bumpMode = bumpMode; // inherited from bumped connection
         return false;
@@ -1487,10 +1499,19 @@
         return;
 
     const Ssl::BumpMode bumpMode = answer == ACCESS_ALLOWED ?
-                                   static_cast<Ssl::BumpMode>(answer.kind) : Ssl::bumpNone;
+                                   static_cast<Ssl::BumpMode>(answer.kind) : Ssl::bumpSplice;
     http->sslBumpNeed(bumpMode); // for processRequest() to bump if needed
     http->al->ssl.bumpMode = bumpMode; // for logging
 
+    if (bumpMode == Ssl::bumpTerminate) {
+        const Comm::ConnectionPointer clientConn = http->getConn() ? http->getConn()->clientConnection : nullptr;
+        if (Comm::IsConnOpen(clientConn)) {
+            debugs(85, 3, "closing after Ssl::bumpTerminate ");
+            clientConn->close();
+        }
+        return;
+    }
+
     http->doCallouts();
 }
 #endif
diff -u -r -N squid-4.0.19/src/comm/Connection.cc squid-4.0.20/src/comm/Connection.cc
--- squid-4.0.19/src/comm/Connection.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/comm/Connection.cc	2017-06-02 00:49:17.000000000 +1200
@@ -12,6 +12,7 @@
 #include "comm.h"
 #include "comm/Connection.h"
 #include "fde.h"
+#include "FwdState.h"
 #include "neighbors.h"
 #include "security/NegotiationHistory.h"
 #include "SquidConfig.h"
@@ -131,3 +132,23 @@
     return tlsHistory;
 }
 
+time_t
+Comm::Connection::connectTimeout(const time_t fwdStart) const
+{
+    // a connection opening timeout (ignoring forwarding time limits for now)
+    const CachePeer *peer = getPeer();
+    const time_t ctimeout = peer ? peerConnectTimeout(peer) : Config.Timeout.connect;
+
+    // time we have left to finish the whole forwarding process
+    const time_t fwdTimeLeft = FwdState::ForwardTimeout(fwdStart);
+
+    // The caller decided to connect. If there is no time left, to protect
+    // connecting code from trying to establish a connection while a zero (i.e.,
+    // "immediate") timeout notification is firing, ensure a positive timeout.
+    // XXX: This hack gives some timed-out forwarding sequences more time than
+    // some sequences that have not quite reached the forwarding timeout yet!
+    const time_t ftimeout = fwdTimeLeft ? fwdTimeLeft : 5; // seconds
+
+    return min(ctimeout, ftimeout);
+}
+
diff -u -r -N squid-4.0.19/src/comm/Connection.h squid-4.0.20/src/comm/Connection.h
--- squid-4.0.19/src/comm/Connection.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/comm/Connection.h	2017-06-02 00:49:17.000000000 +1200
@@ -111,6 +111,13 @@
     /** The time left for this connection*/
     time_t timeLeft(const time_t idleTimeout) const;
 
+    /// Connection establishment timeout for callers that have already decided
+    /// to connect(2), either for the first time or after checking
+    /// EnoughTimeToReForward() during any re-forwarding attempts.
+    /// \returns the time left for this connection to become connected
+    /// \param fwdStart The start time of the peer selection/connection process.
+    time_t connectTimeout(const time_t fwdStart) const;
+
     void noteStart() {startTime_ = squid_curtime;}
 
     Security::NegotiationHistory *tlsNegotiations();
diff -u -r -N squid-4.0.19/src/comm/ConnOpener.cc squid-4.0.20/src/comm/ConnOpener.cc
--- squid-4.0.19/src/comm/ConnOpener.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/comm/ConnOpener.cc	2017-06-02 00:49:17.000000000 +1200
@@ -39,7 +39,9 @@
     totalTries_(0),
     failRetries_(0),
     deadline_(squid_curtime + static_cast<time_t>(ctimeout))
-{}
+{
+    debugs(5, 3, "will connect to " << c << " with " << ctimeout << " timeout");
+}
 
 Comm::ConnOpener::~ConnOpener()
 {
diff -u -r -N squid-4.0.19/src/errorpage.cc squid-4.0.20/src/errorpage.cc
--- squid-4.0.19/src/errorpage.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/errorpage.cc	2017-06-02 00:49:17.000000000 +1200
@@ -332,7 +332,7 @@
         /* with dynamic locale negotiation we may see some failures before a success. */
         if (!silent && templateCode < TCP_RESET) {
             int xerrno = errno;
-            debugs(4, DBG_CRITICAL, MYNAME << "'" << path << "': " << xstrerr(xerrno));
+            debugs(4, DBG_CRITICAL, "ERROR: loading file '" << path << "': " << xstrerr(xerrno));
         }
         wasLoaded = false;
         return wasLoaded;
@@ -340,7 +340,7 @@
 
     while ((len = FD_READ_METHOD(fd, buf, sizeof(buf))) > 0) {
         if (!parse(buf, len, false)) {
-            debugs(4, DBG_CRITICAL, MYNAME << "parse error while reading template file: " << path);
+            debugs(4, DBG_CRITICAL, "ERROR: parsing error in template file: " << path);
             wasLoaded = false;
             return wasLoaded;
         }
diff -u -r -N squid-4.0.19/src/esi/Expression.cc squid-4.0.20/src/esi/Expression.cc
--- squid-4.0.19/src/esi/Expression.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/esi/Expression.cc	2017-06-02 00:49:17.000000000 +1200
@@ -743,7 +743,7 @@
             /* Special case for zero length strings */
 
             if (t - s - 1)
-                rv.value.string = xstrndup(s + 1, t - s - 1);
+                rv.value.string = xstrndup(s + 1, t - (s + 1) + 1);
             else
                 rv.value.string = static_cast<char *>(xcalloc(1,1));
 
diff -u -r -N squid-4.0.19/src/FwdState.cc squid-4.0.20/src/FwdState.cc
--- squid-4.0.19/src/FwdState.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/FwdState.cc	2017-06-02 00:49:17.000000000 +1200
@@ -389,6 +389,29 @@
     Start(clientConn, entry, request, NULL);
 }
 
+/// subtracts time_t values, returning zero if smaller exceeds the larger value
+/// time_t might be unsigned so we need to be careful when subtracting times...
+static inline time_t
+diffOrZero(const time_t larger, const time_t smaller)
+{
+    return (larger > smaller) ? (larger - smaller) : 0;
+}
+
+/// time left to finish the whole forwarding process (which started at fwdStart)
+time_t
+FwdState::ForwardTimeout(const time_t fwdStart)
+{
+    // time already spent on forwarding (0 if clock went backwards)
+    const time_t timeSpent = diffOrZero(squid_curtime, fwdStart);
+    return diffOrZero(Config.Timeout.forward, timeSpent);
+}
+
+bool
+FwdState::EnoughTimeToReForward(const time_t fwdStart)
+{
+    return ForwardTimeout(fwdStart) > 0;
+}
+
 void
 FwdState::startConnectionOrFail()
 {
@@ -568,7 +591,7 @@
     if (n_tries > Config.forward_max_tries)
         return false;
 
-    if (squid_curtime - start_t > Config.Timeout.forward)
+    if (!EnoughTimeToReForward(start_t))
         return false;
 
     if (flags.dont_retry)
@@ -696,7 +719,8 @@
                                                     "FwdState::ConnectedToPeer",
                                                     FwdStatePeerAnswerDialer(&FwdState::connectedToPeer, this));
             // Use positive timeout when less than one second is left.
-            const time_t sslNegotiationTimeout = max(static_cast<time_t>(1), timeLeft());
+            const time_t connTimeout = serverDestinations[0]->connectTimeout(start_t);
+            const time_t sslNegotiationTimeout = positiveTimeout(connTimeout);
             Security::PeerConnector *connector = nullptr;
 #if USE_OPENSSL
             if (request->flags.sslPeek)
@@ -769,29 +793,6 @@
     }
 }
 
-time_t
-FwdState::timeLeft() const
-{
-    /* connection timeout */
-    int ctimeout;
-    if (serverDestinations[0]->getPeer()) {
-        ctimeout = serverDestinations[0]->getPeer()->connect_timeout > 0 ?
-                   serverDestinations[0]->getPeer()->connect_timeout : Config.Timeout.peer_connect;
-    } else {
-        ctimeout = Config.Timeout.connect;
-    }
-
-    /* calculate total forwarding timeout ??? */
-    int ftimeout = Config.Timeout.forward - (squid_curtime - start_t);
-    if (ftimeout < 0)
-        ftimeout = 5;
-
-    if (ftimeout < ctimeout)
-        return (time_t)ftimeout;
-    else
-        return (time_t)ctimeout;
-}
-
 /// called when serverConn is set to an _open_ to-peer connection
 void
 FwdState::syncWithServerConn(const char *host)
@@ -917,7 +918,8 @@
     GetMarkingsToServer(request, *serverDestinations[0]);
 
     calls.connector = commCbCall(17,3, "fwdConnectDoneWrapper", CommConnectCbPtrFun(fwdConnectDoneWrapper, this));
-    Comm::ConnOpener *cs = new Comm::ConnOpener(serverDestinations[0], calls.connector, timeLeft());
+    const time_t connTimeout = serverDestinations[0]->connectTimeout(start_t);
+    Comm::ConnOpener *cs = new Comm::ConnOpener(serverDestinations[0], calls.connector, connTimeout);
     if (host)
         cs->setHost(host);
     AsyncJob::Start(cs);
diff -u -r -N squid-4.0.19/src/FwdState.h squid-4.0.20/src/FwdState.h
--- squid-4.0.19/src/FwdState.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/FwdState.h	2017-06-02 00:49:17.000000000 +1200
@@ -68,6 +68,11 @@
     static void Start(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp);
     /// Same as Start() but no master xaction info (AccessLogEntry) available.
     static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *);
+    /// time left to finish the whole forwarding process (which started at fwdStart)
+    static time_t ForwardTimeout(const time_t fwdStart);
+    /// Whether there is still time to re-try after a previous connection failure.
+    /// \param fwdStart The start time of the peer selection/connection process.
+    static bool EnoughTimeToReForward(const time_t fwdStart);
 
     /// This is the real beginning of server connection. Call it whenever
     /// the forwarding server destination has changed and a new one needs to be opened.
@@ -85,7 +90,6 @@
     void connectStart();
     void connectDone(const Comm::ConnectionPointer & conn, Comm::Flag status, int xerrno);
     void connectTimeout(int fd);
-    time_t timeLeft() const; ///< the time left before the forwarding timeout expired
     bool checkRetry();
     bool checkRetriable();
     void dispatch();
diff -u -r -N squid-4.0.19/src/http/url_rewriters/LFS/url_lfs_rewrite.8 squid-4.0.20/src/http/url_rewriters/LFS/url_lfs_rewrite.8
--- squid-4.0.19/src/http/url_rewriters/LFS/url_lfs_rewrite.8	2017-04-02 23:49:59.000000000 +1200
+++ squid-4.0.20/src/http/url_rewriters/LFS/url_lfs_rewrite.8	2017-06-02 09:57:33.000000000 +1200
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "URL_LFS_REWRITE 8"
-.TH URL_LFS_REWRITE 8 "2017-04-02" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH URL_LFS_REWRITE 8 "2017-06-01" "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.19/src/http.cc squid-4.0.20/src/http.cc
--- squid-4.0.19/src/http.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/http.cc	2017-06-02 00:49:17.000000000 +1200
@@ -284,7 +284,7 @@
         HttpHdrScTarget *sctusable = reply->surrogate_control->getMergedTarget(Config.Accel.surrogate_id);
 
         if (sctusable) {
-            if (sctusable->noStore() ||
+            if (sctusable->hasNoStore() ||
                     (Config.onoff.surrogate_is_remote
                      && sctusable->noStoreRemote())) {
                 surrogateNoStore = true;
@@ -361,14 +361,14 @@
         // for now we are not reliably doing that so we waste CPU re-checking request CC
 
         // RFC 2616 section 14.9.2 - MUST NOT cache any response with request CC:no-store
-        if (request && request->cache_control && request->cache_control->noStore() &&
+        if (request && request->cache_control && request->cache_control->hasNoStore() &&
                 !REFRESH_OVERRIDE(ignore_no_store)) {
             debugs(22, 3, HERE << "NO because client request Cache-Control:no-store");
             return 0;
         }
 
         // NP: request CC:no-cache only means cache READ is forbidden. STORE is permitted.
-        if (rep->cache_control && rep->cache_control->hasNoCache() && rep->cache_control->noCache().size() > 0) {
+        if (rep->cache_control && rep->cache_control->hasNoCacheWithParameters()) {
             /* TODO: we are allowed to cache when no-cache= has parameters.
              * Provided we strip away any of the listed headers unless they are revalidated
              * successfully (ie, must revalidate AND these headers are prohibited on stale replies).
@@ -382,7 +382,7 @@
         // NP: other request CC flags are limiters on HIT/MISS. We don't care about here.
 
         // RFC 2616 section 14.9.2 - MUST NOT cache any response with CC:no-store
-        if (rep->cache_control && rep->cache_control->noStore() &&
+        if (rep->cache_control && rep->cache_control->hasNoStore() &&
                 !REFRESH_OVERRIDE(ignore_no_store)) {
             debugs(22, 3, HERE << "NO because server reply Cache-Control:no-store");
             return 0;
@@ -419,12 +419,12 @@
 
         bool mayStore = false;
         // HTTPbis pt6 section 3.2: a response CC:public is present
-        if (rep->cache_control->Public()) {
+        if (rep->cache_control->hasPublic()) {
             debugs(22, 3, HERE << "Authenticated but server reply Cache-Control:public");
             mayStore = true;
 
             // HTTPbis pt6 section 3.2: a response CC:must-revalidate is present
-        } else if (rep->cache_control->mustRevalidate()) {
+        } else if (rep->cache_control->hasMustRevalidate()) {
             debugs(22, 3, HERE << "Authenticated but server reply Cache-Control:must-revalidate");
             mayStore = true;
 
@@ -433,13 +433,13 @@
             // HTTPbis WG verdict on this is that it is omitted from the spec due to being 'unexpected' by
             // some. The caching+revalidate is not exactly unsafe though with Squids interpretation of no-cache
             // (without parameters) as equivalent to must-revalidate in the reply.
-        } else if (rep->cache_control->hasNoCache() && rep->cache_control->noCache().size() == 0) {
+        } else if (rep->cache_control->hasNoCacheWithoutParameters()) {
             debugs(22, 3, HERE << "Authenticated but server reply Cache-Control:no-cache (equivalent to must-revalidate)");
             mayStore = true;
 #endif
 
             // HTTPbis pt6 section 3.2: a response CC:s-maxage is present
-        } else if (rep->cache_control->sMaxAge()) {
+        } else if (rep->cache_control->hasSMaxAge()) {
             debugs(22, 3, HERE << "Authenticated but server reply Cache-Control:s-maxage");
             mayStore = true;
         }
@@ -997,10 +997,10 @@
             // For security reasons we do so even if storage was caused by refresh_pattern ignore-* option
 
             // CC:must-revalidate or CC:proxy-revalidate
-            const bool ccMustRevalidate = (rep->cache_control->proxyRevalidate() || rep->cache_control->mustRevalidate());
+            const bool ccMustRevalidate = (rep->cache_control->hasProxyRevalidate() || rep->cache_control->hasMustRevalidate());
 
             // CC:no-cache (only if there are no parameters)
-            const bool ccNoCacheNoParams = (rep->cache_control->hasNoCache() && rep->cache_control->noCache().size()==0);
+            const bool ccNoCacheNoParams = rep->cache_control->hasNoCacheWithoutParameters();
 
             // CC:s-maxage=N
             const bool ccSMaxAge = rep->cache_control->hasSMaxAge();
diff -u -r -N squid-4.0.19/src/HttpHdrCc.cc squid-4.0.20/src/HttpHdrCc.cc
--- squid-4.0.19/src/HttpHdrCc.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/HttpHdrCc.cc	2017-06-02 00:49:17.000000000 +1200
@@ -245,13 +245,13 @@
             case HttpHdrCcType::CC_PUBLIC:
                 break;
             case HttpHdrCcType::CC_PRIVATE:
-                if (Private().size())
-                    p->appendf("=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(Private()));
+                if (private_.size())
+                    p->appendf("=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(private_));
                 break;
 
             case HttpHdrCcType::CC_NO_CACHE:
-                if (noCache().size())
-                    p->appendf("=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(noCache()));
+                if (no_cache.size())
+                    p->appendf("=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(no_cache));
                 break;
             case HttpHdrCcType::CC_NO_STORE:
                 break;
@@ -262,24 +262,24 @@
             case HttpHdrCcType::CC_PROXY_REVALIDATE:
                 break;
             case HttpHdrCcType::CC_MAX_AGE:
-                p->appendf("=%d", maxAge());
+                p->appendf("=%d", max_age);
                 break;
             case HttpHdrCcType::CC_S_MAXAGE:
-                p->appendf("=%d", sMaxAge());
+                p->appendf("=%d", s_maxage);
                 break;
             case HttpHdrCcType::CC_MAX_STALE:
                 /* max-stale's value is optional.
                   If we didn't receive it, don't send it */
-                if (maxStale()!=MAX_STALE_ANY)
-                    p->appendf("=%d", maxStale());
+                if (max_stale != MAX_STALE_ANY)
+                    p->appendf("=%d", max_stale);
                 break;
             case HttpHdrCcType::CC_MIN_FRESH:
-                p->appendf("=%d", minFresh());
+                p->appendf("=%d", min_fresh);
                 break;
             case HttpHdrCcType::CC_ONLY_IF_CACHED:
                 break;
             case HttpHdrCcType::CC_STALE_IF_ERROR:
-                p->appendf("=%d", staleIfError());
+                p->appendf("=%d", stale_if_error);
                 break;
             case HttpHdrCcType::CC_IMMUTABLE:
                 break;
diff -u -r -N squid-4.0.19/src/HttpHdrCc.h squid-4.0.20/src/HttpHdrCc.h
--- squid-4.0.19/src/HttpHdrCc.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/HttpHdrCc.h	2017-06-02 00:49:17.000000000 +1200
@@ -66,13 +66,11 @@
 
     //manipulation for Cache-Control: public header
     bool hasPublic() const {return isSet(HttpHdrCcType::CC_PUBLIC);}
-    bool Public() const {return isSet(HttpHdrCcType::CC_PUBLIC);}
     void Public(bool v) {setMask(HttpHdrCcType::CC_PUBLIC,v);}
     void clearPublic() {setMask(HttpHdrCcType::CC_PUBLIC,false);}
 
     //manipulation for Cache-Control: private header
-    bool hasPrivate() const {return isSet(HttpHdrCcType::CC_PRIVATE);}
-    const String &Private() const {return private_;}
+    bool hasPrivate(const String **val = nullptr) const { return hasDirective(HttpHdrCcType::CC_PRIVATE, &private_, val); }
     void Private(const String &v) {
         setMask(HttpHdrCcType::CC_PRIVATE,true);
         if (!v.size())
@@ -85,8 +83,9 @@
     void clearPrivate() {setMask(HttpHdrCcType::CC_PRIVATE,false); private_.clean();}
 
     //manipulation for Cache-Control: no-cache header
-    bool hasNoCache() const {return isSet(HttpHdrCcType::CC_NO_CACHE);}
-    const String &noCache() const {return no_cache;}
+    bool hasNoCacheWithParameters() const { return hasNoCache() && no_cache.size(); }
+    bool hasNoCacheWithoutParameters() const { return hasNoCache() && !no_cache.size(); }
+    bool hasNoCache(const String **val = nullptr) const { return hasDirective(HttpHdrCcType::CC_NO_CACHE, &no_cache, val); }
     void noCache(const String &v) {
         setMask(HttpHdrCcType::CC_NO_CACHE,true);
         if (!v.size())
@@ -100,43 +99,36 @@
 
     //manipulation for Cache-Control: no-store header
     bool hasNoStore() const {return isSet(HttpHdrCcType::CC_NO_STORE);}
-    bool noStore() const {return isSet(HttpHdrCcType::CC_NO_STORE);}
     void noStore(bool v) {setMask(HttpHdrCcType::CC_NO_STORE,v);}
     void clearNoStore() {setMask(HttpHdrCcType::CC_NO_STORE,false);}
 
     //manipulation for Cache-Control: no-transform header
     bool hasNoTransform() const {return isSet(HttpHdrCcType::CC_NO_TRANSFORM);}
-    bool noTransform() const {return isSet(HttpHdrCcType::CC_NO_TRANSFORM);}
     void noTransform(bool v) {setMask(HttpHdrCcType::CC_NO_TRANSFORM,v);}
     void clearNoTransform() {setMask(HttpHdrCcType::CC_NO_TRANSFORM,false);}
 
     //manipulation for Cache-Control: must-revalidate header
     bool hasMustRevalidate() const {return isSet(HttpHdrCcType::CC_MUST_REVALIDATE);}
-    bool mustRevalidate() const {return isSet(HttpHdrCcType::CC_MUST_REVALIDATE);}
     void mustRevalidate(bool v) {setMask(HttpHdrCcType::CC_MUST_REVALIDATE,v);}
     void clearMustRevalidate() {setMask(HttpHdrCcType::CC_MUST_REVALIDATE,false);}
 
     //manipulation for Cache-Control: proxy-revalidate header
     bool hasProxyRevalidate() const {return isSet(HttpHdrCcType::CC_PROXY_REVALIDATE);}
-    bool proxyRevalidate() const {return isSet(HttpHdrCcType::CC_PROXY_REVALIDATE);}
     void proxyRevalidate(bool v) {setMask(HttpHdrCcType::CC_PROXY_REVALIDATE,v);}
     void clearProxyRevalidate() {setMask(HttpHdrCcType::CC_PROXY_REVALIDATE,false);}
 
     //manipulation for Cache-Control: max-age header
-    bool hasMaxAge() const {return isSet(HttpHdrCcType::CC_MAX_AGE);}
-    int32_t maxAge() const { return max_age;}
+    bool hasMaxAge(int32_t *val = nullptr) const { return hasDirective(HttpHdrCcType::CC_MAX_AGE, max_age, val); }
     void maxAge(int32_t v) {setValue(max_age,v,HttpHdrCcType::CC_MAX_AGE); }
     void clearMaxAge() {setValue(max_age,MAX_AGE_UNKNOWN,HttpHdrCcType::CC_MAX_AGE,false);}
 
     //manipulation for Cache-Control: s-maxage header
-    bool hasSMaxAge() const {return isSet(HttpHdrCcType::CC_S_MAXAGE);}
-    int32_t sMaxAge() const { return s_maxage;}
+    bool hasSMaxAge(int32_t *val = nullptr) const { return hasDirective(HttpHdrCcType::CC_S_MAXAGE, s_maxage, val); }
     void sMaxAge(int32_t v) {setValue(s_maxage,v,HttpHdrCcType::CC_S_MAXAGE); }
     void clearSMaxAge() {setValue(s_maxage,MAX_AGE_UNKNOWN,HttpHdrCcType::CC_S_MAXAGE,false);}
 
     //manipulation for Cache-Control: max-stale header
-    bool hasMaxStale() const {return isSet(HttpHdrCcType::CC_MAX_STALE);}
-    int32_t maxStale() const { return max_stale;}
+    bool hasMaxStale(int32_t *val = nullptr) const { return hasDirective(HttpHdrCcType::CC_MAX_STALE, max_stale, val); }
     // max-stale has a special value (MAX_STALE_ANY) which correspond to having
     // the directive without a numeric specification, and directs to consider the object
     // as always-expired.
@@ -144,25 +136,22 @@
     void clearMaxStale() {setValue(max_stale,MAX_STALE_UNKNOWN,HttpHdrCcType::CC_MAX_STALE,false);}
 
     //manipulation for Cache-Control:min-fresh header
-    bool hasMinFresh() const {return isSet(HttpHdrCcType::CC_MIN_FRESH);}
-    int32_t minFresh() const { return min_fresh;}
+    bool hasMinFresh(int32_t *val = nullptr) const { return hasDirective(HttpHdrCcType::CC_MIN_FRESH, max_stale, val); }
     void minFresh(int32_t v) {if (v < 0) return; setValue(min_fresh,v,HttpHdrCcType::CC_MIN_FRESH); }
     void clearMinFresh() {setValue(min_fresh,MIN_FRESH_UNKNOWN,HttpHdrCcType::CC_MIN_FRESH,false);}
 
     //manipulation for Cache-Control: only-if-cached header
     bool hasOnlyIfCached() const {return isSet(HttpHdrCcType::CC_ONLY_IF_CACHED);}
-    bool onlyIfCached() const {return isSet(HttpHdrCcType::CC_ONLY_IF_CACHED);}
     void onlyIfCached(bool v) {setMask(HttpHdrCcType::CC_ONLY_IF_CACHED,v);}
     void clearOnlyIfCached() {setMask(HttpHdrCcType::CC_ONLY_IF_CACHED,false);}
 
     //manipulation for Cache-Control: stale-if-error header
-    bool hasStaleIfError() const {return isSet(HttpHdrCcType::CC_STALE_IF_ERROR);}
-    int32_t staleIfError() const { return stale_if_error;}
+    bool hasStaleIfError(int32_t *val = nullptr) const { return hasDirective(HttpHdrCcType::CC_STALE_IF_ERROR, stale_if_error, val); }
     void staleIfError(int32_t v) {setValue(stale_if_error,v,HttpHdrCcType::CC_STALE_IF_ERROR); }
     void clearStaleIfError() {setValue(stale_if_error,STALE_IF_ERROR_UNKNOWN,HttpHdrCcType::CC_STALE_IF_ERROR,false);}
 
     //manipulation for Cache-Control: immutable header
-    bool Immutable() const {return isSet(HttpHdrCcType::CC_IMMUTABLE);}
+    bool hasImmutable() const {return isSet(HttpHdrCcType::CC_IMMUTABLE);}
     void Immutable(bool v) {setMask(HttpHdrCcType::CC_IMMUTABLE,v);}
     void clearImmutable() {setMask(HttpHdrCcType::CC_IMMUTABLE,false);}
 
@@ -186,6 +175,17 @@
     String private_; ///< List of headers sent as value for CC:private="...". May be empty/undefined if the value is missing.
     String no_cache; ///< List of headers sent as value for CC:no-cache="...". May be empty/undefined if the value is missing.
 
+    /// implements typical has*() method logic
+    template<class Value>
+    bool hasDirective(const HttpHdrCcType hdrType, const Value &parsedVal, Value *outVal = nullptr) const {
+        if (isSet(hdrType)) {
+            if (outVal)
+                *outVal = parsedVal;
+            return true;
+        }
+        return false;
+    }
+
     /// low-level part of the public set method, performs no checks
     _SQUID_INLINE_ void setMask(HttpHdrCcType id, bool newval=true);
     _SQUID_INLINE_ void setValue(int32_t &value, int32_t new_value, HttpHdrCcType hdr, bool setting=true);
diff -u -r -N squid-4.0.19/src/HttpHeader.cc squid-4.0.20/src/HttpHeader.cc
--- squid-4.0.19/src/HttpHeader.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/HttpHeader.cc	2017-06-02 00:49:17.000000000 +1200
@@ -248,7 +248,7 @@
             continue;
         String value;
         const char *name = e->name.termedBuf();
-        if (!getByNameIfPresent(name, strlen(name), value) ||
+        if (!hasNamed(name, strlen(name), &value) ||
                 (value != fresh->getByName(name)))
             return true;
     }
@@ -825,7 +825,7 @@
 {
     String result;
     // ignore presence: return undefined string if an empty header is present
-    (void)getByNameIfPresent(name, strlen(name), result);
+    (void)hasNamed(name, strlen(name), &result);
     return result;
 }
 
@@ -834,7 +834,7 @@
 {
     String result;
     // ignore presence: return undefined string if an empty header is present
-    (void)getByNameIfPresent(name, result);
+    (void)hasNamed(name, &result);
     return result;
 }
 
@@ -842,29 +842,30 @@
 HttpHeader::getById(Http::HdrType id) const
 {
     String result;
-    (void)getByIdIfPresent(id,result);
+    (void)getByIdIfPresent(id, &result);
     return result;
 }
 
 bool
-HttpHeader::getByNameIfPresent(const SBuf &s, String &result) const
+HttpHeader::hasNamed(const SBuf &s, String *result) const
 {
-    return getByNameIfPresent(s.rawContent(), s.length(), result);
+    return hasNamed(s.rawContent(), s.length(), result);
 }
 
 bool
-HttpHeader::getByIdIfPresent(Http::HdrType id, String &result) const
+HttpHeader::getByIdIfPresent(Http::HdrType id, String *result) const
 {
     if (id == Http::HdrType::BAD_HDR)
         return false;
     if (!has(id))
         return false;
-    result = getStrOrList(id);
+    if (result)
+        *result = getStrOrList(id);
     return true;
 }
 
 bool
-HttpHeader::getByNameIfPresent(const char *name, int namelen, String &result) const
+HttpHeader::hasNamed(const char *name, int namelen, String *result) const
 {
     Http::HdrType id;
     HttpHeaderPos pos = HttpHeaderInitPos;
@@ -885,7 +886,9 @@
     while ((e = getEntry(&pos))) {
         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(), ',');
+            if (!result)
+                break;
+            strListAdd(result, e->value.termedBuf(), ',');
         }
     }
 
diff -u -r -N squid-4.0.19/src/HttpHeader.h squid-4.0.20/src/HttpHeader.h
--- squid-4.0.19/src/HttpHeader.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/HttpHeader.h	2017-06-02 00:49:17.000000000 +1200
@@ -101,11 +101,13 @@
     String getByName(const SBuf &name) const;
     String getByName(const char *name) const;
     String getById(Http::HdrType id) const;
-    /// sets value and returns true iff a [possibly empty] field identified by id is there
-    bool getByIdIfPresent(Http::HdrType id, String &result) const;
-    /// sets value and returns true iff a [possibly empty] named field is there
-    bool getByNameIfPresent(const SBuf &s, String &value) const;
-    bool getByNameIfPresent(const char *name, int namelen, String &value) const;
+    /// returns true iff a [possibly empty] field identified by id is there
+    /// when returning true, also sets the `result` parameter (if it is not nil)
+    bool getByIdIfPresent(Http::HdrType id, String *result) const;
+    /// returns true iff a [possibly empty] named field is there
+    /// when returning true, also sets the `value` parameter (if it is not nil)
+    bool hasNamed(const SBuf &s, String *value = 0) const;
+    bool hasNamed(const char *name, int namelen, String *value = 0) const;
     String getByNameListMember(const char *name, const char *member, const char separator) const;
     String getListMember(Http::HdrType id, const char *member, const char separator) const;
     int has(Http::HdrType id) const;
diff -u -r -N squid-4.0.19/src/HttpReply.cc squid-4.0.20/src/HttpReply.cc
--- squid-4.0.19/src/HttpReply.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/HttpReply.cc	2017-06-02 00:49:17.000000000 +1200
@@ -262,24 +262,13 @@
     /* The s-maxage and max-age directive takes priority over Expires */
 
     if (cache_control) {
-        if (date >= 0) {
-            if (cache_control->hasSMaxAge())
-                return date + cache_control->sMaxAge();
-
-            if (cache_control->hasMaxAge())
-                return date + cache_control->maxAge();
-        } else {
-            /*
-             * Conservatively handle the case when we have a max-age
-             * header, but no Date for reference?
-             */
-
-            if (cache_control->hasSMaxAge())
-                return squid_curtime;
-
-            if (cache_control->hasMaxAge())
-                return squid_curtime;
-        }
+        int maxAge = -1;
+        /*
+         * Conservatively handle the case when we have a max-age
+         * header, but no Date for reference?
+         */
+        if (cache_control->hasSMaxAge(&maxAge) || cache_control->hasMaxAge(&maxAge))
+            return (date >= 0) ? date + maxAge : squid_curtime;
     }
 
     if (Config.onoff.vary_ignore_expire &&
diff -u -r -N squid-4.0.19/src/HttpRequest.cc squid-4.0.20/src/HttpRequest.cc
--- squid-4.0.19/src/HttpRequest.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/HttpRequest.cc	2017-06-02 00:49:17.000000000 +1200
@@ -548,7 +548,7 @@
         //
         // NP: refresh_pattern ignore-no-store only applies to response messages
         //     this test is handling request message CC header.
-        if (!flags.ignoreCc && cache_control && cache_control->noStore())
+        if (!flags.ignoreCc && cache_control && cache_control->hasNoStore())
             return false;
         break;
 
diff -u -r -N squid-4.0.19/src/Instance.cc squid-4.0.20/src/Instance.cc
--- squid-4.0.19/src/Instance.cc	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.20/src/Instance.cc	2017-06-02 00:49:17.000000000 +1200
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "base/File.h"
+#include "fs_io.h"
+#include "Instance.h"
+#include "parser/Tokenizer.h"
+#include "sbuf/Stream.h"
+#include "SquidConfig.h"
+#include "tools.h"
+
+#include <cerrno>
+
+/* To support concurrent PID files, convert local statics into PidFile class */
+
+/// Describes the (last) instance PID file being processed.
+/// This hack shortens reporting code while keeping its messages consistent.
+static SBuf TheFile;
+
+/// PidFilename() helper
+/// \returns PID file name or, if PID signaling was disabled, an empty SBuf
+static SBuf
+PidFilenameCalc()
+{
+    if (!Config.pidFilename || strcmp(Config.pidFilename, "none") == 0)
+        return SBuf();
+
+    // If chroot has been requested, then we first read the PID file before
+    // chroot() and then create/update it inside a chrooted environment.
+    // TODO: Consider removing half-baked chroot support from Squid.
+    extern bool Chrooted;
+    if (!Config.chroot_dir || Chrooted) // no need to compensate
+        return SBuf(Config.pidFilename);
+
+    SBuf filename;
+    filename.append(Config.chroot_dir);
+    filename.append("/");
+    filename.append(Config.pidFilename);
+    debugs(50, 3, "outside chroot: " << filename);
+    return filename;
+}
+
+/// \returns PID file description for debugging messages and error reporting
+static SBuf
+PidFileDescription(const SBuf &filename)
+{
+    return ToSBuf("PID file (", filename, ')');
+}
+
+/// Instance entry points are expected to call this first.
+/// \returns PidFilenameCalc() result while updating TheFile context
+static SBuf
+PidFilename()
+{
+    const auto name = PidFilenameCalc();
+    TheFile = PidFileDescription(name);
+    return name;
+}
+
+/// \returns the PID of another Squid instance (or throws)
+static pid_t
+GetOtherPid(File &pidFile)
+{
+    const auto input = pidFile.readSmall(1, 32);
+    int64_t rawPid = -1;
+
+    Parser::Tokenizer tok(input);
+    if (!(tok.int64(rawPid, 10, false) && // PID digits
+            (tok.skipOne(CharacterSet::CR)||true) && // optional CR (Windows/etc.)
+            tok.skipOne(CharacterSet::LF) && // required end of line
+            tok.atEnd())) { // no trailing garbage
+        throw TexcHere(ToSBuf("Malformed ", TheFile));
+    }
+
+    debugs(50, 7, "found PID " << rawPid << " in " << TheFile);
+
+    if (rawPid <= 1)
+        throw TexcHere(ToSBuf("Bad ", TheFile, " contains unreasonably small PID value: ", rawPid));
+    const auto finalPid = static_cast<pid_t>(rawPid);
+    if (static_cast<int64_t>(finalPid) != rawPid)
+        throw TexcHere(ToSBuf("Bad ", TheFile, " contains unreasonably large PID value: ", rawPid));
+
+    return finalPid;
+}
+
+/// determines whether a given process is running at the time of the call
+static bool
+ProcessIsRunning(const pid_t pid)
+{
+    const auto result = kill(pid, 0);
+    const auto savedErrno = errno;
+    if (result != 0)
+        debugs(50, 3, "kill(" << pid << ", 0) failed: " << xstrerr(savedErrno));
+    // if we do not have permissions to signal the process, then it is running
+    return (result == 0 || savedErrno == EPERM);
+}
+
+/// quits if another Squid instance (that owns the given PID file) is running
+static void
+ThrowIfAlreadyRunningWith(File &pidFile)
+{
+    bool running = false;
+    SBuf description;
+    try {
+        const auto pid = GetOtherPid(pidFile);
+        description = ToSBuf(TheFile, " with PID ", pid);
+        running = ProcessIsRunning(pid);
+    }
+    catch (const std::exception &ex) {
+        debugs(50, 5, "assuming no other Squid instance: " << ex.what());
+        return;
+    }
+
+    if (running)
+        throw TexcHere(ToSBuf("Squid is already running: Found fresh instance ", description));
+
+    debugs(50, 5, "assuming stale instance " << description);
+}
+
+pid_t
+Instance::Other()
+{
+    const auto filename = PidFilename();
+    if (filename.isEmpty())
+        throw TexcHere("no pid_filename configured");
+
+    File pidFile(filename, File::Be::ReadOnly().locked());
+    return GetOtherPid(pidFile);
+}
+
+void
+Instance::ThrowIfAlreadyRunning()
+{
+    const auto filename = PidFilename();
+    if (filename.isEmpty())
+        return; // the check is impossible
+
+    if (const auto filePtr = File::Optional(filename, File::Be::ReadOnly().locked())) {
+        const std::unique_ptr<File> pidFile(filePtr);
+        ThrowIfAlreadyRunningWith(*pidFile);
+    } else {
+        // It is best to assume then to check because checking without a lock
+        // might lead to false positives that lead to no Squid starting at all!
+        debugs(50, 5, "cannot lock " << TheFile << "; assuming no other Squid is running");
+        // If our assumption is false, we will fail to _create_ the PID file,
+        // and, hence, will not start, allowing that other Squid to run.
+    }
+}
+
+/// ties Instance::WriteOurPid() scheduler and RemoveInstance(void) handler
+static SBuf ThePidFileToRemove;
+
+/// atexit() handler; removes the PID file created with Instance::WriteOurPid()
+static void
+RemoveInstance()
+{
+    if (ThePidFileToRemove.isEmpty()) // not the PidFilename()!
+        return; // nothing to do
+
+    debugs(50, DBG_IMPORTANT, "Removing " << PidFileDescription(ThePidFileToRemove));
+    const char *filename = ThePidFileToRemove.c_str(); // avoid complex operations inside enter_suid()
+    enter_suid();
+    safeunlink(filename, 0);
+    leave_suid();
+
+    ThePidFileToRemove.clear();
+}
+
+/// creates a PID file; throws on error
+void
+Instance::WriteOurPid()
+{
+    // Instance code assumes that we do not support PID filename reconfiguration
+    static bool called = false;
+    Must(!called);
+    called = true;
+
+    const auto filename = PidFilename();
+    if (filename.isEmpty())
+        return; // nothing to do
+
+    File pidFile(filename, File::Be::ReadWrite().locked().createdIfMissing().openedByRoot());
+
+    // another instance may have started after the caller checked (if it did)
+    ThrowIfAlreadyRunningWith(pidFile);
+
+    /* now we know that we own the PID file created and/or locked above */
+
+    // Cleanup is scheduled through atexit() to ensure both:
+    // - cleanup upon fatal() and similar "unplanned" exits and
+    // - enter_suid() existence and proper logging support during cleanup.
+    // Even without PID filename reconfiguration support, we have to remember
+    // the file name we have used because Config.pidFilename may change!
+    (void)std::atexit(&RemoveInstance); // failures leave the PID file on disk
+    ThePidFileToRemove = filename;
+
+    /* write our PID to the locked file */
+    SBuf pidBuf;
+    pidBuf.Printf("%d\n", static_cast<int>(getpid()));
+    pidFile.truncate();
+    pidFile.writeAll(pidBuf);
+
+    // We must fsync before releasing the lock or other Squid processes may not see
+    // our written PID (and decide that they are dealing with a corrupted PID file).
+    pidFile.synchronize();
+
+    debugs(50, DBG_IMPORTANT, "Created " << TheFile);
+}
+
diff -u -r -N squid-4.0.19/src/Instance.h squid-4.0.20/src/Instance.h
--- squid-4.0.19/src/Instance.h	1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.20/src/Instance.h	2017-06-02 00:49:17.000000000 +1200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_INSTANCE_H
+#define SQUID_INSTANCE_H
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+/// code related to Squid Instance and PID file management
+namespace Instance {
+
+/// Usually throws if another Squid instance is running. False positives are
+/// highly unlikely, but the caller must tolerate false negatives well:
+/// We may not detect another running instance and, hence, may not throw.
+/// Does nothing if PID file maintenance is disabled.
+void ThrowIfAlreadyRunning();
+
+/// Creates or updates the PID file for the current process.
+/// Does nothing if PID file maintenance is disabled.
+void WriteOurPid();
+
+/// \returns another Squid instance PID
+/// Throws if PID file maintenance is disabled.
+pid_t Other();
+
+} // namespace Instance
+
+#endif
+
diff -u -r -N squid-4.0.19/src/log/DB/log_db_daemon.8 squid-4.0.20/src/log/DB/log_db_daemon.8
--- squid-4.0.19/src/log/DB/log_db_daemon.8	2017-04-02 23:50:09.000000000 +1200
+++ squid-4.0.20/src/log/DB/log_db_daemon.8	2017-06-02 09:57:57.000000000 +1200
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "LOG_DB_DAEMON 8"
-.TH LOG_DB_DAEMON 8 "2017-04-02" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH LOG_DB_DAEMON 8 "2017-06-01" "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.19/src/main.cc squid-4.0.20/src/main.cc
--- squid-4.0.19/src/main.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/main.cc	2017-06-02 00:49:17.000000000 +1200
@@ -46,6 +46,7 @@
 #include "icmp/net_db.h"
 #include "ICP.h"
 #include "ident/Ident.h"
+#include "Instance.h"
 #include "ip/tools.h"
 #include "ipc/Coordinator.h"
 #include "ipc/Kids.h"
@@ -61,6 +62,7 @@
 #include "profiler/Profiler.h"
 #include "redirect.h"
 #include "refresh.h"
+#include "sbuf/Stream.h"
 #include "SBufStatsAction.h"
 #include "send-announce.h"
 #include "SquidConfig.h"
@@ -171,7 +173,6 @@
 static void setEffectiveUser(void);
 static void SquidShutdown(void);
 static void mainSetCwd(void);
-static int checkRunningPid(void);
 
 #if !_SQUID_WINDOWS_
 static const char *squid_start_script = "squid_start";
@@ -662,6 +663,10 @@
             printf("Service Name: " SQUIDSBUFPH "\n", SQUIDSBUFPRINT(service_name));
             if (strlen(SQUID_BUILD_INFO))
                 printf("%s\n",SQUID_BUILD_INFO);
+#if USE_OPENSSL
+            printf("\nThis binary uses %s. ", SSLeay_version(SSLEAY_VERSION));
+            printf("For legal restrictions on distribution see https://www.openssl.org/source/license.html\n\n");
+#endif
             printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS);
 
 #if USE_WIN32_SERVICE
@@ -1003,9 +1008,6 @@
             eventDelete(start_announce, NULL);
     }
 
-    if (!InDaemonMode())
-        writePidFile(); /* write PID file */
-
     reconfiguring = 0;
 }
 
@@ -1069,13 +1071,16 @@
     return false;
 }
 
+/// Hack: Have we called chroot()? This exposure is needed because some code has
+/// to open the same files before and after chroot()
+bool Chrooted = false;
+
 /// set the working directory.
 static void
 mainSetCwd(void)
 {
-    static bool chrooted = false;
-    if (Config.chroot_dir && !chrooted) {
-        chrooted = true;
+    if (Config.chroot_dir && !Chrooted) {
+        Chrooted = true;
 
         if (chroot(Config.chroot_dir) != 0) {
             int xerrno = errno;
@@ -1257,9 +1262,6 @@
     if (Config.chroot_dir)
         no_suid();
 
-    if (!configured_once && !InDaemonMode())
-        writePidFile();     /* write PID file */
-
 #if defined(_SQUID_LINUX_THREADS_)
 
     squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
@@ -1373,14 +1375,11 @@
     try {
         return SquidMain(argc, argv);
     } catch (const std::exception &e) {
-        debugs(1, DBG_CRITICAL, "FATAL: dying from an unhandled exception: " <<
-               e.what());
-        throw;
+        debugs(1, DBG_CRITICAL, "FATAL: " << e.what());
     } catch (...) {
         debugs(1, DBG_CRITICAL, "FATAL: dying from an unhandled exception.");
-        throw;
     }
-    return -1; // not reached
+    return -1; // TODO: return EXIT_FAILURE instead
 }
 
 /// computes name and ID for the current kid process
@@ -1409,6 +1408,12 @@
     }
 }
 
+static void StartUsingConfig()
+{
+    RunRegisteredHere(RegisteredRunner::claimMemoryNeeds);
+    RunRegisteredHere(RegisteredRunner::useConfig);
+}
+
 int
 SquidMain(int argc, char **argv)
 {
@@ -1536,9 +1541,12 @@
             return parse_err;
     }
     setUmask(Config.umask);
-    if (-1 == opt_send_signal)
-        if (checkRunningPid())
-            exit(0);
+
+    // Master optimization: Where possible, avoid pointless daemon fork() and/or
+    // pointless wait for the exclusive PID file lock. This optional/weak check
+    // is not applicable to kids because they always co-exist with their master.
+    if (opt_send_signal == -1 && IamMasterProcess())
+        Instance::ThrowIfAlreadyRunning();
 
 #if TEST_ACCESS
 
@@ -1563,21 +1571,25 @@
         }
 
         sendSignal();
-        /* NOTREACHED */
+        return 0;
     }
 
     debugs(1,2, HERE << "Doing post-config initialization\n");
     leave_suid();
     RunRegisteredHere(RegisteredRunner::finalizeConfig);
-    RunRegisteredHere(RegisteredRunner::claimMemoryNeeds);
-    RunRegisteredHere(RegisteredRunner::useConfig);
-    enter_suid();
 
-    if (InDaemonMode() && IamMasterProcess()) {
-        watch_child(argv);
-        // NOTREACHED
+    if (IamMasterProcess()) {
+        if (InDaemonMode()) {
+            watch_child(argv);
+            // NOTREACHED
+        } else {
+            Instance::WriteOurPid();
+        }
     }
 
+    StartUsingConfig();
+    enter_suid();
+
     if (opt_create_swap_dirs) {
         /* chroot if configured to run inside chroot */
         mainSetCwd();
@@ -1667,50 +1679,26 @@
 static void
 sendSignal(void)
 {
-    pid_t pid;
     debug_log = stderr;
 
-    if (strcmp(Config.pidFilename, "none") == 0) {
-        debugs(0, DBG_IMPORTANT, "No pid_filename specified. Trusting you know what you are doing.");
-    }
-
-    pid = readPidFile();
-
-    if (pid > 1) {
 #if USE_WIN32_SERVICE
-        if (opt_signal_service) {
-            WIN32_sendSignal(opt_send_signal);
-            exit(0);
-        } else {
-            fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
-            fprintf(stderr, "signal to Squid Service:\n");
-            fprintf(stderr, "missing -n command line switch.\n");
-            exit(1);
-        }
-        /* NOTREACHED */
-#endif
-
-        if (kill(pid, opt_send_signal) &&
-                /* ignore permissions if just running check */
-                !(opt_send_signal == 0 && errno == EPERM)) {
-            int xerrno = errno;
-            fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
-            fprintf(stderr, "signal %d to process %d: %s\n",
-                    opt_send_signal, (int) pid, xstrerr(xerrno));
-            exit(1);
-        }
-    } else {
-        if (opt_send_signal != SIGTERM) {
-            fprintf(stderr, "%s: ERROR: No running copy\n", APP_SHORTNAME);
-            exit(1);
-        } else {
-            fprintf(stderr, "%s: No running copy\n", APP_SHORTNAME);
-            exit(0);
-        }
+    // WIN32_sendSignal() does not need the PID value to signal,
+    // but we must exit if there is no valid PID (TODO: Why?).
+    (void)Instance::Other();
+    if (!opt_signal_service)
+        throw TexcHere("missing -n command line switch");
+    WIN32_sendSignal(opt_send_signal);
+#else
+    const auto pid = Instance::Other();
+    if (kill(pid, opt_send_signal) &&
+            /* ignore permissions if just running check */
+            !(opt_send_signal == 0 && errno == EPERM)) {
+        const auto savedErrno = errno;
+        throw TexcHere(ToSBuf("failed to send signal ", opt_send_signal,
+                              " to Squid instance with PID ", pid, ": ", xstrerr(savedErrno)));
     }
-
+#endif
     /* signal successfully sent */
-    exit(0);
 }
 
 #if !_SQUID_WINDOWS_
@@ -1751,31 +1739,6 @@
 
 #endif /* _SQUID_WINDOWS_ */
 
-static int
-checkRunningPid(void)
-{
-    // master process must start alone, but its kids processes may co-exist
-    if (!IamMasterProcess())
-        return 0;
-
-    pid_t pid;
-
-    if (!debug_log)
-        debug_log = stderr;
-
-    pid = readPidFile();
-
-    if (pid < 2)
-        return 0;
-
-    if (kill(pid, 0) < 0)
-        return 0;
-
-    debugs(0, DBG_CRITICAL, "Squid is already running!  Process ID " <<  pid);
-
-    return 1;
-}
-
 #if !_SQUID_WINDOWS_
 static void
 masterCheckAndBroadcastSignals()
@@ -1813,6 +1776,8 @@
 
     int nullfd;
 
+    enter_suid();
+
     openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
 
     if ((pid = fork()) < 0) {
@@ -1866,8 +1831,10 @@
         dup2(nullfd, 2);
     }
 
-    writePidFile();
-    enter_suid(); // writePidFile() uses leave_suid()
+    leave_suid();
+    Instance::WriteOurPid();
+    StartUsingConfig();
+    enter_suid();
 
 #if defined(_SQUID_LINUX_THREADS_)
     squid_signal(SIGQUIT, rotate_logs, 0);
@@ -1973,8 +1940,6 @@
             RunRegisteredHere(RegisteredRunner::finishShutdown);
             enter_suid();
 
-            removePidFile();
-            enter_suid(); // removePidFile() uses leave_suid()
             if (TheKids.someSignaled(SIGINT) || TheKids.someSignaled(SIGTERM)) {
                 syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
                 exit(1);
@@ -2094,10 +2059,6 @@
 
     memClean();
 
-    if (!InDaemonMode()) {
-        removePidFile();
-    }
-
     debugs(1, DBG_IMPORTANT, "Squid Cache (Version " << version_string << "): Exiting normally.");
 
     /*
diff -u -r -N squid-4.0.19/src/Makefile.am squid-4.0.20/src/Makefile.am
--- squid-4.0.19/src/Makefile.am	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/Makefile.am	2017-06-02 00:49:17.000000000 +1200
@@ -348,6 +348,8 @@
 	icp_opcode.h \
 	icp_v2.cc \
 	icp_v3.cc \
+	Instance.h \
+	Instance.cc \
 	int.h \
 	int.cc \
 	internal.h \
@@ -1159,6 +1161,7 @@
 	tests/testBoilerplate.h \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
+	tests/stub_SBuf.cc \
 	tests/stub_time.cc
 nodist_tests_testBoilerplate_SOURCES = \
 	tests/stub_cbdata.cc \
@@ -1182,7 +1185,8 @@
 	tests/stub_cbdata.cc \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
-	tests/stub_MemBuf.cc
+	tests/stub_MemBuf.cc \
+	tests/stub_SBuf.cc
 tests_testCharacterSet_LDFLAGS = $(LIBADD_DL)
 tests_testCharacterSet_LDADD= \
 	base/libbase.la \
@@ -2638,6 +2642,7 @@
 	SquidTime.h \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
+	tests/stub_SBuf.cc \
 	time.cc \
 	globals.cc
 tests_testIcmp_LDFLAGS = $(LIBADD_DL)
@@ -2656,6 +2661,7 @@
 	SquidTime.h \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
+	tests/stub_SBuf.cc \
 	time.cc \
 	globals.cc
 tests_testNetDb_LDFLAGS = $(LIBADD_DL)
@@ -3621,6 +3627,7 @@
 	base/EnumIterator.h \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
+	tests/stub_SBuf.cc \
 	tests/testEnumIterator.h \
 	tests/testEnumIterator.cc
 nodist_tests_testEnumIterator_SOURCES = \
@@ -3639,6 +3646,7 @@
 	tests/STUB.h \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
+	tests/stub_SBuf.cc \
 	base/YesNoNone.h
 tests_testYesNoNone_LDADD= \
 	base/libbase.la \
diff -u -r -N squid-4.0.19/src/Makefile.in squid-4.0.20/src/Makefile.in
--- squid-4.0.19/src/Makefile.in	2017-04-02 19:45:34.000000000 +1200
+++ squid-4.0.20/src/Makefile.in	2017-06-02 00:54:20.000000000 +1200
@@ -273,14 +273,14 @@
 	HttpHeaderTools.cc HttpBody.h HttpBody.cc HttpControlMsg.cc \
 	HttpControlMsg.h HttpMsg.cc HttpMsg.h HttpReply.cc HttpReply.h \
 	RequestFlags.h RequestFlags.cc HttpRequest.cc HttpRequest.h \
-	ICP.h icp_opcode.h icp_v2.cc icp_v3.cc int.h int.cc internal.h \
-	internal.cc SquidIpc.h ipc.cc ipc_win32.cc ipcache.cc \
-	ipcache.h LeakFinder.cc LogTags.cc LogTags.h lookup_t.h \
-	main.cc MasterXaction.cc MasterXaction.h mem_node.cc \
-	mem_node.h MemBuf.cc MemObject.cc MemObject.h MessageSizes.h \
-	mime.h mime.cc mime_header.h mime_header.cc multicast.h \
-	multicast.cc neighbors.h neighbors.cc Notes.h Notes.cc \
-	Parsing.cc Parsing.h ProfStats.cc pconn.cc pconn.h \
+	ICP.h icp_opcode.h icp_v2.cc icp_v3.cc Instance.h Instance.cc \
+	int.h int.cc internal.h internal.cc SquidIpc.h ipc.cc \
+	ipc_win32.cc ipcache.cc ipcache.h LeakFinder.cc LogTags.cc \
+	LogTags.h lookup_t.h main.cc MasterXaction.cc MasterXaction.h \
+	mem_node.cc mem_node.h MemBuf.cc MemObject.cc MemObject.h \
+	MessageSizes.h mime.h mime.cc mime_header.h mime_header.cc \
+	multicast.h multicast.cc neighbors.h neighbors.cc Notes.h \
+	Notes.cc Parsing.cc Parsing.h ProfStats.cc pconn.cc pconn.h \
 	PeerDigest.h peer_digest.cc peer_proxy_negotiate_auth.h \
 	peer_proxy_negotiate_auth.cc peer_select.cc peer_sourcehash.h \
 	peer_sourcehash.cc peer_userhash.h peer_userhash.cc \
@@ -357,13 +357,13 @@
 	HttpBody.$(OBJEXT) HttpControlMsg.$(OBJEXT) HttpMsg.$(OBJEXT) \
 	HttpReply.$(OBJEXT) RequestFlags.$(OBJEXT) \
 	HttpRequest.$(OBJEXT) icp_v2.$(OBJEXT) icp_v3.$(OBJEXT) \
-	int.$(OBJEXT) internal.$(OBJEXT) $(am__objects_6) \
-	ipcache.$(OBJEXT) $(am__objects_7) LogTags.$(OBJEXT) \
-	main.$(OBJEXT) MasterXaction.$(OBJEXT) mem_node.$(OBJEXT) \
-	MemBuf.$(OBJEXT) MemObject.$(OBJEXT) mime.$(OBJEXT) \
-	mime_header.$(OBJEXT) multicast.$(OBJEXT) neighbors.$(OBJEXT) \
-	Notes.$(OBJEXT) Parsing.$(OBJEXT) $(am__objects_8) \
-	pconn.$(OBJEXT) peer_digest.$(OBJEXT) \
+	Instance.$(OBJEXT) int.$(OBJEXT) internal.$(OBJEXT) \
+	$(am__objects_6) ipcache.$(OBJEXT) $(am__objects_7) \
+	LogTags.$(OBJEXT) main.$(OBJEXT) MasterXaction.$(OBJEXT) \
+	mem_node.$(OBJEXT) MemBuf.$(OBJEXT) MemObject.$(OBJEXT) \
+	mime.$(OBJEXT) mime_header.$(OBJEXT) multicast.$(OBJEXT) \
+	neighbors.$(OBJEXT) Notes.$(OBJEXT) Parsing.$(OBJEXT) \
+	$(am__objects_8) pconn.$(OBJEXT) peer_digest.$(OBJEXT) \
 	peer_proxy_negotiate_auth.$(OBJEXT) peer_select.$(OBJEXT) \
 	peer_sourcehash.$(OBJEXT) peer_userhash.$(OBJEXT) \
 	PeerPoolMgr.$(OBJEXT) Pipeline.$(OBJEXT) redirect.$(OBJEXT) \
@@ -499,7 +499,7 @@
 	$(LDFLAGS) -o $@
 am_tests_testBoilerplate_OBJECTS = tests/testBoilerplate.$(OBJEXT) \
 	tests/stub_debug.$(OBJEXT) tests/stub_libmem.$(OBJEXT) \
-	tests/stub_time.$(OBJEXT)
+	tests/stub_SBuf.$(OBJEXT) tests/stub_time.$(OBJEXT)
 nodist_tests_testBoilerplate_OBJECTS = tests/stub_cbdata.$(OBJEXT) \
 	tests/stub_MemBuf.$(OBJEXT) $(am__objects_18)
 tests_testBoilerplate_OBJECTS = $(am_tests_testBoilerplate_OBJECTS) \
@@ -652,7 +652,8 @@
 am_tests_testCharacterSet_OBJECTS = tests/testCharacterSet.$(OBJEXT)
 nodist_tests_testCharacterSet_OBJECTS = $(am__objects_18) \
 	tests/stub_cbdata.$(OBJEXT) tests/stub_debug.$(OBJEXT) \
-	tests/stub_libmem.$(OBJEXT) tests/stub_MemBuf.$(OBJEXT)
+	tests/stub_libmem.$(OBJEXT) tests/stub_MemBuf.$(OBJEXT) \
+	tests/stub_SBuf.$(OBJEXT)
 tests_testCharacterSet_OBJECTS = $(am_tests_testCharacterSet_OBJECTS) \
 	$(nodist_tests_testCharacterSet_OBJECTS)
 tests_testCharacterSet_DEPENDENCIES = base/libbase.la \
@@ -801,7 +802,8 @@
 	$(AM_CXXFLAGS) $(CXXFLAGS) $(tests_testDns_LDFLAGS) $(LDFLAGS) \
 	-o $@
 am_tests_testEnumIterator_OBJECTS = tests/stub_debug.$(OBJEXT) \
-	tests/stub_libmem.$(OBJEXT) tests/testEnumIterator.$(OBJEXT)
+	tests/stub_libmem.$(OBJEXT) tests/stub_SBuf.$(OBJEXT) \
+	tests/testEnumIterator.$(OBJEXT)
 nodist_tests_testEnumIterator_OBJECTS = $(am__objects_18)
 tests_testEnumIterator_OBJECTS = $(am_tests_testEnumIterator_OBJECTS) \
 	$(nodist_tests_testEnumIterator_OBJECTS)
@@ -1297,7 +1299,8 @@
 	$(LDFLAGS) -o $@
 am_tests_testIcmp_OBJECTS = tests/testIcmp.$(OBJEXT)
 nodist_tests_testIcmp_OBJECTS = tests/stub_debug.$(OBJEXT) \
-	tests/stub_libmem.$(OBJEXT) time.$(OBJEXT) globals.$(OBJEXT)
+	tests/stub_libmem.$(OBJEXT) tests/stub_SBuf.$(OBJEXT) \
+	time.$(OBJEXT) globals.$(OBJEXT)
 tests_testIcmp_OBJECTS = $(am_tests_testIcmp_OBJECTS) \
 	$(nodist_tests_testIcmp_OBJECTS)
 tests_testIcmp_DEPENDENCIES = icmp/libicmpcore.la ip/libip.la \
@@ -1334,7 +1337,8 @@
 	$(LDFLAGS) -o $@
 am_tests_testNetDb_OBJECTS = tests/testNetDb.$(OBJEXT)
 nodist_tests_testNetDb_OBJECTS = tests/stub_debug.$(OBJEXT) \
-	tests/stub_libmem.$(OBJEXT) time.$(OBJEXT) globals.$(OBJEXT)
+	tests/stub_libmem.$(OBJEXT) tests/stub_SBuf.$(OBJEXT) \
+	time.$(OBJEXT) globals.$(OBJEXT)
 tests_testNetDb_OBJECTS = $(am_tests_testNetDb_OBJECTS) \
 	$(nodist_tests_testNetDb_OBJECTS)
 tests_testNetDb_DEPENDENCIES = icmp/libicmp.la ip/libip.la \
@@ -1885,7 +1889,7 @@
 	-o $@
 am_tests_testYesNoNone_OBJECTS = tests/testYesNoNone.$(OBJEXT)
 nodist_tests_testYesNoNone_OBJECTS = tests/stub_debug.$(OBJEXT) \
-	tests/stub_libmem.$(OBJEXT)
+	tests/stub_libmem.$(OBJEXT) tests/stub_SBuf.$(OBJEXT)
 tests_testYesNoNone_OBJECTS = $(am_tests_testYesNoNone_OBJECTS) \
 	$(nodist_tests_testYesNoNone_OBJECTS)
 tests_testYesNoNone_DEPENDENCIES = base/libbase.la \
@@ -2870,15 +2874,15 @@
 	HttpBody.h HttpBody.cc HttpControlMsg.cc HttpControlMsg.h \
 	HttpMsg.cc HttpMsg.h HttpReply.cc HttpReply.h RequestFlags.h \
 	RequestFlags.cc HttpRequest.cc HttpRequest.h ICP.h \
-	icp_opcode.h icp_v2.cc icp_v3.cc int.h int.cc internal.h \
-	internal.cc $(IPC_SOURCE) ipcache.cc ipcache.h \
-	$(LEAKFINDERSOURCE) LogTags.cc LogTags.h lookup_t.h main.cc \
-	MasterXaction.cc MasterXaction.h mem_node.cc mem_node.h \
-	MemBuf.cc MemObject.cc MemObject.h MessageSizes.h mime.h \
-	mime.cc mime_header.h mime_header.cc multicast.h multicast.cc \
-	neighbors.h neighbors.cc Notes.h Notes.cc Parsing.cc Parsing.h \
-	$(XPROF_STATS_SOURCE) pconn.cc pconn.h PeerDigest.h \
-	peer_digest.cc peer_proxy_negotiate_auth.h \
+	icp_opcode.h icp_v2.cc icp_v3.cc Instance.h Instance.cc int.h \
+	int.cc internal.h internal.cc $(IPC_SOURCE) ipcache.cc \
+	ipcache.h $(LEAKFINDERSOURCE) LogTags.cc LogTags.h lookup_t.h \
+	main.cc MasterXaction.cc MasterXaction.h mem_node.cc \
+	mem_node.h MemBuf.cc MemObject.cc MemObject.h MessageSizes.h \
+	mime.h mime.cc mime_header.h mime_header.cc multicast.h \
+	multicast.cc neighbors.h neighbors.cc Notes.h Notes.cc \
+	Parsing.cc Parsing.h $(XPROF_STATS_SOURCE) pconn.cc pconn.h \
+	PeerDigest.h peer_digest.cc peer_proxy_negotiate_auth.h \
 	peer_proxy_negotiate_auth.cc peer_select.cc peer_sourcehash.h \
 	peer_sourcehash.cc peer_userhash.h peer_userhash.cc \
 	PeerPoolMgr.h PeerPoolMgr.cc PeerSelectState.h PingData.h \
@@ -3422,6 +3426,7 @@
 	tests/testBoilerplate.h \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
+	tests/stub_SBuf.cc \
 	tests/stub_time.cc
 
 nodist_tests_testBoilerplate_SOURCES = \
@@ -3447,7 +3452,8 @@
 	tests/stub_cbdata.cc \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
-	tests/stub_MemBuf.cc
+	tests/stub_MemBuf.cc \
+	tests/stub_SBuf.cc
 
 tests_testCharacterSet_LDFLAGS = $(LIBADD_DL)
 tests_testCharacterSet_LDADD = \
@@ -4920,6 +4926,7 @@
 	SquidTime.h \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
+	tests/stub_SBuf.cc \
 	time.cc \
 	globals.cc
 
@@ -4940,6 +4947,7 @@
 	SquidTime.h \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
+	tests/stub_SBuf.cc \
 	time.cc \
 	globals.cc
 
@@ -5916,6 +5924,7 @@
 	base/EnumIterator.h \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
+	tests/stub_SBuf.cc \
 	tests/testEnumIterator.h \
 	tests/testEnumIterator.cc
 
@@ -5937,6 +5946,7 @@
 	tests/STUB.h \
 	tests/stub_debug.cc \
 	tests/stub_libmem.cc \
+	tests/stub_SBuf.cc \
 	base/YesNoNone.h
 
 tests_testYesNoNone_LDADD = \
@@ -6268,6 +6278,8 @@
 	$(AM_V_CXXLD)$(tests_testACLMaxUserIP_LINK) $(tests_testACLMaxUserIP_OBJECTS) $(tests_testACLMaxUserIP_LDADD) $(LIBS)
 tests/testBoilerplate.$(OBJEXT): tests/$(am__dirstamp) \
 	tests/$(DEPDIR)/$(am__dirstamp)
+tests/stub_SBuf.$(OBJEXT): tests/$(am__dirstamp) \
+	tests/$(DEPDIR)/$(am__dirstamp)
 
 tests/testBoilerplate$(EXEEXT): $(tests_testBoilerplate_OBJECTS) $(tests_testBoilerplate_DEPENDENCIES) $(EXTRA_tests_testBoilerplate_DEPENDENCIES) tests/$(am__dirstamp)
 	@rm -f tests/testBoilerplate$(EXEEXT)
@@ -6354,8 +6366,6 @@
 	$(AM_V_CXXLD)$(tests_testDiskIO_LINK) $(tests_testDiskIO_OBJECTS) $(tests_testDiskIO_LDADD) $(LIBS)
 tests/testRFC1035.$(OBJEXT): tests/$(am__dirstamp) \
 	tests/$(DEPDIR)/$(am__dirstamp)
-tests/stub_SBuf.$(OBJEXT): tests/$(am__dirstamp) \
-	tests/$(DEPDIR)/$(am__dirstamp)
 
 tests/testDns$(EXEEXT): $(tests_testDns_OBJECTS) $(tests_testDns_DEPENDENCIES) $(EXTRA_tests_testDns_DEPENDENCIES) tests/$(am__dirstamp)
 	@rm -f tests/testDns$(EXEEXT)
@@ -6569,6 +6579,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpMsg.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpReply.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpRequest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Instance.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LeakFinder.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LoadableModule.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LoadableModules.Po@am__quote@
diff -u -r -N squid-4.0.19/src/neighbors.cc squid-4.0.20/src/neighbors.cc
--- squid-4.0.19/src/neighbors.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/neighbors.cc	2017-06-02 00:49:17.000000000 +1200
@@ -59,7 +59,7 @@
 static void neighborCountIgnored(CachePeer *);
 static void peerRefreshDNS(void *);
 static IPH peerDNSConfigure;
-static bool peerProbeConnect(CachePeer *);
+static void peerProbeConnect(CachePeer *, const bool reprobeIfBusy = false);
 static CNCB peerProbeConnectDone;
 static void peerCountMcastPeersDone(void *data);
 static void peerCountMcastPeersStart(void *data);
@@ -1123,10 +1123,8 @@
 neighborUp(const CachePeer * p)
 {
     if (!p->tcp_up) {
-        if (!peerProbeConnect((CachePeer *) p)) {
-            debugs(15, 8, "neighborUp: DOWN (probed): " << p->host << " (" << p->in_addr << ")");
-            return 0;
-        }
+        peerProbeConnect(const_cast<CachePeer*>(p));
+        return 0;
     }
 
     /*
@@ -1161,6 +1159,20 @@
 #endif
 }
 
+/// \returns the effective connect timeout for this peer
+time_t
+peerConnectTimeout(const CachePeer *peer)
+{
+    return peer->connect_timeout_raw > 0 ?
+           peer->connect_timeout_raw : Config.Timeout.peer_connect;
+}
+
+time_t
+positiveTimeout(const time_t timeout)
+{
+    return max(static_cast<time_t>(1), timeout);
+}
+
 static void
 peerDNSConfigure(const ipcache_addrs *ia, const Dns::LookupDetails &, void *data)
 {
@@ -1190,8 +1202,6 @@
         return;
     }
 
-    p->tcp_up = p->connect_fail_limit;
-
     for (j = 0; j < (int) ia->count && j < PEER_MAX_ADDRESSES; ++j) {
         p->addresses[j] = ia->in_addrs[j];
         debugs(15, 2, "--> IP address #" << j << ": " << p->addresses[j]);
@@ -1202,6 +1212,8 @@
     p->in_addr = p->addresses[0];
     p->in_addr.port(p->icp.port);
 
+    peerProbeConnect(p, true); // detect any died or revived peers ASAP
+
     if (p->type == PEER_MULTICAST)
         peerCountMcastPeersSchedule(p, 10);
 
@@ -1275,21 +1287,33 @@
         p->tcp_up = p->connect_fail_limit;
 }
 
+/// whether new TCP probes are currently banned
+static bool
+peerProbeIsBusy(const CachePeer *p)
+{
+    if (p->testing_now > 0) {
+        debugs(15, 8, "yes, probing " << p);
+        return true;
+    }
+    if (squid_curtime - p->stats.last_connect_probe == 0) {
+        debugs(15, 8, "yes, just probed " << p);
+        return true;
+    }
+    return false;
+}
 /*
 * peerProbeConnect will be called on dead peers by neighborUp
 */
-static bool
-peerProbeConnect(CachePeer * p)
+static void
+peerProbeConnect(CachePeer *p, const bool reprobeIfBusy)
 {
-    time_t ctimeout = p->connect_timeout > 0 ? p->connect_timeout : Config.Timeout.peer_connect;
-    bool ret = (squid_curtime - p->stats.last_connect_failure) > (ctimeout * 10);
-
-    if (p->testing_now > 0)
-        return ret;/* probe already running */
-
-    if (squid_curtime - p->stats.last_connect_probe == 0)
-        return ret;/* don't probe to often */
+    if (peerProbeIsBusy(p)) {
+        p->reprobe = reprobeIfBusy;
+        return;
+    }
+    p->reprobe = false;
 
+    const time_t ctimeout = peerConnectTimeout(p);
     /* for each IP address of this CachePeer. find one that we can connect to and probe it. */
     for (int i = 0; i < p->n_addresses; ++i) {
         Comm::ConnectionPointer conn = new Comm::Connection;
@@ -1307,8 +1331,6 @@
     }
 
     p->stats.last_connect_probe = squid_curtime;
-
-    return ret;
 }
 
 static void
@@ -1325,6 +1347,9 @@
     -- p->testing_now;
     conn->close();
     // TODO: log this traffic.
+
+    if (p->reprobe)
+        peerProbeConnect(p);
 }
 
 static void
@@ -1528,8 +1553,8 @@
     if (p->mcast.ttl > 0)
         storeAppendPrintf(sentry, " ttl=%d", p->mcast.ttl);
 
-    if (p->connect_timeout > 0)
-        storeAppendPrintf(sentry, " connect-timeout=%d", (int) p->connect_timeout);
+    if (p->connect_timeout_raw > 0)
+        storeAppendPrintf(sentry, " connect-timeout=%d", (int)p->connect_timeout_raw);
 
     if (p->connect_fail_limit != PEER_TCP_MAGIC_COUNT)
         storeAppendPrintf(sentry, " connect-fail-limit=%d", p->connect_fail_limit);
diff -u -r -N squid-4.0.19/src/neighbors.h squid-4.0.20/src/neighbors.h
--- squid-4.0.19/src/neighbors.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/neighbors.h	2017-06-02 00:49:17.000000000 +1200
@@ -60,6 +60,13 @@
 void dump_peer_options(StoreEntry *, CachePeer *);
 int peerHTTPOkay(const CachePeer *, HttpRequest *);
 
+// TODO: Consider moving this method to CachePeer class.
+/// \returns the effective connect timeout for the given peer
+time_t peerConnectTimeout(const CachePeer *peer);
+
+/// \returns max(1, timeout)
+time_t positiveTimeout(const time_t timeout);
+
 /// Whether we can open new connections to the peer (e.g., despite max-conn)
 bool peerCanOpenMore(const CachePeer *p);
 /// Whether the peer has idle or standby connections that can be used now
diff -u -r -N squid-4.0.19/src/PeerPoolMgr.cc squid-4.0.20/src/PeerPoolMgr.cc
--- squid-4.0.19/src/PeerPoolMgr.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/PeerPoolMgr.cc	2017-06-02 00:49:17.000000000 +1200
@@ -118,11 +118,10 @@
         securer = asyncCall(48, 4, "PeerPoolMgr::handleSecuredPeer",
                             MyAnswerDialer(this, &PeerPoolMgr::handleSecuredPeer));
 
-        const int peerTimeout = peer->connect_timeout > 0 ?
-                                peer->connect_timeout : Config.Timeout.peer_connect;
+        const int peerTimeout = peerConnectTimeout(peer);
         const int timeUsed = squid_curtime - params.conn->startTime();
         // Use positive timeout when less than one second is left for conn.
-        const int timeLeft = max(1, (peerTimeout - timeUsed));
+        const int timeLeft = positiveTimeout(peerTimeout - timeUsed);
         auto *connector = new Security::BlindPeerConnector(request, params.conn, securer, nullptr, timeLeft);
         AsyncJob::Start(connector); // will call our callback
         return;
@@ -224,8 +223,7 @@
     getOutgoingAddress(request.getRaw(), conn);
     GetMarkingsToServer(request.getRaw(), *conn);
 
-    const int ctimeout = peer->connect_timeout > 0 ?
-                         peer->connect_timeout : Config.Timeout.peer_connect;
+    const int ctimeout = peerConnectTimeout(peer);
     typedef CommCbMemFunT<PeerPoolMgr, CommConnectCbParams> Dialer;
     opener = JobCallback(48, 5, Dialer, this, PeerPoolMgr::handleOpenedConnection);
     Comm::ConnOpener *cs = new Comm::ConnOpener(conn, opener, ctimeout);
diff -u -r -N squid-4.0.19/src/refresh.cc squid-4.0.20/src/refresh.cc
--- squid-4.0.19/src/refresh.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/refresh.cc	2017-06-02 00:49:17.000000000 +1200
@@ -309,8 +309,8 @@
 
     if (request && !request->flags.ignoreCc) {
         const HttpHdrCc *const cc = request->cache_control;
-        if (cc && cc->hasMinFresh()) {
-            const int32_t minFresh=cc->minFresh();
+        int minFresh = -1;
+        if (cc && cc->hasMinFresh(&minFresh)) {
             debugs(22, 3, "\tage + min-fresh:\t" << age << " + " <<
                    minFresh << " = " << age + minFresh);
             debugs(22, 3, "\tcheck_time + min-fresh:\t" << check_time << " + "
@@ -330,9 +330,10 @@
     const auto *reply = (entry->mem_obj && entry->mem_obj->getReply() ? entry->mem_obj->getReply() : nullptr);
 
     // stale-if-error requires any failure be passed thru when its period is over.
+    int staleIfError = -1;
     if (request && reply && reply->cache_control &&
-            reply->cache_control->hasStaleIfError() &&
-            reply->cache_control->staleIfError() < staleness) {
+            reply->cache_control->hasStaleIfError(&staleIfError) &&
+            staleIfError < staleness) {
 
         debugs(22, 3, "stale-if-error period expired. Will produce error if validation fails.");
         request->flags.failOnValidationError = true;
@@ -416,32 +417,34 @@
         if (NULL != cc) {
 
             // max-age directive
-            if (cc->hasMaxAge()) {
+            int maxAge = -1;
+            if (cc->hasMaxAge(&maxAge)) {
 
                 // draft-mcmanus-immutable-00: reply contains CC:immutable then ignore client CC:max-age=N
-                if (reply && reply->cache_control && reply->cache_control->Immutable()) {
-                    debugs(22, 3, "MAYBE: Ignoring client CC:max-age=" << cc->maxAge() << " request - 'Cache-Control: immutable'");
+                if (reply && reply->cache_control && reply->cache_control->hasImmutable()) {
+                    debugs(22, 3, "MAYBE: Ignoring client CC:max-age=" << maxAge << " request - 'Cache-Control: immutable'");
 
 #if USE_HTTP_VIOLATIONS
                     // Ignore of client "Cache-Control: max-age=0" header
-                } else if (R->flags.ignore_reload && cc->maxAge() == 0) {
+                } else if (R->flags.ignore_reload && maxAge == 0) {
                     debugs(22, 3, "MAYBE: Ignoring client reload request - trying to serve from cache (ignore-reload option)");
 #endif
 
                     // Honour client "Cache-Control: max-age=x" header
-                } else if (age > cc->maxAge() || cc->maxAge() == 0) {
-                    debugs(22, 3, "YES: Revalidating object - client 'Cache-Control: max-age=" << cc->maxAge() << "'");
+                } else if (age > maxAge || maxAge == 0) {
+                    debugs(22, 3, "YES: Revalidating object - client 'Cache-Control: max-age=" << maxAge << "'");
                     return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE;
                 }
             }
 
             // max-stale directive
-            if (cc->hasMaxStale() && staleness > -1) {
-                if (cc->maxStale()==HttpHdrCc::MAX_STALE_ANY) {
+            int maxStale = -1;
+            if (cc->hasMaxStale(&maxStale) && staleness > -1) {
+                if (maxStale==HttpHdrCc::MAX_STALE_ANY) {
                     debugs(22, 3, "NO: Client accepts a stale response of any age - 'Cache-Control: max-stale'");
                     return FRESH_REQUEST_MAX_STALE_ALL;
-                } else if (staleness < cc->maxStale()) {
-                    debugs(22, 3, "NO: Client accepts a stale response - 'Cache-Control: max-stale=" << cc->maxStale() << "'");
+                } else if (staleness < maxStale) {
+                    debugs(22, 3, "NO: Client accepts a stale response - 'Cache-Control: max-stale=" << maxStale << "'");
                     return FRESH_REQUEST_MAX_STALE_VALUE;
                 }
             }
diff -u -r -N squid-4.0.19/src/sbuf/Exceptions.cc squid-4.0.20/src/sbuf/Exceptions.cc
--- squid-4.0.19/src/sbuf/Exceptions.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/sbuf/Exceptions.cc	2017-06-02 00:49:17.000000000 +1200
@@ -25,9 +25,7 @@
         explanatoryText.appendf(" in file %s", aFileName);
     explanatoryText.appendf(" while accessing position %d in a SBuf long %d",
                             pos, throwingBuf.length());
-    // we can safely alias c_str as both are local to the object
-    //  and will not further manipulated.
-    message = xstrndup(explanatoryText.c_str(),explanatoryText.length());
+    message = xstrdup(explanatoryText.c_str());
 }
 
 OutOfBoundsException::~OutOfBoundsException() throw()
diff -u -r -N squid-4.0.19/src/sbuf/Stream.h squid-4.0.20/src/sbuf/Stream.h
--- squid-4.0.19/src/sbuf/Stream.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/sbuf/Stream.h	2017-06-02 00:49:17.000000000 +1200
@@ -118,5 +118,17 @@
     SBufStreamBuf theBuffer;
 };
 
+/// slowly stream-prints all arguments into a freshly allocated SBuf
+template <typename... Args>
+inline
+SBuf ToSBuf(Args&&... args)
+{
+    // TODO: Make this code readable after requiring C++17.
+    SBufStream out;
+    using expander = int[];
+    (void)expander {0, (void(out << std::forward<Args>(args)),0)...};
+    return out.buf();
+}
+
 #endif /* SQUID_SBUFSTREAM_H */
 
diff -u -r -N squid-4.0.19/src/security/cert_generators/file/security_file_certgen.cc squid-4.0.20/src/security/cert_generators/file/security_file_certgen.cc
--- squid-4.0.19/src/security/cert_generators/file/security_file_certgen.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/security/cert_generators/file/security_file_certgen.cc	2017-06-02 00:49:17.000000000 +1200
@@ -337,7 +337,7 @@
         }
     } catch (std::runtime_error & error) {
         std::cerr << argv[0] << ": " << error.what() << std::endl;
-        return 0;
+        return -1;
     }
     return 0;
 }
diff -u -r -N squid-4.0.19/src/security/cert_validators/fake/security_fake_certverify.8 squid-4.0.20/src/security/cert_validators/fake/security_fake_certverify.8
--- squid-4.0.19/src/security/cert_validators/fake/security_fake_certverify.8	2017-04-02 23:50:29.000000000 +1200
+++ squid-4.0.20/src/security/cert_validators/fake/security_fake_certverify.8	2017-06-02 09:59:08.000000000 +1200
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "SECURITY_FAKE_CERTVERIFY 8"
-.TH SECURITY_FAKE_CERTVERIFY 8 "2017-04-02" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH SECURITY_FAKE_CERTVERIFY 8 "2017-06-01" "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.19/src/security/forward.h squid-4.0.20/src/security/forward.h
--- squid-4.0.19/src/security/forward.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/security/forward.h	2017-06-02 00:49:17.000000000 +1200
@@ -30,6 +30,31 @@
         struct sk_object ## _free_wrapper { \
             void operator()(argument_type a) { sk_object ## _pop_free(a, freefunction); } \
         }
+
+#if !HAVE_LIBCRYPTO_X509_UP_REF // OpenSSL 1.1 API
+#if defined(CRYPTO_LOCK_X509) // OpenSSL 1.0 API
+inline int X509_up_ref(X509 *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_X509); return 0;}
+#else
+#error missing both OpenSSL API features X509_up_ref (v1.1) and CRYPTO_LOCK_X509 (v1.0)
+#endif /* CRYPTO_LOCK_X509 */
+#endif /* X509_up_ref */
+
+#if !HAVE_LIBCRYPTO_X509_CRL_UP_REF // OpenSSL 1.1 API
+#if defined(CRYPTO_LOCK_X509_CRL) // OpenSSL 1.0 API
+inline int X509_CRL_up_ref(X509_CRL *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_X509_CRL); return 0;}
+#else
+#error missing both OpenSSL API features X509_up_ref (v1.1) and CRYPTO_LOCK_X509 (v1.0)
+#endif /* CRYPTO_LOCK_X509_CRL */
+#endif /* X509_CRL_up_ref */
+#if !HAVE_LIBCRYPTO_DH_UP_REF // OpenSSL 1.1 API
+#if defined(CRYPTO_LOCK_DH) // OpenSSL 1.0 API
+inline int DH_up_ref(DH *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_DH); return 0;}
+#else
+
+#error missing both OpenSSL API features DH_up_ref (v1.1) and CRYPTO_LOCK_DH (v1.0)
+#endif /* OpenSSL 1.0 CRYPTO_LOCK_X509_CRL */
+#endif /* OpenSSL 1.1 DH_up_ref */
+
 #endif /* USE_OPENSSL */
 
 /* flags a SSL connection can be configured with */
@@ -51,9 +76,6 @@
 
 #if USE_OPENSSL
 CtoCpp1(X509_free, X509 *)
-#if defined(CRYPTO_LOCK_X509) // OpenSSL 1.0
-inline int X509_up_ref(X509 *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_X509); return 0;}
-#endif
 typedef Security::LockingPointer<X509, X509_free_cpp, HardFun<int, X509 *, X509_up_ref> > CertPointer;
 #elif USE_GNUTLS
 CtoCpp1(gnutls_x509_crt_deinit, gnutls_x509_crt_t)
@@ -64,9 +86,6 @@
 
 #if USE_OPENSSL
 CtoCpp1(X509_CRL_free, X509_CRL *)
-#if defined(CRYPTO_LOCK_X509_CRL) // OpenSSL 1.0
-inline int X509_CRL_up_ref(X509_CRL *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_X509_CRL); return 0;}
-#endif
 typedef Security::LockingPointer<X509_CRL, X509_CRL_free_cpp, HardFun<int, X509_CRL *, X509_CRL_up_ref> > CrlPointer;
 #elif USE_GNUTLS
 CtoCpp1(gnutls_x509_crl_deinit, gnutls_x509_crl_t)
@@ -81,9 +100,6 @@
 
 #if USE_OPENSSL
 CtoCpp1(DH_free, DH *);
-#if defined(CRYPTO_LOCK_DH) // OpenSSL 1.0
-inline int DH_up_ref(DH *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_DH); return 0;}
-#endif
 typedef Security::LockingPointer<DH, DH_free_cpp, HardFun<int, DH *, DH_up_ref> > DhePointer;
 #else
 typedef void *DhePointer;
diff -u -r -N squid-4.0.19/src/security/PeerOptions.cc squid-4.0.20/src/security/PeerOptions.cc
--- squid-4.0.19/src/security/PeerOptions.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/security/PeerOptions.cc	2017-06-02 00:49:17.000000000 +1200
@@ -248,7 +248,7 @@
 #if USE_OPENSSL
     Ssl::Initialize();
 
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#if HAVE_OPENSSL_TLS_CLIENT_METHOD
     SSL_CTX *t = SSL_CTX_new(TLS_client_method());
 #else
     SSL_CTX *t = SSL_CTX_new(SSLv23_client_method());
diff -u -r -N squid-4.0.19/src/security/ServerOptions.cc squid-4.0.20/src/security/ServerOptions.cc
--- squid-4.0.19/src/security/ServerOptions.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/security/ServerOptions.cc	2017-06-02 00:49:17.000000000 +1200
@@ -92,7 +92,7 @@
 #if USE_OPENSSL
     Ssl::Initialize();
 
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#if HAVE_OPENSSL_SERVER_METHOD
     SSL_CTX *t = SSL_CTX_new(TLS_server_method());
 #else
     SSL_CTX *t = SSL_CTX_new(SSLv23_server_method());
diff -u -r -N squid-4.0.19/src/ssl/bio.cc squid-4.0.20/src/ssl/bio.cc
--- squid-4.0.19/src/ssl/bio.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/ssl/bio.cc	2017-06-02 00:49:17.000000000 +1200
@@ -43,7 +43,9 @@
 /* SSL callbacks */
 static void squid_ssl_info(const SSL *ssl, int where, int ret);
 
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if HAVE_LIBCRYPTO_BIO_METH_NEW
+static BIO_METHOD *SquidMethods = nullptr;
+#else
 /// Initialization structure for the BIO table with
 /// Squid-specific methods and BIO method wrappers.
 static BIO_METHOD SquidMethods = {
@@ -58,16 +60,12 @@
     squid_bio_destroy,
     NULL // squid_callback_ctrl not supported
 };
-#else
-static BIO_METHOD *SquidMethods = NULL;
 #endif
 
 BIO *
 Ssl::Bio::Create(const int fd, Security::Io::Type type)
 {
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
-    BIO_METHOD *useMethod = &SquidMethods;
-#else
+#if HAVE_LIBCRYPTO_BIO_METH_NEW
     if (!SquidMethods) {
         SquidMethods = BIO_meth_new(BIO_TYPE_SOCKET, "squid");
         BIO_meth_set_write(SquidMethods, squid_bio_write);
@@ -79,6 +77,8 @@
         BIO_meth_set_destroy(SquidMethods, squid_bio_destroy);
     }
     const BIO_METHOD *useMethod = SquidMethods;
+#else
+    BIO_METHOD *useMethod = &SquidMethods;
 #endif
 
     if (BIO *bio = BIO_new(useMethod)) {
@@ -562,7 +562,7 @@
 static int
 squid_bio_create(BIO *bi)
 {
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if !HAVE_LIBCRYPTO_BIO_GET_INIT
     bi->init = 0; // set when we store Bio object and socket fd (BIO_C_SET_FD)
     bi->num = 0;
     bi->flags = 0;
@@ -706,11 +706,11 @@
             cbytes[0] = (cipherId >> 8) & 0xFF;
             cbytes[1] = cipherId & 0xFF;
             cbytes[2] = 0;
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if HAVE_LIBSSL_SSL_CIPHER_FIND
+            const SSL_CIPHER *c = SSL_CIPHER_find(ssl, cbytes);
+#else
             const SSL_METHOD *method = SSLv23_method();
             const SSL_CIPHER *c = method->get_cipher_by_char(cbytes);
-#else
-            const SSL_CIPHER *c = SSL_CIPHER_find(ssl, cbytes);
 #endif
             if (c != NULL) {
                 if (!strCiphers.isEmpty())
diff -u -r -N squid-4.0.19/src/ssl/bio.h squid-4.0.20/src/ssl/bio.h
--- squid-4.0.19/src/ssl/bio.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/ssl/bio.h	2017-06-02 00:49:17.000000000 +1200
@@ -202,7 +202,7 @@
 void
 applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl::BumpMode bumpMode);
 
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if !HAVE_LIBCRYPTO_BIO_GET_INIT
 // OpenSSL v1.0 bio compatibility functions
 inline void *BIO_get_data(BIO *table) { return table->ptr; }
 inline void BIO_set_data(BIO *table, void *data) { table->ptr = data; }
diff -u -r -N squid-4.0.19/src/ssl/gadgets.cc squid-4.0.20/src/ssl/gadgets.cc
--- squid-4.0.19/src/ssl/gadgets.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/ssl/gadgets.cc	2017-06-02 00:49:17.000000000 +1200
@@ -387,12 +387,12 @@
         DecipherOnly
     };
 
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if HAVE_LIBCRYPTO_EVP_PKEY_GET0_RSA
+    EVP_PKEY *certKey = X509_get_pubkey(mimicCert.get());
+    const bool rsaPkey = (EVP_PKEY_get0_RSA(certKey) != nullptr);
+#else
     const int mimicAlgo = OBJ_obj2nid(mimicCert.get()->cert_info->key->algor->algorithm);
     const bool rsaPkey = (mimicAlgo == NID_rsaEncryption);
-#else
-    EVP_PKEY *certKey = X509_get_pubkey(mimicCert.get());
-    const bool rsaPkey = (EVP_PKEY_get0_RSA(certKey) != NULL);
 #endif
 
     int added = 0;
@@ -443,6 +443,38 @@
     return added;
 }
 
+/// Adds a new subjectAltName extension contining Subject CN or returns false
+/// expects the caller to check for the existing subjectAltName extension
+static bool
+addAltNameWithSubjectCn(Security::CertPointer &cert)
+{
+    X509_NAME *name = X509_get_subject_name(cert.get());
+    if (!name)
+        return false;
+
+    const int loc = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
+    if (loc < 0)
+        return false;
+
+    ASN1_STRING *cn_data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, loc));
+    if (!cn_data)
+        return false;
+
+    char dnsName[1024]; // DNS names are limited to 256 characters
+    const int res = snprintf(dnsName, sizeof(dnsName), "DNS:%*s", cn_data->length, cn_data->data);
+    if (res <= 0 || res >= static_cast<int>(sizeof(dnsName)))
+        return false;
+
+    X509_EXTENSION *ext = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name, dnsName);
+    if (!ext)
+        return false;
+
+    const bool result = X509_add_ext(cert.get(), ext, -1);
+
+    X509_EXTENSION_free(ext);
+    return result;
+}
+
 static bool buildCertificate(Security::CertPointer & cert, Ssl::CertificateProperties const &properties)
 {
     // not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
@@ -491,6 +523,8 @@
     } else if (!X509_gmtime_adj(X509_get_notAfter(cert.get()), 60*60*24*356*3))
         return false;
 
+    int addedExtensions = 0;
+    bool useCommonNameAsAltName = true;
     // mimic the alias and possibly subjectAltName
     if (properties.mimicCert.get()) {
         unsigned char *alStr;
@@ -500,26 +534,29 @@
             X509_alias_set1(cert.get(), alStr, alLen);
         }
 
-        int addedExtensions = 0;
-
         // Mimic subjectAltName unless we used a configured CN: browsers reject
         // certificates with CN unrelated to subjectAltNames.
         if (!properties.setCommonName) {
-            int pos=X509_get_ext_by_NID (properties.mimicCert.get(), OBJ_sn2nid("subjectAltName"), -1);
+            int pos = X509_get_ext_by_NID(properties.mimicCert.get(), NID_subject_alt_name, -1);
             X509_EXTENSION *ext=X509_get_ext(properties.mimicCert.get(), pos);
             if (ext) {
                 if (X509_add_ext(cert.get(), ext, -1))
                     ++addedExtensions;
             }
+            // We want to mimic the server-sent subjectAltName, not enhance it.
+            useCommonNameAsAltName = false;
         }
 
         addedExtensions += mimicExtensions(cert, properties.mimicCert, properties.signWithX509);
-
-        // According to RFC 5280, using extensions requires v3 certificate.
-        if (addedExtensions)
-            X509_set_version(cert.get(), 2); // value 2 means v3
     }
 
+    if (useCommonNameAsAltName && addAltNameWithSubjectCn(cert))
+        ++addedExtensions;
+
+    // According to RFC 5280, using extensions requires v3 certificate.
+    if (addedExtensions)
+        X509_set_version(cert.get(), 2); // value 2 means v3
+
     return true;
 }
 
diff -u -r -N squid-4.0.19/src/ssl/PeekingPeerConnector.cc squid-4.0.20/src/ssl/PeekingPeerConnector.cc
--- squid-4.0.19/src/ssl/PeekingPeerConnector.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/ssl/PeekingPeerConnector.cc	2017-06-02 00:49:17.000000000 +1200
@@ -88,6 +88,7 @@
         request->clientConnectionManager->sslBumpMode = finalAction;
         request->clientConnectionManager->serverBump()->act.step3 = finalAction;
     }
+    al->ssl.bumpMode = finalAction;
 
     if (finalAction == Ssl::bumpTerminate) {
         serverConn->close();
diff -u -r -N squid-4.0.19/src/ssl/support.cc squid-4.0.20/src/ssl/support.cc
--- squid-4.0.19/src/ssl/support.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/ssl/support.cc	2017-06-02 00:49:17.000000000 +1200
@@ -97,7 +97,7 @@
     }
 }
 
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
 static RSA *
 ssl_temp_rsa_cb(SSL * ssl, int anInt, int keylen)
 {
@@ -152,7 +152,7 @@
 static void
 maybeSetupRsaCallback(Security::ContextPointer &ctx)
 {
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
     debugs(83, 9, "Setting RSA key generation callback.");
     SSL_CTX_set_tmp_rsa_callback(ctx.get(), ssl_temp_rsa_cb);
 #endif
@@ -236,7 +236,7 @@
     return matchX509CommonNames(cert, (void *)server, check_domain);
 }
 
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if !HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_CERT
 static inline X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx)
 {
     return ctx->cert;
@@ -380,7 +380,7 @@
 }
 
 // "dup" function for SSL_get_ex_new_index("cert_err_check")
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#if SQUID_USE_CONST_CRYPTO_EX_DATA_DUP
 static int
 ssl_dupAclChecklist(CRYPTO_EX_DATA *, const CRYPTO_EX_DATA *, void *,
                     int, long, void *)
@@ -986,9 +986,11 @@
 bool
 Ssl::verifySslCertificate(Security::ContextPointer &ctx, CertificateProperties const &properties)
 {
+#if HAVE_SSL_CTX_GET0_CERTIFICATE
+    X509 * cert = SSL_CTX_get0_certificate(ctx.get());
+#elif SQUID_USE_SSLGETCERTIFICATE_HACK
     // SSL_get_certificate is buggy in openssl versions 1.0.1d and 1.0.1e
     // Try to retrieve certificate directly from Security::ContextPointer object
-#if SQUID_USE_SSLGETCERTIFICATE_HACK
     X509 ***pCert = (X509 ***)ctx->cert;
     X509 * cert = pCert && *pCert ? **pCert : NULL;
 #elif SQUID_SSLGETCERTIFICATE_BUGGY
@@ -1066,10 +1068,10 @@
             if (ad->location->type == GEN_URI) {
                 xstrncpy(uri,
                          reinterpret_cast<const char *>(
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
-                             ASN1_STRING_data(ad->location->d.uniformResourceIdentifier)
-#else
+#if HAVE_LIBCRYPTO_ASN1_STRING_GET0_DATA
                              ASN1_STRING_get0_data(ad->location->d.uniformResourceIdentifier)
+#else
+                             ASN1_STRING_data(ad->location->d.uniformResourceIdentifier)
 #endif
                          ),
                          sizeof(uri));
@@ -1116,7 +1118,7 @@
     const auto ret = list.equal_range(SBuf(buffer));
     for (Ssl::CertsIndexedList::iterator it = ret.first; it != ret.second; ++it) {
         X509 *issuer = it->second;
-        if (X509_check_issued(cert, issuer)) {
+        if (X509_check_issued(issuer, cert) == X509_V_OK) {
             return issuer;
         }
     }
@@ -1201,16 +1203,16 @@
 {
     debugs(83, 2,  "completing " << sk_X509_num(untrustedCerts) << " OpenSSL untrusted certs using " << SquidUntrustedCerts.size() << " configured untrusted certificates");
 
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
-    int depth = ctx->param->depth;
-#else
+#if HAVE_LIBCRYPTO_X509_VERIFY_PARAM_GET_DEPTH
     const X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(ctx);
     int depth = X509_VERIFY_PARAM_get_depth(param);
+#else
+    int depth = ctx->param->depth;
 #endif
     X509 *current = X509_STORE_CTX_get0_cert(ctx);
     int i = 0;
     for (i = 0; current && (i < depth); ++i) {
-        if (X509_check_issued(current, current)) {
+        if (X509_check_issued(current, current) == X509_V_OK) {
             // either ctx->cert is itself self-signed or untrustedCerts
             // aready contain the self-signed current certificate
             break;
@@ -1241,10 +1243,10 @@
     // OpenSSL already maintains ctx->untrusted but we cannot modify
     // internal OpenSSL list directly. We have to give OpenSSL our own
     // list, but it must include certificates on the OpenSSL ctx->untrusted
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
-    STACK_OF(X509) *oldUntrusted = ctx->untrusted;
-#else
+#if HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_UNTRUSTED
     STACK_OF(X509) *oldUntrusted = X509_STORE_CTX_get0_untrusted(ctx);
+#else
+    STACK_OF(X509) *oldUntrusted = ctx->untrusted;
 #endif
     STACK_OF(X509) *sk = sk_X509_dup(oldUntrusted); // oldUntrusted is always not NULL
 
@@ -1260,10 +1262,10 @@
 
     X509_STORE_CTX_set_chain(ctx, sk); // No locking/unlocking, just sets ctx->untrusted
     int ret = X509_verify_cert(ctx);
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
-    X509_STORE_CTX_set_chain(ctx, oldUntrusted); // Set back the old untrusted list
-#else
+#if HAVE_LIBCRYPTO_X509_STORE_CTX_SET0_UNTRUSTED
     X509_STORE_CTX_set0_untrusted(ctx, oldUntrusted);
+#else
+    X509_STORE_CTX_set_chain(ctx, oldUntrusted); // Set back the old untrusted list
 #endif
     sk_X509_free(sk); // Release sk list
     return ret;
@@ -1389,12 +1391,12 @@
 
     SSL_SESSION_set_timeout(session, Config.SSL.session_ttl);
 
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
-    unsigned char *id = session->session_id;
-    unsigned int idlen = session->session_id_length;
-#else
+#if HAVE_LIBSSL_SSL_SESSION_GET_ID
     unsigned int idlen;
     const unsigned char *id = SSL_SESSION_get_id(session, &idlen);
+#else
+    unsigned char *id = session->session_id;
+    unsigned int idlen = session->session_id_length;
 #endif
     unsigned char key[MEMMAP_SLOT_KEY_SIZE];
     // Session ids are of size 32bytes. They should always fit to a
@@ -1438,10 +1440,10 @@
 }
 
 static SSL_SESSION *
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
-get_session_cb(SSL *, unsigned char *sessionID, int len, int *copy)
-#else
+#if SQUID_USE_CONST_SSL_SESSION_CBID
 get_session_cb(SSL *, const unsigned char *sessionID, int len, int *copy)
+#else
+get_session_cb(SSL *, unsigned char *sessionID, int len, int *copy)
 #endif
 {
     if (!Ssl::SessionCache)
diff -u -r -N squid-4.0.19/src/ssl/support.h squid-4.0.20/src/ssl/support.h
--- squid-4.0.19/src/ssl/support.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/ssl/support.h	2017-06-02 00:49:17.000000000 +1200
@@ -83,12 +83,6 @@
 /// initialize a TLS client context with OpenSSL specific settings
 bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, long flags);
 
-#if defined(CRYPTO_LOCK_X509)
-// portability wrapper for OpenSSL 1.0 vs 1.1
-// use Security::CertPointer instead where possible
-inline int X509_up_ref(X509 *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_X509); return 0;}
-#endif
-
 } //namespace Ssl
 
 /// \ingroup ServerProtocolSSLAPI
diff -u -r -N squid-4.0.19/src/store/id_rewriters/file/storeid_file_rewrite.8 squid-4.0.20/src/store/id_rewriters/file/storeid_file_rewrite.8
--- squid-4.0.19/src/store/id_rewriters/file/storeid_file_rewrite.8	2017-04-02 23:48:57.000000000 +1200
+++ squid-4.0.20/src/store/id_rewriters/file/storeid_file_rewrite.8	2017-06-02 09:54:12.000000000 +1200
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "STOREID_FILE_REWRITE 8"
-.TH STOREID_FILE_REWRITE 8 "2017-04-02" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH STOREID_FILE_REWRITE 8 "2017-06-01" "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.19/src/tests/stub_neighbors.cc squid-4.0.20/src/tests/stub_neighbors.cc
--- squid-4.0.19/src/tests/stub_neighbors.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/tests/stub_neighbors.cc	2017-06-02 00:49:17.000000000 +1200
@@ -11,8 +11,16 @@
 #define STUB_API "neighbors.cc"
 #include "tests/STUB.h"
 
+#include "FwdState.h"
 #include "neighbors.h"
 
 void
 peerConnClosed(CachePeer *p) STUB
 
+time_t
+peerConnectTimeout(const CachePeer *peer) STUB_RETVAL(0)
+time_t
+FwdState::ForwardTimeout(const time_t) STUB_RETVAL(0)
+bool
+FwdState::EnoughTimeToReForward(const time_t fwdStart) STUB_RETVAL(false)
+
diff -u -r -N squid-4.0.19/src/tests/stub_tools.cc squid-4.0.20/src/tests/stub_tools.cc
--- squid-4.0.19/src/tests/stub_tools.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/tests/stub_tools.cc	2017-06-02 00:49:17.000000000 +1200
@@ -61,9 +61,6 @@
 
 //not actually needed in the Stub, causes dependency on SBuf
 //SBuf ProcessRoles() STUB_RETVAL(SBuf())
-void writePidFile(void) STUB
-void removePidFile(void) STUB
-pid_t readPidFile(void) STUB_RETVAL(0)
 void setMaxFD(void) STUB
 void setSystemLimits(void) STUB
 void squid_signal(int sig, SIGHDLR * func, int flags) STUB
@@ -77,3 +74,7 @@
 void restoreCapabilities(bool keep) STUB
 pid_t WaitForOnePid(pid_t pid, PidStatus &status, int flags) STUB_RETVAL(0)
 
+#if _SQUID_WINDOWS_
+SBuf WindowsErrorMessage(DWORD) STUB_RETVAL(SBuf())
+#endif // _SQUID_WINDOWS_
+
diff -u -r -N squid-4.0.19/src/tools.cc squid-4.0.20/src/tools.cc
--- squid-4.0.19/src/tools.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/tools.cc	2017-06-02 00:49:17.000000000 +1200
@@ -25,6 +25,7 @@
 #include "ipc/Kids.h"
 #include "ipcache.h"
 #include "MemBuf.h"
+#include "sbuf/Stream.h"
 #include "SquidConfig.h"
 #include "SquidMath.h"
 #include "SquidTime.h"
@@ -710,97 +711,6 @@
     return roles;
 }
 
-void
-writePidFile(void)
-{
-    int fd;
-    const char *f = NULL;
-    mode_t old_umask;
-    char buf[32];
-
-    debugs(50, DBG_IMPORTANT, "creating PID file: " << Config.pidFilename);
-
-    if ((f = Config.pidFilename) == NULL)
-        return;
-
-    if (!strcmp(Config.pidFilename, "none"))
-        return;
-
-    enter_suid();
-
-    old_umask = umask(022);
-
-    fd = open(f, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, 0644);
-    int xerrno = errno;
-
-    umask(old_umask);
-
-    leave_suid();
-
-    if (fd < 0) {
-        debugs(50, DBG_CRITICAL, "" << f << ": " << xstrerr(xerrno));
-        debug_trap("Could not open PID file for write");
-        return;
-    }
-
-    snprintf(buf, 32, "%d\n", (int) getpid());
-    const size_t ws = write(fd, buf, strlen(buf));
-    assert(ws == strlen(buf));
-    close(fd);
-}
-
-void
-removePidFile()
-{
-    if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
-        debugs(50, DBG_IMPORTANT, "removing PID file: " << Config.pidFilename);
-        enter_suid();
-        safeunlink(Config.pidFilename, 0);
-        leave_suid();
-    }
-}
-
-pid_t
-readPidFile(void)
-{
-    FILE *pid_fp = NULL;
-    const char *f = Config.pidFilename;
-    char *chroot_f = NULL;
-    pid_t pid = -1;
-    int i;
-
-    if (f == NULL || !strcmp(Config.pidFilename, "none")) {
-        fprintf(stderr, APP_SHORTNAME ": ERROR: No PID file name defined\n");
-        exit(1);
-    }
-
-    if (Config.chroot_dir && geteuid() == 0) {
-        int len = strlen(Config.chroot_dir) + 1 + strlen(f) + 1;
-        chroot_f = (char *)xmalloc(strlen(Config.chroot_dir) + 1 + strlen(f) + 1);
-        snprintf(chroot_f, len, "%s/%s", Config.chroot_dir, f);
-        f = chroot_f;
-    }
-
-    if ((pid_fp = fopen(f, "r"))) {
-        pid = 0;
-
-        if (fscanf(pid_fp, "%d", &i) == 1)
-            pid = (pid_t) i;
-
-        fclose(pid_fp);
-    } else {
-        int xerrno = errno;
-        if (xerrno != ENOENT) {
-            fprintf(stderr, APP_SHORTNAME ": ERROR: Could not open PID file for read\n");
-            fprintf(stderr, "\t%s: %s\n", f, xstrerr(xerrno));
-            exit(1);
-        }
-    }
-
-    safe_free(chroot_f);
-    return pid;
-}
-
 /* A little piece of glue for odd systems */
 #ifndef RLIMIT_NOFILE
 #ifdef RLIMIT_OFILE
@@ -1234,3 +1144,28 @@
 #endif
 }
 
+#if _SQUID_WINDOWS_
+SBuf
+WindowsErrorMessage(DWORD errorId)
+{
+    char *rawMessage = nullptr;
+    const auto length = FormatMessage(
+                            FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                            FORMAT_MESSAGE_FROM_SYSTEM |
+                            FORMAT_MESSAGE_IGNORE_INSERTS,
+                            nullptr,
+                            errorId,
+                            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+                            static_cast<LPTSTR>(&rawMessage),
+                            0,
+                            nullptr);
+    if (!length) {
+        Must(!rawMessage); // nothing to LocalFree()
+        return ToSBuf("windows error ", errorId);
+    }
+    const auto result = SBuf(rawMessage, length);
+    LocalFree(rawMessage);
+    return result;
+}
+#endif // _SQUID_WINDOWS_
+
diff -u -r -N squid-4.0.19/src/tools.h squid-4.0.20/src/tools.h
--- squid-4.0.19/src/tools.h	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/tools.h	2017-06-02 00:49:17.000000000 +1200
@@ -48,12 +48,9 @@
 void leave_suid(void);
 void enter_suid(void);
 void no_suid(void);
-void writePidFile(void);
-void removePidFile();
 void setMaxFD(void);
 void setSystemLimits(void);
 void squid_signal(int sig, SIGHDLR *, int flags);
-pid_t readPidFile(void);
 void keepCapabilities(void);
 void BroadcastSignalIfAny(int& sig);
 
@@ -116,5 +113,10 @@
     return WaitForOnePid(-1, status, flags);
 }
 
+#if _SQUID_WINDOWS_
+/// xstrerror(errno) equivalent for Windows errors returned by GetLastError()
+SBuf WindowsErrorMessage(DWORD errorId);
+#endif // _SQUID_WINDOWS_
+
 #endif /* SQUID_TOOLS_H_ */
 
diff -u -r -N squid-4.0.19/src/tunnel.cc squid-4.0.20/src/tunnel.cc
--- squid-4.0.19/src/tunnel.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/src/tunnel.cc	2017-06-02 00:49:17.000000000 +1200
@@ -31,6 +31,7 @@
 #include "ip/QosConfig.h"
 #include "LogTags.h"
 #include "MemBuf.h"
+#include "neighbors.h"
 #include "PeerSelectState.h"
 #include "sbuf/SBuf.h"
 #include "security/BlindPeerConnector.h"
@@ -121,6 +122,10 @@
     /// if it is waiting for Squid CONNECT response, closing connections.
     void informUserOfPeerError(const char *errMsg, size_t);
 
+    /// starts connecting to the next hop, either for the first time or while
+    /// recovering from the previous connect failure
+    void startConnecting();
+
     class Connection
     {
 
@@ -169,7 +174,7 @@
     bool connectReqWriting; ///< whether we are writing a CONNECT request to a peer
     SBuf preReadClientData;
     SBuf preReadServerData;
-    time_t started;         ///< when this tunnel was initiated.
+    time_t startTime; ///< object creation time, before any peer selection/connection attempts
 
     void copyRead(Connection &from, IOCB *completion);
 
@@ -291,7 +296,7 @@
 TunnelStateData::TunnelStateData(ClientHttpRequest *clientRequest) :
     connectRespBuf(NULL),
     connectReqWriting(false),
-    started(squid_curtime)
+    startTime(squid_curtime)
 {
     debugs(26, 3, "TunnelStateData constructed this=" << this);
     client.readPendingFunc = &tunnelDelayedClientRead;
@@ -894,7 +899,7 @@
  * Call the tunnelStartShoveling to start the blind pump.
  */
 static void
-tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t, Comm::Flag flag, int, void *data)
+tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
 {
     TunnelStateData *tunnelState = (TunnelStateData *)data;
     debugs(26, 3, HERE << conn << ", flag=" << flag);
@@ -906,6 +911,11 @@
         return;
     }
 
+    if (auto http = tunnelState->http.get()) {
+        http->out.headers_sz += len;
+        http->out.size += len;
+    }
+
     tunnelStartShoveling(tunnelState);
 }
 
@@ -983,25 +993,21 @@
 
     if (status != Comm::OK) {
         debugs(26, 4, HERE << conn << ", comm failure recovery.");
+        {
+            assert(!tunnelState->serverDestinations.empty());
+            const Comm::Connection &failedDest = *tunnelState->serverDestinations.front();
+            if (CachePeer *peer = failedDest.getPeer())
+                peerConnectFailed(peer);
+            debugs(26, 4, "removing the failed one from " << tunnelState->serverDestinations.size() <<
+                   " destinations: " << failedDest);
+        }
         /* At this point only the TCP handshake has failed. no data has been passed.
          * we are allowed to re-try the TCP-level connection to alternate IPs for CONNECT.
          */
-        debugs(26, 4, "removing server 1 of " << tunnelState->serverDestinations.size() <<
-               " from destinations (" << tunnelState->serverDestinations[0] << ")");
         tunnelState->serverDestinations.erase(tunnelState->serverDestinations.begin());
-        time_t fwdTimeout = tunnelState->started + Config.Timeout.forward;
-        if (fwdTimeout > squid_curtime && tunnelState->serverDestinations.size() > 0) {
-            // find remaining forward_timeout available for this attempt
-            fwdTimeout -= squid_curtime;
-            if (fwdTimeout > Config.Timeout.connect)
-                fwdTimeout = Config.Timeout.connect;
-            /* Try another IP of this destination host */
-            GetMarkingsToServer(tunnelState->request.getRaw(), *tunnelState->serverDestinations[0]);
-            debugs(26, 4, HERE << "retry with : " << tunnelState->serverDestinations[0]);
-            AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
-            Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, fwdTimeout);
-            cs->setHost(tunnelState->url);
-            AsyncJob::Start(cs);
+        if (!tunnelState->serverDestinations.empty() && FwdState::EnoughTimeToReForward(tunnelState->startTime)) {
+            debugs(26, 4, "re-forwarding");
+            tunnelState->startConnecting();
         } else {
             debugs(26, 4, HERE << "terminate with error.");
             ErrorState *err = new ErrorState(ERR_CONNECT_FAIL, Http::scServiceUnavailable, tunnelState->request.getRaw());
@@ -1226,17 +1232,25 @@
     }
     delete err;
 
-    GetMarkingsToServer(tunnelState->request.getRaw(), *tunnelState->serverDestinations[0]);
-
     if (tunnelState->request != NULL)
         tunnelState->request->hier.startPeerClock();
 
-    debugs(26, 3, HERE << "paths=" << peer_paths->size() << ", p[0]={" << (*peer_paths)[0] << "}, serverDest[0]={" <<
+    debugs(26, 3, "paths=" << peer_paths->size() << ", p[0]={" << (*peer_paths)[0] << "}, serverDest[0]={" <<
            tunnelState->serverDestinations[0] << "}");
 
-    AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
-    Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
-    cs->setHost(tunnelState->url);
+    tunnelState->startConnecting();
+}
+
+void
+TunnelStateData::startConnecting()
+{
+    Comm::ConnectionPointer &dest = serverDestinations.front();
+    GetMarkingsToServer(request.getRaw(), *dest);
+
+    const time_t connectTimeout = dest->connectTimeout(startTime);
+    AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, this));
+    Comm::ConnOpener *cs = new Comm::ConnOpener(dest, call, connectTimeout);
+    cs->setHost(url);
     AsyncJob::Start(cs);
 }
 
diff -u -r -N squid-4.0.19/test-suite/stub_tools.cc squid-4.0.20/test-suite/stub_tools.cc
--- squid-4.0.19/test-suite/stub_tools.cc	2017-04-02 23:50:42.000000000 +1200
+++ squid-4.0.20/test-suite/stub_tools.cc	2017-06-02 09:59:53.000000000 +1200
@@ -61,9 +61,6 @@
 
 //not actually needed in the Stub, causes dependency on SBuf
 //SBuf ProcessRoles() STUB_RETVAL(SBuf())
-void writePidFile(void) STUB
-void removePidFile(void) STUB
-pid_t readPidFile(void) STUB_RETVAL(0)
 void setMaxFD(void) STUB
 void setSystemLimits(void) STUB
 void squid_signal(int sig, SIGHDLR * func, int flags) STUB
@@ -77,3 +74,7 @@
 void restoreCapabilities(bool keep) STUB
 pid_t WaitForOnePid(pid_t pid, PidStatus &status, int flags) STUB_RETVAL(0)
 
+#if _SQUID_WINDOWS_
+SBuf WindowsErrorMessage(DWORD) STUB_RETVAL(SBuf())
+#endif // _SQUID_WINDOWS_
+
diff -u -r -N squid-4.0.19/tools/cachemgr.cc squid-4.0.20/tools/cachemgr.cc
--- squid-4.0.19/tools/cachemgr.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/tools/cachemgr.cc	2017-06-02 00:49:17.000000000 +1200
@@ -440,7 +440,7 @@
         return;
     }
 
-    buf_copy = x = xstrndup(buf, bufLen);
+    buf_copy = x = xstrndup(buf, bufLen+1);
 
     a = xstrtok(&x, '\t');
 
diff -u -r -N squid-4.0.19/tools/helper-mux/helper-mux.8 squid-4.0.20/tools/helper-mux/helper-mux.8
--- squid-4.0.19/tools/helper-mux/helper-mux.8	2017-04-02 23:50:48.000000000 +1200
+++ squid-4.0.20/tools/helper-mux/helper-mux.8	2017-06-02 10:00:07.000000000 +1200
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "HELPER-MUX 8"
-.TH HELPER-MUX 8 "2017-04-02" "perl v5.24.1" "User Contributed Perl Documentation"
+.TH HELPER-MUX 8 "2017-06-01" "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.19/tools/purge/purge.cc squid-4.0.20/tools/purge/purge.cc
--- squid-4.0.19/tools/purge/purge.cc	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/tools/purge/purge.cc	2017-06-02 00:49:17.000000000 +1200
@@ -272,7 +272,7 @@
         snprintf( md5, sizeof(md5), "%-32s", "(no_md5_data_available)" );
     }
 
-    char timeb[64];
+    char timeb[256];
     if ( meta && (findings = meta->search( STORE_META_STD )) ) {
         StoreMetaStd temp;
         // make data aligned, avoid SIGBUS on RISC machines (ARGH!)
@@ -283,7 +283,7 @@
     } else if ( meta && (findings = meta->search( STORE_META_STD_LFS )) ) {
         StoreMetaStdLFS temp;
         // make data aligned, avoid SIGBUS on RISC machines (ARGH!)
-        memcpy( &temp, findings->data, sizeof(StoreMetaStd) );
+        memcpy( &temp, findings->data, sizeof(StoreMetaStdLFS) );
         snprintf( timeb, sizeof(timeb), "%08lx %08lx %08lx %08lx %04x %5hu ",
                   (unsigned long)temp.timestamp, (unsigned long)temp.lastref,
                   (unsigned long)temp.expires, (unsigned long)temp.lastmod, temp.flags, temp.refcount );
diff -u -r -N squid-4.0.19/tools/squidclient/squidclient.1 squid-4.0.20/tools/squidclient/squidclient.1
--- squid-4.0.19/tools/squidclient/squidclient.1	2017-04-02 19:43:45.000000000 +1200
+++ squid-4.0.20/tools/squidclient/squidclient.1	2017-06-02 00:49:17.000000000 +1200
@@ -86,7 +86,7 @@
 .if !'po4a'hide' .TP
 .if !'po4a'hide' .B "\-H 'string'"
 Extra headers to send. Use
-.B '\\n'
+.B '\en'
 for new lines.
 .
 .if !'po4a'hide' .TP
