]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/HttpHdrSc.cc
Maintenance: Remove FIXME and \todo labels (#647)
[thirdparty/squid.git] / src / HttpHdrSc.cc
index 3ee98faf55fce1cf7a474249015869afd35572c6..a30498230dbbad048c23114af69534d69772f181 100644 (file)
-
 /*
- * $Id$
- *
- * DEBUG: section 90    HTTP Cache Control Header
- * AUTHOR: Alex Rousskov
- *         Robert Collins (Surrogate-Control is derived from
- *                        Cache-Control).
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
  *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
+/* DEBUG: section 90    HTTP Cache Control Header */
+
 #include "squid.h"
-#include "Store.h"
+#include "base/LookupTable.h"
+//#include "HttpHdrSc.h" // pulled in by HttpHdrScTarget.h
+#include "HttpHdrScTarget.h"
 #include "HttpHeader.h"
-#include "HttpHdrSc.h"
+#include "HttpHeaderFieldStat.h"
+#include "HttpHeaderStat.h"
+#include "HttpHeaderTools.h"
+#include "Store.h"
+#include "StrList.h"
+#include "util.h"
 
-/* this table is used for parsing surrogate control header */
-static const HttpHeaderFieldAttrs ScAttrs[SC_ENUM_END] = {
-    {"no-store", (http_hdr_type)SC_NO_STORE},
+#include <map>
+#include <vector>
 
-    {"no-store-remote", (http_hdr_type)SC_NO_STORE_REMOTE},
-    {"max-age", (http_hdr_type)SC_MAX_AGE},
-    {"content", (http_hdr_type)SC_CONTENT},
-    {"Other,", (http_hdr_type)SC_OTHER}        /* ',' will protect from matches */
+/* this table is used for parsing surrogate control header */
+/* order must match that of enum http_hdr_sc_type. The constraint is verified at initialization time */
+// TODO: implement constraint
+static const LookupTable<http_hdr_sc_type>::Record ScAttrs[] {
+    {"no-store", SC_NO_STORE},
+    {"no-store-remote", SC_NO_STORE_REMOTE},
+    {"max-age", SC_MAX_AGE},
+    {"content", SC_CONTENT},
+    {"Other,", SC_OTHER}, /* ',' will protect from matches */
+    {nullptr, SC_ENUM_END} /* SC_ENUM_END taken as invalid value */
 };
+LookupTable<http_hdr_sc_type> scLookupTable(SC_ENUM_END, ScAttrs);
+std::vector<HttpHeaderFieldStat> scHeaderStats(SC_ENUM_END);
 
-HttpHeaderFieldInfo *ScFieldsInfo = NULL;
-
+// used when iterating over flags
 http_hdr_sc_type &operator++ (http_hdr_sc_type &aHeader)
 {
-    int tmp = (int)aHeader;
-    aHeader = (http_hdr_sc_type)(++tmp);
+    int tmp = static_cast<int>(aHeader);
+    aHeader = static_cast<http_hdr_sc_type>(++tmp);
     return aHeader;
 }
 
-int operator - (http_hdr_sc_type const &anSc, http_hdr_sc_type const &anSc2)
-{
-    return (int)anSc - (int)anSc2;
-}
-
-
-/* local prototypes */
-static int httpHdrScParseInit(HttpHdrSc * sc, const String * str);
-
-/* module initialization */
-
 void
 httpHdrScInitModule(void)
 {
-    ScFieldsInfo = httpHeaderBuildFieldsInfo(ScAttrs, SC_ENUM_END);
-}
-
-void
-httpHdrScCleanModule(void)
-{
-    httpHeaderDestroyFieldsInfo(ScFieldsInfo, SC_ENUM_END);
-    ScFieldsInfo = NULL;
+    // check invariant on ScAttrs
+    for (int i = 0; ScAttrs[i].name != nullptr; ++i)
+        assert(i == ScAttrs[i].id);
 }
 
 /* implementation */
 
-HttpHdrSc *
-httpHdrScCreate(void)
-{
-    return new HttpHdrSc();
-}
-
 /* creates an sc object from a 0-terminating string */
 HttpHdrSc *
-httpHdrScParseCreate(const String * str)
+httpHdrScParseCreate(const String & str)
 {
-    HttpHdrSc *sc = httpHdrScCreate();
+    HttpHdrSc *sc = new HttpHdrSc();
 
-    if (!httpHdrScParseInit(sc, str)) {
-        httpHdrScDestroy(sc);
+    if (!sc->parse(&str)) {
+        delete sc;
         sc = NULL;
     }
 
@@ -106,19 +70,20 @@ httpHdrScParseCreate(const String * str)
 }
 
 /* parses a 0-terminating string and inits sc */
-static int
-httpHdrScParseInit(HttpHdrSc * sc, const String * str)
+bool
+HttpHdrSc::parse(const String * str)
 {
+    HttpHdrSc * sc=this;
     const char *item;
-    const char *p;             /* '=' parameter */
+    const char *p;      /* '=' parameter */
     const char *pos = NULL;
     const char *target = NULL; /* ;foo */
     const char *temp = NULL; /* temp buffer */
-    int type;
+    http_hdr_sc_type type;
     int ilen, vlen;
     int initiallen;
     HttpHdrScTarget *sct;
-    assert(sc && str);
+    assert(str);
 
     /* iterate through comma separated list */
 
@@ -130,24 +95,25 @@ httpHdrScParseInit(HttpHdrSc * sc, const String * str)
         if ((p = strchr(item, '=')) && (p - item < ilen)) {
             vlen = ilen - (p + 1 - item);
             ilen = p - item;
-            p++;
+            ++p;
         }
 
-        /* decrease ilen to still match the token for ';' qualified non '=' statments */
-        else if ((p = strchr(item, ';')) && (p - item < ilen))
-            ilen = p++ - item;
+        /* decrease ilen to still match the token for ';' qualified non '=' statements */
+        else if ((p = strchr(item, ';')) && (p - item < ilen)) {
+            ilen = p - item;
+            ++p;
+        }
 
         /* find type */
-        type = httpHeaderIdByName(item, ilen,
-                                  ScFieldsInfo, SC_ENUM_END);
+        type = scLookupTable.lookup(SBuf(item,ilen));
 
-        if (type < 0) {
+        if (type == SC_ENUM_END) {
             debugs(90, 2, "hdr sc: unknown control-directive: near '" << item << "' in '" << str << "'");
             type = SC_OTHER;
         }
 
         /* Is this a targeted directive? */
-        /* TODO sometime: implement a strnrchr that looks at a substring */
+        /* TODO: remove the temporary usage and use memrchr and the information we have instead */
         temp = xstrndup (item, initiallen + 1);
 
         if (!((target = strrchr (temp, ';')) && !strchr (target, '"') && *(target + 1) != '\0'))
@@ -155,55 +121,69 @@ httpHdrScParseInit(HttpHdrSc * sc, const String * str)
         else
             ++target;
 
-        sct = httpHdrScFindTarget (sc, target);
+        sct = sc->findTarget(target);
 
         if (!sct) {
-            sct = httpHdrScTargetCreate (target);
-            dlinkAdd(sct, &sct->node, &sc->targets);
+            sct = new HttpHdrScTarget(target);
+            addTarget(sct);
         }
 
         safe_free (temp);
 
-        if (EBIT_TEST(sct->mask, type)) {
+        if (sct->isSet(type)) {
             if (type != SC_OTHER)
                 debugs(90, 2, "hdr sc: ignoring duplicate control-directive: near '" << item << "' in '" << str << "'");
 
-            ScFieldsInfo[type].stat.repCount++;
+            ++ scHeaderStats[type].repCount;
 
             continue;
         }
 
-        /* update mask */
-        EBIT_SET(sct->mask, type);
-
-        /* post-processing special cases */
+        /* process directives */
         switch (type) {
+        case SC_NO_STORE:
+            sct->noStore(true);
+            break;
 
-        case SC_MAX_AGE:
+        case SC_NO_STORE_REMOTE:
+            sct->noStoreRemote(true);
+            break;
 
-            if (!p || !httpHeaderParseInt(p, &sct->max_age)) {
+        case SC_MAX_AGE: {
+            int ma;
+            if (p && httpHeaderParseInt(p, &ma)) {
+                sct->maxAge(ma);
+
+                if ((p = strchr (p, '+'))) {
+                    int ms;
+                    ++p; //skip the + char
+                    if (httpHeaderParseInt(p, &ms)) {
+                        sct->maxStale(ms);
+                    } else {
+                        debugs(90, 2, "sc: invalid max-stale specs near '" << item << "'");
+                        sct->clearMaxStale();
+                        /* leave the max-age alone */
+                    }
+                }
+            } else {
                 debugs(90, 2, "sc: invalid max-age specs near '" << item << "'");
-                sct->max_age = -1;
-                EBIT_CLR(sct->mask, type);
+                sct->clearMaxAge();
             }
 
-            if ((p = strchr (p, '+')))
-                if (!httpHeaderParseInt(++p, &sct->max_stale)) {
-                    debugs(90, 2, "sc: invalid max-stale specs near '" << item << "'");
-                    sct->max_stale = 0;
-                    /* leave the max-age alone */
-                }
-
             break;
+        }
 
         case SC_CONTENT:
 
-            if (!p || !httpHeaderParseQuotedString(p, vlen, &sct->content)) {
+            if ( p && httpHeaderParseQuotedString(p, vlen, &sct->content_)) {
+                sct->setMask(SC_CONTENT,true); // ugly but saves a copy
+            } else {
                 debugs(90, 2, "sc: invalid content= quoted string near '" << item << "'");
-                sct->content.clean();
-                EBIT_CLR(sct->mask, type);
+                sct->clearContent();
             }
+            break;
 
+        case SC_OTHER:
         default:
             break;
         }
@@ -212,139 +192,105 @@ httpHdrScParseInit(HttpHdrSc * sc, const String * str)
     return sc->targets.head != NULL;
 }
 
-void
-httpHdrScDestroy(HttpHdrSc * sc)
+HttpHdrSc::~HttpHdrSc()
 {
-    assert(sc);
-
-    if (sc->targets.head) {
-        dlink_node *sct = sc->targets.head;
+    if (targets.head) {
+        dlink_node *sct = targets.head;
 
         while (sct) {
-            HttpHdrScTarget *t = (HttpHdrScTarget *)sct->data;
+            HttpHdrScTarget *t = static_cast<HttpHdrScTarget *>(sct->data);
             sct = sct->next;
-            dlinkDelete (&t->node, &sc->targets);
-            httpHdrScTargetDestroy (t);
+            dlinkDelete (&t->node, &targets);
+            delete t;
         }
     }
-
-    delete sc;
 }
 
-HttpHdrSc *
-httpHdrScDup(const HttpHdrSc * sc)
+HttpHdrSc::HttpHdrSc(const HttpHdrSc &sc)
 {
-    HttpHdrSc *dup;
-    dlink_node *node;
-    assert(sc);
-    node = sc->targets.head;
-    dup = httpHdrScCreate();
+    dlink_node *node = sc.targets.head;
 
     while (node) {
-        HttpHdrScTarget *dupsct;
-        dupsct = httpHdrScTargetDup ((HttpHdrScTarget *)node->data);
-        dlinkAddTail (dupsct, &dupsct->node, &dup->targets);
+        HttpHdrScTarget *dupsct = new HttpHdrScTarget(*static_cast<HttpHdrScTarget *>(node->data));
+        addTargetAtTail(dupsct);
         node = node->next;
     }
-
-    return dup;
 }
 
 void
-httpHdrScTargetPackInto(const HttpHdrScTarget * sc, Packer * p)
+HttpHdrScTarget::packInto(Packable * p) const
 {
     http_hdr_sc_type flag;
     int pcount = 0;
-    assert(sc && p);
+    assert (p);
 
     for (flag = SC_NO_STORE; flag < SC_ENUM_END; ++flag) {
-        if (EBIT_TEST(sc->mask, flag) && flag != SC_OTHER) {
+        if (isSet(flag) && flag != SC_OTHER) {
 
             /* print option name */
-            packerPrintf(p, (pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH),
-                         SQUIDSTRINGPRINT(ScFieldsInfo[flag].name));
+            p->appendf((pcount ? ", %s" : "%s"), ScAttrs[flag].name);
 
             /* handle options with values */
 
             if (flag == SC_MAX_AGE)
-                packerPrintf(p, "=%d", (int) sc->max_age);
+                p->appendf("=%d", (int) max_age);
 
             if (flag == SC_CONTENT)
-                packerPrintf(p, "=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(sc->content));
+                p->appendf("=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(content_));
 
-            pcount++;
+            ++pcount;
         }
     }
 
-    if (sc->target.size())
-        packerPrintf (p, ";" SQUIDSTRINGPH, SQUIDSTRINGPRINT(sc->target));
+    if (hasTarget())
+        p->appendf(";" SQUIDSTRINGPH, SQUIDSTRINGPRINT(target));
 }
 
 void
-httpHdrScPackInto(const HttpHdrSc * sc, Packer * p)
+HttpHdrSc::packInto(Packable * p) const
 {
     dlink_node *node;
-    assert(sc && p);
-    node = sc->targets.head;
+    assert(p);
+    node = targets.head;
 
     while (node) {
-        httpHdrScTargetPackInto((HttpHdrScTarget *)node->data, p);
+        static_cast<HttpHdrScTarget *>(node->data)->packInto(p);
         node = node->next;
     }
 }
 
-void
-httpHdrScJoinWith(HttpHdrSc * sc, const HttpHdrSc * new_sc)
-{
-    assert(sc && new_sc);
-#if 0
-    /* RC TODO: check that both have the same target */
-
-    if (sc->max_age < 0)
-        sc->max_age = new_sc->max_age;
-
-    /* RC TODO: copy unique missing stringlist entries */
-    cc->mask |= new_cc->mask;
-
-#endif
-}
-
 /* negative max_age will clean old max_Age setting */
 void
-httpHdrScSetMaxAge(HttpHdrSc * sc, char const *target, int max_age)
+HttpHdrSc::setMaxAge(char const *target, int max_age)
 {
-    HttpHdrScTarget *sct;
-    assert(sc);
-    sct = httpHdrScFindTarget (sc, target);
+    HttpHdrScTarget *sct = findTarget(target);
 
     if (!sct) {
-        sct = httpHdrScTargetCreate (target);
-        dlinkAddTail (sct, &sct->node, &sc->targets);
+        sct = new HttpHdrScTarget(target);
+        dlinkAddTail (sct, &sct->node, &targets);
     }
 
-    httpHdrScTargetSetMaxAge(sct, max_age);
+    sct->maxAge(max_age);
 }
 
 void
-httpHdrScUpdateStats(const HttpHdrSc * sc, StatHist * hist)
+HttpHdrSc::updateStats(StatHist * hist) const
 {
-    dlink_node *sct;
-    assert(sc);
-    sct = sc->targets.head;
+    dlink_node *sct = targets.head;
 
     while (sct) {
-        httpHdrScTargetUpdateStats((HttpHdrScTarget *)sct->data, hist);
+        static_cast<HttpHdrScTarget *>(sct->data)->updateStats(hist);
         sct = sct->next;
     }
 }
 
 void
-httpHdrScTargetStatDumper(StoreEntry * sentry, int idx, double val, double size, int count)
+httpHdrScTargetStatDumper(StoreEntry * sentry, int, double val, double, int count)
 {
     extern const HttpHeaderStat *dump_stat;     /* argh! */
     const int id = (int) val;
-    const int valid_id = id >= 0 && id < SC_ENUM_END;
-    const char *name = valid_id ? ScFieldsInfo[id].name.termedBuf() : "INVALID";
+    const bool valid_id = id >= 0 && id < SC_ENUM_END;
+    const char *name = valid_id ? ScAttrs[id].name : "INVALID";
 
     if (count || valid_id)
         storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
@@ -352,12 +298,12 @@ httpHdrScTargetStatDumper(StoreEntry * sentry, int idx, double val, double size,
 }
 
 void
-httpHdrScStatDumper(StoreEntry * sentry, int idx, double val, double size, int count)
+httpHdrScStatDumper(StoreEntry * sentry, int, double val, double, int count)
 {
-    extern const HttpHeaderStat *dump_stat;    /* argh! */
+    extern const HttpHeaderStat *dump_stat; /* argh! */
     const int id = (int) val;
-    const int valid_id = id >= 0 && id < SC_ENUM_END;
-    const char *name = valid_id ? ScFieldsInfo[id].name.termedBuf() : "INVALID";
+    const bool valid_id = id >= 0 && id < SC_ENUM_END;
+    const char *name = valid_id ? ScAttrs[id].name : "INVALID";
 
     if (count || valid_id)
         storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
@@ -365,18 +311,17 @@ httpHdrScStatDumper(StoreEntry * sentry, int idx, double val, double size, int c
 }
 
 HttpHdrScTarget *
-httpHdrScFindTarget (HttpHdrSc *sc, const char *target)
+HttpHdrSc::findTarget(const char *target)
 {
     dlink_node *node;
-    assert (sc);
-    node = sc->targets.head;
+    node = targets.head;
 
     while (node) {
         HttpHdrScTarget *sct = (HttpHdrScTarget *)node->data;
 
-        if (target && sct->target.defined() && !strcmp (target, sct->target.termedBuf()))
+        if (target && sct->target.size() > 0 && !strcmp(target, sct->target.termedBuf()))
             return sct;
-        else if (!target && sct->target.undefined())
+        else if (!target && sct->target.size() == 0)
             return sct;
 
         node = node->next;
@@ -386,22 +331,33 @@ httpHdrScFindTarget (HttpHdrSc *sc, const char *target)
 }
 
 HttpHdrScTarget *
-httpHdrScGetMergedTarget (HttpHdrSc *sc, const char *ourtarget)
+HttpHdrSc::getMergedTarget(const char *ourtarget)
 {
-    HttpHdrScTarget *sctus = httpHdrScFindTarget (sc, ourtarget);
-    HttpHdrScTarget *sctgeneric = httpHdrScFindTarget (sc, NULL);
+    HttpHdrScTarget *sctus = findTarget(ourtarget);
+    HttpHdrScTarget *sctgeneric = findTarget(NULL);
 
     if (sctgeneric || sctus) {
-        HttpHdrScTarget *sctusable = httpHdrScTargetCreate (NULL);
+        HttpHdrScTarget *sctusable = new HttpHdrScTarget(NULL);
 
         if (sctgeneric)
-            httpHdrScTargetMergeWith (sctusable, sctgeneric);
+            sctusable->mergeWith(sctgeneric);
 
         if (sctus)
-            httpHdrScTargetMergeWith (sctusable, sctus);
+            sctusable->mergeWith(sctus);
 
         return sctusable;
     }
 
     return NULL;
 }
+
+void
+HttpHdrSc::addTarget(HttpHdrScTarget *t) {
+    dlinkAdd(t, &t->node, &targets);
+}
+
+void
+HttpHdrSc::addTargetAtTail(HttpHdrScTarget *t) {
+    dlinkAddTail (t, &t->node, &targets);
+}
+