]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpHdrSc.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / HttpHdrSc.cc
CommitLineData
43ae1d95 1
2/*
262a0e14 3 * $Id$
43ae1d95 4 *
5 * DEBUG: section 90 HTTP Cache Control Header
6 * AUTHOR: Alex Rousskov
7 * Robert Collins (Surrogate-Control is derived from
8 * Cache-Control).
45a58345 9 * Francesco Chemolli (c++ refactoring)
43ae1d95 10 *
11 * SQUID Web Proxy Cache http://www.squid-cache.org/
12 * ----------------------------------------------------------
13 *
14 * Squid is the result of efforts by numerous individuals from
15 * the Internet community; see the CONTRIBUTORS file for full
16 * details. Many organizations have provided support for Squid's
17 * development; see the SPONSORS file for full details. Squid is
18 * Copyrighted (C) 2001 by the Regents of the University of
19 * California; see the COPYRIGHT file for full details. Squid
20 * incorporates software developed and/or copyrighted by other
21 * sources; see the CREDITS file for full details.
22 *
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation; either version 2 of the License, or
26 * (at your option) any later version.
26ac0430 27 *
43ae1d95 28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
26ac0430 32 *
43ae1d95 33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
36 *
37 */
38
f7f3304a 39#include "squid-old.h"
43ae1d95 40#include "Store.h"
41#include "HttpHeader.h"
e1656dc4 42#include "HttpHeaderStat.h"
25b6a907 43#include "HttpHdrSc.h"
43ae1d95 44
45a58345
FC
45#if HAVE_MAP
46#include <map>
47#endif
48
49/* a row in the table used for parsing surrogate-control header and statistics */
50typedef struct {
633b9845
A
51 const char *name;
52 http_hdr_sc_type id;
53 HttpHeaderFieldStat stat;
45a58345
FC
54} HttpHeaderScFields;
55
43ae1d95 56/* this table is used for parsing surrogate control header */
45a58345
FC
57/* order must match that of enum http_hdr_sc_type. The constraint is verified at initialization time */
58//todo: implement constraint
26ac0430
AJ
59static const HttpHeaderFieldAttrs ScAttrs[SC_ENUM_END] = {
60 {"no-store", (http_hdr_type)SC_NO_STORE},
26ac0430
AJ
61 {"no-store-remote", (http_hdr_type)SC_NO_STORE_REMOTE},
62 {"max-age", (http_hdr_type)SC_MAX_AGE},
63 {"content", (http_hdr_type)SC_CONTENT},
64 {"Other,", (http_hdr_type)SC_OTHER} /* ',' will protect from matches */
65};
43ae1d95 66
67HttpHeaderFieldInfo *ScFieldsInfo = NULL;
68
69http_hdr_sc_type &operator++ (http_hdr_sc_type &aHeader)
70{
892e7ba7 71 int tmp = (int)aHeader;
72 aHeader = (http_hdr_sc_type)(++tmp);
43ae1d95 73 return aHeader;
74}
75
76int operator - (http_hdr_sc_type const &anSc, http_hdr_sc_type const &anSc2)
77{
78 return (int)anSc - (int)anSc2;
79}
80
81
43ae1d95 82/* module initialization */
83
84void
85httpHdrScInitModule(void)
86{
87 ScFieldsInfo = httpHeaderBuildFieldsInfo(ScAttrs, SC_ENUM_END);
88}
89
90void
91httpHdrScCleanModule(void)
92{
93 httpHeaderDestroyFieldsInfo(ScFieldsInfo, SC_ENUM_END);
94 ScFieldsInfo = NULL;
95}
96
97/* implementation */
98
43ae1d95 99/* creates an sc object from a 0-terminating string */
100HttpHdrSc *
45a58345 101httpHdrScParseCreate(const String & str)
43ae1d95 102{
45a58345 103 HttpHdrSc *sc = new HttpHdrSc();
43ae1d95 104
45a58345
FC
105 if (!sc->parse(&str)) {
106 delete sc;
43ae1d95 107 sc = NULL;
108 }
109
110 return sc;
111}
112
113/* parses a 0-terminating string and inits sc */
45a58345
FC
114bool
115HttpHdrSc::parse(const String * str)
43ae1d95 116{
45a58345 117 HttpHdrSc * sc=this;
43ae1d95 118 const char *item;
119 const char *p; /* '=' parameter */
120 const char *pos = NULL;
121 const char *target = NULL; /* ;foo */
122 const char *temp = NULL; /* temp buffer */
123 int type;
34460e19 124 int ilen, vlen;
43ae1d95 125 int initiallen;
126 HttpHdrScTarget *sct;
45a58345 127 assert(str);
43ae1d95 128
129 /* iterate through comma separated list */
130
131 while (strListGetItem(str, ',', &item, &ilen, &pos)) {
132 initiallen = ilen;
34460e19 133 vlen = 0;
43ae1d95 134 /* decrease ilen to still match the token for '=' statements */
135
34460e19 136 if ((p = strchr(item, '=')) && (p - item < ilen)) {
7c0f9f7e 137 vlen = ilen - (p + 1 - item);
34460e19 138 ilen = p - item;
7c0f9f7e 139 p++;
34460e19 140 }
43ae1d95 141
142 /* decrease ilen to still match the token for ';' qualified non '=' statments */
143 else if ((p = strchr(item, ';')) && (p - item < ilen))
144 ilen = p++ - item;
145
146 /* find type */
45a58345 147 /* TODO: use a type-safe map-based lookup */
30abd221 148 type = httpHeaderIdByName(item, ilen,
149 ScFieldsInfo, SC_ENUM_END);
43ae1d95 150
151 if (type < 0) {
550cc09e 152 debugs(90, 2, "hdr sc: unknown control-directive: near '" << item << "' in '" << str << "'");
43ae1d95 153 type = SC_OTHER;
154 }
155
156 /* Is this a targeted directive? */
45a58345 157 /* TODO: remove the temporary useage and use memrchr and the information we have instead */
43ae1d95 158 temp = xstrndup (item, initiallen + 1);
159
160 if (!((target = strrchr (temp, ';')) && !strchr (target, '"') && *(target + 1) != '\0'))
161 target = NULL;
162 else
163 ++target;
164
45a58345 165 sct = sc->findTarget(target);
43ae1d95 166
167 if (!sct) {
45a58345
FC
168 sct = new HttpHdrScTarget(target);
169 addTarget(sct);
43ae1d95 170 }
171
172 safe_free (temp);
173
45a58345 174 if (sct->isSet(static_cast<http_hdr_sc_type>(type))) {
43ae1d95 175 if (type != SC_OTHER)
550cc09e 176 debugs(90, 2, "hdr sc: ignoring duplicate control-directive: near '" << item << "' in '" << str << "'");
43ae1d95 177
178 ScFieldsInfo[type].stat.repCount++;
179
180 continue;
181 }
182
45a58345 183 /* process directives */
43ae1d95 184 switch (type) {
45a58345
FC
185 case SC_NO_STORE:
186 sct->noStore(true);
187 break;
43ae1d95 188
45a58345
FC
189 case SC_NO_STORE_REMOTE:
190 sct->noStoreRemote(true);
43ae1d95 191 break;
192
633b9845
A
193 case SC_MAX_AGE: {
194 int ma;
195 if (p && httpHeaderParseInt(p, &ma)) {
196 sct->maxAge(ma);
197 } else {
198 debugs(90, 2, "sc: invalid max-age specs near '" << item << "'");
199 sct->clearMaxAge();
200 }
201
202 if ((p = strchr (p, '+'))) {
203 int ms;
204 ++p; //skip the + char
205 if (httpHeaderParseInt(p, &ms)) {
206 sct->maxStale(ms);
207 } else {
208 debugs(90, 2, "sc: invalid max-stale specs near '" << item << "'");
209 sct->clearMaxStale();
210 /* leave the max-age alone */
211 }
212 }
213 break;
214 }
45a58345 215
43ae1d95 216 case SC_CONTENT:
217
633b9845
A
218 if ( p && httpHeaderParseQuotedString(p, vlen, &sct->content_)) {
219 sct->setMask(SC_CONTENT,true); // ugly but saves a copy
220 } else {
bf8fe701 221 debugs(90, 2, "sc: invalid content= quoted string near '" << item << "'");
45a58345 222 sct->clearContent();
43ae1d95 223 }
633b9845 224 break;
43ae1d95 225
45a58345 226 case SC_OTHER:
43ae1d95 227 default:
228 break;
229 }
230 }
231
232 return sc->targets.head != NULL;
233}
234
45a58345 235HttpHdrSc::~HttpHdrSc()
43ae1d95 236{
45a58345
FC
237 if (targets.head) {
238 dlink_node *sct = targets.head;
43ae1d95 239
240 while (sct) {
45a58345 241 HttpHdrScTarget *t = static_cast<HttpHdrScTarget *>(sct->data);
43ae1d95 242 sct = sct->next;
45a58345
FC
243 dlinkDelete (&t->node, &targets);
244 delete t;
43ae1d95 245 }
246 }
43ae1d95 247}
248
45a58345
FC
249
250HttpHdrSc::HttpHdrSc(const HttpHdrSc &sc)
43ae1d95 251{
45a58345 252 dlink_node *node = sc.targets.head;
43ae1d95 253
254 while (node) {
45a58345
FC
255 HttpHdrScTarget *dupsct = new HttpHdrScTarget(*static_cast<HttpHdrScTarget *>(node->data));
256 addTargetAtTail(dupsct);
43ae1d95 257 node = node->next;
258 }
43ae1d95 259}
260
261void
45a58345 262HttpHdrScTarget::packInto(Packer * p) const
43ae1d95 263{
264 http_hdr_sc_type flag;
265 int pcount = 0;
45a58345 266 assert (p);
43ae1d95 267
268 for (flag = SC_NO_STORE; flag < SC_ENUM_END; ++flag) {
45a58345 269 if (isSet(flag) && flag != SC_OTHER) {
43ae1d95 270
271 /* print option name */
826a1fed 272 packerPrintf(p, (pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH),
af6a12ee 273 SQUIDSTRINGPRINT(ScFieldsInfo[flag].name));
43ae1d95 274
275 /* handle options with values */
276
277 if (flag == SC_MAX_AGE)
45a58345 278 packerPrintf(p, "=%d", (int) max_age);
43ae1d95 279
280 if (flag == SC_CONTENT)
45a58345 281 packerPrintf(p, "=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(content_));
43ae1d95 282
283 pcount++;
284 }
285 }
286
45a58345
FC
287 if (hasTarget())
288 packerPrintf (p, ";" SQUIDSTRINGPH, SQUIDSTRINGPRINT(target));
43ae1d95 289}
290
291void
45a58345 292HttpHdrSc::packInto(Packer * p) const
43ae1d95 293{
294 dlink_node *node;
45a58345
FC
295 assert(p);
296 node = targets.head;
43ae1d95 297
298 while (node) {
633b9845 299 static_cast<HttpHdrScTarget *>(node->data)->packInto(p);
43ae1d95 300 node = node->next;
301 }
302}
303
43ae1d95 304/* negative max_age will clean old max_Age setting */
305void
45a58345 306HttpHdrSc::setMaxAge(char const *target, int max_age)
43ae1d95 307{
45a58345 308 HttpHdrScTarget *sct = findTarget(target);
43ae1d95 309
310 if (!sct) {
45a58345
FC
311 sct = new HttpHdrScTarget(target);
312 dlinkAddTail (sct, &sct->node, &targets);
43ae1d95 313 }
314
45a58345 315 sct->maxAge(max_age);
43ae1d95 316}
317
318void
45a58345 319HttpHdrSc::updateStats(StatHist * hist) const
43ae1d95 320{
45a58345 321 dlink_node *sct = targets.head;
43ae1d95 322
323 while (sct) {
633b9845 324 static_cast<HttpHdrScTarget *>(sct->data)->updateStats(hist);
43ae1d95 325 sct = sct->next;
326 }
327}
328
329void
330httpHdrScTargetStatDumper(StoreEntry * sentry, int idx, double val, double size, int count)
331{
332 extern const HttpHeaderStat *dump_stat; /* argh! */
333 const int id = (int) val;
334 const int valid_id = id >= 0 && id < SC_ENUM_END;
550cc09e 335 const char *name = valid_id ? ScFieldsInfo[id].name.termedBuf() : "INVALID";
43ae1d95 336
337 if (count || valid_id)
338 storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
339 id, name, count, xdiv(count, dump_stat->scParsedCount));
340}
341
342void
343httpHdrScStatDumper(StoreEntry * sentry, int idx, double val, double size, int count)
344{
345 extern const HttpHeaderStat *dump_stat; /* argh! */
346 const int id = (int) val;
347 const int valid_id = id >= 0 && id < SC_ENUM_END;
550cc09e 348 const char *name = valid_id ? ScFieldsInfo[id].name.termedBuf() : "INVALID";
43ae1d95 349
350 if (count || valid_id)
351 storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
352 id, name, count, xdiv(count, dump_stat->scParsedCount));
353}
354
355HttpHdrScTarget *
45a58345 356HttpHdrSc::findTarget(const char *target)
43ae1d95 357{
358 dlink_node *node;
45a58345 359 node = targets.head;
43ae1d95 360
361 while (node) {
362 HttpHdrScTarget *sct = (HttpHdrScTarget *)node->data;
363
550cc09e 364 if (target && sct->target.defined() && !strcmp (target, sct->target.termedBuf()))
43ae1d95 365 return sct;
550cc09e 366 else if (!target && sct->target.undefined())
43ae1d95 367 return sct;
368
369 node = node->next;
370 }
371
372 return NULL;
373}
374
375HttpHdrScTarget *
45a58345 376HttpHdrSc::getMergedTarget(const char *ourtarget)
43ae1d95 377{
45a58345
FC
378 HttpHdrScTarget *sctus = findTarget(ourtarget);
379 HttpHdrScTarget *sctgeneric = findTarget(NULL);
43ae1d95 380
381 if (sctgeneric || sctus) {
45a58345 382 HttpHdrScTarget *sctusable = new HttpHdrScTarget(NULL);
43ae1d95 383
384 if (sctgeneric)
45a58345 385 sctusable->mergeWith(sctgeneric);
43ae1d95 386
387 if (sctus)
45a58345 388 sctusable->mergeWith(sctus);
43ae1d95 389
390 return sctusable;
391 }
392
393 return NULL;
394}