]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/cache_cf.cc
Enable length configuration for pipeline_prefetch queue
[thirdparty/squid.git] / src / cache_cf.cc
index 7d1dfc89595f020bcb27fd6a9ea777746b57c02a..d340169518eb257fe0d77fe4b6d2059c96fb07a5 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * DEBUG: section 03    Configuration File Parsing
  * AUTHOR: Harvest Derived
  *
 
 #include "squid.h"
 #include "acl/Acl.h"
+#include "acl/AclAddress.h"
+#include "acl/AclDenyInfoList.h"
+#include "acl/AclNameList.h"
+#include "acl/AclSizeLimit.h"
 #include "acl/Gadgets.h"
 #include "acl/MethodData.h"
 #include "anyp/PortCfg.h"
+#include "AuthReg.h"
 #include "base/RunnersRegistry.h"
+#include "mgr/ActionPasswordList.h"
+#include "CachePeer.h"
+#include "CachePeerDomainList.h"
+#include "cache_cf.h"
 #include "ConfigParser.h"
 #include "CpuAffinityMap.h"
 #include "DiskIO/DiskIOModule.h"
@@ -45,6 +52,7 @@
 #include "ExternalACL.h"
 #include "format/Format.h"
 #include "globals.h"
+#include "HttpHeaderTools.h"
 #include "HttpRequestMethod.h"
 #include "ident/Config.h"
 #include "ip/Intercept.h"
 #include "ip/tools.h"
 #include "ipc/Kids.h"
 #include "log/Config.h"
+#include "log/CustomLog.h"
+#include "Mem.h"
 #include "MemBuf.h"
 #include "mgr/Registration.h"
+#include "NeighborTypeDomainList.h"
 #include "Parsing.h"
 #include "PeerDigest.h"
-#include "protos.h"
+#include "RefreshPattern.h"
 #include "rfc1738.h"
+#include "SquidConfig.h"
+#include "SquidString.h"
+#include "ssl/ProxyCerts.h"
 #include "Store.h"
 #include "StoreFileSystem.h"
-#include "structs.h"
 #include "SwapDir.h"
 #include "wordlist.h"
 #include "neighbors.h"
+#include "tools.h"
 /* wccp2 has its own conditional definitions */
 #include "wccp2.h"
 #if USE_ADAPTATION
 #include "snmp.h"
 #endif
 
-
-
-
 #if HAVE_GLOB_H
 #include <glob.h>
 #endif
-
 #if HAVE_LIMITS_H
 #include <limits>
 #endif
-
 #if HAVE_LIST
 #include <list>
 #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
@@ -148,7 +154,9 @@ static void dump_ecap_service_type(StoreEntry *, const char *, const Adaptation:
 static void free_ecap_service_type(Adaptation::Ecap::Config *);
 #endif
 
-CBDATA_TYPE(peer);
+static peer_t parseNeighborType(const char *s);
+
+CBDATA_TYPE(CachePeer);
 
 static const char *const T_MILLISECOND_STR = "millisecond";
 static const char *const T_SECOND_STR = "second";
@@ -168,14 +176,15 @@ static const char *const B_GBYTES_STR = "GB";
 
 static const char *const list_sep = ", \t\n\r";
 
-static void parse_access_log(customlog ** customlog_definitions);
-static int check_null_access_log(customlog *customlog_definitions);
-static void dump_access_log(StoreEntry * entry, const char *name, customlog * definitions);
-static void free_access_log(customlog ** definitions);
+static void parse_access_log(CustomLog ** customlog_definitions);
+static int check_null_access_log(CustomLog *customlog_definitions);
+static void dump_access_log(StoreEntry * entry, const char *name, CustomLog * definitions);
+static void free_access_log(CustomLog ** definitions);
+static bool setLogformat(CustomLog *cl, const char *name, const bool dieWhenMissing);
 
 static void update_maxobjsize(void);
 static void configDoConfigure(void);
-static void parse_refreshpattern(refresh_t **);
+static void parse_refreshpattern(RefreshPattern **);
 static uint64_t parseTimeUnits(const char *unit,  bool allowMsec);
 static void parseTimeLine(time_msec_t * tptr, const char *units, bool allowMsec);
 static void parse_u_short(unsigned short * var);
@@ -208,9 +217,12 @@ static void parse_http_header_replace(HeaderManglers **manglers);
 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);
+static void parse_note(Notes *);
+static void dump_note(StoreEntry *, const char *, Notes &);
+static void free_note(Notes *);
+static void parse_denyinfo(AclDenyInfoList ** var);
+static void dump_denyinfo(StoreEntry * entry, const char *name, AclDenyInfoList * var);
+static void free_denyinfo(AclDenyInfoList ** var);
 
 #if USE_WCCPv2
 static void parse_IpAddress_list(Ip::Address_list **);
@@ -266,30 +278,33 @@ self_destruct(void)
 static void
 update_maxobjsize(void)
 {
-    int i;
     int64_t ms = -1;
 
-    for (i = 0; i < Config.cacheSwap.n_configured; ++i) {
+    // determine the maximum size object that can be stored to disk
+    for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
         assert (Config.cacheSwap.swapDirs[i].getRaw());
 
-        if (dynamic_cast<SwapDir *>(Config.cacheSwap.swapDirs[i].getRaw())->
-                max_objsize > ms)
-            ms = dynamic_cast<SwapDir *>(Config.cacheSwap.swapDirs[i].getRaw())->max_objsize;
+        const int64_t storeMax = dynamic_cast<SwapDir *>(Config.cacheSwap.swapDirs[i].getRaw())->maxObjectSize();
+        if (ms < storeMax)
+            ms = storeMax;
     }
+
+    // Ensure that we do not discard objects which could be stored only in memory.
+    // It is governed by maximum_object_size_in_memory (for now)
+    // TODO: update this to check each in-memory location (SMP and local memory limits differ)
+    if (ms < static_cast<int64_t>(Config.Store.maxInMemObjSize))
+        ms = Config.Store.maxInMemObjSize;
+
     store_maxobjsize = ms;
 }
 
 static void
 SetConfigFilename(char const *file_name, bool is_pipe)
 {
-    cfg_filename = file_name;
-
-    char const *token;
-
     if (is_pipe)
         cfg_filename = file_name + 1;
-    else if ((token = strrchr(cfg_filename, '/')))
-        cfg_filename = token + 1;
+    else
+        cfg_filename = file_name;
 }
 
 static const char*
@@ -510,7 +525,7 @@ parseOneConfigFile(const char *file_name, unsigned int depth)
                 if ((token = strchr(new_file_name, '"')))
                     *token = '\0';
 
-                cfg_filename = new_file_name;
+                SetConfigFilename(new_file_name, false);
             }
 
             config_lineno = new_lineno;
@@ -580,9 +595,10 @@ parseOneConfigFile(const char *file_name, unsigned int depth)
         fclose(fp);
     }
 
-    cfg_filename = orig_cfg_filename;
+    SetConfigFilename(orig_cfg_filename, false);
     config_lineno = orig_config_lineno;
 
+    xfree(tmp_line);
     return err_count;
 }
 
@@ -628,7 +644,6 @@ parseConfigFile(const char *file_name)
     return err_count;
 }
 
-
 static void
 configDoConfigure(void)
 {
@@ -637,6 +652,7 @@ configDoConfigure(void)
     memConfigure();
     /* Sanity checks */
 
+    Config.cacheSwap.n_strands = 0; // no diskers by default
     if (Config.cacheSwap.swapDirs == NULL) {
         /* Memory-only cache probably in effect. */
         /* turn off the cache rebuild delays... */
@@ -668,7 +684,7 @@ configDoConfigure(void)
 
     if (Config.Announce.period > 0) {
         Config.onoff.announce = 1;
-    } else if (Config.Announce.period < 1) {
+    } else {
         Config.Announce.period = 86400 * 365;  /* one year */
         Config.onoff.announce = 0;
     }
@@ -690,6 +706,13 @@ configDoConfigure(void)
         }
     }
 
+    if (Config.Program.store_id) {
+        if (Config.storeIdChildren.n_max < 1) {
+            Config.storeIdChildren.n_max = 0;
+            wordlistDestroy(&Config.Program.store_id);
+        }
+    }
+
     if (Config.appendDomain)
         if (*Config.appendDomain != '.')
             fatal("append_domain must begin with a '.'");
@@ -752,6 +775,9 @@ configDoConfigure(void)
     if (Config.Program.redirect)
         requirePathnameExists("redirect_program", Config.Program.redirect->key);
 
+    if (Config.Program.store_id)
+        requirePathnameExists("store_id_program", Config.Program.store_id->key);
+
     requirePathnameExists("Icon Directory", Config.icons.directory);
 
     if (Config.errorDirectory)
@@ -760,7 +786,7 @@ configDoConfigure(void)
 #if USE_HTTP_VIOLATIONS
 
     {
-        const refresh_t *R;
+        const RefreshPattern *R;
 
         for (R = Config.Refresh; R; R = R->next) {
             if (!R->flags.override_expire)
@@ -798,15 +824,6 @@ configDoConfigure(void)
             break;
         }
 
-        for (R = Config.Refresh; R; R = R->next) {
-            if (!R->flags.ignore_no_cache)
-                continue;
-
-            debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-no-cache' in 'refresh_pattern' violates HTTP");
-
-            break;
-        }
-
         for (R = Config.Refresh; R; R = R->next) {
             if (!R->flags.ignore_no_store)
                 continue;
@@ -912,14 +929,13 @@ configDoConfigure(void)
         Config2.effectiveGroupID = grp->gr_gid;
     }
 
-    HttpRequestMethod::Configure(Config);
 #if USE_SSL
 
     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);
 
-    for (peer *p = Config.peers; p != NULL; p = p->next) {
+    for (CachePeer *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);
@@ -927,7 +943,7 @@ configDoConfigure(void)
     }
 
     for (AnyP::PortCfg *s = Config.Sockaddr.http; s != NULL; s = s->next) {
-        if (!s->sslBump)
+        if (!s->flags.tunnelSslBumping)
             continue;
 
         debugs(3, DBG_IMPORTANT, "Initializing http_port " << s->s << " SSL context");
@@ -949,6 +965,16 @@ configDoConfigure(void)
                (uint32_t)Config.maxRequestBufferSize, (uint32_t)Config.maxRequestHeaderSize);
     }
 
+    /*
+     * Disable client side request pipelining if client_persistent_connections OFF.
+     * Waste of resources queueing any pipelined requests when the first will close the connection.
+     */
+    if (Config.pipeline_max_prefetch > 0 && !Config.onoff.client_pconns) {
+        debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: pipeline_prefetch " << Config.pipeline_max_prefetch <<
+                   " requires client_persistent_connections ON. Forced pipeline_prefetch 0.");
+        Config.pipeline_max_prefetch = 0;
+    }
+
 #if USE_AUTH
     /*
      * disable client side request pipelining. There is a race with
@@ -957,12 +983,12 @@ configDoConfigure(void)
      * pipelining OFF, the client may fail to authenticate, but squid's
      * state will be preserved.
      */
-    if (Config.onoff.pipeline_prefetch) {
+    if (Config.pipeline_max_prefetch > 0) {
         Auth::Config *nego = Auth::Config::Find("Negotiate");
         Auth::Config *ntlm = Auth::Config::Find("NTLM");
         if ((nego && nego->active()) || (ntlm && ntlm->active())) {
-            debugs(3, DBG_IMPORTANT, "WARNING: pipeline_prefetch breaks NTLM and Negotiate authentication. Forced OFF.");
-            Config.onoff.pipeline_prefetch = 0;
+            debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: pipeline_prefetch breaks NTLM and Negotiate authentication. Forced pipeline_prefetch 0.");
+            Config.pipeline_max_prefetch = 0;
         }
     }
 #endif
@@ -1016,6 +1042,12 @@ parseTimeLine(time_msec_t * tptr, const char *units,  bool allowMsec)
         self_destruct();
 
     *tptr = static_cast<time_msec_t>(m * d);
+
+    if (static_cast<double>(*tptr) * 2 != m * d * 2) {
+        debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" <<
+               d << " " << token << ": integer overflow (time_msec_t).");
+        self_destruct();
+    }
 }
 
 static uint64_t
@@ -1096,11 +1128,13 @@ parseBytesLine64(int64_t * bptr, const char *units)
 
     *bptr = static_cast<int64_t>(m * d / u);
 
-    if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
+    if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2) {
+        debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" <<
+               d << " " << token << ": integer overflow (int64_t).");
         self_destruct();
+    }
 }
 
-
 static void
 parseBytesLine(size_t * bptr, const char *units)
 {
@@ -1141,8 +1175,11 @@ parseBytesLine(size_t * bptr, const char *units)
 
     *bptr = static_cast<size_t>(m * d / u);
 
-    if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
+    if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2) {
+        debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" <<
+               d << " " << token << ": integer overflow (size_t).");
         self_destruct();
+    }
 }
 
 #if !USE_DNSHELPER
@@ -1184,14 +1221,16 @@ parseBytesLineSigned(ssize_t * bptr, const char *units)
         return;
     }
 
-    *bptr = static_cast<size_t>(m * d / u);
+    *bptr = static_cast<ssize_t>(m * d / u);
 
-    if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
+    if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2) {
+        debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" <<
+               d << " " << token << ": integer overflow (ssize_t).");
         self_destruct();
+    }
 }
 #endif
 
-#if USE_SSL
 /**
  * Parse bytes from a string.
  * Similar to the parseBytesLine function but parses the string value instead of
@@ -1224,10 +1263,9 @@ static void parseBytesOptionValue(size_t * bptr, const char *units, char const *
     }
 
     *bptr = static_cast<size_t>(m * d / u);
-    if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
+    if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2)
         self_destruct();
 }
-#endif
 
 static size_t
 parseBytesUnits(const char *unit)
@@ -1261,10 +1299,11 @@ dump_acl(StoreEntry * entry, const char *name, ACL * ae)
 
     while (ae != NULL) {
         debugs(3, 3, "dump_acl: " << name << " " << ae->name);
-        storeAppendPrintf(entry, "%s %s %s ",
+        storeAppendPrintf(entry, "%s %s %s %s ",
                           name,
                           ae->name,
-                          ae->typeString());
+                          ae->typeString(),
+                          ae->flags.flagsStr());
         v = w = ae->dump();
 
         while (v != NULL) {
@@ -1362,13 +1401,13 @@ free_address(Ip::Address *addr)
     addr->SetEmpty();
 }
 
-CBDATA_TYPE(acl_address);
+CBDATA_TYPE(AclAddress);
 
 static void
-dump_acl_address(StoreEntry * entry, const char *name, acl_address * head)
+dump_acl_address(StoreEntry * entry, const char *name, AclAddress * head)
 {
     char buf[MAX_IPSTRLEN];
-    acl_address *l;
+    AclAddress *l;
 
     for (l = head; l; l = l->next) {
         if (!l->addr.IsAnyAddr())
@@ -1385,17 +1424,17 @@ dump_acl_address(StoreEntry * entry, const char *name, acl_address * head)
 static void
 freed_acl_address(void *data)
 {
-    acl_address *l = static_cast<acl_address *>(data);
+    AclAddress *l = static_cast<AclAddress *>(data);
     aclDestroyAclList(&l->aclList);
 }
 
 static void
-parse_acl_address(acl_address ** head)
+parse_acl_address(AclAddress ** head)
 {
-    acl_address *l;
-    acl_address **tail = head; /* sane name below */
-    CBDATA_INIT_TYPE_FREECB(acl_address, freed_acl_address);
-    l = cbdataAlloc(acl_address);
+    AclAddress *l;
+    AclAddress **tail = head;  /* sane name below */
+    CBDATA_INIT_TYPE_FREECB(AclAddress, freed_acl_address);
+    l = cbdataAlloc(AclAddress);
     parse_address(&l->addr);
     aclParseAclList(LegacyParser, &l->aclList);
 
@@ -1406,10 +1445,10 @@ parse_acl_address(acl_address ** head)
 }
 
 static void
-free_acl_address(acl_address ** head)
+free_acl_address(AclAddress ** head)
 {
     while (*head) {
-        acl_address *l = *head;
+        AclAddress *l = *head;
         *head = l->next;
         cbdataFree(l);
     }
@@ -1556,12 +1595,12 @@ free_acl_nfmark(acl_nfmark ** head)
 }
 #endif /* SO_MARK */
 
-CBDATA_TYPE(acl_size_t);
+CBDATA_TYPE(AclSizeLimit);
 
 static void
-dump_acl_b_size_t(StoreEntry * entry, const char *name, acl_size_t * head)
+dump_acl_b_size_t(StoreEntry * entry, const char *name, AclSizeLimit * head)
 {
-    acl_size_t *l;
+    AclSizeLimit *l;
 
     for (l = head; l; l = l->next) {
         if (l->size != -1)
@@ -1578,19 +1617,19 @@ dump_acl_b_size_t(StoreEntry * entry, const char *name, acl_size_t * head)
 static void
 freed_acl_b_size_t(void *data)
 {
-    acl_size_t *l = static_cast<acl_size_t *>(data);
+    AclSizeLimit *l = static_cast<AclSizeLimit *>(data);
     aclDestroyAclList(&l->aclList);
 }
 
 static void
-parse_acl_b_size_t(acl_size_t ** head)
+parse_acl_b_size_t(AclSizeLimit ** head)
 {
-    acl_size_t *l;
-    acl_size_t **tail = head;  /* sane name below */
+    AclSizeLimit *l;
+    AclSizeLimit **tail = head;        /* sane name below */
 
-    CBDATA_INIT_TYPE_FREECB(acl_size_t, freed_acl_b_size_t);
+    CBDATA_INIT_TYPE_FREECB(AclSizeLimit, freed_acl_b_size_t);
 
-    l = cbdataAlloc(acl_size_t);
+    l = cbdataAlloc(AclSizeLimit);
 
     parse_b_int64_t(&l->size);
 
@@ -1603,10 +1642,10 @@ parse_acl_b_size_t(acl_size_t ** head)
 }
 
 static void
-free_acl_b_size_t(acl_size_t ** head)
+free_acl_b_size_t(AclSizeLimit ** head)
 {
     while (*head) {
-        acl_size_t *l = *head;
+        AclSizeLimit *l = *head;
         *head = l->next;
         l->next = NULL;
         cbdataFree(l);
@@ -1729,7 +1768,7 @@ parse_http_header_access(HeaderManglers **pm)
     if (!*pm)
         *pm = new HeaderManglers;
     HeaderManglers *manglers = *pm;
-    header_mangler *mangler = manglers->track(t);
+    headerMangler *mangler = manglers->track(t);
     assert(mangler);
     parse_acl_access(&mangler->access_list);
 }
@@ -1883,8 +1922,10 @@ parse_cachedir(SquidConfig::_cacheSwap * swap)
 
     fs = find_fstype(type_str);
 
-    if (fs < 0)
-        self_destruct();
+    if (fs < 0) {
+        debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: This proxy does not support the '" << type_str << "' cache type. Ignoring.");
+        return;
+    }
 
     /* reconfigure existing dir */
 
@@ -1967,10 +2008,10 @@ peer_type_str(const peer_t type)
 }
 
 static void
-dump_peer(StoreEntry * entry, const char *name, peer * p)
+dump_peer(StoreEntry * entry, const char *name, CachePeer * p)
 {
-    domain_ping *d;
-    domain_type *t;
+    CachePeerDomainList *d;
+    NeighborTypeDomainList *t;
     LOCAL_ARRAY(char, xname, 128);
 
     while (p != NULL) {
@@ -2067,12 +2108,12 @@ GetUdpService(void)
 }
 
 static void
-parse_peer(peer ** head)
+parse_peer(CachePeer ** head)
 {
     char *token = NULL;
-    peer *p;
-    CBDATA_INIT_TYPE_FREECB(peer, peerDestroy);
-    p = cbdataAlloc(peer);
+    CachePeer *p;
+    CBDATA_INIT_TYPE_FREECB(CachePeer, peerDestroy);
+    p = cbdataAlloc(CachePeer);
     p->http_port = CACHE_HTTP_PORT;
     p->icp.port = CACHE_ICP_PORT;
     p->weight = 1;
@@ -2092,8 +2133,8 @@ parse_peer(peer ** head)
     p->type = parseNeighborType(token);
 
     if (p->type == PEER_MULTICAST) {
-        p->options.no_digest = 1;
-        p->options.no_netdb_exchange = 1;
+        p->options.no_digest = true;
+        p->options.no_netdb_exchange = true;
     }
 
     p->http_port = GetTcpService();
@@ -2105,29 +2146,29 @@ parse_peer(peer ** head)
     p->connection_auth = 2;    /* auto */
 
     while ((token = strtok(NULL, w_space))) {
-        if (!strcasecmp(token, "proxy-only")) {
-            p->options.proxy_only = 1;
-        } else if (!strcasecmp(token, "no-query")) {
-            p->options.no_query = 1;
-        } else if (!strcasecmp(token, "background-ping")) {
-            p->options.background_ping = 1;
-        } else if (!strcasecmp(token, "no-digest")) {
-            p->options.no_digest = 1;
-        } else if (!strcasecmp(token, "no-tproxy")) {
-            p->options.no_tproxy = 1;
-        } else if (!strcasecmp(token, "multicast-responder")) {
-            p->options.mcast_responder = 1;
+        if (!strcmp(token, "proxy-only")) {
+            p->options.proxy_only = true;
+        } else if (!strcmp(token, "no-query")) {
+            p->options.no_query = true;
+        } else if (!strcmp(token, "background-ping")) {
+            p->options.background_ping = true;
+        } else if (!strcmp(token, "no-digest")) {
+            p->options.no_digest = true;
+        } else if (!strcmp(token, "no-tproxy")) {
+            p->options.no_tproxy = true;
+        } else if (!strcmp(token, "multicast-responder")) {
+            p->options.mcast_responder = true;
 #if PEER_MULTICAST_SIBLINGS
-        } else if (!strcasecmp(token, "multicast-siblings")) {
-            p->options.mcast_siblings = 1;
+        } else if (!strcmp(token, "multicast-siblings")) {
+            p->options.mcast_siblings = true;
 #endif
-        } else if (!strncasecmp(token, "weight=", 7)) {
+        } else if (!strncmp(token, "weight=", 7)) {
             p->weight = xatoi(token + 7);
-        } else if (!strncasecmp(token, "basetime=", 9)) {
+        } else if (!strncmp(token, "basetime=", 9)) {
             p->basetime = xatoi(token + 9);
-        } else if (!strcasecmp(token, "closest-only")) {
-            p->options.closest_only = 1;
-        } else if (!strncasecmp(token, "ttl=", 4)) {
+        } else if (!strcmp(token, "closest-only")) {
+            p->options.closest_only = true;
+        } else if (!strncmp(token, "ttl=", 4)) {
             p->mcast.ttl = xatoi(token + 4);
 
             if (p->mcast.ttl < 0)
@@ -2135,18 +2176,18 @@ parse_peer(peer ** head)
 
             if (p->mcast.ttl > 128)
                 p->mcast.ttl = 128;
-        } else if (!strcasecmp(token, "default")) {
-            p->options.default_parent = 1;
-        } else if (!strcasecmp(token, "round-robin")) {
-            p->options.roundrobin = 1;
-        } else if (!strcasecmp(token, "weighted-round-robin")) {
-            p->options.weighted_roundrobin = 1;
+        } else if (!strcmp(token, "default")) {
+            p->options.default_parent = true;
+        } else if (!strcmp(token, "round-robin")) {
+            p->options.roundrobin = true;
+        } else if (!strcmp(token, "weighted-round-robin")) {
+            p->options.weighted_roundrobin = true;
 #if USE_HTCP
-        } else if (!strcasecmp(token, "htcp")) {
-            p->options.htcp = 1;
-        } else if (!strncasecmp(token, "htcp=", 5) || !strncasecmp(token, "htcp-", 5)) {
+        } else if (!strcmp(token, "htcp")) {
+            p->options.htcp = true;
+        } else if (!strncmp(token, "htcp=", 5) || !strncmp(token, "htcp-", 5)) {
             /* Note: The htcp- form is deprecated, replaced by htcp= */
-            p->options.htcp = 1;
+            p->options.htcp = true;
             char *tmp = xstrdup(token+5);
             char *mode, *nextmode;
             for (mode = nextmode = tmp; mode; mode = nextmode) {
@@ -2155,101 +2196,101 @@ parse_peer(peer ** head)
                     *nextmode = '\0';
                     ++nextmode;
                 }
-                if (!strcasecmp(mode, "no-clr")) {
+                if (!strcmp(mode, "no-clr")) {
                     if (p->options.htcp_only_clr)
                         fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
-                    p->options.htcp_no_clr = 1;
-                } else if (!strcasecmp(mode, "no-purge-clr")) {
-                    p->options.htcp_no_purge_clr = 1;
-                } else if (!strcasecmp(mode, "only-clr")) {
+                    p->options.htcp_no_clr = true;
+                } else if (!strcmp(mode, "no-purge-clr")) {
+                    p->options.htcp_no_purge_clr = true;
+                } else if (!strcmp(mode, "only-clr")) {
                     if (p->options.htcp_no_clr)
                         fatalf("parse_peer: can't set htcp no-clr and only-clr simultaneously");
-                    p->options.htcp_only_clr = 1;
-                } else if (!strcasecmp(mode, "forward-clr")) {
-                    p->options.htcp_forward_clr = 1;
-                } else if (!strcasecmp(mode, "oldsquid")) {
-                    p->options.htcp_oldsquid = 1;
+                    p->options.htcp_only_clr = true;
+                } else if (!strcmp(mode, "forward-clr")) {
+                    p->options.htcp_forward_clr = true;
+                } else if (!strcmp(mode, "oldsquid")) {
+                    p->options.htcp_oldsquid = true;
                 } else {
                     fatalf("invalid HTCP mode '%s'", mode);
                 }
             }
             safe_free(tmp);
 #endif
-        } else if (!strcasecmp(token, "no-netdb-exchange")) {
-            p->options.no_netdb_exchange = 1;
+        } else if (!strcmp(token, "no-netdb-exchange")) {
+            p->options.no_netdb_exchange = true;
 
-        } else if (!strcasecmp(token, "carp")) {
+        } else if (!strcmp(token, "carp")) {
             if (p->type != PEER_PARENT)
                 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)
+            p->options.carp = true;
+        } else if (!strncmp(token, "carp-key=", 9)) {
+            if (p->options.carp != true)
                 fatalf("parse_peer: carp-key specified on non-carp peer %s/%d\n", p->host, p->http_port);
-            p->options.carp_key.set=1;
+            p->options.carp_key.set = true;
             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;
+                if (0==strncmp(key,"scheme",6)) {
+                    p->options.carp_key.scheme = true;
+                } else if (0==strncmp(key,"host",4)) {
+                    p->options.carp_key.host = true;
+                } else if (0==strncmp(key,"port",4)) {
+                    p->options.carp_key.port = true;
+                } else if (0==strncmp(key,"path",4)) {
+                    p->options.carp_key.path = true;
+                } else if (0==strncmp(key,"params",6)) {
+                    p->options.carp_key.params = true;
                 } else {
                     fatalf("invalid carp-key '%s'",key);
                 }
             }
-        } else if (!strcasecmp(token, "userhash")) {
+        } else if (!strcmp(token, "userhash")) {
 #if USE_AUTH
             if (p->type != PEER_PARENT)
                 fatalf("parse_peer: non-parent userhash peer %s/%d\n", p->host, p->http_port);
 
-            p->options.userhash = 1;
+            p->options.userhash = true;
 #else
             fatalf("parse_peer: userhash requires authentication. peer %s/%d\n", p->host, p->http_port);
 #endif
-        } else if (!strcasecmp(token, "sourcehash")) {
+        } else if (!strcmp(token, "sourcehash")) {
             if (p->type != PEER_PARENT)
                 fatalf("parse_peer: non-parent sourcehash peer %s/%d\n", p->host, p->http_port);
 
-            p->options.sourcehash = 1;
+            p->options.sourcehash = true;
 
-        } else if (!strcasecmp(token, "no-delay")) {
+        } else if (!strcmp(token, "no-delay")) {
 #if USE_DELAY_POOLS
-            p->options.no_delay = 1;
+            p->options.no_delay = true;
 #else
             debugs(0, DBG_CRITICAL, "WARNING: cache_peer option 'no-delay' requires --enable-delay-pools");
 #endif
-        } else if (!strncasecmp(token, "login=", 6)) {
+        } else if (!strncmp(token, "login=", 6)) {
             p->login = xstrdup(token + 6);
             rfc1738_unescape(p->login);
-        } else if (!strncasecmp(token, "connect-timeout=", 16)) {
+        } else if (!strncmp(token, "connect-timeout=", 16)) {
             p->connect_timeout = xatoi(token + 16);
-        } else if (!strncasecmp(token, "connect-fail-limit=", 19)) {
+        } else if (!strncmp(token, "connect-fail-limit=", 19)) {
             p->connect_fail_limit = xatoi(token + 19);
 #if USE_CACHE_DIGESTS
-        } else if (!strncasecmp(token, "digest-url=", 11)) {
+        } else if (!strncmp(token, "digest-url=", 11)) {
             p->digest_url = xstrdup(token + 11);
 #endif
 
-        } else if (!strcasecmp(token, "allow-miss")) {
-            p->options.allow_miss = 1;
-        } else if (!strncasecmp(token, "max-conn=", 9)) {
+        } else if (!strcmp(token, "allow-miss")) {
+            p->options.allow_miss = true;
+        } else if (!strncmp(token, "max-conn=", 9)) {
             p->max_conn = xatoi(token + 9);
-        } else if (!strcasecmp(token, "originserver")) {
-            p->options.originserver = 1;
-        } else if (!strncasecmp(token, "name=", 5)) {
+        } else if (!strcmp(token, "originserver")) {
+            p->options.originserver = true;
+        } else if (!strncmp(token, "name=", 5)) {
             safe_free(p->name);
 
             if (token[5])
                 p->name = xstrdup(token + 5);
-        } else if (!strncasecmp(token, "forceddomain=", 13)) {
+        } else if (!strncmp(token, "forceddomain=", 13)) {
             safe_free(p->domain);
 
             if (token[13])
@@ -2266,7 +2307,7 @@ parse_peer(peer ** head)
             safe_free(p->sslkey);
             p->sslkey = xstrdup(token + 7);
         } else if (strncmp(token, "sslversion=", 11) == 0) {
-            p->sslversion = atoi(token + 11);
+            p->sslversion = xatoi(token + 11);
         } else if (strncmp(token, "ssloptions=", 11) == 0) {
             safe_free(p->ssloptions);
             p->ssloptions = xstrdup(token + 11);
@@ -2281,7 +2322,7 @@ parse_peer(peer ** head)
             p->sslcapath = xstrdup(token + 10);
         } else if (strncmp(token, "sslcrlfile=", 11) == 0) {
             safe_free(p->sslcrlfile);
-            p->sslcapath = xstrdup(token + 10);
+            p->sslcrlfile = xstrdup(token + 11);
         } else if (strncmp(token, "sslflags=", 9) == 0) {
             safe_free(p->sslflags);
             p->sslflags = xstrdup(token + 9);
@@ -2304,9 +2345,11 @@ parse_peer(peer ** head)
             p->connection_auth = 1;
         } else if (strcmp(token, "connection-auth=auto") == 0) {
             p->connection_auth = 2;
+        } else if (token[0] == '#') {
+            // start of a text comment. stop reading this line.
+            break;
         } else {
-            debugs(3, DBG_CRITICAL, "parse_peer: token='" << token << "'");
-            self_destruct();
+            debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Ignoring unknown cache_peer option '" << token << "'");
         }
     }
 
@@ -2346,9 +2389,9 @@ parse_peer(peer ** head)
 }
 
 static void
-free_peer(peer ** P)
+free_peer(CachePeer ** P)
 {
-    peer *p;
+    CachePeer *p;
 
     while ((p = *P) != NULL) {
         *P = p->next;
@@ -2364,7 +2407,7 @@ free_peer(peer ** P)
 }
 
 static void
-dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
+dump_cachemgrpasswd(StoreEntry * entry, const char *name, Mgr::ActionPasswordList * list)
 {
     wordlist *w;
 
@@ -2384,15 +2427,15 @@ dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list
 }
 
 static void
-parse_cachemgrpasswd(cachemgr_passwd ** head)
+parse_cachemgrpasswd(Mgr::ActionPasswordList ** head)
 {
     char *passwd = NULL;
     wordlist *actions = NULL;
-    cachemgr_passwd *p;
-    cachemgr_passwd **P;
+    Mgr::ActionPasswordList *p;
+    Mgr::ActionPasswordList **P;
     parse_string(&passwd);
     parse_wordlist(&actions);
-    p = static_cast<cachemgr_passwd *>(xcalloc(1, sizeof(cachemgr_passwd)));
+    p = new Mgr::ActionPasswordList;
     p->passwd = passwd;
     p->actions = actions;
 
@@ -2401,7 +2444,7 @@ parse_cachemgrpasswd(cachemgr_passwd ** head)
          * See if any of the actions from this line already have a
          * password from previous lines.  The password checking
          * routines in cache_manager.c take the the password from
-         * the first cachemgr_passwd struct that contains the
+         * the first Mgr::ActionPasswordList that contains the
          * requested action.  Thus, we should warn users who might
          * think they can have two passwords for the same action.
          */
@@ -2422,9 +2465,9 @@ parse_cachemgrpasswd(cachemgr_passwd ** head)
 }
 
 static void
-free_cachemgrpasswd(cachemgr_passwd ** head)
+free_cachemgrpasswd(Mgr::ActionPasswordList ** head)
 {
-    cachemgr_passwd *p;
+    Mgr::ActionPasswordList *p;
 
     while ((p = *head) != NULL) {
         *head = p->next;
@@ -2435,9 +2478,9 @@ free_cachemgrpasswd(cachemgr_passwd ** head)
 }
 
 static void
-dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
+dump_denyinfo(StoreEntry * entry, const char *name, AclDenyInfoList * var)
 {
-    acl_name_list *a;
+    AclNameList *a;
 
     while (var != NULL) {
         storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
@@ -2452,18 +2495,18 @@ dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
 }
 
 static void
-parse_denyinfo(acl_deny_info_list ** var)
+parse_denyinfo(AclDenyInfoList ** var)
 {
     aclParseDenyInfoLine(var);
 }
 
 void
-free_denyinfo(acl_deny_info_list ** list)
+free_denyinfo(AclDenyInfoList ** list)
 {
-    acl_deny_info_list *a = NULL;
-    acl_deny_info_list *a_next = NULL;
-    acl_name_list *l = NULL;
-    acl_name_list *l_next = NULL;
+    AclDenyInfoList *a = NULL;
+    AclDenyInfoList *a_next = NULL;
+    AclNameList *l = NULL;
+    AclNameList *l_next = NULL;
 
     for (a = *list; a; a = a_next) {
         for (l = a->acl_list; l; l = l_next) {
@@ -2484,7 +2527,7 @@ static void
 parse_peer_access(void)
 {
     char *host = NULL;
-    peer *p;
+    CachePeer *p;
 
     if (!(host = strtok(NULL, w_space)))
         self_destruct();
@@ -2507,20 +2550,20 @@ parse_hostdomain(void)
         self_destruct();
 
     while ((domain = strtok(NULL, list_sep))) {
-        domain_ping *l = NULL;
-        domain_ping **L = NULL;
-        peer *p;
+        CachePeerDomainList *l = NULL;
+        CachePeerDomainList **L = NULL;
+        CachePeer *p;
 
         if ((p = peerFindByName(host)) == NULL) {
             debugs(15, DBG_CRITICAL, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
             continue;
         }
 
-        l = static_cast<domain_ping *>(xcalloc(1, sizeof(domain_ping)));
-        l->do_ping = 1;
+        l = static_cast<CachePeerDomainList *>(xcalloc(1, sizeof(CachePeerDomainList)));
+        l->do_ping = true;
 
         if (*domain == '!') {  /* check for !.edu */
-            l->do_ping = 0;
+            l->do_ping = false;
             ++domain;
         }
 
@@ -2545,16 +2588,16 @@ parse_hostdomaintype(void)
         self_destruct();
 
     while ((domain = strtok(NULL, list_sep))) {
-        domain_type *l = NULL;
-        domain_type **L = NULL;
-        peer *p;
+        NeighborTypeDomainList *l = NULL;
+        NeighborTypeDomainList **L = NULL;
+        CachePeer *p;
 
         if ((p = peerFindByName(host)) == NULL) {
             debugs(15, DBG_CRITICAL, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
             return;
         }
 
-        l = static_cast<domain_type *>(xcalloc(1, sizeof(domain_type)));
+        l = static_cast<NeighborTypeDomainList *>(xcalloc(1, sizeof(NeighborTypeDomainList)));
         l->type = parseNeighborType(type);
         l->domain = xstrdup(domain);
 
@@ -2597,10 +2640,20 @@ parse_onoff(int *var)
     if (token == NULL)
         self_destruct();
 
-    if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
+    if (!strcmp(token, "on")) {
         *var = 1;
-    else
+    } else if (!strcmp(token, "enable")) {
+        debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' is deprecated. Please update to use 'on'.");
+        *var = 1;
+    } else if (!strcmp(token, "off")) {
+        *var = 0;
+    } else if (!strcmp(token, "disable")) {
+        debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'disable' is deprecated. Please update to use 'off'.");
         *var = 0;
+    } else {
+        debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid option: Boolean options can only be 'on' or 'off'.");
+        self_destruct();
+    }
 }
 
 #define free_onoff free_int
@@ -2628,18 +2681,51 @@ parse_tristate(int *var)
     if (token == NULL)
         self_destruct();
 
-    if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
+    if (!strcmp(token, "on")) {
         *var = 1;
-    else if (!strcasecmp(token, "warn"))
+    } else if (!strcmp(token, "enable")) {
+        debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' is deprecated. Please update to use value 'on'.");
+        *var = 1;
+    } else if (!strcmp(token, "warn")) {
         *var = -1;
-    else
+    } else if (!strcmp(token, "off")) {
         *var = 0;
+    } else if (!strcmp(token, "disable")) {
+        debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'disable' is deprecated. Please update to use value 'off'.");
+        *var = 0;
+    } else {
+        debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid option: Tristate options can only be 'on', 'off', or 'warn'.");
+        self_destruct();
+    }
 }
 
 #define free_tristate free_int
 
+void
+parse_pipelinePrefetch(int *var)
+{
+    char *token = ConfigParser::strtokFile();
+
+    if (token == NULL)
+        self_destruct();
+
+    if (!strcmp(token, "on")) {
+        debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'pipeline_prefetch on' is deprecated. Please update to use 1 (or a higher number).");
+        *var = 1;
+    } else if (!strcmp(token, "off")) {
+        debugs(0, DBG_PARSE_NOTE(2), "WARNING: 'pipeline_prefetch off' is deprecated. Please update to use '0'.");
+        *var = 0;
+    } else {
+        ConfigParser::strtokFileUndo();
+        parse_int(var);
+    }
+}
+
+#define free_pipelinePrefetch free_int
+#define dump_pipelinePrefetch dump_int
+
 static void
-dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
+dump_refreshpattern(StoreEntry * entry, const char *name, RefreshPattern * head)
 {
     while (head != NULL) {
         storeAppendPrintf(entry, "%s%s %s %d %d%% %d",
@@ -2673,9 +2759,6 @@ dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
         if (head->flags.ignore_reload)
             storeAppendPrintf(entry, " ignore-reload");
 
-        if (head->flags.ignore_no_cache)
-            storeAppendPrintf(entry, " ignore-no-cache");
-
         if (head->flags.ignore_no_store)
             storeAppendPrintf(entry, " ignore-no-store");
 
@@ -2697,7 +2780,7 @@ dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
 }
 
 static void
-parse_refreshpattern(refresh_t ** head)
+parse_refreshpattern(RefreshPattern ** head)
 {
     char *token;
     char *pattern;
@@ -2714,7 +2797,6 @@ parse_refreshpattern(refresh_t ** head)
     int override_lastmod = 0;
     int reload_into_ims = 0;
     int ignore_reload = 0;
-    int ignore_no_cache = 0;
     int ignore_no_store = 0;
     int ignore_must_revalidate = 0;
     int ignore_private = 0;
@@ -2722,7 +2804,7 @@ parse_refreshpattern(refresh_t ** head)
 #endif
 
     int i;
-    refresh_t *t;
+    RefreshPattern *t;
     regex_t comp;
     int errcode;
     int flags = REG_EXTENDED | REG_NOSUB;
@@ -2761,7 +2843,7 @@ parse_refreshpattern(refresh_t ** head)
 
     min = (time_t) (i * 60);   /* convert minutes to seconds */
 
-    i = GetInteger();          /* token: pct */
+    i = GetPercentage();       /* token: pct */
 
     pct = (double) i / 100.0;
 
@@ -2786,15 +2868,13 @@ parse_refreshpattern(refresh_t ** head)
         } else if (!strcmp(token, "store-stale")) {
             store_stale = 1;
         } else if (!strncmp(token, "max-stale=", 10)) {
-            max_stale = atoi(token + 10);
+            max_stale = xatoi(token + 10);
 #if USE_HTTP_VIOLATIONS
 
         } else if (!strcmp(token, "override-expire"))
             override_expire = 1;
         else if (!strcmp(token, "override-lastmod"))
             override_lastmod = 1;
-        else if (!strcmp(token, "ignore-no-cache"))
-            ignore_no_cache = 1;
         else if (!strcmp(token, "ignore-no-store"))
             ignore_no_store = 1;
         else if (!strcmp(token, "ignore-must-revalidate"))
@@ -2813,6 +2893,8 @@ parse_refreshpattern(refresh_t ** head)
             /* tell client_side.c that this is used */
 #endif
 
+        } else if (!strcmp(token, "ignore-no-cache")) {
+            debugs(22, DBG_PARSE_NOTE(2), "UPGRADE: refresh_pattern option 'ignore-no-cache' is obsolete. Remove it.");
         } else
             debugs(22, DBG_CRITICAL, "refreshAddToList: Unknown option '" << pattern << "': " << token);
     }
@@ -2827,7 +2909,7 @@ parse_refreshpattern(refresh_t ** head)
 
     pct = pct < 0.0 ? 0.0 : pct;
     max = max < 0 ? 0 : max;
-    t = static_cast<refresh_t *>(xcalloc(1, sizeof(refresh_t)));
+    t = static_cast<RefreshPattern *>(xcalloc(1, sizeof(RefreshPattern)));
     t->pattern = (char *) xstrdup(pattern);
     t->compiled_pattern = comp;
     t->min = min;
@@ -2835,44 +2917,41 @@ parse_refreshpattern(refresh_t ** head)
     t->max = max;
 
     if (flags & REG_ICASE)
-        t->flags.icase = 1;
+        t->flags.icase = true;
 
     if (refresh_ims)
-        t->flags.refresh_ims = 1;
+        t->flags.refresh_ims = true;
 
     if (store_stale)
-        t->flags.store_stale = 1;
+        t->flags.store_stale = true;
 
     t->max_stale = max_stale;
 
 #if USE_HTTP_VIOLATIONS
 
     if (override_expire)
-        t->flags.override_expire = 1;
+        t->flags.override_expire = true;
 
     if (override_lastmod)
-        t->flags.override_lastmod = 1;
+        t->flags.override_lastmod = true;
 
     if (reload_into_ims)
-        t->flags.reload_into_ims = 1;
+        t->flags.reload_into_ims = true;
 
     if (ignore_reload)
-        t->flags.ignore_reload = 1;
-
-    if (ignore_no_cache)
-        t->flags.ignore_no_cache = 1;
+        t->flags.ignore_reload = true;
 
     if (ignore_no_store)
-        t->flags.ignore_no_store = 1;
+        t->flags.ignore_no_store = true;
 
     if (ignore_must_revalidate)
-        t->flags.ignore_must_revalidate = 1;
+        t->flags.ignore_must_revalidate = true;
 
     if (ignore_private)
-        t->flags.ignore_private = 1;
+        t->flags.ignore_private = true;
 
     if (ignore_auth)
-        t->flags.ignore_auth = 1;
+        t->flags.ignore_auth = true;
 
 #endif
 
@@ -2887,9 +2966,9 @@ parse_refreshpattern(refresh_t ** head)
 }
 
 static void
-free_refreshpattern(refresh_t ** head)
+free_refreshpattern(RefreshPattern ** head)
 {
-    refresh_t *t;
+    RefreshPattern *t;
 
     while ((t = *head) != NULL) {
         *head = t->next;
@@ -3220,18 +3299,20 @@ parse_uri_whitespace(int *var)
     if (token == NULL)
         self_destruct();
 
-    if (!strcasecmp(token, "strip"))
+    if (!strcmp(token, "strip"))
         *var = URI_WHITESPACE_STRIP;
-    else if (!strcasecmp(token, "deny"))
+    else if (!strcmp(token, "deny"))
         *var = URI_WHITESPACE_DENY;
-    else if (!strcasecmp(token, "allow"))
+    else if (!strcmp(token, "allow"))
         *var = URI_WHITESPACE_ALLOW;
-    else if (!strcasecmp(token, "encode"))
+    else if (!strcmp(token, "encode"))
         *var = URI_WHITESPACE_ENCODE;
-    else if (!strcasecmp(token, "chop"))
+    else if (!strcmp(token, "chop"))
         *var = URI_WHITESPACE_CHOP;
-    else
+    else {
+        debugs(0, DBG_PARSE_NOTE(2), "ERROR: Invalid option '" << token << "': 'uri_whitespace' accepts 'strip', 'deny', 'allow', 'encode', and 'chop'.");
         self_destruct();
+    }
 }
 
 static void
@@ -3296,19 +3377,6 @@ 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 *)
 {
@@ -3355,8 +3423,10 @@ parse_memcachemode(SquidConfig * config)
     } else if (strcmp(token, "never") == 0) {
         Config.onoff.memory_cache_first = 0;
         Config.onoff.memory_cache_disk = 0;
-    } else
+    } else {
+        debugs(0, DBG_PARSE_NOTE(2), "ERROR: Invalid option '" << token << "': 'memory_cache_mode' accepts 'always', 'disk', 'network', and 'never'.");
         self_destruct();
+    }
 }
 
 static void
@@ -3379,19 +3449,19 @@ dump_memcachemode(StoreEntry * entry, const char *name, SquidConfig &config)
 peer_t
 parseNeighborType(const char *s)
 {
-    if (!strcasecmp(s, "parent"))
+    if (!strcmp(s, "parent"))
         return PEER_PARENT;
 
-    if (!strcasecmp(s, "neighbor"))
+    if (!strcmp(s, "neighbor"))
         return PEER_SIBLING;
 
-    if (!strcasecmp(s, "neighbour"))
+    if (!strcmp(s, "neighbour"))
         return PEER_SIBLING;
 
-    if (!strcasecmp(s, "sibling"))
+    if (!strcmp(s, "sibling"))
         return PEER_SIBLING;
 
-    if (!strcasecmp(s, "multicast"))
+    if (!strcmp(s, "multicast"))
         return PEER_MULTICAST;
 
     debugs(15, DBG_CRITICAL, "WARNING: Unknown neighbor type: " << s);
@@ -3493,8 +3563,8 @@ parsePortSpecification(AnyP::PortCfg * s, char *token)
         *t = '\0';
         port = xatos(t + 1);
 
-    } else if ((port = strtol(token, &junk, 10)), !*junk) {
-        /* port */
+    } else if (strtol(token, &junk, 10) && !*junk) {
+        port = xatos(token);
         debugs(3, 3, s->protocol << "_port: found Listen on Port: " << port);
     } else {
         debugs(3, DBG_CRITICAL, s->protocol << "_port: missing Port: " << token);
@@ -3536,17 +3606,18 @@ parse_port_option(AnyP::PortCfg * s, char *token)
     /* modes first */
 
     if (strcmp(token, "accel") == 0) {
-        if (s->intercepted || s->spoof_client_ip) {
+        if (s->flags.isIntercepted()) {
             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 = s->vhost = 1;
+        s->flags.accelSurrogate = true;
+        s->vhost = true;
     } else if (strcmp(token, "transparent") == 0 || strcmp(token, "intercept") == 0) {
-        if (s->accel || s->spoof_client_ip) {
+        if (s->flags.accelSurrogate || s->flags.tproxyIntercept) {
             debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: Intercept mode requires its own interception port. It cannot be shared with other modes.");
             self_destruct();
         }
-        s->intercepted = 1;
+        s->flags.natIntercept = true;
         Ip::Interceptor.StartInterception();
         /* Log information regarding the port modes under interception. */
         debugs(3, DBG_IMPORTANT, "Starting Authentication on port " << s->s);
@@ -3560,15 +3631,14 @@ parse_port_option(AnyP::PortCfg * s, char *token)
             self_destruct();
         }
     } else if (strcmp(token, "tproxy") == 0) {
-        if (s->intercepted || s->accel) {
+        if (s->flags.natIntercept || s->flags.accelSurrogate) {
             debugs(3,DBG_CRITICAL, "FATAL: http(s)_port: TPROXY option requires its own interception port. It cannot be shared with other modes.");
             self_destruct();
         }
-        s->spoof_client_ip = 1;
+        s->flags.tproxyIntercept = true;
         Ip::Interceptor.StartTransparency();
         /* Log information regarding the port modes under transparency. */
-        debugs(3, DBG_IMPORTANT, "Starting IP Spoofing on port " << s->s);
-        debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (IP spoofing enabled)");
+        debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (TPROXY enabled)");
 
         if (!Ip::Interceptor.ProbeForTproxy(s->s)) {
             debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: TPROXY support in the system does not work.");
@@ -3576,59 +3646,60 @@ parse_port_option(AnyP::PortCfg * s, char *token)
         }
 
     } else if (strncmp(token, "defaultsite=", 12) == 0) {
-        if (!s->accel) {
+        if (!s->flags.accelSurrogate) {
             debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: defaultsite option requires Acceleration mode flag.");
             self_destruct();
         }
         safe_free(s->defaultsite);
         s->defaultsite = xstrdup(token + 12);
     } else if (strcmp(token, "vhost") == 0) {
-        if (!s->accel) {
+        if (!s->flags.accelSurrogate) {
             debugs(3, DBG_CRITICAL, "WARNING: http(s)_port: vhost option is deprecated. Use 'accel' mode flag instead.");
         }
-        s->accel = s->vhost = 1;
+        s->flags.accelSurrogate = true;
+        s->vhost = true;
     } else if (strcmp(token, "no-vhost") == 0) {
-        if (!s->accel) {
+        if (!s->flags.accelSurrogate) {
             debugs(3, DBG_IMPORTANT, "ERROR: http(s)_port: no-vhost option requires Acceleration mode flag.");
         }
-        s->vhost = 0;
+        s->vhost = false;
     } else if (strcmp(token, "vport") == 0) {
-        if (!s->accel) {
+        if (!s->flags.accelSurrogate) {
             debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vport option requires Acceleration mode flag.");
             self_destruct();
         }
         s->vport = -1;
     } else if (strncmp(token, "vport=", 6) == 0) {
-        if (!s->accel) {
+        if (!s->flags.accelSurrogate) {
             debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vport option requires Acceleration mode flag.");
             self_destruct();
         }
         s->vport = xatos(token + 6);
     } else if (strncmp(token, "protocol=", 9) == 0) {
-        if (!s->accel) {
+        if (!s->flags.accelSurrogate) {
             debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: protocol option requires Acceleration mode flag.");
             self_destruct();
         }
         s->protocol = xstrdup(token + 9);
     } else if (strcmp(token, "allow-direct") == 0) {
-        if (!s->accel) {
+        if (!s->flags.accelSurrogate) {
             debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: allow-direct option requires Acceleration mode flag.");
             self_destruct();
         }
-        s->allow_direct = 1;
+        s->allow_direct = true;
     } else if (strcmp(token, "act-as-origin") == 0) {
-        if (!s->accel) {
+        if (!s->flags.accelSurrogate) {
             debugs(3, DBG_IMPORTANT, "ERROR: http(s)_port: act-as-origin option requires Acceleration mode flag.");
         } else
-            s->actAsOrigin = 1;
+            s->actAsOrigin = true;
     } else if (strcmp(token, "ignore-cc") == 0) {
 #if !USE_HTTP_VIOLATIONS
-        if (!s->accel) {
-            debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: ignore-cc option requires Scceleration mode flag.");
+        if (!s->flags.accelSurrogate) {
+            debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: ignore-cc option requires Acceleration mode flag.");
             self_destruct();
         }
 #endif
-        s->ignore_cc = 1;
+        s->ignore_cc = true;
     } else if (strncmp(token, "name=", 5) == 0) {
         safe_free(s->name);
         s->name = xstrdup(token + 5);
@@ -3641,11 +3712,11 @@ parse_port_option(AnyP::PortCfg * s, char *token)
     } else if (strcmp(token, "connection-auth=on") == 0) {
         s->connection_auth_disabled = false;
     } else if (strncmp(token, "disable-pmtu-discovery=", 23) == 0) {
-        if (!strcasecmp(token + 23, "off"))
+        if (!strcmp(token + 23, "off"))
             s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
-        else if (!strcasecmp(token + 23, "transparent"))
+        else if (!strcmp(token + 23, "transparent"))
             s->disable_pmtu_discovery = DISABLE_PMTU_TRANSPARENT;
-        else if (!strcasecmp(token + 23, "always"))
+        else if (!strcmp(token + 23, "always"))
             s->disable_pmtu_discovery = DISABLE_PMTU_ALWAYS;
         else
             self_destruct();
@@ -3655,29 +3726,28 @@ parse_port_option(AnyP::PortCfg * s, char *token)
             self_destruct();
         }
     } else if (strcmp(token, "tcpkeepalive") == 0) {
-        s->tcp_keepalive.enabled = 1;
+        s->tcp_keepalive.enabled = true;
     } else if (strncmp(token, "tcpkeepalive=", 13) == 0) {
         char *t = token + 13;
-        s->tcp_keepalive.enabled = 1;
-        s->tcp_keepalive.idle = atoi(t);
+        s->tcp_keepalive.enabled = true;
+        s->tcp_keepalive.idle = xatoui(t,',');
         t = strchr(t, ',');
         if (t) {
             ++t;
-            s->tcp_keepalive.interval = atoi(t);
+            s->tcp_keepalive.interval = xatoui(t,',');
             t = strchr(t, ',');
         }
         if (t) {
             ++t;
-            s->tcp_keepalive.timeout = atoi(t);
-            t = strchr(t, ',');
+            s->tcp_keepalive.timeout = xatoui(t);
         }
 #if USE_SSL
-    } else if (strcasecmp(token, "sslBump") == 0) {
+    } else if (strcmp(token, "sslBump") == 0) {
         debugs(3, DBG_CRITICAL, "WARNING: '" << token << "' is deprecated " <<
                "in http_port. Use 'ssl-bump' instead.");
-        s->sslBump = 1; // accelerated when bumped, otherwise not
+        s->flags.tunnelSslBumping = true;
     } else if (strcmp(token, "ssl-bump") == 0) {
-        s->sslBump = 1; // accelerated when bumped, otherwise not
+        s->flags.tunnelSslBumping = true;
     } else if (strncmp(token, "cert=", 5) == 0) {
         safe_free(s->cert);
         s->cert = xstrdup(token + 5);
@@ -3725,6 +3795,7 @@ parse_port_option(AnyP::PortCfg * s, char *token)
         parseBytesOptionValue(&s->dynamicCertMemCacheSize, B_BYTES_STR, token + 28);
 #endif
     } else {
+        debugs(3, DBG_CRITICAL, "FATAL: Unknown http(s)_port option '" << token << "'.");
         self_destruct();
     }
 }
@@ -3771,14 +3842,14 @@ parsePortCfg(AnyP::PortCfg ** head, const char *optionName)
     }
 
 #if USE_SSL
-    if (strcasecmp(protocol, "https") == 0) {
+    if (strcmp(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) {
+        const bool hijacked = s->flags.isIntercepted();
+        if (s->flags.tunnelSslBumping && !hijacked) {
             debugs(3, DBG_CRITICAL, "FATAL: ssl-bump on https_port requires tproxy/intercept which is missing.");
             self_destruct();
         }
-        if (hijacked && !s->sslBump) {
+        if (hijacked && !s->flags.tunnelSslBumping) {
             debugs(3, DBG_CRITICAL, "FATAL: tproxy/intercept on https_port requires ssl-bump which is missing.");
             self_destruct();
         }
@@ -3808,13 +3879,13 @@ dump_generic_port(StoreEntry * e, const char *n, const AnyP::PortCfg * s)
                       s->s.ToURL(buf,MAX_IPSTRLEN));
 
     // MODES and specific sub-options.
-    if (s->intercepted)
+    if (s->flags.natIntercept)
         storeAppendPrintf(e, " intercept");
 
-    else if (s->spoof_client_ip)
+    else if (s->flags.tproxyIntercept)
         storeAppendPrintf(e, " tproxy");
 
-    else if (s->accel) {
+    else if (s->flags.accelSurrogate) {
         storeAppendPrintf(e, " accel");
 
         if (s->vhost)
@@ -3845,7 +3916,7 @@ dump_generic_port(StoreEntry * e, const char *n, const AnyP::PortCfg * s)
         storeAppendPrintf(e, " name=%s", s->name);
 
 #if USE_HTTP_VIOLATIONS
-    if (!s->accel && s->ignore_cc)
+    if (!s->flags.accelSurrogate && s->ignore_cc)
         storeAppendPrintf(e, " ignore-cc");
 #endif
 
@@ -3877,7 +3948,7 @@ dump_generic_port(StoreEntry * e, const char *n, const AnyP::PortCfg * s)
     }
 
 #if USE_SSL
-    if (s->sslBump)
+    if (s->flags.tunnelSslBumping)
         storeAppendPrintf(e, " ssl-bump");
 
     if (s->cert)
@@ -3983,14 +4054,39 @@ strtokFile(void)
 
 #include "AccessLogEntry.h"
 
+/**
+ * We support several access_log configuration styles:
+ *
+ * #1: Deprecated ancient style without an explicit logging module:
+ * access_log /var/log/access.log
+ *
+ * #2: The "none" logging module (i.e., no logging [of matching transactions]):
+ * access_log none [acl ...]
+ *
+ * #3: Configurable logging module without named options:
+ * Logformat or the first ACL name, whichever comes first, may not contain '='.
+ * If no explicit logformat name is given, the first ACL name, if any,
+ * should not be an existing logformat name or it will be treated as such.
+ * access_log module:place [logformat_name] [acl ...]
+ *
+ * #4: Configurable logging module with name=value options such as logformat=x:
+ * The first ACL name may not contain '='.
+ * access_log module:place [option ...] [acl ...]
+ *
+ */
 static void
-parse_access_log(customlog ** logs)
+parse_access_log(CustomLog ** logs)
 {
-    const char *filename, *logdef_name;
+    CustomLog *cl = (CustomLog *)xcalloc(1, sizeof(*cl));
 
-    customlog *cl = (customlog *)xcalloc(1, sizeof(*cl));
+    // default buffer size and fatal settings
+    cl->bufferSize = 8*MAX_URL;
+    cl->fatal = true;
 
-    if ((filename = strtok(NULL, w_space)) == NULL) {
+    /* determine configuration style */
+
+    const char *filename = strtok(NULL, w_space);
+    if (!filename) {
         self_destruct();
         return;
     }
@@ -4004,12 +4100,72 @@ parse_access_log(customlog ** logs)
         return;
     }
 
-    if ((logdef_name = strtok(NULL, w_space)) == NULL)
-        logdef_name = "squid";
+    cl->filename = xstrdup(filename);
+    cl->type = Log::Format::CLF_UNKNOWN;
+
+    const char *token = ConfigParser::strtokFile();
+    if (!token) { // style #1
+        // no options to deal with
+    } else if (!strchr(token, '=')) { // style #3
+        // if logformat name is not recognized,
+        // put back the token; it must be an ACL name
+        if (!setLogformat(cl, token, false))
+            ConfigParser::strtokFileUndo();
+    } else { // style #4
+        do {
+            if (strncasecmp(token, "on-error=", 9) == 0) {
+                if (strncasecmp(token+9, "die", 3) == 0) {
+                    cl->fatal = true;
+                } else if (strncasecmp(token+9, "drop", 4) == 0) {
+                    cl->fatal = false;
+                } else {
+                    debugs(3, DBG_CRITICAL, "Unknown value for on-error '" <<
+                           token << "' expected 'drop' or 'die'");
+                    self_destruct();
+                }
+            } else if (strncasecmp(token, "buffer-size=", 12) == 0) {
+                parseBytesOptionValue(&cl->bufferSize, B_BYTES_STR, token+12);
+            } else if (strncasecmp(token, "logformat=", 10) == 0) {
+                setLogformat(cl, token+10, true);
+            } else if (!strchr(token, '=')) {
+                // put back the token; it must be an ACL name
+                ConfigParser::strtokFileUndo();
+                break; // done with name=value options, now to ACLs
+            } else {
+                debugs(3, DBG_CRITICAL, "Unknown access_log option " << token);
+                self_destruct();
+            }
+        } while ((token = ConfigParser::strtokFile()) != NULL);
+    }
 
-    debugs(3, 9, "Log definition name '" << logdef_name << "' file '" << filename << "'");
+    // set format if it has not been specified explicitly
+    if (cl->type == Log::Format::CLF_UNKNOWN)
+        setLogformat(cl, "squid", true);
 
-    cl->filename = xstrdup(filename);
+    aclParseAclList(LegacyParser, &cl->aclList);
+
+    while (*logs)
+        logs = &(*logs)->next;
+
+    *logs = cl;
+}
+
+/// sets CustomLog::type and, if needed, CustomLog::lf
+/// returns false iff there is no named log format
+static bool
+setLogformat(CustomLog *cl, const char *logdef_name, const bool dieWhenMissing)
+{
+    assert(cl);
+    assert(logdef_name);
+
+    debugs(3, 9, "possible " << cl->filename << " logformat: " << logdef_name);
+
+    if (cl->type != Log::Format::CLF_UNKNOWN) {
+        debugs(3, DBG_CRITICAL, "Second logformat name in one access_log: " <<
+               logdef_name << " " << cl->type << " ? " << Log::Format::CLF_NONE);
+        self_destruct();
+        return false;
+    }
 
     /* look for the definition pointer corresponding to this name */
     Format::Format *lf = Log::TheConfig.logformats;
@@ -4043,30 +4199,27 @@ parse_access_log(customlog ** logs)
         cl->type = Log::Format::CLF_USERAGENT;
     } else if (strcmp(logdef_name, "referrer") == 0) {
         cl->type = Log::Format::CLF_REFERER;
-    } else {
+    } else if (dieWhenMissing) {
         debugs(3, DBG_CRITICAL, "Log format '" << logdef_name << "' is not defined");
         self_destruct();
-        return;
+        return false;
+    } else {
+        return false;
     }
 
-    aclParseAclList(LegacyParser, &cl->aclList);
-
-    while (*logs)
-        logs = &(*logs)->next;
-
-    *logs = cl;
+    return true;
 }
 
 static int
-check_null_access_log(customlog *customlog_definitions)
+check_null_access_log(CustomLog *customlog_definitions)
 {
     return customlog_definitions == NULL;
 }
 
 static void
-dump_access_log(StoreEntry * entry, const char *name, customlog * logs)
+dump_access_log(StoreEntry * entry, const char *name, CustomLog * logs)
 {
-    customlog *log;
+    CustomLog *log;
 
     for (log = logs; log; log = log->next) {
         storeAppendPrintf(entry, "%s ", name);
@@ -4118,10 +4271,10 @@ dump_access_log(StoreEntry * entry, const char *name, customlog * logs)
 }
 
 static void
-free_access_log(customlog ** definitions)
+free_access_log(CustomLog ** definitions)
 {
     while (*definitions) {
-        customlog *log = *definitions;
+        CustomLog *log = *definitions;
         *definitions = log->next;
 
         log->logFormat = NULL;
@@ -4198,7 +4351,7 @@ dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAf
                               cpuAffinityMap->processes()[i]);
         }
         storeAppendPrintf(entry, " cores=");
-        for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
+        for (size_t i = 0; i < cpuAffinityMap->cores().size(); ++i) {
             storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
                               cpuAffinityMap->cores()[i]);
         }
@@ -4232,27 +4385,8 @@ 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 */
 
-
 #if ICAP_CLIENT
 
 static void
@@ -4291,7 +4425,6 @@ parse_icap_access_type()
 
 #endif
 
-
 #if USE_ECAP
 
 static void
@@ -4683,3 +4816,19 @@ static void free_HeaderWithAclList(HeaderWithAclList **header)
     delete *header;
     *header = NULL;
 }
+
+static void parse_note(Notes *notes)
+{
+    assert(notes);
+    notes->parse(LegacyParser);
+}
+
+static void dump_note(StoreEntry *entry, const char *name, Notes &notes)
+{
+    notes.dump(entry, name);
+}
+
+static void free_note(Notes *notes)
+{
+    notes->clean();
+}