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