]>
Commit | Line | Data |
---|---|---|
7faf2bdb | 1 | |
2 | /* | |
262a0e14 | 3 | * $Id$ |
7faf2bdb | 4 | * |
5 | * DEBUG: section 65 HTTP Cache Control Header | |
6 | * AUTHOR: Alex Rousskov | |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 9 | * ---------------------------------------------------------- |
7faf2bdb | 10 | * |
2b6662ba | 11 | * Squid is the result of efforts by numerous individuals from |
12 | * the Internet community; see the CONTRIBUTORS file for full | |
13 | * details. Many organizations have provided support for Squid's | |
14 | * development; see the SPONSORS file for full details. Squid is | |
15 | * Copyrighted (C) 2001 by the Regents of the University of | |
16 | * California; see the COPYRIGHT file for full details. Squid | |
17 | * incorporates software developed and/or copyrighted by other | |
18 | * sources; see the CREDITS file for full details. | |
7faf2bdb | 19 | * |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
26ac0430 | 24 | * |
7faf2bdb | 25 | * This program is distributed in the hope that it will be useful, |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
26ac0430 | 29 | * |
7faf2bdb | 30 | * You should have received a copy of the GNU General Public License |
31 | * along with this program; if not, write to the Free Software | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
7faf2bdb | 33 | * |
34 | */ | |
35 | ||
36 | #include "squid.h" | |
e6ccf245 | 37 | #include "Store.h" |
38 | #include "HttpHeader.h" | |
7faf2bdb | 39 | |
de336bbe | 40 | /* this table is used for parsing cache control header */ |
26ac0430 AJ |
41 | static const HttpHeaderFieldAttrs CcAttrs[CC_ENUM_END] = { |
42 | {"public", (http_hdr_type)CC_PUBLIC}, | |
62e76326 | 43 | |
26ac0430 AJ |
44 | {"private", (http_hdr_type)CC_PRIVATE}, |
45 | {"no-cache", (http_hdr_type)CC_NO_CACHE}, | |
46 | {"no-store", (http_hdr_type)CC_NO_STORE}, | |
47 | {"no-transform", (http_hdr_type)CC_NO_TRANSFORM}, | |
48 | {"must-revalidate", (http_hdr_type)CC_MUST_REVALIDATE}, | |
49 | {"proxy-revalidate", (http_hdr_type)CC_PROXY_REVALIDATE}, | |
50 | {"only-if-cached", (http_hdr_type)CC_ONLY_IF_CACHED}, | |
51 | {"max-age", (http_hdr_type)CC_MAX_AGE}, | |
52 | {"s-maxage", (http_hdr_type)CC_S_MAXAGE}, | |
53 | {"max-stale", (http_hdr_type)CC_MAX_STALE}, | |
54 | {"Other,", (http_hdr_type)CC_OTHER} /* ',' will protect from matches */ | |
55 | }; | |
62e76326 | 56 | |
de336bbe | 57 | HttpHeaderFieldInfo *CcFieldsInfo = NULL; |
7faf2bdb | 58 | |
e6ccf245 | 59 | http_hdr_cc_type &operator++ (http_hdr_cc_type &aHeader) |
60 | { | |
1f1ae50a | 61 | int tmp = (int)aHeader; |
62 | aHeader = (http_hdr_cc_type)(++tmp); | |
e6ccf245 | 63 | return aHeader; |
64 | } | |
65 | ||
66 | ||
b5107edb | 67 | /* local prototypes */ |
30abd221 | 68 | static int httpHdrCcParseInit(HttpHdrCc * cc, const String * str); |
7faf2bdb | 69 | |
70 | ||
71 | /* module initialization */ | |
72 | ||
73 | void | |
9bc73deb | 74 | httpHdrCcInitModule(void) |
7faf2bdb | 75 | { |
de336bbe | 76 | CcFieldsInfo = httpHeaderBuildFieldsInfo(CcAttrs, CC_ENUM_END); |
77 | } | |
78 | ||
79 | void | |
9bc73deb | 80 | httpHdrCcCleanModule(void) |
de336bbe | 81 | { |
82 | httpHeaderDestroyFieldsInfo(CcFieldsInfo, CC_ENUM_END); | |
83 | CcFieldsInfo = NULL; | |
7faf2bdb | 84 | } |
85 | ||
86 | /* implementation */ | |
87 | ||
88 | HttpHdrCc * | |
9bc73deb | 89 | httpHdrCcCreate(void) |
7faf2bdb | 90 | { |
e6ccf245 | 91 | HttpHdrCc *cc = (HttpHdrCc *)memAllocate(MEM_HTTP_HDR_CC); |
49ff0930 | 92 | cc->max_age = cc->s_maxage = cc->max_stale = -1; |
7faf2bdb | 93 | return cc; |
94 | } | |
95 | ||
96 | /* creates an cc object from a 0-terminating string */ | |
97 | HttpHdrCc * | |
30abd221 | 98 | httpHdrCcParseCreate(const String * str) |
7faf2bdb | 99 | { |
100 | HttpHdrCc *cc = httpHdrCcCreate(); | |
62e76326 | 101 | |
b5107edb | 102 | if (!httpHdrCcParseInit(cc, str)) { |
62e76326 | 103 | httpHdrCcDestroy(cc); |
104 | cc = NULL; | |
b5107edb | 105 | } |
62e76326 | 106 | |
7faf2bdb | 107 | return cc; |
108 | } | |
109 | ||
110 | /* parses a 0-terminating string and inits cc */ | |
b5107edb | 111 | static int |
30abd221 | 112 | httpHdrCcParseInit(HttpHdrCc * cc, const String * str) |
7faf2bdb | 113 | { |
114 | const char *item; | |
115 | const char *p; /* '=' parameter */ | |
116 | const char *pos = NULL; | |
e6ccf245 | 117 | http_hdr_cc_type type; |
7faf2bdb | 118 | int ilen; |
1b2e9616 | 119 | int nlen; |
7faf2bdb | 120 | assert(cc && str); |
121 | ||
7faf2bdb | 122 | /* iterate through comma separated list */ |
62e76326 | 123 | |
7faf2bdb | 124 | while (strListGetItem(str, ',', &item, &ilen, &pos)) { |
1b2e9616 | 125 | /* isolate directive name */ |
62e76326 | 126 | |
1b2e9616 | 127 | if ((p = (const char *)memchr(item, '=', ilen)) && (p - item < ilen)) |
128 | nlen = p++ - item; | |
129 | else | |
130 | nlen = ilen; | |
62e76326 | 131 | |
132 | /* find type */ | |
30abd221 | 133 | type = (http_hdr_cc_type ) httpHeaderIdByName(item, nlen, |
134 | CcFieldsInfo, CC_ENUM_END); | |
62e76326 | 135 | |
136 | if (type < 0) { | |
99524de7 | 137 | debugs(65, 2, "hdr cc: unknown cache-directive: near '" << item << "' in '" << str->unsafeBuf() << "'"); |
62e76326 | 138 | type = CC_OTHER; |
139 | } | |
140 | ||
141 | if (EBIT_TEST(cc->mask, type)) { | |
142 | if (type != CC_OTHER) | |
99524de7 | 143 | debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item << "' in '" << str->unsafeBuf() << "'"); |
62e76326 | 144 | |
145 | CcFieldsInfo[type].stat.repCount++; | |
146 | ||
147 | continue; | |
148 | } | |
149 | ||
150 | /* update mask */ | |
151 | EBIT_SET(cc->mask, type); | |
152 | ||
153 | /* post-processing special cases */ | |
154 | switch (type) { | |
155 | ||
156 | case CC_MAX_AGE: | |
157 | ||
158 | if (!p || !httpHeaderParseInt(p, &cc->max_age)) { | |
bf8fe701 | 159 | debugs(65, 2, "cc: invalid max-age specs near '" << item << "'"); |
62e76326 | 160 | cc->max_age = -1; |
161 | EBIT_CLR(cc->mask, type); | |
162 | } | |
163 | ||
164 | break; | |
165 | ||
166 | case CC_S_MAXAGE: | |
167 | ||
168 | if (!p || !httpHeaderParseInt(p, &cc->s_maxage)) { | |
bf8fe701 | 169 | debugs(65, 2, "cc: invalid s-maxage specs near '" << item << "'"); |
62e76326 | 170 | cc->s_maxage = -1; |
171 | EBIT_CLR(cc->mask, type); | |
172 | } | |
173 | ||
174 | break; | |
175 | ||
176 | case CC_MAX_STALE: | |
177 | ||
178 | if (!p || !httpHeaderParseInt(p, &cc->max_stale)) { | |
bf8fe701 | 179 | debugs(65, 2, "cc: max-stale directive is valid without value"); |
62e76326 | 180 | cc->max_stale = -1; |
181 | } | |
182 | ||
183 | break; | |
184 | ||
1b2e9616 | 185 | case CC_OTHER: |
186 | ||
187 | if (cc->other.size()) | |
188 | cc->other.append(", "); | |
189 | ||
190 | cc->other.append(item, ilen); | |
191 | ||
192 | break; | |
193 | ||
62e76326 | 194 | default: |
1b2e9616 | 195 | /* note that we ignore most of '=' specs (RFCVIOLATION) */ |
62e76326 | 196 | break; |
197 | } | |
7faf2bdb | 198 | } |
62e76326 | 199 | |
b5107edb | 200 | return cc->mask != 0; |
7faf2bdb | 201 | } |
202 | ||
203 | void | |
204 | httpHdrCcDestroy(HttpHdrCc * cc) | |
205 | { | |
206 | assert(cc); | |
1b2e9616 | 207 | |
99524de7 | 208 | if (cc->other.unsafeBuf()) |
30abd221 | 209 | cc->other.clean(); |
1b2e9616 | 210 | |
db1cd23c | 211 | memFree(cc, MEM_HTTP_HDR_CC); |
7faf2bdb | 212 | } |
213 | ||
214 | HttpHdrCc * | |
02922e76 | 215 | httpHdrCcDup(const HttpHdrCc * cc) |
7faf2bdb | 216 | { |
217 | HttpHdrCc *dup; | |
218 | assert(cc); | |
219 | dup = httpHdrCcCreate(); | |
220 | dup->mask = cc->mask; | |
221 | dup->max_age = cc->max_age; | |
7e3ce7b9 | 222 | dup->s_maxage = cc->s_maxage; |
49ff0930 | 223 | dup->max_stale = cc->max_stale; |
7faf2bdb | 224 | return dup; |
225 | } | |
226 | ||
227 | void | |
d76fcfa7 | 228 | httpHdrCcPackInto(const HttpHdrCc * cc, Packer * p) |
7faf2bdb | 229 | { |
230 | http_hdr_cc_type flag; | |
231 | int pcount = 0; | |
232 | assert(cc && p); | |
62e76326 | 233 | |
e6ccf245 | 234 | for (flag = CC_PUBLIC; flag < CC_ENUM_END; ++flag) { |
62e76326 | 235 | if (EBIT_TEST(cc->mask, flag) && flag != CC_OTHER) { |
236 | ||
237 | /* print option name */ | |
99524de7 | 238 | packerPrintf(p, (pcount ? ", %s" : "%s"), CcFieldsInfo[flag].name.unsafeBuf()); |
91274dd0 | 239 | |
62e76326 | 240 | /* handle options with values */ |
91274dd0 | 241 | |
62e76326 | 242 | if (flag == CC_MAX_AGE) |
243 | packerPrintf(p, "=%d", (int) cc->max_age); | |
91274dd0 | 244 | |
62e76326 | 245 | if (flag == CC_S_MAXAGE) |
246 | packerPrintf(p, "=%d", (int) cc->s_maxage); | |
7e3ce7b9 | 247 | |
410c4eb1 | 248 | if (flag == CC_MAX_STALE && cc->max_stale >= 0) |
62e76326 | 249 | packerPrintf(p, "=%d", (int) cc->max_stale); |
49ff0930 | 250 | |
62e76326 | 251 | pcount++; |
252 | } | |
7faf2bdb | 253 | } |
1b2e9616 | 254 | |
255 | if (cc->other.size()) | |
99524de7 | 256 | packerPrintf(p, (pcount ? ", %s" : "%s"), cc->other.unsafeBuf()); |
7faf2bdb | 257 | } |
258 | ||
99edd1c3 | 259 | /* negative max_age will clean old max_Age setting */ |
260 | void | |
261 | httpHdrCcSetMaxAge(HttpHdrCc * cc, int max_age) | |
262 | { | |
263 | assert(cc); | |
264 | cc->max_age = max_age; | |
62e76326 | 265 | |
99edd1c3 | 266 | if (max_age >= 0) |
62e76326 | 267 | EBIT_SET(cc->mask, CC_MAX_AGE); |
99edd1c3 | 268 | else |
62e76326 | 269 | EBIT_CLR(cc->mask, CC_MAX_AGE); |
99edd1c3 | 270 | } |
271 | ||
7e3ce7b9 | 272 | /* negative s_maxage will clean old s-maxage setting */ |
273 | void | |
274 | httpHdrCcSetSMaxAge(HttpHdrCc * cc, int s_maxage) | |
275 | { | |
276 | assert(cc); | |
277 | cc->s_maxage = s_maxage; | |
62e76326 | 278 | |
7e3ce7b9 | 279 | if (s_maxage >= 0) |
62e76326 | 280 | EBIT_SET(cc->mask, CC_S_MAXAGE); |
7e3ce7b9 | 281 | else |
62e76326 | 282 | EBIT_CLR(cc->mask, CC_S_MAXAGE); |
7e3ce7b9 | 283 | } |
284 | ||
7faf2bdb | 285 | void |
286 | httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist) | |
287 | { | |
288 | http_hdr_cc_type c; | |
289 | assert(cc); | |
62e76326 | 290 | |
e6ccf245 | 291 | for (c = CC_PUBLIC; c < CC_ENUM_END; ++c) |
62e76326 | 292 | if (EBIT_TEST(cc->mask, c)) |
293 | statHistCount(hist, c); | |
7faf2bdb | 294 | } |
295 | ||
296 | void | |
297 | httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count) | |
298 | { | |
0cdcddb9 | 299 | extern const HttpHeaderStat *dump_stat; /* argh! */ |
7faf2bdb | 300 | const int id = (int) val; |
301 | const int valid_id = id >= 0 && id < CC_ENUM_END; | |
99524de7 | 302 | const char *name = valid_id ? CcFieldsInfo[id].name.unsafeBuf() : "INVALID"; |
62e76326 | 303 | |
7faf2bdb | 304 | if (count || valid_id) |
62e76326 | 305 | storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n", |
306 | id, name, count, xdiv(count, dump_stat->ccParsedCount)); | |
7faf2bdb | 307 | } |