3 * DEBUG: section 65 HTTP Cache Control Header
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
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.
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.
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.
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.
34 #include "base/StringArea.h"
35 #include "HttpHeader.h"
36 #include "HttpHeaderStat.h"
37 #include "HttpHeaderTools.h"
38 #include "HttpHdrCc.h"
48 /* a row in the table used for parsing cache control header and statistics */
52 HttpHeaderFieldStat stat
;
55 /* order must match that of enum http_hdr_cc_type. The constraint is verified at initialization time */
56 static HttpHeaderCcFields CcAttrs
[CC_ENUM_END
] = {
57 {"public", CC_PUBLIC
},
58 {"private", CC_PRIVATE
},
59 {"no-cache", CC_NO_CACHE
},
60 {"no-store", CC_NO_STORE
},
61 {"no-transform", CC_NO_TRANSFORM
},
62 {"must-revalidate", CC_MUST_REVALIDATE
},
63 {"proxy-revalidate", CC_PROXY_REVALIDATE
},
64 {"max-age", CC_MAX_AGE
},
65 {"s-maxage", CC_S_MAXAGE
},
66 {"max-stale", CC_MAX_STALE
},
67 {"min-fresh", CC_MIN_FRESH
},
68 {"only-if-cached", CC_ONLY_IF_CACHED
},
69 {"stale-if-error", CC_STALE_IF_ERROR
},
70 {"Other,", CC_OTHER
} /* ',' will protect from matches */
73 /// Map an header name to its type, to expedite parsing
74 typedef std::map
<const StringArea
,http_hdr_cc_type
> CcNameToIdMap_t
;
75 static CcNameToIdMap_t CcNameToIdMap
;
77 /// used to walk a table of http_header_cc_type structs
78 http_hdr_cc_type
&operator++ (http_hdr_cc_type
&aHeader
)
80 int tmp
= (int)aHeader
;
81 aHeader
= (http_hdr_cc_type
)(++tmp
);
85 /// Module initialization hook
87 httpHdrCcInitModule(void)
89 /* build lookup and accounting structures */
90 for (int32_t i
= 0; i
< CC_ENUM_END
; ++i
) {
91 const HttpHeaderCcFields
&f
=CcAttrs
[i
];
92 assert(i
== f
.id
); /* verify assumption: the id is the key into the array */
93 const StringArea
k(f
.name
,strlen(f
.name
));
94 CcNameToIdMap
[k
]=f
.id
;
98 /// Module cleanup hook.
100 httpHdrCcCleanModule(void)
102 // HdrCcNameToIdMap is self-cleaning
112 HttpHdrCc::parse(const String
& str
)
115 const char *p
; /* '=' parameter */
116 const char *pos
= NULL
;
117 http_hdr_cc_type type
;
121 /* iterate through comma separated list */
123 while (strListGetItem(&str
, ',', &item
, &ilen
, &pos
)) {
124 /* isolate directive name */
126 if ((p
= (const char *)memchr(item
, '=', ilen
)) && (p
- item
< ilen
)) {
134 const CcNameToIdMap_t::const_iterator i
=CcNameToIdMap
.find(StringArea(item
,nlen
));
135 if (i
==CcNameToIdMap
.end())
140 // ignore known duplicate directives
142 if (type
!= CC_OTHER
) {
143 debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item
<< "' in '" << str
<< "'");
144 ++CcAttrs
[type
].stat
.repCount
;
149 /* special-case-parsing and attribute-setting */
153 if (!p
|| !httpHeaderParseInt(p
, &max_age
) || max_age
< 0) {
154 debugs(65, 2, "cc: invalid max-age specs near '" << item
<< "'");
162 if (!p
|| !httpHeaderParseInt(p
, &s_maxage
) || s_maxage
< 0) {
163 debugs(65, 2, "cc: invalid s-maxage specs near '" << item
<< "'");
171 if (!p
|| !httpHeaderParseInt(p
, &max_stale
) || max_stale
< 0) {
172 debugs(65, 2, "cc: max-stale directive is valid without value");
173 maxStale(MAX_STALE_ANY
);
180 if (!p
|| !httpHeaderParseInt(p
, &min_fresh
) || min_fresh
< 0) {
181 debugs(65, 2, "cc: invalid min-fresh specs near '" << item
<< "'");
188 case CC_STALE_IF_ERROR
:
189 if (!p
|| !httpHeaderParseInt(p
, &stale_if_error
) || stale_if_error
< 0) {
190 debugs(65, 2, "cc: invalid stale-if-error specs near '" << item
<< "'");
209 case CC_NO_TRANSFORM
:
212 case CC_MUST_REVALIDATE
:
213 mustRevalidate(true);
215 case CC_PROXY_REVALIDATE
:
216 proxyRevalidate(true);
218 case CC_ONLY_IF_CACHED
:
226 other
.append(item
, ilen
);
230 /* note that we ignore most of '=' specs (RFCVIOLATION) */
239 HttpHdrCc::packInto(Packer
* p
) const
241 // optimization: if the mask is empty do nothing
245 http_hdr_cc_type flag
;
249 for (flag
= CC_PUBLIC
; flag
< CC_ENUM_END
; ++flag
) {
250 if (isSet(flag
) && flag
!= CC_OTHER
) {
252 /* print option name for all options */
253 packerPrintf(p
, (pcount
? ", %s": "%s") , CcAttrs
[flag
].name
);
255 /* for all options having values, "=value" after the name */
258 packerPrintf(p
, "=%d", (int) maxAge());
261 packerPrintf(p
, "=%d", (int) sMaxAge());
264 /* max-stale's value is optional.
265 If we didn't receive it, don't send it */
266 if (maxStale()!=MAX_STALE_ANY
)
267 packerPrintf(p
, "=%d", (int) maxStale());
270 packerPrintf(p
, "=%d", (int) minFresh());
273 /* do nothing, directive was already printed */
281 if (other
.size() != 0)
282 packerPrintf(p
, (pcount
? ", " SQUIDSTRINGPH
: SQUIDSTRINGPH
),
283 SQUIDSTRINGPRINT(other
));
287 httpHdrCcUpdateStats(const HttpHdrCc
* cc
, StatHist
* hist
)
292 for (c
= CC_PUBLIC
; c
< CC_ENUM_END
; ++c
)
298 httpHdrCcStatDumper(StoreEntry
* sentry
, int idx
, double val
, double size
, int count
)
300 extern const HttpHeaderStat
*dump_stat
; /* argh! */
301 const int id
= (int) val
;
302 const int valid_id
= id
>= 0 && id
< CC_ENUM_END
;
303 const char *name
= valid_id
? CcAttrs
[id
].name
: "INVALID";
305 if (count
|| valid_id
)
306 storeAppendPrintf(sentry
, "%2d\t %-20s\t %5d\t %6.2f\n",
307 id
, name
, count
, xdiv(count
, dump_stat
->ccParsedCount
));
311 #include "HttpHdrCc.cci"