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