]> git.ipfire.org Git - thirdparty/squid.git/blob - src/HttpHdrCc.cc
Merged from trunk
[thirdparty/squid.git] / src / HttpHdrCc.cc
1 /*
2 *
3 * DEBUG: section 65 HTTP Cache Control Header
4 *
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
7 *
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
30 *
31 */
32
33 #include "squid.h"
34 #include "HttpHdrCc.h"
35 #include "HttpHeader.h"
36 #include "HttpHeaderFieldStat.h"
37 #include "HttpHeaderStat.h"
38 #include "HttpHeaderTools.h"
39 #include "SBuf.h"
40 #include "StatHist.h"
41 #include "Store.h"
42 #include "StrList.h"
43
44 #if HAVE_MAP
45 #include <map>
46 #endif
47
48 /* a row in the table used for parsing cache control header and statistics */
49 typedef struct {
50 const char *name;
51 http_hdr_cc_type id;
52 HttpHeaderFieldStat stat;
53 } HttpHeaderCcFields;
54
55 /* order must match that of enum http_hdr_cc_type. The constraint is verified at initialization time */
56 static HttpHeaderCcFields CcAttrs[CC_ENUM_END] = {
57 {"public", CC_PUBLIC},
58 {"private", CC_PRIVATE},
59 {"no-cache", CC_NO_CACHE},
60 {"no-store", CC_NO_STORE},
61 {"no-transform", CC_NO_TRANSFORM},
62 {"must-revalidate", CC_MUST_REVALIDATE},
63 {"proxy-revalidate", CC_PROXY_REVALIDATE},
64 {"max-age", CC_MAX_AGE},
65 {"s-maxage", CC_S_MAXAGE},
66 {"max-stale", CC_MAX_STALE},
67 {"min-fresh", CC_MIN_FRESH},
68 {"only-if-cached", CC_ONLY_IF_CACHED},
69 {"stale-if-error", CC_STALE_IF_ERROR},
70 {"Other,", CC_OTHER} /* ',' will protect from matches */
71 };
72
73 /// Map an header name to its type, to expedite parsing
74 typedef std::map<const SBuf,http_hdr_cc_type> CcNameToIdMap_t;
75 static CcNameToIdMap_t CcNameToIdMap;
76
77 /// used to walk a table of http_header_cc_type structs
78 http_hdr_cc_type &operator++ (http_hdr_cc_type &aHeader)
79 {
80 int tmp = (int)aHeader;
81 aHeader = (http_hdr_cc_type)(++tmp);
82 return aHeader;
83 }
84
85 /// Module initialization hook
86 void
87 httpHdrCcInitModule(void)
88 {
89 /* build lookup and accounting structures */
90 for (int32_t i = 0; i < CC_ENUM_END; ++i) {
91 const HttpHeaderCcFields &f=CcAttrs[i];
92 assert(i == f.id); /* verify assumption: the id is the key into the array */
93 const SBuf k(f.name);
94 CcNameToIdMap[k]=f.id;
95 }
96 }
97
98 /// Module cleanup hook.
99 void
100 httpHdrCcCleanModule(void)
101 {
102 // HdrCcNameToIdMap is self-cleaning
103 }
104
105 void
106 HttpHdrCc::clear()
107 {
108 *this=HttpHdrCc();
109 }
110
111 bool
112 HttpHdrCc::parse(const String & str)
113 {
114 const char *item;
115 const char *p; /* '=' parameter */
116 const char *pos = NULL;
117 http_hdr_cc_type type;
118 int ilen;
119 int nlen;
120
121 /* iterate through comma separated list */
122
123 while (strListGetItem(&str, ',', &item, &ilen, &pos)) {
124 /* isolate directive name */
125
126 if ((p = (const char *)memchr(item, '=', ilen)) && (p - item < ilen)) {
127 nlen = p - item;
128 ++p;
129 } else {
130 nlen = ilen;
131 }
132
133 /* find type */
134 const CcNameToIdMap_t::const_iterator i=CcNameToIdMap.find(SBuf(item,nlen));
135 if (i==CcNameToIdMap.end())
136 type=CC_OTHER;
137 else
138 type=i->second;
139
140 // ignore known duplicate directives
141 if (isSet(type)) {
142 if (type != CC_OTHER) {
143 debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item << "' in '" << str << "'");
144 ++CcAttrs[type].stat.repCount;
145 continue;
146 }
147 }
148
149 /* special-case-parsing and attribute-setting */
150 switch (type) {
151
152 case CC_MAX_AGE:
153 if (!p || !httpHeaderParseInt(p, &max_age) || max_age < 0) {
154 debugs(65, 2, "cc: invalid max-age specs near '" << item << "'");
155 clearMaxAge();
156 } else {
157 setMask(type,true);
158 }
159 break;
160
161 case CC_S_MAXAGE:
162 if (!p || !httpHeaderParseInt(p, &s_maxage) || s_maxage < 0) {
163 debugs(65, 2, "cc: invalid s-maxage specs near '" << item << "'");
164 clearSMaxAge();
165 } else {
166 setMask(type,true);
167 }
168 break;
169
170 case CC_MAX_STALE:
171 if (!p || !httpHeaderParseInt(p, &max_stale) || max_stale < 0) {
172 debugs(65, 2, "cc: max-stale directive is valid without value");
173 maxStale(MAX_STALE_ANY);
174 } else {
175 setMask(type,true);
176 }
177 break;
178
179 case CC_MIN_FRESH:
180 if (!p || !httpHeaderParseInt(p, &min_fresh) || min_fresh < 0) {
181 debugs(65, 2, "cc: invalid min-fresh specs near '" << item << "'");
182 clearMinFresh();
183 } else {
184 setMask(type,true);
185 }
186 break;
187
188 case CC_STALE_IF_ERROR:
189 if (!p || !httpHeaderParseInt(p, &stale_if_error) || stale_if_error < 0) {
190 debugs(65, 2, "cc: invalid stale-if-error specs near '" << item << "'");
191 clearStaleIfError();
192 } else {
193 setMask(type,true);
194 }
195 break;
196
197 case CC_PRIVATE: {
198 String temp;
199 if (!p) {
200 // Value parameter is optional.
201 private_.clean();
202 } else if (/* p &&*/ httpHeaderParseQuotedString(p, (ilen-nlen-1), &temp)) {
203 private_.append(temp);
204 } else {
205 debugs(65, 2, "cc: invalid private= specs near '" << item << "'");
206 }
207 // to be safe we ignore broken parameters, but always remember the 'private' part.
208 setMask(type,true);
209 }
210 break;
211
212 case CC_NO_CACHE: {
213 String temp;
214 if (!p) {
215 // On Requests, missing value parameter is expected syntax.
216 // On Responses, value parameter is optional.
217 setMask(type,true);
218 no_cache.clean();
219 } else if (/* p &&*/ httpHeaderParseQuotedString(p, (ilen-nlen-1), &temp)) {
220 // On Requests, a value parameter is invalid syntax.
221 // XXX: identify when parsing request header and dump err message here.
222 setMask(type,true);
223 no_cache.append(temp);
224 } else {
225 debugs(65, 2, "cc: invalid no-cache= specs near '" << item << "'");
226 }
227 }
228 break;
229
230 case CC_PUBLIC:
231 Public(true);
232 break;
233 case CC_NO_STORE:
234 noStore(true);
235 break;
236 case CC_NO_TRANSFORM:
237 noTransform(true);
238 break;
239 case CC_MUST_REVALIDATE:
240 mustRevalidate(true);
241 break;
242 case CC_PROXY_REVALIDATE:
243 proxyRevalidate(true);
244 break;
245 case CC_ONLY_IF_CACHED:
246 onlyIfCached(true);
247 break;
248
249 case CC_OTHER:
250 if (other.size())
251 other.append(", ");
252
253 other.append(item, ilen);
254 break;
255
256 default:
257 /* note that we ignore most of '=' specs (RFCVIOLATION) */
258 break;
259 }
260 }
261
262 return (mask != 0);
263 }
264
265 void
266 HttpHdrCc::packInto(Packer * p) const
267 {
268 // optimization: if the mask is empty do nothing
269 if (mask==0)
270 return;
271
272 http_hdr_cc_type flag;
273 int pcount = 0;
274 assert(p);
275
276 for (flag = CC_PUBLIC; flag < CC_ENUM_END; ++flag) {
277 if (isSet(flag) && flag != CC_OTHER) {
278
279 /* print option name for all options */
280 packerPrintf(p, (pcount ? ", %s": "%s") , CcAttrs[flag].name);
281
282 /* for all options having values, "=value" after the name */
283 switch (flag) {
284 case CC_MAX_AGE:
285 packerPrintf(p, "=%d", (int) maxAge());
286 break;
287 case CC_S_MAXAGE:
288 packerPrintf(p, "=%d", (int) sMaxAge());
289 break;
290 case CC_MAX_STALE:
291 /* max-stale's value is optional.
292 If we didn't receive it, don't send it */
293 if (maxStale()!=MAX_STALE_ANY)
294 packerPrintf(p, "=%d", (int) maxStale());
295 break;
296 case CC_MIN_FRESH:
297 packerPrintf(p, "=%d", (int) minFresh());
298 break;
299 default:
300 /* do nothing, directive was already printed */
301 break;
302 }
303
304 ++pcount;
305 }
306 }
307
308 if (other.size() != 0)
309 packerPrintf(p, (pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH),
310 SQUIDSTRINGPRINT(other));
311 }
312
313 void
314 httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist)
315 {
316 http_hdr_cc_type c;
317 assert(cc);
318
319 for (c = CC_PUBLIC; c < CC_ENUM_END; ++c)
320 if (cc->isSet(c))
321 hist->count(c);
322 }
323
324 void
325 httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count)
326 {
327 extern const HttpHeaderStat *dump_stat; /* argh! */
328 const int id = (int) val;
329 const int valid_id = id >= 0 && id < CC_ENUM_END;
330 const char *name = valid_id ? CcAttrs[id].name : "INVALID";
331
332 if (count || valid_id)
333 storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
334 id, name, count, xdiv(count, dump_stat->ccParsedCount));
335 }
336
337 #if !_USE_INLINE_
338 #include "HttpHdrCc.cci"
339 #endif