Squid Web Cache master
Loading...
Searching...
No Matches
HttpHdrCc.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 65 HTTP Cache Control Header */
10
11#include "squid.h"
12#include "base/EnumIterator.h"
13#include "base/LookupTable.h"
14#include "HttpHdrCc.h"
15#include "HttpHeader.h"
16#include "HttpHeaderStat.h"
17#include "HttpHeaderTools.h"
18#include "sbuf/SBuf.h"
19#include "SquidMath.h"
20#include "StatHist.h"
21#include "Store.h"
22#include "StrList.h"
23#include "util.h"
24
25#include <map>
26#include <vector>
27#include <optional>
28#include <ostream>
29
31 {"public", HttpHdrCcType::CC_PUBLIC},
32 {"private", HttpHdrCcType::CC_PRIVATE},
33 {"no-cache", HttpHdrCcType::CC_NO_CACHE},
34 {"no-store", HttpHdrCcType::CC_NO_STORE},
35 {"no-transform", HttpHdrCcType::CC_NO_TRANSFORM},
36 {"must-revalidate", HttpHdrCcType::CC_MUST_REVALIDATE},
37 {"proxy-revalidate", HttpHdrCcType::CC_PROXY_REVALIDATE},
38 {"max-age", HttpHdrCcType::CC_MAX_AGE},
39 {"s-maxage", HttpHdrCcType::CC_S_MAXAGE},
40 {"max-stale", HttpHdrCcType::CC_MAX_STALE},
41 {"min-fresh", HttpHdrCcType::CC_MIN_FRESH},
42 {"only-if-cached", HttpHdrCcType::CC_ONLY_IF_CACHED},
43 {"stale-if-error", HttpHdrCcType::CC_STALE_IF_ERROR},
44 {"immutable", HttpHdrCcType::CC_IMMUTABLE},
45 {"Other,", HttpHdrCcType::CC_OTHER}, /* ',' will protect from matches */
47};
48
49constexpr const auto &
51 // TODO: Move these compile-time checks into LookupTable
52 ConstexprForEnum<HttpHdrCcType::CC_PUBLIC, HttpHdrCcType::CC_ENUM_END>([](const auto ev) {
53 const auto idx = static_cast<std::underlying_type<HttpHdrCcType>::type>(ev);
54 // invariant: each row has a name except the last one
55 static_assert(!attrsList[idx].name == (ev == HttpHdrCcType::CC_ENUM_END));
56 // invariant: row[idx].id == idx
57 static_assert(attrsList[idx].id == ev);
58 });
59 return attrsList;
60}
61
62static auto
63ccTypeByName(const SBuf &name) {
64 const static auto table = new LookupTable<HttpHdrCcType>(HttpHdrCcType::CC_OTHER, CcAttrs());
65 return table->lookup(name);
66}
67
70template <typename RawId>
71static std::optional<const char *>
72ccNameByType(const RawId rawId)
73{
74 // TODO: Store a by-ID index in (and move this functionality into) LookupTable.
75 if (!Less(rawId, 0) && Less(rawId, int(HttpHdrCcType::CC_ENUM_END))) {
76 const auto idx = static_cast<std::underlying_type<HttpHdrCcType>::type>(rawId);
77 return CcAttrs()[idx].name;
78 }
79 return std::nullopt;
80}
81
83static HttpHdrCcType &
85{
86 int tmp = (int)aHeader;
87 aHeader = (HttpHdrCcType)(++tmp);
88 return aHeader;
89}
90
91void
93{
94 *this=HttpHdrCc();
95}
96
99void
100HttpHdrCc::setValue(int32_t &value, int32_t new_value, HttpHdrCcType hdr, bool setting)
101{
102 if (setting) {
103 if (new_value < 0) {
104 debugs(65, 3, "rejecting negative-value Cache-Control directive " << hdr
105 << " value " << new_value);
106 return;
107 }
108 } else {
109 new_value = -1; //rely on the convention that "unknown" is -1
110 }
111
112 value = new_value;
113 setMask(hdr,setting);
114}
115
116bool
118{
119 const char *item;
120 const char *p; /* '=' parameter */
121 const char *pos = nullptr;
122 int ilen;
123 int nlen;
124
125 /* iterate through comma separated list */
126
127 while (strListGetItem(&str, ',', &item, &ilen, &pos)) {
128 /* isolate directive name */
129
130 if ((p = (const char *)memchr(item, '=', ilen)) && (p - item < ilen)) {
131 nlen = p - item;
132 ++p;
133 } else {
134 nlen = ilen;
135 }
136
137 /* find type */
138 const auto type = ccTypeByName(SBuf(item, nlen));
139
140 // ignore known duplicate directives
141 if (isSet(type)) {
142 if (type != HttpHdrCcType::CC_OTHER) {
143 debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item << "' in '" << str << "'");
144 continue;
145 }
146 }
147
148 /* special-case-parsing and attribute-setting */
149 switch (type) {
150
152 if (!p || !httpHeaderParseInt(p, &max_age) || max_age < 0) {
153 debugs(65, 2, "cc: invalid max-age specs near '" << item << "'");
154 clearMaxAge();
155 } else {
156 setMask(type,true);
157 }
158 break;
159
161 if (!p || !httpHeaderParseInt(p, &s_maxage) || s_maxage < 0) {
162 debugs(65, 2, "cc: invalid s-maxage specs near '" << item << "'");
163 clearSMaxAge();
164 } else {
165 setMask(type,true);
166 }
167 break;
168
170 if (!p || !httpHeaderParseInt(p, &max_stale) || max_stale < 0) {
171 debugs(65, 2, "cc: max-stale directive is valid without value");
173 } else {
174 setMask(type,true);
175 }
176 break;
177
179 if (!p || !httpHeaderParseInt(p, &min_fresh) || min_fresh < 0) {
180 debugs(65, 2, "cc: invalid min-fresh specs near '" << item << "'");
182 } else {
183 setMask(type,true);
184 }
185 break;
186
188 if (!p || !httpHeaderParseInt(p, &stale_if_error) || stale_if_error < 0) {
189 debugs(65, 2, "cc: invalid stale-if-error specs near '" << item << "'");
191 } else {
192 setMask(type,true);
193 }
194 break;
195
197 String temp;
198 if (!p) {
199 // Value parameter is optional.
200 private_.clean();
201 } else if (/* p &&*/ httpHeaderParseQuotedString(p, (ilen-nlen-1), &temp)) {
202 private_.append(temp);
203 } else {
204 debugs(65, 2, "cc: invalid private= specs near '" << item << "'");
205 }
206 // to be safe we ignore broken parameters, but always remember the 'private' part.
207 setMask(type,true);
208 }
209 break;
210
212 String temp;
213 if (!p) {
214 // On Requests, missing value parameter is expected syntax.
215 // On Responses, value parameter is optional.
216 setMask(type,true);
217 no_cache.clean();
218 } else if (/* p &&*/ httpHeaderParseQuotedString(p, (ilen-nlen-1), &temp)) {
219 // On Requests, a value parameter is invalid syntax.
220 // XXX: identify when parsing request header and dump err message here.
221 setMask(type,true);
222 no_cache.append(temp);
223 } else {
224 debugs(65, 2, "cc: invalid no-cache= specs near '" << item << "'");
225 }
226 }
227 break;
228
230 Public(true);
231 break;
233 noStore(true);
234 break;
236 noTransform(true);
237 break;
239 mustRevalidate(true);
240 break;
242 proxyRevalidate(true);
243 break;
245 onlyIfCached(true);
246 break;
248 Immutable(true);
249 break;
250
252 if (other.size())
253 other.append(", ");
254
255 other.append(item, ilen);
256 break;
257
258 default:
259 /* note that we ignore most of '=' specs (RFCVIOLATION) */
260 break;
261 }
262 }
263
264 return (mask != 0);
265}
266
267void
269{
270 // optimization: if the mask is empty do nothing
271 if (mask==0)
272 return;
273
274 HttpHdrCcType flag;
275 int pcount = 0;
276 assert(p);
277
278 for (flag = HttpHdrCcType::CC_PUBLIC; flag < HttpHdrCcType::CC_ENUM_END; ++flag) {
279 if (isSet(flag) && flag != HttpHdrCcType::CC_OTHER) {
280
281 /* print option name for all options */
282 p->appendf((pcount ? ", %s": "%s"), *ccNameByType(flag));
283
284 /* for all options having values, "=value" after the name */
285 switch (flag) {
287 break;
289 if (private_.size())
291 break;
292
294 if (no_cache.size())
296 break;
298 break;
300 break;
302 break;
304 break;
306 p->appendf("=%d", max_age);
307 break;
309 p->appendf("=%d", s_maxage);
310 break;
312 /* max-stale's value is optional.
313 If we didn't receive it, don't send it */
315 p->appendf("=%d", max_stale);
316 break;
318 p->appendf("=%d", min_fresh);
319 break;
321 break;
323 p->appendf("=%d", stale_if_error);
324 break;
326 break;
329 // done below after the loop
330 break;
331 }
332
333 ++pcount;
334 }
335 }
336
337 if (other.size() != 0)
339}
340
341void
343{
344 assert(cc);
345
347 if (cc->isSet(c))
348 hist->count(c);
349}
350
351void
352httpHdrCcStatDumper(StoreEntry * sentry, int, double val, double, int count)
353{
354 extern const HttpHeaderStat *dump_stat; /* argh! */
355 const int id = static_cast<int>(val);
356 const auto name = ccNameByType(id);
357 if (count || name)
358 storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
359 id, name.value_or("INVALID"), count, xdiv(count, dump_stat->ccParsedCount));
360}
361
362std::ostream &
363operator<< (std::ostream &s, HttpHdrCcType c)
364{
365 s << ccNameByType(c).value_or("INVALID") << '[' << static_cast<int>(c) << ']';
366 return s;
367}
368
void httpHdrCcUpdateStats(const HttpHdrCc *cc, StatHist *hist)
Definition HttpHdrCc.cc:342
static auto ccTypeByName(const SBuf &name)
Definition HttpHdrCc.cc:63
constexpr LookupTable< HttpHdrCcType >::Record attrsList[]
Definition HttpHdrCc.cc:30
std::ostream & operator<<(std::ostream &s, HttpHdrCcType c)
Definition HttpHdrCc.cc:363
static std::optional< const char * > ccNameByType(const RawId rawId)
Definition HttpHdrCc.cc:72
void httpHdrCcStatDumper(StoreEntry *sentry, int, double val, double, int count)
Definition HttpHdrCc.cc:352
constexpr const auto & CcAttrs()
Definition HttpHdrCc.cc:50
static HttpHdrCcType & operator++(HttpHdrCcType &aHeader)
used to walk a table of http_header_cc_type structs
Definition HttpHdrCc.cc:84
HttpHdrCcType
Definition HttpHdrCc.h:20
@ CC_MUST_REVALIDATE
Definition HttpHdrCc.h:26
@ CC_S_MAXAGE
Definition HttpHdrCc.h:29
@ CC_ONLY_IF_CACHED
Definition HttpHdrCc.h:32
@ CC_OTHER
Definition HttpHdrCc.h:35
@ CC_ENUM_END
Definition HttpHdrCc.h:36
@ CC_NO_STORE
Definition HttpHdrCc.h:24
@ CC_PUBLIC
Definition HttpHdrCc.h:21
@ CC_PRIVATE
Definition HttpHdrCc.h:22
@ CC_MAX_STALE
Definition HttpHdrCc.h:30
@ CC_STALE_IF_ERROR
Definition HttpHdrCc.h:33
@ CC_IMMUTABLE
Definition HttpHdrCc.h:34
@ CC_PROXY_REVALIDATE
Definition HttpHdrCc.h:27
@ CC_NO_CACHE
Definition HttpHdrCc.h:23
@ CC_MAX_AGE
Definition HttpHdrCc.h:28
@ CC_NO_TRANSFORM
Definition HttpHdrCc.h:25
@ CC_MIN_FRESH
Definition HttpHdrCc.h:31
int httpHeaderParseInt(const char *start, int *value)
const HttpHeaderStat * dump_stat
int httpHeaderParseQuotedString(const char *start, const int len, String *val)
constexpr bool Less(const A a, const B b)
whether integer a is less than integer b, with correct overflow handling
Definition SquidMath.h:48
#define SQUIDSTRINGPH
Definition SquidString.h:22
#define SQUIDSTRINGPRINT(s)
Definition SquidString.h:23
int strListGetItem(const String *str, char del, const char **item, int *ilen, const char **pos)
Definition StrList.cc:78
#define assert(EX)
Definition assert.h:17
void clear()
reset data-members to default state
Definition HttpHdrCc.cc:92
String no_cache
List of headers sent as value for CC:no-cache="...". May be empty/undefined if the value is missing.
Definition HttpHdrCc.h:180
void mustRevalidate(bool v)
Definition HttpHdrCc.h:113
void clearMinFresh()
Definition HttpHdrCc.h:142
void Immutable(bool v)
Definition HttpHdrCc.h:156
void Public(bool v)
Definition HttpHdrCc.h:70
void noTransform(bool v)
Definition HttpHdrCc.h:108
void setMask(HttpHdrCcType id, bool newval=true)
low-level part of the public set method, performs no checks
Definition HttpHdrCc.h:194
bool parse(const String &s)
parse a header-string and fill in appropriate values.
Definition HttpHdrCc.cc:117
void clearMaxAge()
Definition HttpHdrCc.h:124
bool isSet(HttpHdrCcType id) const
check whether the attribute value supplied by id is set
Definition HttpHdrCc.h:160
String private_
List of headers sent as value for CC:private="...". May be empty/undefined if the value is missing.
Definition HttpHdrCc.h:179
int32_t max_stale
Definition HttpHdrCc.h:176
void onlyIfCached(bool v)
Definition HttpHdrCc.h:146
void clearSMaxAge()
Definition HttpHdrCc.h:129
static const int32_t MAX_STALE_ANY
Definition HttpHdrCc.h:53
void setValue(int32_t &value, int32_t new_value, HttpHdrCcType hdr, bool setting=true)
Definition HttpHdrCc.cc:100
int32_t mask
Definition HttpHdrCc.h:173
int32_t min_fresh
Definition HttpHdrCc.h:178
void clearStaleIfError()
Definition HttpHdrCc.h:152
int32_t max_age
Definition HttpHdrCc.h:174
void noStore(bool v)
Definition HttpHdrCc.h:103
String other
Definition HttpHdrCc.h:207
void maxStale(int32_t v)
Definition HttpHdrCc.h:136
void proxyRevalidate(bool v)
Definition HttpHdrCc.h:118
int32_t s_maxage
Definition HttpHdrCc.h:175
void packInto(Packable *p) const
Definition HttpHdrCc.cc:268
int32_t stale_if_error
Definition HttpHdrCc.h:177
HTTP per header statistics.
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition Packable.h:61
Definition SBuf.h:94
void count(double val)
Definition StatHist.cc:55
void clean()
Definition String.cc:104
void append(char const *buf, int len)
Definition String.cc:131
size_type size() const
Definition SquidString.h:74
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition store.cc:855
int unsigned int
Definition stub_fd.cc:19
double xdiv(double nom, double denom)
Definition util.cc:53