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