]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/HttpHdrCc.cc
2 * Copyright (C) 1996-2017 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 "base/LookupTable.h"
13 #include "HttpHdrCc.h"
14 #include "HttpHeader.h"
15 #include "HttpHeaderFieldStat.h"
16 #include "HttpHeaderStat.h"
17 #include "HttpHeaderTools.h"
18 #include "sbuf/SBuf.h"
28 // invariant: row[j].id == j
29 static LookupTable
<HttpHdrCcType
>::Record CcAttrs
[] = {
30 {"public", HttpHdrCcType::CC_PUBLIC
},
31 {"private", HttpHdrCcType::CC_PRIVATE
},
32 {"no-cache", HttpHdrCcType::CC_NO_CACHE
},
33 {"no-store", HttpHdrCcType::CC_NO_STORE
},
34 {"no-transform", HttpHdrCcType::CC_NO_TRANSFORM
},
35 {"must-revalidate", HttpHdrCcType::CC_MUST_REVALIDATE
},
36 {"proxy-revalidate", HttpHdrCcType::CC_PROXY_REVALIDATE
},
37 {"max-age", HttpHdrCcType::CC_MAX_AGE
},
38 {"s-maxage", HttpHdrCcType::CC_S_MAXAGE
},
39 {"max-stale", HttpHdrCcType::CC_MAX_STALE
},
40 {"min-fresh", HttpHdrCcType::CC_MIN_FRESH
},
41 {"only-if-cached", HttpHdrCcType::CC_ONLY_IF_CACHED
},
42 {"stale-if-error", HttpHdrCcType::CC_STALE_IF_ERROR
},
43 {"immutable", HttpHdrCcType::CC_IMMUTABLE
},
44 {"Other,", HttpHdrCcType::CC_OTHER
}, /* ',' will protect from matches */
45 {nullptr, HttpHdrCcType::CC_ENUM_END
}
47 LookupTable
<HttpHdrCcType
> ccLookupTable(HttpHdrCcType::CC_OTHER
,CcAttrs
);
48 std::vector
<HttpHeaderFieldStat
> ccHeaderStats(HttpHdrCcType::CC_ENUM_END
);
50 /// used to walk a table of http_header_cc_type structs
51 HttpHdrCcType
&operator++ (HttpHdrCcType
&aHeader
)
53 int tmp
= (int)aHeader
;
54 aHeader
= (HttpHdrCcType
)(++tmp
);
58 /// Module initialization hook
60 httpHdrCcInitModule(void)
62 // check invariant on initialization table
63 for (unsigned int j
= 0; CcAttrs
[j
].name
!= nullptr; ++j
) {
64 assert (static_cast<int>(CcAttrs
[j
].id
) == j
);
75 HttpHdrCc::parse(const String
& str
)
78 const char *p
; /* '=' parameter */
79 const char *pos
= NULL
;
83 /* iterate through comma separated list */
85 while (strListGetItem(&str
, ',', &item
, &ilen
, &pos
)) {
86 /* isolate directive name */
88 if ((p
= (const char *)memchr(item
, '=', ilen
)) && (p
- item
< ilen
)) {
96 const HttpHdrCcType type
= ccLookupTable
.lookup(SBuf(item
,nlen
));
98 // ignore known duplicate directives
100 if (type
!= HttpHdrCcType::CC_OTHER
) {
101 debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item
<< "' in '" << str
<< "'");
102 ++ ccHeaderStats
[type
].repCount
;
107 /* special-case-parsing and attribute-setting */
110 case HttpHdrCcType::CC_MAX_AGE
:
111 if (!p
|| !httpHeaderParseInt(p
, &max_age
) || max_age
< 0) {
112 debugs(65, 2, "cc: invalid max-age specs near '" << item
<< "'");
119 case HttpHdrCcType::CC_S_MAXAGE
:
120 if (!p
|| !httpHeaderParseInt(p
, &s_maxage
) || s_maxage
< 0) {
121 debugs(65, 2, "cc: invalid s-maxage specs near '" << item
<< "'");
128 case HttpHdrCcType::CC_MAX_STALE
:
129 if (!p
|| !httpHeaderParseInt(p
, &max_stale
) || max_stale
< 0) {
130 debugs(65, 2, "cc: max-stale directive is valid without value");
131 maxStale(MAX_STALE_ANY
);
137 case HttpHdrCcType::CC_MIN_FRESH
:
138 if (!p
|| !httpHeaderParseInt(p
, &min_fresh
) || min_fresh
< 0) {
139 debugs(65, 2, "cc: invalid min-fresh specs near '" << item
<< "'");
146 case HttpHdrCcType::CC_STALE_IF_ERROR
:
147 if (!p
|| !httpHeaderParseInt(p
, &stale_if_error
) || stale_if_error
< 0) {
148 debugs(65, 2, "cc: invalid stale-if-error specs near '" << item
<< "'");
155 case HttpHdrCcType::CC_PRIVATE
: {
158 // Value parameter is optional.
160 } else if (/* p &&*/ httpHeaderParseQuotedString(p
, (ilen
-nlen
-1), &temp
)) {
161 private_
.append(temp
);
163 debugs(65, 2, "cc: invalid private= specs near '" << item
<< "'");
165 // to be safe we ignore broken parameters, but always remember the 'private' part.
170 case HttpHdrCcType::CC_NO_CACHE
: {
173 // On Requests, missing value parameter is expected syntax.
174 // On Responses, value parameter is optional.
177 } else if (/* p &&*/ httpHeaderParseQuotedString(p
, (ilen
-nlen
-1), &temp
)) {
178 // On Requests, a value parameter is invalid syntax.
179 // XXX: identify when parsing request header and dump err message here.
181 no_cache
.append(temp
);
183 debugs(65, 2, "cc: invalid no-cache= specs near '" << item
<< "'");
188 case HttpHdrCcType::CC_PUBLIC
:
191 case HttpHdrCcType::CC_NO_STORE
:
194 case HttpHdrCcType::CC_NO_TRANSFORM
:
197 case HttpHdrCcType::CC_MUST_REVALIDATE
:
198 mustRevalidate(true);
200 case HttpHdrCcType::CC_PROXY_REVALIDATE
:
201 proxyRevalidate(true);
203 case HttpHdrCcType::CC_ONLY_IF_CACHED
:
206 case HttpHdrCcType::CC_IMMUTABLE
:
210 case HttpHdrCcType::CC_OTHER
:
214 other
.append(item
, ilen
);
218 /* note that we ignore most of '=' specs (RFCVIOLATION) */
227 HttpHdrCc::packInto(Packable
* p
) const
229 // optimization: if the mask is empty do nothing
237 for (flag
= HttpHdrCcType::CC_PUBLIC
; flag
< HttpHdrCcType::CC_ENUM_END
; ++flag
) {
238 if (isSet(flag
) && flag
!= HttpHdrCcType::CC_OTHER
) {
240 /* print option name for all options */
241 p
->appendf((pcount
? ", %s": "%s") , CcAttrs
[flag
].name
);
243 /* for all options having values, "=value" after the name */
245 case HttpHdrCcType::CC_PUBLIC
:
247 case HttpHdrCcType::CC_PRIVATE
:
248 if (Private().size())
249 p
->appendf("=\"" SQUIDSTRINGPH
"\"", SQUIDSTRINGPRINT(Private()));
252 case HttpHdrCcType::CC_NO_CACHE
:
253 if (noCache().size())
254 p
->appendf("=\"" SQUIDSTRINGPH
"\"", SQUIDSTRINGPRINT(noCache()));
256 case HttpHdrCcType::CC_NO_STORE
:
258 case HttpHdrCcType::CC_NO_TRANSFORM
:
260 case HttpHdrCcType::CC_MUST_REVALIDATE
:
262 case HttpHdrCcType::CC_PROXY_REVALIDATE
:
264 case HttpHdrCcType::CC_MAX_AGE
:
265 p
->appendf("=%d", maxAge());
267 case HttpHdrCcType::CC_S_MAXAGE
:
268 p
->appendf("=%d", sMaxAge());
270 case HttpHdrCcType::CC_MAX_STALE
:
271 /* max-stale's value is optional.
272 If we didn't receive it, don't send it */
273 if (maxStale()!=MAX_STALE_ANY
)
274 p
->appendf("=%d", maxStale());
276 case HttpHdrCcType::CC_MIN_FRESH
:
277 p
->appendf("=%d", minFresh());
279 case HttpHdrCcType::CC_ONLY_IF_CACHED
:
281 case HttpHdrCcType::CC_STALE_IF_ERROR
:
282 p
->appendf("=%d", staleIfError());
284 case HttpHdrCcType::CC_IMMUTABLE
:
286 case HttpHdrCcType::CC_OTHER
:
287 case HttpHdrCcType::CC_ENUM_END
:
288 // done below after the loop
296 if (other
.size() != 0)
297 p
->appendf((pcount
? ", " SQUIDSTRINGPH
: SQUIDSTRINGPH
), SQUIDSTRINGPRINT(other
));
301 httpHdrCcUpdateStats(const HttpHdrCc
* cc
, StatHist
* hist
)
305 for (HttpHdrCcType c
= HttpHdrCcType::CC_PUBLIC
; c
< HttpHdrCcType::CC_ENUM_END
; ++c
)
311 httpHdrCcStatDumper(StoreEntry
* sentry
, int, double val
, double, int count
)
313 extern const HttpHeaderStat
*dump_stat
; /* argh! */
314 const int id
= static_cast<int>(val
);
315 const bool valid_id
= id
>= 0 && id
< static_cast<int>(HttpHdrCcType::CC_ENUM_END
);
316 const char *name
= valid_id
? CcAttrs
[id
].name
: "INVALID";
318 if (count
|| valid_id
)
319 storeAppendPrintf(sentry
, "%2d\t %-20s\t %5d\t %6.2f\n",
320 id
, name
, count
, xdiv(count
, dump_stat
->ccParsedCount
));
324 operator<< (std::ostream
&s
, HttpHdrCcType c
)
326 const unsigned char ic
= static_cast<int>(c
);
327 if (c
< HttpHdrCcType::CC_ENUM_END
)
328 s
<< CcAttrs
[ic
].name
<< '[' << ic
<< ']' ;
330 s
<< "*invalid hdrcc* [" << ic
<< ']';
335 #include "HttpHdrCc.cci"