2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 65 HTTP Cache Control Header */
12 #include "HttpHdrCc.h"
13 #include "HttpHeader.h"
14 #include "HttpHeaderFieldStat.h"
15 #include "HttpHeaderStat.h"
16 #include "HttpHeaderTools.h"
25 /* a row in the table used for parsing cache control header and statistics */
26 class HttpHeaderCcFields
29 HttpHeaderCcFields() : name(NULL
), id(CC_BADHDR
), stat() {}
30 HttpHeaderCcFields(const char *aName
, http_hdr_cc_type aTypeId
) : name(aName
), id(aTypeId
) {}
31 HttpHeaderCcFields(const HttpHeaderCcFields
&f
) : name(f
.name
), id(f
.id
) {}
32 // nothing to do as name is a pointer to global static string
33 ~HttpHeaderCcFields() {}
37 HttpHeaderFieldStat stat
;
40 HttpHeaderCcFields
&operator =(const HttpHeaderCcFields
&); // not implemented
43 /* order must match that of enum http_hdr_cc_type. The constraint is verified at initialization time */
44 static HttpHeaderCcFields CcAttrs
[CC_ENUM_END
] = {
45 HttpHeaderCcFields("public", CC_PUBLIC
),
46 HttpHeaderCcFields("private", CC_PRIVATE
),
47 HttpHeaderCcFields("no-cache", CC_NO_CACHE
),
48 HttpHeaderCcFields("no-store", CC_NO_STORE
),
49 HttpHeaderCcFields("no-transform", CC_NO_TRANSFORM
),
50 HttpHeaderCcFields("must-revalidate", CC_MUST_REVALIDATE
),
51 HttpHeaderCcFields("proxy-revalidate", CC_PROXY_REVALIDATE
),
52 HttpHeaderCcFields("max-age", CC_MAX_AGE
),
53 HttpHeaderCcFields("s-maxage", CC_S_MAXAGE
),
54 HttpHeaderCcFields("max-stale", CC_MAX_STALE
),
55 HttpHeaderCcFields("min-fresh", CC_MIN_FRESH
),
56 HttpHeaderCcFields("only-if-cached", CC_ONLY_IF_CACHED
),
57 HttpHeaderCcFields("stale-if-error", CC_STALE_IF_ERROR
),
58 HttpHeaderCcFields("Other,", CC_OTHER
) /* ',' will protect from matches */
61 /// Map an header name to its type, to expedite parsing
62 typedef std::map
<const SBuf
,http_hdr_cc_type
> CcNameToIdMap_t
;
63 static CcNameToIdMap_t CcNameToIdMap
;
65 /// used to walk a table of http_header_cc_type structs
66 http_hdr_cc_type
&operator++ (http_hdr_cc_type
&aHeader
)
68 int tmp
= (int)aHeader
;
69 aHeader
= (http_hdr_cc_type
)(++tmp
);
73 /// Module initialization hook
75 httpHdrCcInitModule(void)
77 /* build lookup and accounting structures */
78 for (int32_t i
= 0; i
< CC_ENUM_END
; ++i
) {
79 const HttpHeaderCcFields
&f
=CcAttrs
[i
];
80 assert(i
== f
.id
); /* verify assumption: the id is the key into the array */
82 CcNameToIdMap
[k
]=f
.id
;
86 /// Module cleanup hook.
88 httpHdrCcCleanModule(void)
90 // HdrCcNameToIdMap is self-cleaning
100 HttpHdrCc::parse(const String
& str
)
103 const char *p
; /* '=' parameter */
104 const char *pos
= NULL
;
105 http_hdr_cc_type type
;
109 /* iterate through comma separated list */
111 while (strListGetItem(&str
, ',', &item
, &ilen
, &pos
)) {
112 /* isolate directive name */
114 if ((p
= (const char *)memchr(item
, '=', ilen
)) && (p
- item
< ilen
)) {
122 const CcNameToIdMap_t::const_iterator i
=CcNameToIdMap
.find(SBuf(item
,nlen
));
123 if (i
==CcNameToIdMap
.end())
128 // ignore known duplicate directives
130 if (type
!= CC_OTHER
) {
131 debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item
<< "' in '" << str
<< "'");
132 ++CcAttrs
[type
].stat
.repCount
;
137 /* special-case-parsing and attribute-setting */
141 if (!p
|| !httpHeaderParseInt(p
, &max_age
) || max_age
< 0) {
142 debugs(65, 2, "cc: invalid max-age specs near '" << item
<< "'");
150 if (!p
|| !httpHeaderParseInt(p
, &s_maxage
) || s_maxage
< 0) {
151 debugs(65, 2, "cc: invalid s-maxage specs near '" << item
<< "'");
159 if (!p
|| !httpHeaderParseInt(p
, &max_stale
) || max_stale
< 0) {
160 debugs(65, 2, "cc: max-stale directive is valid without value");
161 maxStale(MAX_STALE_ANY
);
168 if (!p
|| !httpHeaderParseInt(p
, &min_fresh
) || min_fresh
< 0) {
169 debugs(65, 2, "cc: invalid min-fresh specs near '" << item
<< "'");
176 case CC_STALE_IF_ERROR
:
177 if (!p
|| !httpHeaderParseInt(p
, &stale_if_error
) || stale_if_error
< 0) {
178 debugs(65, 2, "cc: invalid stale-if-error specs near '" << item
<< "'");
188 // Value parameter is optional.
190 } else if (/* p &&*/ httpHeaderParseQuotedString(p
, (ilen
-nlen
-1), &temp
)) {
191 private_
.append(temp
);
193 debugs(65, 2, "cc: invalid private= specs near '" << item
<< "'");
195 // to be safe we ignore broken parameters, but always remember the 'private' part.
203 // On Requests, missing value parameter is expected syntax.
204 // On Responses, value parameter is optional.
207 } else if (/* p &&*/ httpHeaderParseQuotedString(p
, (ilen
-nlen
-1), &temp
)) {
208 // On Requests, a value parameter is invalid syntax.
209 // XXX: identify when parsing request header and dump err message here.
211 no_cache
.append(temp
);
213 debugs(65, 2, "cc: invalid no-cache= specs near '" << item
<< "'");
224 case CC_NO_TRANSFORM
:
227 case CC_MUST_REVALIDATE
:
228 mustRevalidate(true);
230 case CC_PROXY_REVALIDATE
:
231 proxyRevalidate(true);
233 case CC_ONLY_IF_CACHED
:
241 other
.append(item
, ilen
);
245 /* note that we ignore most of '=' specs (RFCVIOLATION) */
254 HttpHdrCc::packInto(Packable
* p
) const
256 // optimization: if the mask is empty do nothing
260 http_hdr_cc_type flag
;
264 for (flag
= CC_PUBLIC
; flag
< CC_ENUM_END
; ++flag
) {
265 if (isSet(flag
) && flag
!= CC_OTHER
) {
267 /* print option name for all options */
268 p
->appendf((pcount
? ", %s": "%s") , CcAttrs
[flag
].name
);
270 /* for all options having values, "=value" after the name */
273 p
->appendf("=%d", maxAge());
276 p
->appendf("=%d", sMaxAge());
279 /* max-stale's value is optional.
280 If we didn't receive it, don't send it */
281 if (maxStale()!=MAX_STALE_ANY
)
282 p
->appendf("=%d", maxStale());
285 p
->appendf("=%d", minFresh());
288 /* do nothing, directive was already printed */
296 if (other
.size() != 0)
297 p
->appendf((pcount
? ", " SQUIDSTRINGPH
: SQUIDSTRINGPH
), SQUIDSTRINGPRINT(other
));
301 httpHdrCcUpdateStats(const HttpHdrCc
* cc
, StatHist
* hist
)
306 for (c
= CC_PUBLIC
; c
< CC_ENUM_END
; ++c
)
312 httpHdrCcStatDumper(StoreEntry
* sentry
, int, double val
, double, int count
)
314 extern const HttpHeaderStat
*dump_stat
; /* argh! */
315 const int id
= (int) val
;
316 const int valid_id
= id
>= 0 && id
< CC_ENUM_END
;
317 const char *name
= valid_id
? CcAttrs
[id
].name
: "INVALID";
319 if (count
|| valid_id
)
320 storeAppendPrintf(sentry
, "%2d\t %-20s\t %5d\t %6.2f\n",
321 id
, name
, count
, xdiv(count
, dump_stat
->ccParsedCount
));
325 #include "HttpHdrCc.cci"