]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/HttpHdrCc.cc
2 * Copyright (C) 1996-2020 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
);
74 /// set a data member to a new value, and set the corresponding mask-bit.
75 /// if setting is false, then the mask-bit is cleared.
77 HttpHdrCc::setValue(int32_t &value
, int32_t new_value
, HttpHdrCcType hdr
, bool setting
)
81 debugs(65, 3, "rejecting negative-value Cache-Control directive " << hdr
82 << " value " << new_value
);
86 new_value
= -1; //rely on the convention that "unknown" is -1
94 HttpHdrCc::parse(const String
& str
)
97 const char *p
; /* '=' parameter */
98 const char *pos
= NULL
;
102 /* iterate through comma separated list */
104 while (strListGetItem(&str
, ',', &item
, &ilen
, &pos
)) {
105 /* isolate directive name */
107 if ((p
= (const char *)memchr(item
, '=', ilen
)) && (p
- item
< ilen
)) {
115 const HttpHdrCcType type
= ccLookupTable
.lookup(SBuf(item
,nlen
));
117 // ignore known duplicate directives
119 if (type
!= HttpHdrCcType::CC_OTHER
) {
120 debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item
<< "' in '" << str
<< "'");
121 ++ ccHeaderStats
[type
].repCount
;
126 /* special-case-parsing and attribute-setting */
129 case HttpHdrCcType::CC_MAX_AGE
:
130 if (!p
|| !httpHeaderParseInt(p
, &max_age
) || max_age
< 0) {
131 debugs(65, 2, "cc: invalid max-age specs near '" << item
<< "'");
138 case HttpHdrCcType::CC_S_MAXAGE
:
139 if (!p
|| !httpHeaderParseInt(p
, &s_maxage
) || s_maxage
< 0) {
140 debugs(65, 2, "cc: invalid s-maxage specs near '" << item
<< "'");
147 case HttpHdrCcType::CC_MAX_STALE
:
148 if (!p
|| !httpHeaderParseInt(p
, &max_stale
) || max_stale
< 0) {
149 debugs(65, 2, "cc: max-stale directive is valid without value");
150 maxStale(MAX_STALE_ANY
);
156 case HttpHdrCcType::CC_MIN_FRESH
:
157 if (!p
|| !httpHeaderParseInt(p
, &min_fresh
) || min_fresh
< 0) {
158 debugs(65, 2, "cc: invalid min-fresh specs near '" << item
<< "'");
165 case HttpHdrCcType::CC_STALE_IF_ERROR
:
166 if (!p
|| !httpHeaderParseInt(p
, &stale_if_error
) || stale_if_error
< 0) {
167 debugs(65, 2, "cc: invalid stale-if-error specs near '" << item
<< "'");
174 case HttpHdrCcType::CC_PRIVATE
: {
177 // Value parameter is optional.
179 } else if (/* p &&*/ httpHeaderParseQuotedString(p
, (ilen
-nlen
-1), &temp
)) {
180 private_
.append(temp
);
182 debugs(65, 2, "cc: invalid private= specs near '" << item
<< "'");
184 // to be safe we ignore broken parameters, but always remember the 'private' part.
189 case HttpHdrCcType::CC_NO_CACHE
: {
192 // On Requests, missing value parameter is expected syntax.
193 // On Responses, value parameter is optional.
196 } else if (/* p &&*/ httpHeaderParseQuotedString(p
, (ilen
-nlen
-1), &temp
)) {
197 // On Requests, a value parameter is invalid syntax.
198 // XXX: identify when parsing request header and dump err message here.
200 no_cache
.append(temp
);
202 debugs(65, 2, "cc: invalid no-cache= specs near '" << item
<< "'");
207 case HttpHdrCcType::CC_PUBLIC
:
210 case HttpHdrCcType::CC_NO_STORE
:
213 case HttpHdrCcType::CC_NO_TRANSFORM
:
216 case HttpHdrCcType::CC_MUST_REVALIDATE
:
217 mustRevalidate(true);
219 case HttpHdrCcType::CC_PROXY_REVALIDATE
:
220 proxyRevalidate(true);
222 case HttpHdrCcType::CC_ONLY_IF_CACHED
:
225 case HttpHdrCcType::CC_IMMUTABLE
:
229 case HttpHdrCcType::CC_OTHER
:
233 other
.append(item
, ilen
);
237 /* note that we ignore most of '=' specs (RFCVIOLATION) */
246 HttpHdrCc::packInto(Packable
* p
) const
248 // optimization: if the mask is empty do nothing
256 for (flag
= HttpHdrCcType::CC_PUBLIC
; flag
< HttpHdrCcType::CC_ENUM_END
; ++flag
) {
257 if (isSet(flag
) && flag
!= HttpHdrCcType::CC_OTHER
) {
259 /* print option name for all options */
260 p
->appendf((pcount
? ", %s": "%s"), CcAttrs
[flag
].name
);
262 /* for all options having values, "=value" after the name */
264 case HttpHdrCcType::CC_PUBLIC
:
266 case HttpHdrCcType::CC_PRIVATE
:
268 p
->appendf("=\"" SQUIDSTRINGPH
"\"", SQUIDSTRINGPRINT(private_
));
271 case HttpHdrCcType::CC_NO_CACHE
:
273 p
->appendf("=\"" SQUIDSTRINGPH
"\"", SQUIDSTRINGPRINT(no_cache
));
275 case HttpHdrCcType::CC_NO_STORE
:
277 case HttpHdrCcType::CC_NO_TRANSFORM
:
279 case HttpHdrCcType::CC_MUST_REVALIDATE
:
281 case HttpHdrCcType::CC_PROXY_REVALIDATE
:
283 case HttpHdrCcType::CC_MAX_AGE
:
284 p
->appendf("=%d", max_age
);
286 case HttpHdrCcType::CC_S_MAXAGE
:
287 p
->appendf("=%d", s_maxage
);
289 case HttpHdrCcType::CC_MAX_STALE
:
290 /* max-stale's value is optional.
291 If we didn't receive it, don't send it */
292 if (max_stale
!= MAX_STALE_ANY
)
293 p
->appendf("=%d", max_stale
);
295 case HttpHdrCcType::CC_MIN_FRESH
:
296 p
->appendf("=%d", min_fresh
);
298 case HttpHdrCcType::CC_ONLY_IF_CACHED
:
300 case HttpHdrCcType::CC_STALE_IF_ERROR
:
301 p
->appendf("=%d", stale_if_error
);
303 case HttpHdrCcType::CC_IMMUTABLE
:
305 case HttpHdrCcType::CC_OTHER
:
306 case HttpHdrCcType::CC_ENUM_END
:
307 // done below after the loop
315 if (other
.size() != 0)
316 p
->appendf((pcount
? ", " SQUIDSTRINGPH
: SQUIDSTRINGPH
), SQUIDSTRINGPRINT(other
));
320 httpHdrCcUpdateStats(const HttpHdrCc
* cc
, StatHist
* hist
)
324 for (HttpHdrCcType c
= HttpHdrCcType::CC_PUBLIC
; c
< HttpHdrCcType::CC_ENUM_END
; ++c
)
330 httpHdrCcStatDumper(StoreEntry
* sentry
, int, double val
, double, int count
)
332 extern const HttpHeaderStat
*dump_stat
; /* argh! */
333 const int id
= static_cast<int>(val
);
334 const bool valid_id
= id
>= 0 && id
< static_cast<int>(HttpHdrCcType::CC_ENUM_END
);
335 const char *name
= valid_id
? CcAttrs
[id
].name
: "INVALID";
337 if (count
|| valid_id
)
338 storeAppendPrintf(sentry
, "%2d\t %-20s\t %5d\t %6.2f\n",
339 id
, name
, count
, xdiv(count
, dump_stat
->ccParsedCount
));
343 operator<< (std::ostream
&s
, HttpHdrCcType c
)
345 const unsigned char ic
= static_cast<int>(c
);
346 if (c
< HttpHdrCcType::CC_ENUM_END
)
347 s
<< CcAttrs
[ic
].name
<< '[' << ic
<< ']' ;
349 s
<< "*invalid hdrcc* [" << ic
<< ']';