]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpHdrSc.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / HttpHdrSc.cc
CommitLineData
43ae1d95 1/*
77b1029d 2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
43ae1d95 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
43ae1d95 7 */
8
bbc27441
AJ
9/* DEBUG: section 90 HTTP Cache Control Header */
10
582c2af2 11#include "squid.h"
4277583a 12#include "base/LookupTable.h"
1da82544 13//#include "HttpHdrSc.h" // pulled in by HttpHdrScTarget.h
96d2a063 14#include "HttpHdrScTarget.h"
43ae1d95 15#include "HttpHeader.h"
db2de30a 16#include "HttpHeaderFieldStat.h"
e1656dc4 17#include "HttpHeaderStat.h"
a5bac1d2 18#include "HttpHeaderTools.h"
582c2af2 19#include "Store.h"
28204b3b 20#include "StrList.h"
ed6e9fb9 21#include "util.h"
43ae1d95 22
45a58345 23#include <map>
4277583a 24#include <vector>
45a58345 25
43ae1d95 26/* this table is used for parsing surrogate control header */
45a58345
FC
27/* order must match that of enum http_hdr_sc_type. The constraint is verified at initialization time */
28//todo: implement constraint
4277583a
FC
29static const LookupTable<http_hdr_sc_type>::Record ScAttrs[] {
30 {"no-store", SC_NO_STORE},
31 {"no-store-remote", SC_NO_STORE_REMOTE},
32 {"max-age", SC_MAX_AGE},
33 {"content", SC_CONTENT},
34 {"Other,", SC_OTHER}, /* ',' will protect from matches */
35 {nullptr, SC_ENUM_END} /* SC_ENUM_END taken as invalid value */
26ac0430 36};
4277583a
FC
37LookupTable<http_hdr_sc_type> scLookupTable(SC_ENUM_END, ScAttrs);
38std::vector<HttpHeaderFieldStat> scHeaderStats(SC_ENUM_END);
43ae1d95 39
a9cfbb83 40// used when iterating over flags
43ae1d95 41http_hdr_sc_type &operator++ (http_hdr_sc_type &aHeader)
42{
a9cfbb83
FC
43 int tmp = static_cast<int>(aHeader);
44 aHeader = static_cast<http_hdr_sc_type>(++tmp);
43ae1d95 45 return aHeader;
46}
47
43ae1d95 48void
49httpHdrScInitModule(void)
50{
4277583a
FC
51 // check invariant on ScAttrs
52 for (int i = 0; ScAttrs[i].name != nullptr; ++i)
53 assert(i == ScAttrs[i].id);
43ae1d95 54}
55
43ae1d95 56/* implementation */
57
43ae1d95 58/* creates an sc object from a 0-terminating string */
59HttpHdrSc *
45a58345 60httpHdrScParseCreate(const String & str)
43ae1d95 61{
45a58345 62 HttpHdrSc *sc = new HttpHdrSc();
43ae1d95 63
45a58345
FC
64 if (!sc->parse(&str)) {
65 delete sc;
43ae1d95 66 sc = NULL;
67 }
68
69 return sc;
70}
71
72/* parses a 0-terminating string and inits sc */
45a58345
FC
73bool
74HttpHdrSc::parse(const String * str)
43ae1d95 75{
45a58345 76 HttpHdrSc * sc=this;
43ae1d95 77 const char *item;
f53969cc 78 const char *p; /* '=' parameter */
43ae1d95 79 const char *pos = NULL;
80 const char *target = NULL; /* ;foo */
81 const char *temp = NULL; /* temp buffer */
4277583a 82 http_hdr_sc_type type;
34460e19 83 int ilen, vlen;
43ae1d95 84 int initiallen;
85 HttpHdrScTarget *sct;
45a58345 86 assert(str);
43ae1d95 87
88 /* iterate through comma separated list */
89
90 while (strListGetItem(str, ',', &item, &ilen, &pos)) {
91 initiallen = ilen;
34460e19 92 vlen = 0;
43ae1d95 93 /* decrease ilen to still match the token for '=' statements */
94
34460e19 95 if ((p = strchr(item, '=')) && (p - item < ilen)) {
7c0f9f7e 96 vlen = ilen - (p + 1 - item);
34460e19 97 ilen = p - item;
95dc7ff4 98 ++p;
34460e19 99 }
43ae1d95 100
101 /* decrease ilen to still match the token for ';' qualified non '=' statments */
a38ec4b1
FC
102 else if ((p = strchr(item, ';')) && (p - item < ilen)) {
103 ilen = p - item;
104 ++p;
105 }
43ae1d95 106
107 /* find type */
4277583a 108 type = scLookupTable.lookup(SBuf(item,ilen));
43ae1d95 109
4277583a 110 if (type == SC_ENUM_END) {
550cc09e 111 debugs(90, 2, "hdr sc: unknown control-directive: near '" << item << "' in '" << str << "'");
43ae1d95 112 type = SC_OTHER;
113 }
114
115 /* Is this a targeted directive? */
45a58345 116 /* TODO: remove the temporary useage and use memrchr and the information we have instead */
43ae1d95 117 temp = xstrndup (item, initiallen + 1);
118
119 if (!((target = strrchr (temp, ';')) && !strchr (target, '"') && *(target + 1) != '\0'))
120 target = NULL;
121 else
122 ++target;
123
45a58345 124 sct = sc->findTarget(target);
43ae1d95 125
126 if (!sct) {
45a58345
FC
127 sct = new HttpHdrScTarget(target);
128 addTarget(sct);
43ae1d95 129 }
130
131 safe_free (temp);
132
4277583a 133 if (sct->isSet(type)) {
43ae1d95 134 if (type != SC_OTHER)
550cc09e 135 debugs(90, 2, "hdr sc: ignoring duplicate control-directive: near '" << item << "' in '" << str << "'");
43ae1d95 136
4277583a 137 ++ scHeaderStats[type].repCount;
43ae1d95 138
139 continue;
140 }
141
45a58345 142 /* process directives */
43ae1d95 143 switch (type) {
45a58345
FC
144 case SC_NO_STORE:
145 sct->noStore(true);
146 break;
43ae1d95 147
45a58345
FC
148 case SC_NO_STORE_REMOTE:
149 sct->noStoreRemote(true);
43ae1d95 150 break;
151
633b9845
A
152 case SC_MAX_AGE: {
153 int ma;
154 if (p && httpHeaderParseInt(p, &ma)) {
155 sct->maxAge(ma);
76d0bd38
AJ
156
157 if ((p = strchr (p, '+'))) {
158 int ms;
159 ++p; //skip the + char
160 if (httpHeaderParseInt(p, &ms)) {
161 sct->maxStale(ms);
162 } else {
163 debugs(90, 2, "sc: invalid max-stale specs near '" << item << "'");
164 sct->clearMaxStale();
165 /* leave the max-age alone */
166 }
167 }
633b9845
A
168 } else {
169 debugs(90, 2, "sc: invalid max-age specs near '" << item << "'");
170 sct->clearMaxAge();
171 }
172
633b9845
A
173 break;
174 }
45a58345 175
43ae1d95 176 case SC_CONTENT:
177
633b9845
A
178 if ( p && httpHeaderParseQuotedString(p, vlen, &sct->content_)) {
179 sct->setMask(SC_CONTENT,true); // ugly but saves a copy
180 } else {
bf8fe701 181 debugs(90, 2, "sc: invalid content= quoted string near '" << item << "'");
45a58345 182 sct->clearContent();
43ae1d95 183 }
633b9845 184 break;
43ae1d95 185
45a58345 186 case SC_OTHER:
43ae1d95 187 default:
188 break;
189 }
190 }
191
192 return sc->targets.head != NULL;
193}
194
45a58345 195HttpHdrSc::~HttpHdrSc()
43ae1d95 196{
45a58345
FC
197 if (targets.head) {
198 dlink_node *sct = targets.head;
43ae1d95 199
200 while (sct) {
45a58345 201 HttpHdrScTarget *t = static_cast<HttpHdrScTarget *>(sct->data);
43ae1d95 202 sct = sct->next;
45a58345
FC
203 dlinkDelete (&t->node, &targets);
204 delete t;
43ae1d95 205 }
206 }
43ae1d95 207}
208
45a58345 209HttpHdrSc::HttpHdrSc(const HttpHdrSc &sc)
43ae1d95 210{
45a58345 211 dlink_node *node = sc.targets.head;
43ae1d95 212
213 while (node) {
45a58345
FC
214 HttpHdrScTarget *dupsct = new HttpHdrScTarget(*static_cast<HttpHdrScTarget *>(node->data));
215 addTargetAtTail(dupsct);
43ae1d95 216 node = node->next;
217 }
43ae1d95 218}
219
220void
17802cf1 221HttpHdrScTarget::packInto(Packable * p) const
43ae1d95 222{
223 http_hdr_sc_type flag;
224 int pcount = 0;
45a58345 225 assert (p);
43ae1d95 226
227 for (flag = SC_NO_STORE; flag < SC_ENUM_END; ++flag) {
45a58345 228 if (isSet(flag) && flag != SC_OTHER) {
43ae1d95 229
230 /* print option name */
4277583a 231 p->appendf((pcount ? ", %s" : "%s"), ScAttrs[flag].name);
43ae1d95 232
233 /* handle options with values */
234
235 if (flag == SC_MAX_AGE)
4391cd15 236 p->appendf("=%d", (int) max_age);
43ae1d95 237
238 if (flag == SC_CONTENT)
4391cd15 239 p->appendf("=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(content_));
43ae1d95 240
95dc7ff4 241 ++pcount;
43ae1d95 242 }
243 }
244
45a58345 245 if (hasTarget())
4391cd15 246 p->appendf(";" SQUIDSTRINGPH, SQUIDSTRINGPRINT(target));
43ae1d95 247}
248
249void
17802cf1 250HttpHdrSc::packInto(Packable * p) const
43ae1d95 251{
252 dlink_node *node;
45a58345
FC
253 assert(p);
254 node = targets.head;
43ae1d95 255
256 while (node) {
633b9845 257 static_cast<HttpHdrScTarget *>(node->data)->packInto(p);
43ae1d95 258 node = node->next;
259 }
260}
261
43ae1d95 262/* negative max_age will clean old max_Age setting */
263void
45a58345 264HttpHdrSc::setMaxAge(char const *target, int max_age)
43ae1d95 265{
45a58345 266 HttpHdrScTarget *sct = findTarget(target);
43ae1d95 267
268 if (!sct) {
45a58345
FC
269 sct = new HttpHdrScTarget(target);
270 dlinkAddTail (sct, &sct->node, &targets);
43ae1d95 271 }
272
45a58345 273 sct->maxAge(max_age);
43ae1d95 274}
275
276void
45a58345 277HttpHdrSc::updateStats(StatHist * hist) const
43ae1d95 278{
45a58345 279 dlink_node *sct = targets.head;
43ae1d95 280
281 while (sct) {
633b9845 282 static_cast<HttpHdrScTarget *>(sct->data)->updateStats(hist);
43ae1d95 283 sct = sct->next;
284 }
285}
286
287void
ced8def3 288httpHdrScTargetStatDumper(StoreEntry * sentry, int, double val, double, int count)
43ae1d95 289{
290 extern const HttpHeaderStat *dump_stat; /* argh! */
291 const int id = (int) val;
4277583a
FC
292 const bool valid_id = id >= 0 && id < SC_ENUM_END;
293 const char *name = valid_id ? ScAttrs[id].name : "INVALID";
43ae1d95 294
295 if (count || valid_id)
296 storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
297 id, name, count, xdiv(count, dump_stat->scParsedCount));
298}
299
300void
ced8def3 301httpHdrScStatDumper(StoreEntry * sentry, int, double val, double, int count)
43ae1d95 302{
f53969cc 303 extern const HttpHeaderStat *dump_stat; /* argh! */
43ae1d95 304 const int id = (int) val;
4277583a
FC
305 const bool valid_id = id >= 0 && id < SC_ENUM_END;
306 const char *name = valid_id ? ScAttrs[id].name : "INVALID";
43ae1d95 307
308 if (count || valid_id)
309 storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
310 id, name, count, xdiv(count, dump_stat->scParsedCount));
311}
312
313HttpHdrScTarget *
45a58345 314HttpHdrSc::findTarget(const char *target)
43ae1d95 315{
316 dlink_node *node;
45a58345 317 node = targets.head;
43ae1d95 318
319 while (node) {
320 HttpHdrScTarget *sct = (HttpHdrScTarget *)node->data;
321
a1377698 322 if (target && sct->target.size() > 0 && !strcmp(target, sct->target.termedBuf()))
43ae1d95 323 return sct;
a1377698 324 else if (!target && sct->target.size() == 0)
43ae1d95 325 return sct;
326
327 node = node->next;
328 }
329
330 return NULL;
331}
332
333HttpHdrScTarget *
45a58345 334HttpHdrSc::getMergedTarget(const char *ourtarget)
43ae1d95 335{
45a58345
FC
336 HttpHdrScTarget *sctus = findTarget(ourtarget);
337 HttpHdrScTarget *sctgeneric = findTarget(NULL);
43ae1d95 338
339 if (sctgeneric || sctus) {
45a58345 340 HttpHdrScTarget *sctusable = new HttpHdrScTarget(NULL);
43ae1d95 341
342 if (sctgeneric)
45a58345 343 sctusable->mergeWith(sctgeneric);
43ae1d95 344
345 if (sctus)
45a58345 346 sctusable->mergeWith(sctus);
43ae1d95 347
348 return sctusable;
349 }
350
351 return NULL;
352}
f53969cc 353
b56ab9e7
FC
354void
355HttpHdrSc::addTarget(HttpHdrScTarget *t) {
356 dlinkAdd(t, &t->node, &targets);
357}
358
359void
360HttpHdrSc::addTargetAtTail(HttpHdrScTarget *t) {
361 dlinkAddTail (t, &t->node, &targets);
362}
96d2a063 363