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

 

Introduction

Documentation

Support

Miscellaneous