HttpHdrSc.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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 std::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 
48 void
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 */
59 HttpHdrSc *
61 {
62  HttpHdrSc *sc = new HttpHdrSc();
63 
64  if (!sc->parse(&str)) {
65  delete sc;
66  sc = NULL;
67  }
68 
69  return sc;
70 }
71 
72 /* parses a 0-terminating string and inits sc */
73 bool
75 {
76  HttpHdrSc * sc=this;
77  const char *item;
78  const char *p; /* '=' parameter */
79  const char *pos = NULL;
80  const char *target = NULL; /* ;foo */
81  const char *temp = NULL; /* 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 '=' statments */
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, "hdr sc: unknown control-directive: near '" << item << "' in '" << str << "'");
112  type = SC_OTHER;
113  }
114 
115  /* Is this a targeted directive? */
116  /* TODO: remove the temporary useage 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 = NULL;
121  else
122  ++target;
123 
124  sct = sc->findTarget(target);
125 
126  if (!sct) {
127  sct = new HttpHdrScTarget(target);
128  addTarget(sct);
129  }
130 
131  safe_free (temp);
132 
133  if (sct->isSet(type)) {
134  if (type != SC_OTHER)
135  debugs(90, 2, "hdr sc: ignoring duplicate control-directive: near '" << item << "' in '" << str << "'");
136 
137  ++ scHeaderStats[type].repCount;
138 
139  continue;
140  }
141 
142  /* process directives */
143  switch (type) {
144  case SC_NO_STORE:
145  sct->noStore(true);
146  break;
147 
148  case SC_NO_STORE_REMOTE:
149  sct->noStoreRemote(true);
150  break;
151 
152  case SC_MAX_AGE: {
153  int ma;
154  if (p && httpHeaderParseInt(p, &ma)) {
155  sct->maxAge(ma);
156 
157  if ((p = strchr (p, '+'))) {
158  int ms;
159  ++p; //skip the + char
160  if (httpHeaderParseInt(p, &ms)) {
161  sct->maxStale(ms);
162  } else {
163  debugs(90, 2, "sc: invalid max-stale specs near '" << item << "'");
164  sct->clearMaxStale();
165  /* leave the max-age alone */
166  }
167  }
168  } else {
169  debugs(90, 2, "sc: invalid max-age specs near '" << item << "'");
170  sct->clearMaxAge();
171  }
172 
173  break;
174  }
175 
176  case SC_CONTENT:
177 
178  if ( p && httpHeaderParseQuotedString(p, vlen, &sct->content_)) {
179  sct->setMask(SC_CONTENT,true); // ugly but saves a copy
180  } else {
181  debugs(90, 2, "sc: invalid content= quoted string near '" << item << "'");
182  sct->clearContent();
183  }
184  break;
185 
186  case SC_OTHER:
187  default:
188  break;
189  }
190  }
191 
192  return sc->targets.head != NULL;
193 }
194 
196 {
197  if (targets.head) {
198  dlink_node *sct = targets.head;
199 
200  while (sct) {
201  HttpHdrScTarget *t = static_cast<HttpHdrScTarget *>(sct->data);
202  sct = sct->next;
203  dlinkDelete (&t->node, &targets);
204  delete t;
205  }
206  }
207 }
208 
210 {
211  dlink_node *node = sc.targets.head;
212 
213  while (node) {
214  HttpHdrScTarget *dupsct = new HttpHdrScTarget(*static_cast<HttpHdrScTarget *>(node->data));
215  addTargetAtTail(dupsct);
216  node = node->next;
217  }
218 }
219 
220 void
222 {
223  http_hdr_sc_type flag;
224  int pcount = 0;
225  assert (p);
226 
227  for (flag = SC_NO_STORE; flag < SC_ENUM_END; ++flag) {
228  if (isSet(flag) && flag != SC_OTHER) {
229 
230  /* print option name */
231  p->appendf((pcount ? ", %s" : "%s"), ScAttrs[flag].name);
232 
233  /* handle options with values */
234 
235  if (flag == SC_MAX_AGE)
236  p->appendf("=%d", (int) max_age);
237 
238  if (flag == SC_CONTENT)
240 
241  ++pcount;
242  }
243  }
244 
245  if (hasTarget())
247 }
248 
249 void
251 {
252  dlink_node *node;
253  assert(p);
254  node = targets.head;
255 
256  while (node) {
257  static_cast<HttpHdrScTarget *>(node->data)->packInto(p);
258  node = node->next;
259  }
260 }
261 
262 /* negative max_age will clean old max_Age setting */
263 void
264 HttpHdrSc::setMaxAge(char const *target, int max_age)
265 {
266  HttpHdrScTarget *sct = findTarget(target);
267 
268  if (!sct) {
269  sct = new HttpHdrScTarget(target);
270  dlinkAddTail (sct, &sct->node, &targets);
271  }
272 
273  sct->maxAge(max_age);
274 }
275 
276 void
278 {
279  dlink_node *sct = targets.head;
280 
281  while (sct) {
282  static_cast<HttpHdrScTarget *>(sct->data)->updateStats(hist);
283  sct = sct->next;
284  }
285 }
286 
287 void
288 httpHdrScTargetStatDumper(StoreEntry * sentry, int, double val, double, int count)
289 {
290  extern const HttpHeaderStat *dump_stat; /* argh! */
291  const int id = (int) val;
292  const bool valid_id = id >= 0 && id < SC_ENUM_END;
293  const char *name = valid_id ? ScAttrs[id].name : "INVALID";
294 
295  if (count || valid_id)
296  storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
297  id, name, count, xdiv(count, dump_stat->scParsedCount));
298 }
299 
300 void
301 httpHdrScStatDumper(StoreEntry * sentry, int, double val, double, int count)
302 {
303  extern const HttpHeaderStat *dump_stat; /* argh! */
304  const int id = (int) val;
305  const bool valid_id = id >= 0 && id < SC_ENUM_END;
306  const char *name = valid_id ? ScAttrs[id].name : "INVALID";
307 
308  if (count || valid_id)
309  storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
310  id, name, count, xdiv(count, dump_stat->scParsedCount));
311 }
312 
314 HttpHdrSc::findTarget(const char *target)
315 {
316  dlink_node *node;
317  node = targets.head;
318 
319  while (node) {
320  HttpHdrScTarget *sct = (HttpHdrScTarget *)node->data;
321 
322  if (target && sct->target.size() > 0 && !strcmp(target, sct->target.termedBuf()))
323  return sct;
324  else if (!target && sct->target.size() == 0)
325  return sct;
326 
327  node = node->next;
328  }
329 
330  return NULL;
331 }
332 
334 HttpHdrSc::getMergedTarget(const char *ourtarget)
335 {
336  HttpHdrScTarget *sctus = findTarget(ourtarget);
337  HttpHdrScTarget *sctgeneric = findTarget(NULL);
338 
339  if (sctgeneric || sctus) {
340  HttpHdrScTarget *sctusable = new HttpHdrScTarget(NULL);
341 
342  if (sctgeneric)
343  sctusable->mergeWith(sctgeneric);
344 
345  if (sctus)
346  sctusable->mergeWith(sctus);
347 
348  return sctusable;
349  }
350 
351  return NULL;
352 }
353 
354 void
356  dlinkAdd(t, &t->node, &targets);
357 }
358 
359 void
361  dlinkAddTail (t, &t->node, &targets);
362 }
363 
std::vector< HttpHeaderFieldStat > scHeaderStats(SC_ENUM_END)
void packInto(Packable *p) const
Definition: HttpHdrSc.cc:221
void maxStale(int v)
HttpHdrSc * httpHdrScParseCreate(const String &str)
Definition: HttpHdrSc.cc:60
#define SQUIDSTRINGPH
Definition: SquidString.h:20
int strListGetItem(const String *str, char del, const char **item, int *ilen, const char **pos)
Definition: StrList.cc:77
void httpHdrScInitModule(void)
Definition: HttpHdrSc.cc:49
#define assert(EX)
Definition: assert.h:17
#define SQUIDSTRINGPRINT(s)
Definition: SquidString.h:21
static int sc[16]
Definition: smbdes.c:121
void noStore(bool v)
int httpHeaderParseQuotedString(const char *start, const int len, String *val)
int type
Definition: errorpage.cc:79
Definition: SBuf.h:87
HttpHdrSc()
Definition: HttpHdrSc.h:37
int i
Definition: membanger.c:49
char * xstrndup(const char *s, size_t n)
Definition: xstring.cc:56
#define safe_free(x)
Definition: xalloc.h:73
static const LookupTable< http_hdr_sc_type >::Record ScAttrs[]
Definition: HttpHdrSc.cc:29
void addTarget(HttpHdrScTarget *t)
Definition: HttpHdrSc.cc:355
char * p
Definition: membanger.c:43
HttpHdrScTarget * getMergedTarget(const char *ourtarget)
Definition: HttpHdrSc.cc:334
size_type size() const
Definition: SquidString.h:71
http_hdr_sc_type & operator++(http_hdr_sc_type &aHeader)
Definition: HttpHdrSc.cc:41
bool hasTarget() const
Definition: parse.c:104
bool parse(const String *str)
Definition: HttpHdrSc.cc:74
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
void httpHdrScStatDumper(StoreEntry *sentry, int, double val, double, int count)
Definition: HttpHdrSc.cc:301
LookupTable< http_hdr_sc_type > scLookupTable(SC_ENUM_END, ScAttrs)
dlink_list targets
Definition: HttpHdrSc.h:48
char const * termedBuf() const
Definition: SquidString.h:90
HttpHdrScTarget * findTarget(const char *target)
Definition: HttpHdrSc.cc:314
void updateStats(StatHist *) const
Definition: HttpHdrSc.cc:277
void setMaxAge(char const *target, int max_age)
Definition: HttpHdrSc.cc:264
void httpHdrScTargetStatDumper(StoreEntry *sentry, int, double val, double, int count)
Definition: HttpHdrSc.cc:288
HTTP per header statistics.
bool SIGHDLR int STUB void int
Definition: stub_tools.cc:68
void maxAge(int v)
bool isSet(http_hdr_sc_type id) const
SQUIDCEXTERN double xdiv(double nom, double denom)
Definition: util.c:72
void packInto(Packable *p) const
Definition: HttpHdrSc.cc:250
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
void addTargetAtTail(HttpHdrScTarget *t)
Definition: HttpHdrSc.cc:360
void setMask(http_hdr_sc_type id, bool newval)
const HttpHeaderStat * dump_stat
Definition: HttpHeader.cc:1565
http_hdr_sc_type
Definition: HttpHdrSc.h:21
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:904
#define NULL
Definition: types.h:166
int httpHeaderParseInt(const char *start, int *value)
void mergeWith(const HttpHdrScTarget *new_sc)
void noStoreRemote(bool v)

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors