HttpHdrSc.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2022 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 90 HTTP Cache Control Header */
10
11#include "squid.h"
12#include "base/LookupTable.h"
13//#include "HttpHdrSc.h" // pulled in by HttpHdrScTarget.h
14#include "HttpHdrScTarget.h"
15#include "HttpHeader.h"
16#include "HttpHeaderFieldStat.h"
17#include "HttpHeaderStat.h"
18#include "HttpHeaderTools.h"
19#include "Store.h"
20#include "StrList.h"
21#include "util.h"
22
23#include <map>
24#include <vector>
25
26/* this table is used for parsing surrogate control header */
27/* order must match that of enum http_hdr_sc_type. The constraint is verified at initialization time */
28// TODO: implement constraint
30 {"no-store", SC_NO_STORE},
31 {"no-store-remote", SC_NO_STORE_REMOTE},
32 {"max-age", SC_MAX_AGE},
33 {"content", SC_CONTENT},
34 {"Other,", SC_OTHER}, /* ',' will protect from matches */
35 {nullptr, SC_ENUM_END} /* SC_ENUM_END taken as invalid value */
36};
38std::vector<HttpHeaderFieldStat> scHeaderStats(SC_ENUM_END);
39
40// used when iterating over flags
42{
43 int tmp = static_cast<int>(aHeader);
44 aHeader = static_cast<http_hdr_sc_type>(++tmp);
45 return aHeader;
46}
47
48void
50{
51 // check invariant on ScAttrs
52 for (int i = 0; ScAttrs[i].name != nullptr; ++i)
53 assert(i == ScAttrs[i].id);
54}
55
56/* implementation */
57
58/* creates an sc object from a 0-terminating string */
61{
62 HttpHdrSc *sc = new HttpHdrSc();
63
64 if (!sc->parse(&str)) {
65 delete sc;
66 sc = nullptr;
67 }
68
69 return sc;
70}
71
72/* parses a 0-terminating string and inits sc */
73bool
75{
76 HttpHdrSc * sc=this;
77 const char *item;
78 const char *p; /* '=' parameter */
79 const char *pos = nullptr;
80 const char *target = nullptr; /* ;foo */
81 const char *temp = nullptr; /* temp buffer */
83 int ilen, vlen;
84 int initiallen;
85 HttpHdrScTarget *sct;
86 assert(str);
87
88 /* iterate through comma separated list */
89
90 while (strListGetItem(str, ',', &item, &ilen, &pos)) {
91 initiallen = ilen;
92 vlen = 0;
93 /* decrease ilen to still match the token for '=' statements */
94
95 if ((p = strchr(item, '=')) && (p - item < ilen)) {
96 vlen = ilen - (p + 1 - item);
97 ilen = p - item;
98 ++p;
99 }
100
101 /* decrease ilen to still match the token for ';' qualified non '=' statements */
102 else if ((p = strchr(item, ';')) && (p - item < ilen)) {
103 ilen = p - item;
104 ++p;
105 }
106
107 /* find type */
108 type = scLookupTable.lookup(SBuf(item,ilen));
109
110 if (type == SC_ENUM_END) {
111 debugs(90, 2, "unknown control-directive near '" << item << "' in '" << *str << "'");
112 type = SC_OTHER;
113 }
114
115 /* Is this a targeted directive? */
116 /* TODO: remove the temporary usage and use memrchr and the information we have instead */
117 temp = xstrndup (item, initiallen + 1);
118
119 if (!((target = strrchr (temp, ';')) && !strchr (target, '"') && *(target + 1) != '\0'))
120 target = nullptr;
121 else
122 ++target;
123
124 sct = sc->findTarget(target);
125
126 if (!sct) {
127 // XXX: if parse is left-to-right over field-value this should be emplace_back()
128 // currently placing on the front reverses the order of headers passed on downstream.
129 targets.emplace_front(target);
130 sct = &targets.front();
131 }
132
133 safe_free (temp);
134
135 if (sct->isSet(type)) {
136 if (type != SC_OTHER)
137 debugs(90, 2, "ignoring duplicate control-directive near '" << item << "' in '" << *str << "'");
138
139 ++ scHeaderStats[type].repCount;
140
141 continue;
142 }
143
144 /* process directives */
145 switch (type) {
146 case SC_NO_STORE:
147 sct->noStore(true);
148 break;
149
151 sct->noStoreRemote(true);
152 break;
153
154 case SC_MAX_AGE: {
155 int ma;
156 if (p && httpHeaderParseInt(p, &ma)) {
157 sct->maxAge(ma);
158
159 if ((p = strchr (p, '+'))) {
160 int ms;
161 ++p; //skip the + char
162 if (httpHeaderParseInt(p, &ms)) {
163 sct->maxStale(ms);
164 } else {
165 debugs(90, 2, "sc: invalid max-stale specs near '" << item << "'");
166 sct->clearMaxStale();
167 /* leave the max-age alone */
168 }
169 }
170 } else {
171 debugs(90, 2, "sc: invalid max-age specs near '" << item << "'");
172 sct->clearMaxAge();
173 }
174
175 break;
176 }
177
178 case SC_CONTENT:
179
180 if ( p && httpHeaderParseQuotedString(p, vlen, &sct->content_)) {
181 sct->setMask(SC_CONTENT,true); // ugly but saves a copy
182 } else {
183 debugs(90, 2, "sc: invalid content= quoted string near '" << item << "'");
184 sct->clearContent();
185 }
186 break;
187
188 case SC_OTHER:
189 default:
190 break;
191 }
192 }
193
194 return !sc->targets.empty();
195}
196
198void
200{
201 http_hdr_sc_type flag;
202 int pcount = 0;
203 assert (p);
204
205 for (flag = SC_NO_STORE; flag < SC_ENUM_END; ++flag) {
206 if (isSet(flag) && flag != SC_OTHER) {
207
208 /* print option name */
209 p->appendf((pcount ? ", %s" : "%s"), ScAttrs[flag].name);
210
211 /* handle options with values */
212
213 if (flag == SC_MAX_AGE)
214 p->appendf("=%d", (int) max_age);
215
216 if (flag == SC_CONTENT)
218
219 ++pcount;
220 }
221 }
222
223 if (hasTarget())
225}
226
227void
229{
230 assert(p);
231 for (const auto &t : targets) {
232 t.packInto(p);
233 }
234}
235
236/* negative max_age will clean old max_Age setting */
237void
238HttpHdrSc::setMaxAge(char const *target, int max_age)
239{
240 HttpHdrScTarget *sct = findTarget(target);
241
242 if (!sct) {
243 targets.emplace_back(target);
244 sct = &targets.back();
245 }
246
247 sct->maxAge(max_age);
248}
249
250void
252{
253 for (auto &t : targets) {
254 t.updateStats(hist);
255 }
256}
257
258void
259httpHdrScTargetStatDumper(StoreEntry * sentry, int, double val, double, int count)
260{
261 extern const HttpHeaderStat *dump_stat; /* argh! */
262 const int id = (int) val;
263 const bool valid_id = id >= 0 && id < SC_ENUM_END;
264 const char *name = valid_id ? ScAttrs[id].name : "INVALID";
265
266 if (count || valid_id)
267 storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
268 id, name, count, xdiv(count, dump_stat->scParsedCount));
269}
270
271void
272httpHdrScStatDumper(StoreEntry * sentry, int, double val, double, int count)
273{
274 extern const HttpHeaderStat *dump_stat; /* argh! */
275 const int id = (int) val;
276 const bool valid_id = id >= 0 && id < SC_ENUM_END;
277 const char *name = valid_id ? ScAttrs[id].name : "INVALID";
278
279 if (count || valid_id)
280 storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
281 id, name, count, xdiv(count, dump_stat->scParsedCount));
282}
283
285HttpHdrSc::findTarget(const char *target)
286{
287 for (auto &sct : targets) {
288 if (sct.target.cmp(target) == 0)
289 return &sct;
290 }
291
292 return nullptr;
293}
294
296HttpHdrSc::getMergedTarget(const char *ourtarget)
297{
298 HttpHdrScTarget *sctus = findTarget(ourtarget);
299 HttpHdrScTarget *sctgeneric = findTarget(nullptr);
300
301 /* W3C Edge Architecture Specification 1.0 section 3
302 *
303 * "If more than one is targeted at a surrogate, the most specific applies.
304 * For example,
305 * Surrogate-Control: max-age=60, no-store;abc
306 * The surrogate that identified itself as 'abc' would apply no-store;
307 * others would apply max-age=60.
308 *
309 * XXX: the if statements below will *merge* the no-store and max-age settings.
310 */
311 if (sctgeneric || sctus) {
312 HttpHdrScTarget *sctusable = new HttpHdrScTarget(nullptr);
313
314 if (sctgeneric)
315 sctusable->mergeWith(sctgeneric);
316
317 if (sctus)
318 sctusable->mergeWith(sctus);
319
320 return sctusable;
321 }
322
323 return nullptr;
324}
325
void httpHdrScStatDumper(StoreEntry *sentry, int, double val, double, int count)
Definition: HttpHdrSc.cc:272
http_hdr_sc_type & operator++(http_hdr_sc_type &aHeader)
Definition: HttpHdrSc.cc:41
std::vector< HttpHeaderFieldStat > scHeaderStats(SC_ENUM_END)
LookupTable< http_hdr_sc_type > scLookupTable(SC_ENUM_END, ScAttrs)
void httpHdrScTargetStatDumper(StoreEntry *sentry, int, double val, double, int count)
Definition: HttpHdrSc.cc:259
static const LookupTable< http_hdr_sc_type >::Record ScAttrs[]
Definition: HttpHdrSc.cc:29
HttpHdrSc * httpHdrScParseCreate(const String &str)
Definition: HttpHdrSc.cc:60
void httpHdrScInitModule(void)
Definition: HttpHdrSc.cc:49
int httpHeaderParseInt(const char *start, int *value)
const HttpHeaderStat * dump_stat
Definition: HttpHeader.cc:1558
int httpHeaderParseQuotedString(const char *start, const int len, String *val)
#define SQUIDSTRINGPH
Definition: SquidString.h:21
#define SQUIDSTRINGPRINT(s)
Definition: SquidString.h:22
int strListGetItem(const String *str, char del, const char **item, int *ilen, const char **pos)
Definition: StrList.cc:86
#define assert(EX)
Definition: assert.h:19
void maxAge(int v)
void noStore(bool v)
bool isSet(http_hdr_sc_type id) const
void mergeWith(const HttpHdrScTarget *new_sc)
bool hasTarget() const
void setMask(http_hdr_sc_type id, bool newval)
void packInto(Packable *p) const
XXX: this function should be in HttpHdrScTarget.cc.
Definition: HttpHdrSc.cc:199
void noStoreRemote(bool v)
void maxStale(int v)
void setMaxAge(char const *target, int max_age)
Definition: HttpHdrSc.cc:238
void packInto(Packable *p) const
Definition: HttpHdrSc.cc:228
HttpHdrScTarget * findTarget(const char *target)
Definition: HttpHdrSc.cc:285
std::list< HttpHdrScTarget, PoolingAllocator< HttpHdrScTarget > > targets
Definition: HttpHdrSc.h:38
HttpHdrScTarget * getMergedTarget(const char *ourtarget)
Definition: HttpHdrSc.cc:296
bool parse(const String *str)
Definition: HttpHdrSc.cc:74
void updateStats(StatHist *) const
Definition: HttpHdrSc.cc:251
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
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
int type
Definition: errorpage.cc:152
http_hdr_sc_type
Definition: forward.h:31
@ SC_OTHER
Definition: forward.h:36
@ SC_CONTENT
Definition: forward.h:35
@ SC_NO_STORE
Definition: forward.h:32
@ SC_NO_STORE_REMOTE
Definition: forward.h:33
@ SC_ENUM_END
Definition: forward.h:37
@ SC_MAX_AGE
Definition: forward.h:34
static int sc[16]
Definition: smbdes.c:121
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:828
int unsigned int
Definition: stub_fd.cc:19
SQUIDCEXTERN double xdiv(double nom, double denom)
Definition: util.c:53
#define safe_free(x)
Definition: xalloc.h:73
char * xstrndup(const char *s, size_t n)
Definition: xstring.cc:56

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors