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