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