]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/cache_cf.cc
Removed squid-old.h
[thirdparty/squid.git] / src / cache_cf.cc
index e486a729233d3589f16226e040208a8ea5b120be..58a693b974653e56305e0b74a51dc612a4e55b33 100644 (file)
  */
 
 #include "squid.h"
-
 #include "acl/Acl.h"
 #include "acl/Gadgets.h"
 #include "acl/MethodData.h"
+#include "anyp/PortCfg.h"
+#include "base/RunnersRegistry.h"
+#include "ConfigParser.h"
+#include "CpuAffinityMap.h"
+#include "DiskIO/DiskIOModule.h"
+#include "eui/Config.h"
+#include "format/Format.h"
+#include "globals.h"
+#include "HttpRequestMethod.h"
+#include "ident/Config.h"
+#include "ip/Intercept.h"
+#include "ip/QosConfig.h"
+#include "ip/tools.h"
+#include "ipc/Kids.h"
+#include "log/Config.h"
+#include "MemBuf.h"
+#include "mgr/Registration.h"
+#include "Parsing.h"
+#include "protos.h"
+#include "rfc1738.h"
+#include "Store.h"
+#include "StoreFileSystem.h"
+#include "structs.h"
+#include "SwapDir.h"
+#include "wordlist.h"
 #if USE_ADAPTATION
 #include "adaptation/Config.h"
 #endif
 #include "auth/Config.h"
 #include "auth/Scheme.h"
 #endif
-#include "ConfigParser.h"
-#include "CpuAffinityMap.h"
-#include "eui/Config.h"
 #if USE_SQUID_ESI
 #include "esi/Parser.h"
 #endif
-#include "HttpRequestMethod.h"
-#include "ident/Config.h"
-#include "ip/Intercept.h"
-#include "ip/QosConfig.h"
-#include "ip/tools.h"
-#include "log/Config.h"
-#include "MemBuf.h"
-#include "mgr/Registration.h"
-#include "Parsing.h"
-#include "ProtoPort.h"
-#include "rfc1738.h"
 #if SQUID_SNMP
 #include "snmp.h"
 #endif
-#include "Store.h"
-#include "StoreFileSystem.h"
-#include "SwapDir.h"
-#include "wordlist.h"
-#include "ipc/Kids.h"
+
+
+
 
 #if HAVE_GLOB_H
 #include <glob.h>
 #include <limits>
 #endif
 
+#if HAVE_LIST
+#include <list>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif
+#if HAVE_GRP_H
+#include <grp.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
 #if USE_SSL
 #include "ssl/gadgets.h"
 #endif
 static void parse_adaptation_service_set_type();
 static void parse_adaptation_service_chain_type();
 static void parse_adaptation_access_type();
+static void parse_adaptation_meta_type(Adaptation::Config::MetaHeaders *);
+static void dump_adaptation_meta_type(StoreEntry *, const char *, Adaptation::Config::MetaHeaders &);
+static void free_adaptation_meta_type(Adaptation::Config::MetaHeaders *);
 #endif
 
 #if ICAP_CLIENT
@@ -146,17 +173,18 @@ static void configDoConfigure(void);
 static void parse_refreshpattern(refresh_t **);
 static uint64_t parseTimeUnits(const char *unit,  bool allowMsec);
 static void parseTimeLine(time_msec_t * tptr, const char *units, bool allowMsec);
-static void parse_ushort(u_short * var);
+static void parse_u_short(unsigned short * var);
 static void parse_string(char **);
 static void default_all(void);
 static void defaults_if_none(void);
+static void defaults_postscriptum(void);
 static int parse_line(char *);
 static void parse_obsolete(const char *);
 static void parseBytesLine(size_t * bptr, const char *units);
 #if USE_SSL
 static void parseBytesOptionValue(size_t * bptr, const char *units, char const * value);
 #endif
-#if !USE_DNSSERVERS
+#if !USE_DNSHELPER
 static void parseBytesLineSigned(ssize_t * bptr, const char *units);
 #endif
 static size_t parseBytesUnits(const char *unit);
@@ -164,13 +192,17 @@ static void free_all(void);
 void requirePathnameExists(const char *name, const char *path);
 static OBJH dump_config;
 #if USE_HTTP_VIOLATIONS
-static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
-static void parse_http_header_access(header_mangler header[]);
-static void free_http_header_access(header_mangler header[]);
-static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
-static void parse_http_header_replace(header_mangler * header);
-static void free_http_header_replace(header_mangler * header);
+static void free_HeaderManglers(HeaderManglers **pm);
+static void dump_http_header_access(StoreEntry * entry, const char *name, const HeaderManglers *manglers);
+static void parse_http_header_access(HeaderManglers **manglers);
+#define free_http_header_access free_HeaderManglers
+static void dump_http_header_replace(StoreEntry * entry, const char *name, const HeaderManglers *manglers);
+static void parse_http_header_replace(HeaderManglers **manglers);
+#define free_http_header_replace free_HeaderManglers
 #endif
+static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers);
+static void parse_HeaderWithAclList(HeaderWithAclList **header);
+static void free_HeaderWithAclList(HeaderWithAclList **header);
 static void parse_denyinfo(acl_deny_info_list ** var);
 static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
 static void free_denyinfo(acl_deny_info_list ** var);
@@ -184,17 +216,21 @@ static int check_null_IpAddress_list(const Ip::Address_list *);
 #endif /* CURRENTLY_UNUSED */
 #endif /* USE_WCCPv2 */
 
-static void parse_http_port_list(http_port_list **);
-static void dump_http_port_list(StoreEntry *, const char *, const http_port_list *);
-static void free_http_port_list(http_port_list **);
+static void parsePortCfg(AnyP::PortCfg **, const char *protocol);
+#define parse_PortCfg(l) parsePortCfg((l), token)
+static void dump_PortCfg(StoreEntry *, const char *, const AnyP::PortCfg *);
+static void free_PortCfg(AnyP::PortCfg **);
 
 #if USE_SSL
-static void parse_https_port_list(https_port_list **);
-static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *);
-static void free_https_port_list(https_port_list **);
-#if 0
-static int check_null_https_port_list(const https_port_list *);
-#endif
+static void parse_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign);
+static void dump_sslproxy_cert_sign(StoreEntry *entry, const char *name, sslproxy_cert_sign *cert_sign);
+static void free_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign);
+static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt);
+static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt);
+static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt);
+static void parse_sslproxy_ssl_bump(acl_access **ssl_bump);
+static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump);
+static void free_sslproxy_ssl_bump(acl_access **ssl_bump);
 #endif /* USE_SSL */
 
 static void parse_b_size_t(size_t * var);
@@ -228,7 +264,7 @@ update_maxobjsize(void)
     int i;
     int64_t ms = -1;
 
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+    for (i = 0; i < Config.cacheSwap.n_configured; ++i) {
         assert (Config.cacheSwap.swapDirs[i].getRaw());
 
         if (dynamic_cast<SwapDir *>(Config.cacheSwap.swapDirs[i].getRaw())->
@@ -276,7 +312,7 @@ parseManyConfigFiles(char* files, int depth)
                    path, xstrerror());
         }
     }
-    for (i = 0; i < (int)globbuf.gl_pathc; i++) {
+    for (i = 0; i < (int)globbuf.gl_pathc; ++i) {
         error_count += parseOneConfigFile(globbuf.gl_pathv[i], depth);
     }
     globfree(&globbuf);
@@ -406,7 +442,7 @@ parseOneConfigFile(const char *file_name, unsigned int depth)
     int err_count = 0;
     int is_pipe = 0;
 
-    debugs(3, 1, "Processing Configuration File: " << file_name << " (depth " << depth << ")");
+    debugs(3, DBG_IMPORTANT, "Processing Configuration File: " << file_name << " (depth " << depth << ")");
     if (depth > 16) {
         fatalf("WARNING: can't include %s: includes are nested too deeply (>16)!\n", file_name);
         return 1;
@@ -434,7 +470,7 @@ parseOneConfigFile(const char *file_name, unsigned int depth)
 
     Vector<bool> if_states;
     while (fgets(config_input_line, BUFSIZ, fp)) {
-        config_lineno++;
+        ++config_lineno;
 
         if ((token = strchr(config_input_line, '\n')))
             *token = '\0';
@@ -442,6 +478,11 @@ parseOneConfigFile(const char *file_name, unsigned int depth)
         if ((token = strchr(config_input_line, '\r')))
             *token = '\0';
 
+        // strip any prefix whitespace off the line.
+        const char *p = skip_ws(config_input_line);
+        if (config_input_line != p)
+            memmove(config_input_line, p, strlen(p)+1);
+
         if (strncmp(config_input_line, "#line ", 6) == 0) {
             static char new_file_name[1024];
             static char *file;
@@ -453,7 +494,7 @@ parseOneConfigFile(const char *file_name, unsigned int depth)
                 continue;      /* Not a valid #line directive, may be a comment */
 
             while (*file && xisspace((unsigned char) *file))
-                file++;
+                ++file;
 
             if (*file) {
                 if (*file != '"')
@@ -494,7 +535,7 @@ parseOneConfigFile(const char *file_name, unsigned int depth)
 
         trim_trailing_ws(tmp_line);
         ProcessMacros(tmp_line, tmp_line_len);
-        debugs(3, 5, "Processing: '" << tmp_line << "'");
+        debugs(3, (opt_parse_cfg_only?1:5), "Processing: " << tmp_line);
 
         if (const char* expr = FindStatement(tmp_line, "if")) {
             if_states.push_back(EvalBoolExpr(expr)); // store last if-statement meaning
@@ -513,8 +554,8 @@ parseOneConfigFile(const char *file_name, unsigned int depth)
             if (tmp_line_len >= 9 && strncmp(tmp_line, "include", 7) == 0 && xisspace(tmp_line[7])) {
                 err_count += parseManyConfigFiles(tmp_line + 8, depth + 1);
             } else if (!parse_line(tmp_line)) {
-                debugs(3, 0, HERE << cfg_filename << ":" << config_lineno << " unrecognized: '" << tmp_line << "'");
-                err_count++;
+                debugs(3, DBG_CRITICAL, HERE << cfg_filename << ":" << config_lineno << " unrecognized: '" << tmp_line << "'");
+                ++err_count;
             }
         }
 
@@ -556,6 +597,8 @@ parseConfigFile(const char *file_name)
 
     defaults_if_none();
 
+    defaults_postscriptum();
+
     /*
      * We must call configDoConfigure() before leave_suid() because
      * configDoConfigure() is where we turn username strings into
@@ -593,6 +636,12 @@ configDoConfigure(void)
         /* Memory-only cache probably in effect. */
         /* turn off the cache rebuild delays... */
         StoreController::store_dirs_rebuilding = 0;
+    } else if (InDaemonMode()) { // no diskers in non-daemon mode
+        for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
+            const RefCount<SwapDir> sd = Config.cacheSwap.swapDirs[i];
+            if (sd->needsDiskStrand())
+                sd->disker = Config.workers + (++Config.cacheSwap.n_strands);
+        }
     }
 
     if (Debug::rotateNumber < 0) {
@@ -601,16 +650,16 @@ configDoConfigure(void)
 
 #if SIZEOF_OFF_T <= 4
     if (Config.Store.maxObjectSize > 0x7FFF0000) {
-        debugs(3, 0, "WARNING: This Squid binary can not handle files larger than 2GB. Limiting maximum_object_size to just below 2GB");
+        debugs(3, DBG_CRITICAL, "WARNING: This Squid binary can not handle files larger than 2GB. Limiting maximum_object_size to just below 2GB");
         Config.Store.maxObjectSize = 0x7FFF0000;
     }
 #endif
     if (0 == Store::Root().maxSize())
         /* people might want a zero-sized cache on purpose */
         (void) 0;
-    else if (Store::Root().maxSize() < (Config.memMaxSize >> 10))
+    else if (Store::Root().maxSize() < Config.memMaxSize)
         /* This is bogus. folk with NULL caches will want this */
-        debugs(3, 0, "WARNING cache_mem is larger than total disk cache space!");
+        debugs(3, DBG_CRITICAL, "WARNING cache_mem is larger than total disk cache space!");
 
     if (Config.Announce.period > 0) {
         Config.onoff.announce = 1;
@@ -624,11 +673,9 @@ configDoConfigure(void)
     else
         visible_appname_string = (char const *)APP_FULLNAME;
 
-#if USE_DNSSERVERS
-
+#if USE_DNSHELPER
     if (Config.dnsChildren.n_max < 1)
-        fatal("No dnsservers allocated");
-
+        fatal("No DNS helpers allocated");
 #endif
 
     if (Config.Program.redirect) {
@@ -645,6 +692,16 @@ configDoConfigure(void)
     if (Config.errHtmlText == NULL)
         Config.errHtmlText = xstrdup(null_string);
 
+#if !HAVE_SETRLIMIT || !defined(RLIMIT_NOFILE)
+    if (Config.max_filedescriptors > 0) {
+        debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors disabled. Operating System setrlimit(RLIMIT_NOFILE) is missing.");
+    }
+#elif USE_SELECT || USE_SELECT_WIN32
+    if (Config.max_filedescriptors > FD_SETSIZE) {
+        debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors limited to " << FD_SETSIZE << " by select() algorithm.");
+    }
+#endif
+
     storeConfigure();
 
     snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
@@ -673,17 +730,13 @@ configDoConfigure(void)
     else
         Config.appendDomainLen = 0;
 
-    if (Config.retry.maxtries > 10)
-        fatal("maximum_single_addr_tries cannot be larger than 10");
-
-    if (Config.retry.maxtries < 1) {
-        debugs(3, 0, "WARNING: resetting 'maximum_single_addr_tries to 1");
-        Config.retry.maxtries = 1;
+    if (Config.connect_retries > 10) {
+        debugs(0,DBG_CRITICAL, "WARNING: connect_retries cannot be larger than 10. Resetting to 10.");
+        Config.connect_retries = 10;
     }
 
     requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
-#if USE_DNSSERVERS
-
+#if USE_DNSHELPER
     requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
 #endif
 #if USE_UNLINKD
@@ -708,7 +761,7 @@ configDoConfigure(void)
             if (!R->flags.override_expire)
                 continue;
 
-            debugs(22, 1, "WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP");
+            debugs(22, DBG_IMPORTANT, "WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP");
 
             break;
         }
@@ -717,7 +770,7 @@ configDoConfigure(void)
             if (!R->flags.override_lastmod)
                 continue;
 
-            debugs(22, 1, "WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP");
+            debugs(22, DBG_IMPORTANT, "WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP");
 
             break;
         }
@@ -726,7 +779,7 @@ configDoConfigure(void)
             if (!R->flags.reload_into_ims)
                 continue;
 
-            debugs(22, 1, "WARNING: use of 'reload-into-ims' in 'refresh_pattern' violates HTTP");
+            debugs(22, DBG_IMPORTANT, "WARNING: use of 'reload-into-ims' in 'refresh_pattern' violates HTTP");
 
             break;
         }
@@ -735,7 +788,7 @@ configDoConfigure(void)
             if (!R->flags.ignore_reload)
                 continue;
 
-            debugs(22, 1, "WARNING: use of 'ignore-reload' in 'refresh_pattern' violates HTTP");
+            debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-reload' in 'refresh_pattern' violates HTTP");
 
             break;
         }
@@ -744,7 +797,7 @@ configDoConfigure(void)
             if (!R->flags.ignore_no_cache)
                 continue;
 
-            debugs(22, 1, "WARNING: use of 'ignore-no-cache' in 'refresh_pattern' violates HTTP");
+            debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-no-cache' in 'refresh_pattern' violates HTTP");
 
             break;
         }
@@ -753,7 +806,7 @@ configDoConfigure(void)
             if (!R->flags.ignore_no_store)
                 continue;
 
-            debugs(22, 1, "WARNING: use of 'ignore-no-store' in 'refresh_pattern' violates HTTP");
+            debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-no-store' in 'refresh_pattern' violates HTTP");
 
             break;
         }
@@ -761,7 +814,7 @@ configDoConfigure(void)
         for (R = Config.Refresh; R; R = R->next) {
             if (!R->flags.ignore_must_revalidate)
                 continue;
-            debugs(22, 1, "WARNING: use of 'ignore-must-revalidate' in 'refresh_pattern' violates HTTP");
+            debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-must-revalidate' in 'refresh_pattern' violates HTTP");
             break;
         }
 
@@ -769,7 +822,7 @@ configDoConfigure(void)
             if (!R->flags.ignore_private)
                 continue;
 
-            debugs(22, 1, "WARNING: use of 'ignore-private' in 'refresh_pattern' violates HTTP");
+            debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-private' in 'refresh_pattern' violates HTTP");
 
             break;
         }
@@ -778,7 +831,7 @@ configDoConfigure(void)
             if (!R->flags.ignore_auth)
                 continue;
 
-            debugs(22, 1, "WARNING: use of 'ignore-auth' in 'refresh_pattern' violates HTTP");
+            debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-auth' in 'refresh_pattern' violates HTTP");
 
             break;
         }
@@ -790,7 +843,7 @@ configDoConfigure(void)
 #else
 
     if (!Config.onoff.via)
-        debugs(22, 1, "WARNING: HTTP requires the use of Via");
+        debugs(22, DBG_IMPORTANT, "WARNING: HTTP requires the use of Via");
 
 #endif
 
@@ -798,7 +851,7 @@ configDoConfigure(void)
     // TODO: replace with a dedicated "purge" ACL option?
     Config2.onoff.enable_purge = (ACLMethodData::ThePurgeCount > 0);
 
-    Config2.onoff.mangle_request_headers = httpReqHdrManglersConfigured();
+    Config2.onoff.mangle_request_headers = (Config.request_header_access != NULL);
 
     if (geteuid() == 0) {
         if (NULL != Config.effectiveUser) {
@@ -857,55 +910,28 @@ configDoConfigure(void)
     HttpRequestMethod::Configure(Config);
 #if USE_SSL
 
-    debugs(3, 1, "Initializing https proxy context");
+    debugs(3, DBG_IMPORTANT, "Initializing https proxy context");
 
     Config.ssl_client.sslContext = sslCreateClientContext(Config.ssl_client.cert, Config.ssl_client.key, Config.ssl_client.version, Config.ssl_client.cipher, Config.ssl_client.options, Config.ssl_client.flags, Config.ssl_client.cafile, Config.ssl_client.capath, Config.ssl_client.crlfile);
 
-    {
-
-        peer *p;
-
-        for (p = Config.peers; p != NULL; p = p->next) {
-            if (p->use_ssl) {
-                debugs(3, 1, "Initializing cache_peer " << p->name << " SSL context");
-                p->sslContext = sslCreateClientContext(p->sslcert, p->sslkey, p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, p->sslcapath, p->sslcrlfile);
-            }
+    for (peer *p = Config.peers; p != NULL; p = p->next) {
+        if (p->use_ssl) {
+            debugs(3, DBG_IMPORTANT, "Initializing cache_peer " << p->name << " SSL context");
+            p->sslContext = sslCreateClientContext(p->sslcert, p->sslkey, p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, p->sslcapath, p->sslcrlfile);
         }
     }
 
-    {
-
-        http_port_list *s;
-
-        for (s = Config.Sockaddr.http; s != NULL; s = (http_port_list *) s->next) {
-            if (!s->cert && !s->key)
-                continue;
-
-            debugs(3, 1, "Initializing http_port " << s->http.s << " SSL context");
-
-            s->staticSslContext.reset(
-                sslCreateServerContext(s->cert, s->key,
-                                       s->version, s->cipher, s->options, s->sslflags, s->clientca,
-                                       s->cafile, s->capath, s->crlfile, s->dhfile,
-                                       s->sslContextSessionId));
+    for (AnyP::PortCfg *s = Config.Sockaddr.http; s != NULL; s = s->next) {
+        if (!s->sslBump)
+            continue;
 
-            Ssl::readCertAndPrivateKeyFromFiles(s->signingCert, s->signPkey, s->cert, s->key);
-        }
+        debugs(3, DBG_IMPORTANT, "Initializing http_port " << s->s << " SSL context");
+        s->configureSslServerContext();
     }
 
-    {
-
-        https_port_list *s;
-
-        for (s = Config.Sockaddr.https; s != NULL; s = (https_port_list *) s->http.next) {
-            debugs(3, 1, "Initializing https_port " << s->http.s << " SSL context");
-
-            s->staticSslContext.reset(
-                sslCreateServerContext(s->cert, s->key,
-                                       s->version, s->cipher, s->options, s->sslflags, s->clientca,
-                                       s->cafile, s->capath, s->crlfile, s->dhfile,
-                                       s->sslContextSessionId));
-        }
+    for (AnyP::PortCfg *s = Config.Sockaddr.https; s != NULL; s = s->next) {
+        debugs(3, DBG_IMPORTANT, "Initializing https_port " << s->s << " SSL context");
+        s->configureSslServerContext();
     }
 
 #endif
@@ -978,7 +1004,7 @@ parseTimeLine(time_msec_t * tptr, const char *units,  bool allowMsec)
     if (0 == d)
         (void) 0;
     else if ((token = strtok(NULL, w_space)) == NULL)
-        debugs(3, 0, "WARNING: No units on '" <<
+        debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
                config_input_line << "', assuming " <<
                d << " " << units  );
     else if ((m = parseTimeUnits(token, allowMsec)) == 0)
@@ -1020,7 +1046,7 @@ parseTimeUnits(const char *unit, bool allowMsec)
     if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
         return static_cast<uint64_t>(86400 * 1000 * 365.2522 * 10);
 
-    debugs(3, 1, "parseTimeUnits: unknown time unit '" << unit << "'");
+    debugs(3, DBG_IMPORTANT, "parseTimeUnits: unknown time unit '" << unit << "'");
 
     return 0;
 }
@@ -1055,7 +1081,7 @@ parseBytesLine64(int64_t * bptr, const char *units)
     if (0.0 == d)
         (void) 0;
     else if ((token = strtok(NULL, w_space)) == NULL)
-        debugs(3, 0, "WARNING: No units on '" <<
+        debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
                config_input_line << "', assuming " <<
                d << " " <<  units  );
     else if ((m = parseBytesUnits(token)) == 0) {
@@ -1100,7 +1126,7 @@ parseBytesLine(size_t * bptr, const char *units)
     if (0.0 == d)
         (void) 0;
     else if ((token = strtok(NULL, w_space)) == NULL)
-        debugs(3, 0, "WARNING: No units on '" <<
+        debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
                config_input_line << "', assuming " <<
                d << " " <<  units  );
     else if ((m = parseBytesUnits(token)) == 0) {
@@ -1114,7 +1140,7 @@ parseBytesLine(size_t * bptr, const char *units)
         self_destruct();
 }
 
-#if !USE_DNSSERVERS
+#if !USE_DNSHELPER
 static void
 parseBytesLineSigned(ssize_t * bptr, const char *units)
 {
@@ -1145,7 +1171,7 @@ parseBytesLineSigned(ssize_t * bptr, const char *units)
     if (0.0 == d)
         (void) 0;
     else if ((token = strtok(NULL, w_space)) == NULL)
-        debugs(3, 0, "WARNING: No units on '" <<
+        debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
                config_input_line << "', assuming " <<
                d << " " <<  units  );
     else if ((m = parseBytesUnits(token)) == 0) {
@@ -1179,7 +1205,7 @@ static void parseBytesOptionValue(size_t * bptr, const char *units, char const *
     char const * number_end = value;
 
     while ((*number_end >= '0' && *number_end <= '9')) {
-        number_end++;
+        ++number_end;
     }
 
     String number;
@@ -1315,14 +1341,14 @@ parse_address(Ip::Address *addr)
         return;
     }
 
-    if (!strcmp(token,"any_addr")) {
+    if (!strcmp(token,"any_addr"))
         addr->SetAnyAddr();
-        (void) 0;
-    } else if ( (!strcmp(token,"no_addr")) || (!strcmp(token,"full_mask")) ) {
+    else if ( (!strcmp(token,"no_addr")) || (!strcmp(token,"full_mask")) )
         addr->SetNoAddr();
+    else if ( (*addr = token) ) // try parse numeric/IPA
         (void) 0;
-    else
-        *addr = token;
+    else
+        addr->GetHostByName(token); // dont use ipcache
 }
 
 static void
@@ -1453,7 +1479,7 @@ free_acl_tos(acl_tos ** head)
     }
 }
 
-#if defined(SO_MARK)
+#if SO_MARK && USE_LIBCAP
 
 CBDATA_TYPE(acl_nfmark);
 
@@ -1587,7 +1613,7 @@ free_acl_b_size_t(acl_size_t ** head)
 #include "DelayPools.h"
 #include "DelayConfig.h"
 /* do nothing - free_delay_pool_count is the magic free function.
- * this is why delay_pool_count isn't just marked TYPE: ushort
+ * this is why delay_pool_count isn't just marked TYPE: u_short
  */
 #define free_delay_pool_class(X)
 #define free_delay_pool_access(X)
@@ -1637,7 +1663,7 @@ parse_delay_pool_access(DelayConfig * cfg)
 #if USE_DELAY_POOLS
 #include "ClientDelayConfig.h"
 /* do nothing - free_client_delay_pool_count is the magic free function.
- * this is why client_delay_pool_count isn't just marked TYPE: ushort
+ * this is why client_delay_pool_count isn't just marked TYPE: u_short
  */
 
 #define free_client_delay_pool_access(X)
@@ -1678,135 +1704,65 @@ parse_client_delay_pool_access(ClientDelayConfig * cfg)
 
 #if USE_HTTP_VIOLATIONS
 static void
-dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
+dump_http_header_access(StoreEntry * entry, const char *name, const HeaderManglers *manglers)
 {
-    int i;
-
-    for (i = 0; i < HDR_ENUM_END; i++) {
-        if (header[i].access_list != NULL) {
-            storeAppendPrintf(entry, "%s ", name);
-            dump_acl_access(entry, httpHeaderNameById(i),
-                            header[i].access_list);
-        }
-    }
+    if (manglers)
+        manglers->dumpAccess(entry, name);
 }
 
 static void
-parse_http_header_access(header_mangler header[])
+parse_http_header_access(HeaderManglers **pm)
 {
-    int id, i;
     char *t = NULL;
 
     if ((t = strtok(NULL, w_space)) == NULL) {
-        debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
-        debugs(3, 0, "parse_http_header_access: missing header name.");
+        debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
+        debugs(3, DBG_CRITICAL, "parse_http_header_access: missing header name.");
         return;
     }
 
-    /* Now lookup index of header. */
-    id = httpHeaderIdByNameDef(t, strlen(t));
-
-    if (strcmp(t, "All") == 0)
-        id = HDR_ENUM_END;
-    else if (strcmp(t, "Other") == 0)
-        id = HDR_OTHER;
-    else if (id == -1) {
-        debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
-        debugs(3, 0, "parse_http_header_access: unknown header name '" << t << "'");
-        return;
-    }
-
-    if (id != HDR_ENUM_END) {
-        parse_acl_access(&header[id].access_list);
-    } else {
-        char *next_string = t + strlen(t) - 1;
-        *next_string = 'A';
-        *(next_string + 1) = ' ';
-
-        for (i = 0; i < HDR_ENUM_END; i++) {
-            char *new_string = xstrdup(next_string);
-            strtok(new_string, w_space);
-            parse_acl_access(&header[i].access_list);
-            safe_free(new_string);
-        }
-    }
+    if (!*pm)
+        *pm = new HeaderManglers;
+    HeaderManglers *manglers = *pm;
+    header_mangler *mangler = manglers->track(t);
+    assert(mangler);
+    parse_acl_access(&mangler->access_list);
 }
 
 static void
-free_http_header_access(header_mangler header[])
+free_HeaderManglers(HeaderManglers **pm)
 {
-    int i;
-
-    for (i = 0; i < HDR_ENUM_END; i++) {
-        free_acl_access(&header[i].access_list);
+    // we delete the entire http_header_* mangler configuration at once
+    if (const HeaderManglers *manglers = *pm) {
+        delete manglers;
+        *pm = NULL;
     }
 }
 
 static void
-dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
-                         header[])
+dump_http_header_replace(StoreEntry * entry, const char *name, const HeaderManglers *manglers)
 {
-    int i;
-
-    for (i = 0; i < HDR_ENUM_END; i++) {
-        if (NULL == header[i].replacement)
-            continue;
-
-        storeAppendPrintf(entry, "%s %s %s\n", name, httpHeaderNameById(i),
-                          header[i].replacement);
-    }
+    if (manglers)
+        manglers->dumpReplacement(entry, name);
 }
 
 static void
-parse_http_header_replace(header_mangler header[])
+parse_http_header_replace(HeaderManglers **pm)
 {
-    int id, i;
     char *t = NULL;
 
     if ((t = strtok(NULL, w_space)) == NULL) {
-        debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
-        debugs(3, 0, "parse_http_header_replace: missing header name.");
-        return;
-    }
-
-    /* Now lookup index of header. */
-    id = httpHeaderIdByNameDef(t, strlen(t));
-
-    if (strcmp(t, "All") == 0)
-        id = HDR_ENUM_END;
-    else if (strcmp(t, "Other") == 0)
-        id = HDR_OTHER;
-    else if (id == -1) {
-        debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
-        debugs(3, 0, "parse_http_header_replace: unknown header name " << t << ".");
-
+        debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
+        debugs(3, DBG_CRITICAL, "parse_http_header_replace: missing header name.");
         return;
     }
 
-    if (id != HDR_ENUM_END) {
-        if (header[id].replacement != NULL)
-            safe_free(header[id].replacement);
-
-        header[id].replacement = xstrdup(t + strlen(t) + 1);
-    } else {
-        for (i = 0; i < HDR_ENUM_END; i++) {
-            if (header[i].replacement != NULL)
-                safe_free(header[i].replacement);
-
-            header[i].replacement = xstrdup(t + strlen(t) + 1);
-        }
-    }
-}
-
-static void
-free_http_header_replace(header_mangler header[])
-{
-    int i;
+    const char *value = t + strlen(t) + 1;
 
-    for (i = 0; i < HDR_ENUM_END; i++) {
-        if (header[i].replacement != NULL)
-            safe_free(header[i].replacement);
-    }
+    if (!*pm)
+        *pm = new HeaderManglers;
+    HeaderManglers *manglers = *pm;
+    manglers->setReplacement(t, value);
 }
 
 #endif
@@ -1818,7 +1774,7 @@ dump_cachedir(StoreEntry * entry, const char *name, SquidConfig::_cacheSwap swap
     int i;
     assert (entry);
 
-    for (i = 0; i < swap.n_configured; i++) {
+    for (i = 0; i < swap.n_configured; ++i) {
         s = dynamic_cast<SwapDir *>(swap.swapDirs[i].getRaw());
         if (!s) continue;
         storeAppendPrintf(entry, "%s %s %s", name, s->type(), s->path);
@@ -1927,7 +1883,7 @@ parse_cachedir(SquidConfig::_cacheSwap * swap)
 
     /* reconfigure existing dir */
 
-    for (i = 0; i < swap->n_configured; i++) {
+    for (i = 0; i < swap->n_configured; ++i) {
         assert (swap->swapDirs[i].getRaw());
 
         if ((strcasecmp(path_str, dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw())->path)) == 0) {
@@ -1940,13 +1896,13 @@ parse_cachedir(SquidConfig::_cacheSwap * swap)
 
             sd = dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw());
 
-            if (sd->type() != StoreFileSystem::FileSystems().items[fs]->type()) {
-                debugs(3, 0, "ERROR: Can't change type of existing cache_dir " <<
+            if (strcmp(sd->type(), StoreFileSystem::FileSystems().items[fs]->type()) != 0) {
+                debugs(3, DBG_CRITICAL, "ERROR: Can't change type of existing cache_dir " <<
                        sd->type() << " " << sd->path << " to " << type_str << ". Restart required");
                 return;
             }
 
-            sd->reconfigure (i, path_str);
+            sd->reconfigure();
 
             update_maxobjsize();
 
@@ -1974,9 +1930,6 @@ parse_cachedir(SquidConfig::_cacheSwap * swap)
 
     ++swap->n_configured;
 
-    if (sd->needsDiskStrand())
-        ++swap->n_strands;
-
     /* Update the max object size */
     update_maxobjsize();
 }
@@ -2057,7 +2010,7 @@ isUnsignedNumeric(const char *str, size_t len)
 {
     if (len < 1) return false;
 
-    for (; len >0 && *str; str++, len--) {
+    for (; len >0 && *str; ++str, --len) {
         if (! isdigit(*str))
             return false;
     }
@@ -2068,7 +2021,7 @@ isUnsignedNumeric(const char *str, size_t len)
  \param proto  'tcp' or 'udp' for protocol
  \returns       Port the named service is supposed to be listening on.
  */
-static u_short
+static unsigned short
 GetService(const char *proto)
 {
     struct servent *port = NULL;
@@ -2082,7 +2035,7 @@ GetService(const char *proto)
     if ( !isUnsignedNumeric(token, strlen(token)) )
         port = getservbyname(token, proto);
     if (port != NULL) {
-        return ntohs((u_short)port->s_port);
+        return ntohs((unsigned short)port->s_port);
     }
     /** Or a numeric translation of the config text. */
     return xatos(token);
@@ -2092,7 +2045,7 @@ GetService(const char *proto)
  \returns       Port the named TCP service is supposed to be listening on.
  \copydoc GetService(const char *proto)
  */
-inline u_short
+inline unsigned short
 GetTcpService(void)
 {
     return GetService("tcp");
@@ -2102,7 +2055,7 @@ GetTcpService(void)
  \returns       Port the named UDP service is supposed to be listening on.
  \copydoc GetService(const char *proto)
  */
-inline u_short
+inline unsigned short
 GetUdpService(void)
 {
     return GetService("udp");
@@ -2193,8 +2146,10 @@ parse_peer(peer ** head)
             char *mode, *nextmode;
             for (mode = nextmode = tmp; mode; mode = nextmode) {
                 nextmode = strchr(mode, ',');
-                if (nextmode)
-                    *nextmode++ = '\0';
+                if (nextmode) {
+                    *nextmode = '\0';
+                    ++nextmode;
+                }
                 if (!strcasecmp(mode, "no-clr")) {
                     if (p->options.htcp_only_clr)
                         fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
@@ -2223,6 +2178,28 @@ parse_peer(peer ** head)
                 fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
 
             p->options.carp = 1;
+        } else if (!strncasecmp(token, "carp-key=", 9)) {
+            if (p->options.carp != 1)
+                fatalf("parse_peer: carp-key specified on non-carp peer %s/%d\n", p->host, p->http_port);
+            p->options.carp_key.set=1;
+            char *nextkey=token+strlen("carp-key="), *key=nextkey;
+            for (; key; key = nextkey) {
+                nextkey=strchr(key,',');
+                if (nextkey) ++nextkey; // skip the comma, any
+                if (0==strncasecmp(key,"scheme",6)) {
+                    p->options.carp_key.scheme=1;
+                } else if (0==strncasecmp(key,"host",4)) {
+                    p->options.carp_key.host=1;
+                } else if (0==strncasecmp(key,"port",4)) {
+                    p->options.carp_key.port=1;
+                } else if (0==strncasecmp(key,"path",4)) {
+                    p->options.carp_key.path=1;
+                } else if (0==strncasecmp(key,"params",6)) {
+                    p->options.carp_key.params=1;
+                } else {
+                    fatalf("invalid carp-key '%s'",key);
+                }
+            }
         } else if (!strcasecmp(token, "userhash")) {
 #if USE_AUTH
             if (p->type != PEER_PARENT)
@@ -2323,7 +2300,7 @@ parse_peer(peer ** head)
         } else if (strcmp(token, "connection-auth=auto") == 0) {
             p->connection_auth = 2;
         } else {
-            debugs(3, 0, "parse_peer: token='" << token << "'");
+            debugs(3, DBG_CRITICAL, "parse_peer: token='" << token << "'");
             self_destruct();
         }
     }
@@ -2339,7 +2316,7 @@ parse_peer(peer ** head)
 
     p->icp.version = ICP_VERSION_CURRENT;
 
-    p->test_fd = -1;
+    p->testing_now = false;
 
 #if USE_CACHE_DIGESTS
 
@@ -2431,7 +2408,7 @@ parse_cachemgrpasswd(cachemgr_passwd ** head)
                 if (strcmp(w->key, u->key))
                     continue;
 
-                debugs(0, 0, "WARNING: action '" << u->key << "' (line " << config_lineno << ") already has a password");
+                debugs(0, DBG_CRITICAL, "WARNING: action '" << u->key << "' (line " << config_lineno << ") already has a password");
             }
         }
     }
@@ -2508,7 +2485,7 @@ parse_peer_access(void)
         self_destruct();
 
     if ((p = peerFindByName(host)) == NULL) {
-        debugs(15, 0, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
+        debugs(15, DBG_CRITICAL, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
         return;
     }
 
@@ -2530,7 +2507,7 @@ parse_hostdomain(void)
         peer *p;
 
         if ((p = peerFindByName(host)) == NULL) {
-            debugs(15, 0, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
+            debugs(15, DBG_CRITICAL, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
             continue;
         }
 
@@ -2539,7 +2516,7 @@ parse_hostdomain(void)
 
         if (*domain == '!') {  /* check for !.edu */
             l->do_ping = 0;
-            domain++;
+            ++domain;
         }
 
         l->domain = xstrdup(domain);
@@ -2568,7 +2545,7 @@ parse_hostdomaintype(void)
         peer *p;
 
         if ((p = peerFindByName(host)) == NULL) {
-            debugs(15, 0, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
+            debugs(15, DBG_CRITICAL, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
             return;
         }
 
@@ -2832,14 +2809,14 @@ parse_refreshpattern(refresh_t ** head)
 #endif
 
         } else
-            debugs(22, 0, "refreshAddToList: Unknown option '" << pattern << "': " << token);
+            debugs(22, DBG_CRITICAL, "refreshAddToList: Unknown option '" << pattern << "': " << token);
     }
 
     if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
         char errbuf[256];
         regerror(errcode, &comp, errbuf, sizeof errbuf);
-        debugs(22, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
-        debugs(22, 0, "refreshAddToList: Invalid regular expression '" << pattern << "': " << errbuf);
+        debugs(22, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
+        debugs(22, DBG_CRITICAL, "refreshAddToList: Invalid regular expression '" << pattern << "': " << errbuf);
         return;
     }
 
@@ -2967,6 +2944,11 @@ free_string(char **var)
 void
 parse_eol(char *volatile *var)
 {
+    if (!var) {
+        self_destruct();
+        return;
+    }
+
     unsigned char *token = (unsigned char *) strtok(NULL, null_string);
     safe_free(*var);
 
@@ -2976,7 +2958,7 @@ parse_eol(char *volatile *var)
     }
 
     while (*token && xisspace(*token))
-        token++;
+        ++token;
 
     if (!*token) {
         self_destruct();
@@ -3009,12 +2991,12 @@ free_time_t(time_t * var)
     *var = 0;
 }
 
-#if !USE_DNSSERVERS
+#if !USE_DNSHELPER
 static void
 dump_time_msec(StoreEntry * entry, const char *name, time_msec_t var)
 {
     if (var % 1000)
-        storeAppendPrintf(entry, "%s %"PRId64" milliseconds\n", name, var);
+        storeAppendPrintf(entry, "%s %" PRId64 " milliseconds\n", name, var);
     else
         storeAppendPrintf(entry, "%s %d seconds\n", name, (int)(var/1000) );
 }
@@ -3046,7 +3028,7 @@ dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
     storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
 }
 
-#if !USE_DNSSERVERS
+#if !USE_DNSHELPER
 static void
 dump_b_ssize_t(StoreEntry * entry, const char *name, ssize_t var)
 {
@@ -3065,13 +3047,13 @@ dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
 static void
 dump_b_int64_t(StoreEntry * entry, const char *name, int64_t var)
 {
-    storeAppendPrintf(entry, "%s %"PRId64" %s\n", name, var, B_BYTES_STR);
+    storeAppendPrintf(entry, "%s %" PRId64 " %s\n", name, var, B_BYTES_STR);
 }
 
 static void
 dump_kb_int64_t(StoreEntry * entry, const char *name, int64_t var)
 {
-    storeAppendPrintf(entry, "%s %"PRId64" %s\n", name, var, B_KBYTES_STR);
+    storeAppendPrintf(entry, "%s %" PRId64 " %s\n", name, var, B_KBYTES_STR);
 }
 
 #if UNUSED_CODE
@@ -3090,7 +3072,7 @@ parse_b_size_t(size_t * var)
     parseBytesLine(var, B_BYTES_STR);
 }
 
-#if !USE_DNSSERVERS
+#if !USE_DNSHELPER
 static void
 parse_b_ssize_t(ssize_t * var)
 {
@@ -3124,7 +3106,7 @@ free_size_t(size_t * var)
     *var = 0;
 }
 
-#if !USE_DNSSERVERS
+#if !USE_DNSHELPER
 static void
 free_ssize_t(ssize_t * var)
 {
@@ -3146,25 +3128,25 @@ free_b_int64_t(int64_t * var)
 #define free_kb_int64_t free_b_int64_t
 
 static void
-dump_ushort(StoreEntry * entry, const char *name, u_short var)
+dump_u_short(StoreEntry * entry, const char *name, unsigned short var)
 {
     storeAppendPrintf(entry, "%s %d\n", name, var);
 }
 
 static void
-free_ushort(u_short * u)
+free_u_short(unsigned short * u)
 {
     *u = 0;
 }
 
 static void
-parse_ushort(u_short * var)
+parse_u_short(unsigned short * var)
 {
     ConfigParser::ParseUShort(var);
 }
 
 void
-ConfigParser::ParseUShort(u_short *var)
+ConfigParser::ParseUShort(unsigned short *var)
 {
     *var = GetShort();
 }
@@ -3309,6 +3291,40 @@ dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings *
     storeAppendPrintf(entry, "\n");
 }
 
+void
+YesNoNone::configure(bool beSet)
+{
+    option = beSet ? +1 : -1;
+}
+
+YesNoNone::operator void*() const
+{
+    assert(option != 0); // must call configure() first
+    return option > 0 ? (void*)this : NULL;
+}
+
+
+inline void
+free_YesNoNone(YesNoNone *)
+{
+    // do nothing: no explicit cleanup is required
+}
+
+static void
+parse_YesNoNone(YesNoNone *option)
+{
+    int value = 0;
+    parse_onoff(&value);
+    option->configure(value > 0);
+}
+
+static void
+dump_YesNoNone(StoreEntry * entry, const char *name, YesNoNone &option)
+{
+    if (option.configured())
+        dump_onoff(entry, name, option ? 1 : 0);
+}
+
 static void
 free_memcachemode(SquidConfig * config)
 {
@@ -3373,7 +3389,7 @@ parseNeighborType(const char *s)
     if (!strcasecmp(s, "multicast"))
         return PEER_MULTICAST;
 
-    debugs(15, 0, "WARNING: Unknown neighbor type: " << s);
+    debugs(15, DBG_CRITICAL, "WARNING: Unknown neighbor type: " << s);
 
     return PEER_SIBLING;
 }
@@ -3434,10 +3450,8 @@ check_null_IpAddress_list(const Ip::Address_list * s)
 #endif /* CURRENTLY_UNUSED */
 #endif /* USE_WCCPv2 */
 
-CBDATA_CLASS_INIT(http_port_list);
-
 static void
-parse_http_port_specification(http_port_list * s, char *token)
+parsePortSpecification(AnyP::PortCfg * s, char *token)
 {
     char *host = NULL;
     unsigned short port = 0;
@@ -3453,16 +3467,17 @@ parse_http_port_specification(http_port_list * s, char *token)
         host = token + 1;
         t = strchr(host, ']');
         if (!t) {
-            debugs(3, 0, "http(s)_port: missing ']' on IPv6 address: " << token);
+            debugs(3, DBG_CRITICAL, s->protocol << "_port: missing ']' on IPv6 address: " << token);
             self_destruct();
         }
-        *t++ = '\0';
+        *t = '\0';
+        ++t;
         if (*t != ':') {
-            debugs(3, 0, "http(s)_port: missing Port in: " << token);
+            debugs(3, DBG_CRITICAL, s->protocol << "_port: missing Port in: " << token);
             self_destruct();
         }
         if (!Ip::EnableIpv6) {
-            debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 is not available.");
+            debugs(3, DBG_CRITICAL, "FATAL: " << s->protocol << "_port: IPv6 is not available.");
             self_destruct();
         }
         port = xatos(t + 1);
@@ -3475,14 +3490,14 @@ parse_http_port_specification(http_port_list * s, char *token)
 
     } else if ((port = strtol(token, &junk, 10)), !*junk) {
         /* port */
-        debugs(3, 3, "http(s)_port: found Listen on Port: " << port);
+        debugs(3, 3, s->protocol << "_port: found Listen on Port: " << port);
     } else {
-        debugs(3, 0, "http(s)_port: missing Port: " << token);
+        debugs(3, DBG_CRITICAL, s->protocol << "_port: missing Port: " << token);
         self_destruct();
     }
 
-    if (port == 0) {
-        debugs(3, 0, "http(s)_port: Port cannot be 0: " << token);
+    if (port == 0 && host != NULL) {
+        debugs(3, DBG_CRITICAL, s->protocol << "_port: Port cannot be 0: " << token);
         self_destruct();
     }
 
@@ -3491,27 +3506,27 @@ parse_http_port_specification(http_port_list * s, char *token)
         s->s.SetPort(port);
         if (!Ip::EnableIpv6)
             s->s.SetIPv4();
-        debugs(3, 3, "http(s)_port: found Listen on wildcard address: *:" << s->s.GetPort() );
-    } else if ( s->s = host ) { /* check/parse numeric IPA */
+        debugs(3, 3, s->protocol << "_port: found Listen on wildcard address: *:" << s->s.GetPort() );
+    } else if ( (s->s = host) ) { /* check/parse numeric IPA */
         s->s.SetPort(port);
         if (!Ip::EnableIpv6)
             s->s.SetIPv4();
-        debugs(3, 3, "http(s)_port: Listen on Host/IP: " << host << " --> " << s->s);
+        debugs(3, 3, s->protocol << "_port: Listen on Host/IP: " << host << " --> " << s->s);
     } else if ( s->s.GetHostByName(host) ) { /* check/parse for FQDN */
         /* dont use ipcache */
         s->defaultsite = xstrdup(host);
         s->s.SetPort(port);
         if (!Ip::EnableIpv6)
             s->s.SetIPv4();
-        debugs(3, 3, "http(s)_port: found Listen as Host " << s->defaultsite << " on IP: " << s->s);
+        debugs(3, 3, s->protocol << "_port: found Listen as Host " << s->defaultsite << " on IP: " << s->s);
     } else {
-        debugs(3, 0, "http(s)_port: failed to resolve Host/IP: " << host);
+        debugs(3, DBG_CRITICAL, s->protocol << "_port: failed to resolve Host/IP: " << host);
         self_destruct();
     }
 }
 
 static void
-parse_http_port_option(http_port_list * s, char *token)
+parse_port_option(AnyP::PortCfg * s, char *token)
 {
     /* modes first */
 
@@ -3520,7 +3535,7 @@ parse_http_port_option(http_port_list * s, char *token)
             debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: Accelerator mode requires its own port. It cannot be shared with other modes.");
             self_destruct();
         }
-        s->accel = 1;
+        s->accel = s->vhost = 1;
     } else if (strcmp(token, "transparent") == 0 || strcmp(token, "intercept") == 0) {
         if (s->accel || s->spoof_client_ip) {
             debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: Intercept mode requires its own interception port. It cannot be shared with other modes.");
@@ -3536,7 +3551,7 @@ parse_http_port_option(http_port_list * s, char *token)
         if (Ip::EnableIpv6)
             debugs(3, DBG_IMPORTANT, "Disabling IPv6 on port " << s->s << " (interception enabled)");
         if ( !s->s.SetIPv4() ) {
-            debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot be transparent (protocol does not provide NAT)" << s->s );
+            debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot NAT intercept (protocol does not provide NAT)" << s->s );
             self_destruct();
         }
     } else if (strcmp(token, "tproxy") == 0) {
@@ -3564,10 +3579,14 @@ parse_http_port_option(http_port_list * s, char *token)
         s->defaultsite = xstrdup(token + 12);
     } else if (strcmp(token, "vhost") == 0) {
         if (!s->accel) {
-            debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vhost option requires Acceleration mode flag.");
-            self_destruct();
+            debugs(3, DBG_CRITICAL, "WARNING: http(s)_port: vhost option is deprecated. Use 'accel' mode flag instead.");
+        }
+        s->accel = s->vhost = 1;
+    } else if (strcmp(token, "no-vhost") == 0) {
+        if (!s->accel) {
+            debugs(3, DBG_IMPORTANT, "ERROR: http(s)_port: no-vhost option requires Acceleration mode flag.");
         }
-        s->vhost = 1;
+        s->vhost = 0;
     } else if (strcmp(token, "vport") == 0) {
         if (!s->accel) {
             debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vport option requires Acceleration mode flag.");
@@ -3588,10 +3607,15 @@ parse_http_port_option(http_port_list * s, char *token)
         s->protocol = xstrdup(token + 9);
     } else if (strcmp(token, "allow-direct") == 0) {
         if (!s->accel) {
-            debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vport option requires Acceleration mode flag.");
+            debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: allow-direct option requires Acceleration mode flag.");
             self_destruct();
         }
         s->allow_direct = 1;
+    } else if (strcmp(token, "act-as-origin") == 0) {
+        if (!s->accel) {
+            debugs(3, DBG_IMPORTANT, "ERROR: http(s)_port: act-as-origin option requires Acceleration mode flag.");
+        } else
+            s->actAsOrigin = 1;
     } else if (strcmp(token, "ignore-cc") == 0) {
 #if !USE_HTTP_VIOLATIONS
         if (!s->accel) {
@@ -3633,12 +3657,12 @@ parse_http_port_option(http_port_list * s, char *token)
         s->tcp_keepalive.idle = atoi(t);
         t = strchr(t, ',');
         if (t) {
-            t++;
+            ++t;
             s->tcp_keepalive.interval = atoi(t);
             t = strchr(t, ',');
         }
         if (t) {
-            t++;
+            ++t;
             s->tcp_keepalive.timeout = atoi(t);
             t = strchr(t, ',');
         }
@@ -3700,77 +3724,32 @@ parse_http_port_option(http_port_list * s, char *token)
     }
 }
 
-static http_port_list *
-create_http_port(char *portspec)
-{
-    http_port_list *s = new http_port_list("http");
-    parse_http_port_specification(s, portspec);
-    return s;
-}
-
 void
 add_http_port(char *portspec)
 {
-    http_port_list *s = create_http_port(portspec);
-    // we may need to merge better of the above returns a list with clones
+    AnyP::PortCfg *s = new AnyP::PortCfg("http_port");
+    parsePortSpecification(s, portspec);
+    // we may need to merge better if the above returns a list with clones
     assert(s->next == NULL);
-    s->next = Config.Sockaddr.http;
-    Config.Sockaddr.http = s;
-}
-
-http_port_list *
-clone_http_port_list(http_port_list *a)
-{
-    http_port_list *b = new http_port_list(a->protocol);
-
-    b->s = a->s;
-    if (a->name)
-        b->name = xstrdup(a->name);
-    if (a->defaultsite)
-        b->defaultsite = xstrdup(a->defaultsite);
-
-    b->intercepted = a->intercepted;
-    b->spoof_client_ip = a->spoof_client_ip;
-    b->accel = a->accel;
-    b->allow_direct = a->allow_direct;
-    b->vhost = a->vhost;
-    b->sslBump = a->sslBump;
-    b->vport = a->vport;
-    b->connection_auth_disabled = a->connection_auth_disabled;
-    b->disable_pmtu_discovery = a->disable_pmtu_discovery;
-
-    memcpy( &(b->tcp_keepalive), &(a->tcp_keepalive), sizeof(a->tcp_keepalive));
-
-#if 0
-    // AYJ: 2009-07-18: for now SSL does not clone. Configure separate ports with IPs and SSL settings
-
-#if USE_SSL
-    // XXX: temporary hack to ease move of SSL options to http_port
-    http_port_list &http;
-
-    char *cert;
-    char *key;
-    int version;
-    char *cipher;
-    char *options;
-    char *clientca;
-    char *cafile;
-    char *capath;
-    char *crlfile;
-    char *dhfile;
-    char *sslflags;
-    char *sslContextSessionId;
-    SSL_CTX *sslContext;
-#endif
-
-#endif /*0*/
-
-    return b;
+    s->next = cbdataReference(Config.Sockaddr.http);
+    cbdataReferenceDone(Config.Sockaddr.http);
+    Config.Sockaddr.http = cbdataReference(s);
 }
 
 static void
-parse_http_port_list(http_port_list ** head)
+parsePortCfg(AnyP::PortCfg ** head, const char *optionName)
 {
+    const char *protocol = NULL;
+    if (strcmp(optionName, "http_port") == 0 ||
+            strcmp(optionName, "ascii_port") == 0)
+        protocol = "http";
+    else if (strcmp(optionName, "https_port") == 0)
+        protocol = "https";
+    if (!protocol) {
+        self_destruct();
+        return;
+    }
+
     char *token = strtok(NULL, w_space);
 
     if (!token) {
@@ -3778,28 +3757,44 @@ parse_http_port_list(http_port_list ** head)
         return;
     }
 
-    http_port_list *s = create_http_port(token);
+    AnyP::PortCfg *s = new AnyP::PortCfg(protocol);
+    parsePortSpecification(s, token);
 
     /* parse options ... */
     while ((token = strtok(NULL, w_space))) {
-        parse_http_port_option(s, token);
+        parse_port_option(s, token);
+    }
+
+#if USE_SSL
+    if (strcasecmp(protocol, "https") == 0) {
+        /* ssl-bump on https_port configuration requires either tproxy or intercept, and vice versa */
+        const bool hijacked = s->spoof_client_ip || s->intercepted;
+        if (s->sslBump && !hijacked) {
+            debugs(3, DBG_CRITICAL, "FATAL: ssl-bump on https_port requires tproxy/intercept which is missing.");
+            self_destruct();
+        }
+        if (hijacked && !s->sslBump) {
+            debugs(3, DBG_CRITICAL, "FATAL: tproxy/intercept on https_port requires ssl-bump which is missing.");
+            self_destruct();
+        }
     }
+#endif
 
     if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && s->s.IsAnyAddr()) {
         // clone the port options from *s to *(s->next)
-        s->next = clone_http_port_list(s);
+        s->next = cbdataReference(s->clone());
         s->next->s.SetIPv4();
-        debugs(3, 3, "http(s)_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s);
+        debugs(3, 3, protocol << "_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s);
     }
 
     while (*head)
         head = &(*head)->next;
 
-    *head = s;
+    *head = cbdataReference(s);
 }
 
 static void
-dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s)
+dump_generic_port(StoreEntry * e, const char *n, const AnyP::PortCfg * s)
 {
     char buf[MAX_IPSTRLEN];
 
@@ -3922,79 +3917,26 @@ dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s)
 }
 
 static void
-dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s)
+dump_PortCfg(StoreEntry * e, const char *n, const AnyP::PortCfg * s)
 {
     while (s) {
-        dump_generic_http_port(e, n, s);
+        dump_generic_port(e, n, s);
         storeAppendPrintf(e, "\n");
         s = s->next;
     }
 }
 
 static void
-free_http_port_list(http_port_list ** head)
+free_PortCfg(AnyP::PortCfg ** head)
 {
-    http_port_list *s;
+    AnyP::PortCfg *s;
 
     while ((s = *head) != NULL) {
         *head = s->next;
-        delete s;
-    }
-}
-
-#if USE_SSL
-
-// TODO: merge better with parse_http_port_list
-static void
-parse_https_port_list(https_port_list ** head)
-{
-    char *token;
-    https_port_list *s;
-
-    token = strtok(NULL, w_space);
-
-    if (!token)
-        self_destruct();
-
-    s = new https_port_list;
-    parse_http_port_specification(&s->http, token);
-
-    /* parse options ... */
-    while ((token = strtok(NULL, w_space))) {
-        parse_http_port_option(s, token);
+        cbdataReferenceDone(s);
     }
-
-    while (*head) {
-        http_port_list ** headTmp = &(*head)->http.next;
-        head = (https_port_list **)headTmp;
-    }
-
-    *head = s;
 }
 
-static void
-dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
-{
-    dump_http_port_list(e, n, s);
-}
-
-static void
-free_https_port_list(https_port_list ** head)
-{
-    free_http_port_list((http_port_list**)head);
-}
-
-#if 0
-static int
-check_null_https_port_list(const https_port_list * s)
-{
-    return NULL == s;
-}
-
-#endif
-
-#endif /* USE_SSL */
-
 void
 configFreeMemory(void)
 {
@@ -4040,10 +3982,8 @@ static void
 parse_access_log(customlog ** logs)
 {
     const char *filename, *logdef_name;
-    customlog *cl;
-    logformat *lf;
 
-    cl = (customlog *)xcalloc(1, sizeof(*cl));
+    customlog *cl = (customlog *)xcalloc(1, sizeof(*cl));
 
     if ((filename = strtok(NULL, w_space)) == NULL) {
         self_destruct();
@@ -4052,7 +3992,11 @@ parse_access_log(customlog ** logs)
 
     if (strcmp(filename, "none") == 0) {
         cl->type = Log::Format::CLF_NONE;
-        goto done;
+        aclParseAclList(LegacyParser, &cl->aclList);
+        while (*logs)
+            logs = &(*logs)->next;
+        *logs = cl;
+        return;
     }
 
     if ((logdef_name = strtok(NULL, w_space)) == NULL)
@@ -4063,7 +4007,7 @@ parse_access_log(customlog ** logs)
     cl->filename = xstrdup(filename);
 
     /* look for the definition pointer corresponding to this name */
-    lf = Log::TheConfig.logformats;
+    Format::Format *lf = Log::TheConfig.logformats;
 
     while (lf != NULL) {
         debugs(3, 9, "Comparing against '" << lf->name << "'");
@@ -4078,7 +4022,7 @@ parse_access_log(customlog ** logs)
         cl->type = Log::Format::CLF_CUSTOM;
         cl->logFormat = lf;
     } else if (strcmp(logdef_name, "auto") == 0) {
-        debugs(0,0, "WARNING: Log format 'auto' no longer exists. Using 'squid' instead.");
+        debugs(0, DBG_CRITICAL, "WARNING: Log format 'auto' no longer exists. Using 'squid' instead.");
         cl->type = Log::Format::CLF_SQUID;
     } else if (strcmp(logdef_name, "squid") == 0) {
         cl->type = Log::Format::CLF_SQUID;
@@ -4095,12 +4039,11 @@ parse_access_log(customlog ** logs)
     } else if (strcmp(logdef_name, "referrer") == 0) {
         cl->type = Log::Format::CLF_REFERER;
     } else {
-        debugs(3, 0, "Log format '" << logdef_name << "' is not defined");
+        debugs(3, DBG_CRITICAL, "Log format '" << logdef_name << "' is not defined");
         self_destruct();
         return;
     }
 
-done:
     aclParseAclList(LegacyParser, &cl->aclList);
 
     while (*logs)
@@ -4285,6 +4228,23 @@ parse_adaptation_access_type()
     Adaptation::Config::ParseAccess(LegacyParser);
 }
 
+static void
+parse_adaptation_meta_type(Adaptation::Config::MetaHeaders *)
+{
+    Adaptation::Config::ParseMetaHeader(LegacyParser);
+}
+
+static void
+dump_adaptation_meta_type(StoreEntry *entry, const char *name, Adaptation::Config::MetaHeaders &)
+{
+    Adaptation::Config::DumpMetaHeader(entry, name);
+}
+
+static void
+free_adaptation_meta_type(Adaptation::Config::MetaHeaders *)
+{
+    // Nothing to do, it is released inside Adaptation::Config::freeService()
+}
 #endif /* USE_ADAPTATION */
 
 
@@ -4311,7 +4271,7 @@ dump_icap_service_type(StoreEntry * entry, const char *name, const Adaptation::I
 static void
 parse_icap_class_type()
 {
-    debugs(93, 0, "WARNING: 'icap_class' is depricated. " <<
+    debugs(93, DBG_CRITICAL, "WARNING: 'icap_class' is depricated. " <<
            "Use 'adaptation_service_set' instead");
     Adaptation::Config::ParseServiceSet();
 }
@@ -4319,7 +4279,7 @@ parse_icap_class_type()
 static void
 parse_icap_access_type()
 {
-    debugs(93, 0, "WARNING: 'icap_access' is depricated. " <<
+    debugs(93, DBG_CRITICAL, "WARNING: 'icap_access' is depricated. " <<
            "Use 'adaptation_access' instead");
     Adaptation::Config::ParseAccess(LegacyParser);
 }
@@ -4361,7 +4321,7 @@ static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
         return;
 
     if (strcmp(token,"in") != 0) {
-        debugs(3, 0, "expecting 'in' on'"  << config_input_line << "'");
+        debugs(3, DBG_CRITICAL, "expecting 'in' on'"  << config_input_line << "'");
         self_destruct();
     }
 
@@ -4376,7 +4336,7 @@ static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
     if (0 == d)
         (void) 0;
     else if ((token = strtok(NULL, w_space)) == NULL) {
-        debugs(3, 0, "No time-units on '" << config_input_line << "'");
+        debugs(3, DBG_CRITICAL, "No time-units on '" << config_input_line << "'");
         self_destruct();
     } else if ((m = parseTimeUnits(token, false)) == 0)
         self_destruct();
@@ -4398,5 +4358,323 @@ static void free_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
     cfg->oldest_service_failure = 0;
     cfg->service_failure_limit = 0;
 }
+#endif
+
+#if USE_SSL
+static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt)
+{
+    char *al;
+    sslproxy_cert_adapt *ca = (sslproxy_cert_adapt *) xcalloc(1, sizeof(sslproxy_cert_adapt));
+    if ((al = strtok(NULL, w_space)) == NULL) {
+        self_destruct();
+        return;
+    }
+
+    const char *param;
+    if ( char *s = strchr(al, '{')) {
+        *s = '\0'; // terminate the al string
+        ++s;
+        param = s;
+        s = strchr(s, '}');
+        if (!s) {
+            self_destruct();
+            return;
+        }
+        *s = '\0';
+    } else
+        param = NULL;
+
+    if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidAfter]) == 0) {
+        ca->alg = Ssl::algSetValidAfter;
+        ca->param = strdup("on");
+    } else if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidBefore]) == 0) {
+        ca->alg = Ssl::algSetValidBefore;
+        ca->param = strdup("on");
+    } else if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetCommonName]) == 0) {
+        ca->alg = Ssl::algSetCommonName;
+        if (param) {
+            if (strlen(param) > 64) {
+                debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: setCommonName{" <<param << "} : using common name longer than 64 bytes is not supported");
+                self_destruct();
+                return;
+            }
+            ca->param = strdup(param);
+        }
+    } else {
+        debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: unknown cert adaptation algorithm: " << al);
+        self_destruct();
+        return;
+    }
+
+    aclParseAclList(LegacyParser, &ca->aclList);
+
+    while (*cert_adapt)
+        cert_adapt = &(*cert_adapt)->next;
+
+    *cert_adapt = ca;
+}
+
+static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt)
+{
+    for (sslproxy_cert_adapt *ca = cert_adapt; ca != NULL; ca = ca->next) {
+        storeAppendPrintf(entry, "%s ", name);
+        storeAppendPrintf(entry, "%s{%s} ", Ssl::sslCertAdaptAlgoritm(ca->alg), ca->param);
+        if (ca->aclList)
+            dump_acl_list(entry, ca->aclList);
+        storeAppendPrintf(entry, "\n");
+    }
+}
+
+static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt)
+{
+    while (*cert_adapt) {
+        sslproxy_cert_adapt *ca = *cert_adapt;
+        *cert_adapt = ca->next;
+        safe_free(ca->param);
+
+        if (ca->aclList)
+            aclDestroyAclList(&ca->aclList);
+
+        safe_free(ca);
+    }
+}
+
+static void parse_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign)
+{
+    char *al;
+    sslproxy_cert_sign *cs = (sslproxy_cert_sign *) xcalloc(1, sizeof(sslproxy_cert_sign));
+    if ((al = strtok(NULL, w_space)) == NULL) {
+        self_destruct();
+        return;
+    }
+
+    if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignTrusted]) == 0)
+        cs->alg = Ssl::algSignTrusted;
+    else if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignUntrusted]) == 0)
+        cs->alg = Ssl::algSignUntrusted;
+    else if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignSelf]) == 0)
+        cs->alg = Ssl::algSignSelf;
+    else {
+        debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_sign: unknown cert signing algorithm: " << al);
+        self_destruct();
+        return;
+    }
+
+    aclParseAclList(LegacyParser, &cs->aclList);
+
+    while (*cert_sign)
+        cert_sign = &(*cert_sign)->next;
+
+    *cert_sign = cs;
+}
+
+static void dump_sslproxy_cert_sign(StoreEntry *entry, const char *name, sslproxy_cert_sign *cert_sign)
+{
+    sslproxy_cert_sign *cs;
+    for (cs = cert_sign; cs != NULL; cs = cs->next) {
+        storeAppendPrintf(entry, "%s ", name);
+        storeAppendPrintf(entry, "%s ", Ssl::certSignAlgorithm(cs->alg));
+        if (cs->aclList)
+            dump_acl_list(entry, cs->aclList);
+        storeAppendPrintf(entry, "\n");
+    }
+}
+
+static void free_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign)
+{
+    while (*cert_sign) {
+        sslproxy_cert_sign *cs = *cert_sign;
+        *cert_sign = cs->next;
+
+        if (cs->aclList)
+            aclDestroyAclList(&cs->aclList);
+
+        safe_free(cs);
+    }
+}
+
+class sslBumpCfgRr: public ::RegisteredRunner
+{
+public:
+    static Ssl::BumpMode lastDeprecatedRule;
+    /* RegisteredRunner API */
+    virtual void run(const RunnerRegistry &);
+};
+
+Ssl::BumpMode sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpEnd;
+
+RunnerRegistrationEntry(rrFinalizeConfig, sslBumpCfgRr);
+
+void sslBumpCfgRr::run(const RunnerRegistry &r)
+{
+    if (lastDeprecatedRule != Ssl::bumpEnd) {
+        assert( lastDeprecatedRule == Ssl::bumpClientFirst || lastDeprecatedRule == Ssl::bumpNone);
+        static char buf[1024];
+        if (lastDeprecatedRule == Ssl::bumpClientFirst) {
+            strcpy(buf, "ssl_bump deny all");
+            debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated implicit "
+                   "\"ssl_bump deny all\" to \"ssl_bump none all\". New ssl_bump configurations "
+                   "must not use implicit rules. Update your ssl_bump rules.");
+        } else {
+            strcpy(buf, "ssl_bump allow all");
+            debugs(3, DBG_CRITICAL, "SECURITY NOTICE: auto-converting deprecated implicit "
+                   "\"ssl_bump allow all\" to \"ssl_bump client-first all\" which is usually "
+                   "inferior to the newer server-first bumping mode. New ssl_bump"
+                   " configurations must not use implicit rules. Update your ssl_bump rules.");
+        }
+        parse_line(buf);
+    }
+}
+
+static void parse_sslproxy_ssl_bump(acl_access **ssl_bump)
+{
+    typedef const char *BumpCfgStyle;
+    BumpCfgStyle bcsNone = NULL;
+    BumpCfgStyle bcsNew = "new client/server-first/none";
+    BumpCfgStyle bcsOld = "deprecated allow/deny";
+    static BumpCfgStyle bumpCfgStyleLast = bcsNone;
+    BumpCfgStyle bumpCfgStyleNow = bcsNone;
+    char *bm;
+    if ((bm = strtok(NULL, w_space)) == NULL) {
+        self_destruct();
+        return;
+    }
+
+    // if this is the first rule proccessed
+    if (*ssl_bump == NULL) {
+        bumpCfgStyleLast = bcsNone;
+        sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpEnd;
+    }
+
+    acl_access *A = new acl_access;
+    A->allow = allow_t(ACCESS_ALLOWED);
+
+    if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpClientFirst]) == 0) {
+        A->allow.kind = Ssl::bumpClientFirst;
+        bumpCfgStyleNow = bcsNew;
+    } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpServerFirst]) == 0) {
+        A->allow.kind = Ssl::bumpServerFirst;
+        bumpCfgStyleNow = bcsNew;
+    } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpNone]) == 0) {
+        A->allow.kind = Ssl::bumpNone;
+        bumpCfgStyleNow = bcsNew;
+    } else if (strcmp(bm, "allow") == 0) {
+        debugs(3, DBG_CRITICAL, "SECURITY NOTICE: auto-converting deprecated "
+               "\"ssl_bump allow <acl>\" to \"ssl_bump client-first <acl>\" which "
+               "is usually inferior to the newer server-first "
+               "bumping mode. Update your ssl_bump rules.");
+        A->allow.kind = Ssl::bumpClientFirst;
+        bumpCfgStyleNow = bcsOld;
+        sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpClientFirst;
+    } else if (strcmp(bm, "deny") == 0) {
+        debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated "
+               "\"ssl_bump deny <acl>\" to \"ssl_bump none <acl>\". Update "
+               "your ssl_bump rules.");
+        A->allow.kind = Ssl::bumpNone;
+        bumpCfgStyleNow = bcsOld;
+        sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpNone;
+    } else {
+        debugs(3, DBG_CRITICAL, "FATAL: unknown ssl_bump mode: " << bm);
+        self_destruct();
+        return;
+    }
+
+    if (bumpCfgStyleLast != bcsNone && bumpCfgStyleNow != bumpCfgStyleLast) {
+        debugs(3, DBG_CRITICAL, "FATAL: do not mix " << bumpCfgStyleNow << " actions with " <<
+               bumpCfgStyleLast << " actions. Update your ssl_bump rules.");
+        self_destruct();
+        return;
+    }
+
+    bumpCfgStyleLast = bumpCfgStyleNow;
+
+    aclParseAclList(LegacyParser, &A->aclList);
+
+    acl_access *B, **T;
+    for (B = *ssl_bump, T = ssl_bump; B; T = &B->next, B = B->next);
+    *T = A;
+}
+
+static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump)
+{
+    acl_access *sb;
+    for (sb = ssl_bump; sb != NULL; sb = sb->next) {
+        storeAppendPrintf(entry, "%s ", name);
+        storeAppendPrintf(entry, "%s ", Ssl::bumpMode(sb->allow.kind));
+        if (sb->aclList)
+            dump_acl_list(entry, sb->aclList);
+        storeAppendPrintf(entry, "\n");
+    }
+}
+
+static void free_sslproxy_ssl_bump(acl_access **ssl_bump)
+{
+    free_acl_access(ssl_bump);
+}
 
 #endif
+
+static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers)
+{
+    if (!headers)
+        return;
+
+    for (HeaderWithAclList::iterator hwa = headers->begin(); hwa != headers->end(); ++hwa) {
+        storeAppendPrintf(entry, "%s ", hwa->fieldName.c_str());
+        storeAppendPrintf(entry, "%s ", hwa->fieldValue.c_str());
+        if (hwa->aclList)
+            dump_acl_list(entry, hwa->aclList);
+        storeAppendPrintf(entry, "\n");
+    }
+}
+
+static void parse_HeaderWithAclList(HeaderWithAclList **headers)
+{
+    char *fn;
+    if (!*headers) {
+        *headers = new HeaderWithAclList;
+    }
+    if ((fn = strtok(NULL, w_space)) == NULL) {
+        self_destruct();
+        return;
+    }
+    HeaderWithAcl hwa;
+    hwa.fieldName = fn;
+    hwa.fieldId = httpHeaderIdByNameDef(fn, strlen(fn));
+    if (hwa.fieldId == HDR_BAD_HDR)
+        hwa.fieldId = HDR_OTHER;
+
+    String buf;
+    bool wasQuoted;
+    ConfigParser::ParseQuotedString(&buf, &wasQuoted);
+    hwa.fieldValue = buf.termedBuf();
+    hwa.quoted = wasQuoted;
+    if (hwa.quoted) {
+        Format::Format *nlf =  new ::Format::Format("hdrWithAcl");
+        if (!nlf->parse(hwa.fieldValue.c_str())) {
+            self_destruct();
+            return;
+        }
+        hwa.valueFormat = nlf;
+    }
+    aclParseAclList(LegacyParser, &hwa.aclList);
+    (*headers)->push_back(hwa);
+}
+
+static void free_HeaderWithAclList(HeaderWithAclList **header)
+{
+    if (!(*header))
+        return;
+
+    for (HeaderWithAclList::iterator hwa = (*header)->begin(); hwa != (*header)->end(); ++hwa) {
+        if (hwa->aclList)
+            aclDestroyAclList(&hwa->aclList);
+
+        if (hwa->valueFormat) {
+            delete hwa->valueFormat;
+            hwa->valueFormat = NULL;
+        }
+    }
+    delete *header;
+    *header = NULL;
+}