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