]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpHdrCc.cc
MemBuf implements Packable interface
[thirdparty/squid.git] / src / HttpHdrCc.cc
CommitLineData
7faf2bdb 1/*
bde978a6 2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
7faf2bdb 3 *
bbc27441
AJ
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.
7faf2bdb 7 */
8
bbc27441
AJ
9/* DEBUG: section 65 HTTP Cache Control Header */
10
582c2af2 11#include "squid.h"
602d9612 12#include "HttpHdrCc.h"
e6ccf245 13#include "HttpHeader.h"
db2de30a 14#include "HttpHeaderFieldStat.h"
e1656dc4 15#include "HttpHeaderStat.h"
a5bac1d2 16#include "HttpHeaderTools.h"
f2853dd9 17#include "SBuf.h"
00a7574e
FC
18#include "StatHist.h"
19#include "Store.h"
28204b3b 20#include "StrList.h"
ed6e9fb9 21#include "util.h"
ce394734 22
ce394734 23#include <map>
ce394734 24
d4cb5913 25/* a row in the table used for parsing cache control header and statistics */
26735116
AJ
26class HttpHeaderCcFields
27{
28public:
29 HttpHeaderCcFields() : name(NULL), id(CC_BADHDR), stat() {}
30 HttpHeaderCcFields(const char *aName, http_hdr_cc_type aTypeId) : name(aName), id(aTypeId) {}
95cc1e3e 31 HttpHeaderCcFields(const HttpHeaderCcFields &f) : name(f.name), id(f.id) {}
26735116
AJ
32 // nothing to do as name is a pointer to global static string
33 ~HttpHeaderCcFields() {}
34
ce394734
FC
35 const char *name;
36 http_hdr_cc_type id;
37 HttpHeaderFieldStat stat;
26735116
AJ
38
39private:
26735116
AJ
40 HttpHeaderCcFields &operator =(const HttpHeaderCcFields &); // not implemented
41};
ce394734
FC
42
43/* order must match that of enum http_hdr_cc_type. The constraint is verified at initialization time */
44static HttpHeaderCcFields CcAttrs[CC_ENUM_END] = {
95cc1e3e
FC
45 HttpHeaderCcFields("public", CC_PUBLIC),
46 HttpHeaderCcFields("private", CC_PRIVATE),
47 HttpHeaderCcFields("no-cache", CC_NO_CACHE),
48 HttpHeaderCcFields("no-store", CC_NO_STORE),
49 HttpHeaderCcFields("no-transform", CC_NO_TRANSFORM),
50 HttpHeaderCcFields("must-revalidate", CC_MUST_REVALIDATE),
51 HttpHeaderCcFields("proxy-revalidate", CC_PROXY_REVALIDATE),
52 HttpHeaderCcFields("max-age", CC_MAX_AGE),
53 HttpHeaderCcFields("s-maxage", CC_S_MAXAGE),
54 HttpHeaderCcFields("max-stale", CC_MAX_STALE),
55 HttpHeaderCcFields("min-fresh", CC_MIN_FRESH),
56 HttpHeaderCcFields("only-if-cached", CC_ONLY_IF_CACHED),
57 HttpHeaderCcFields("stale-if-error", CC_STALE_IF_ERROR),
58 HttpHeaderCcFields("Other,", CC_OTHER) /* ',' will protect from matches */
26ac0430 59};
62e76326 60
ce394734 61/// Map an header name to its type, to expedite parsing
f2853dd9 62typedef std::map<const SBuf,http_hdr_cc_type> CcNameToIdMap_t;
7ebe76de 63static CcNameToIdMap_t CcNameToIdMap;
7faf2bdb 64
d74ad83f 65/// used to walk a table of http_header_cc_type structs
e6ccf245 66http_hdr_cc_type &operator++ (http_hdr_cc_type &aHeader)
67{
1f1ae50a 68 int tmp = (int)aHeader;
69 aHeader = (http_hdr_cc_type)(++tmp);
e6ccf245 70 return aHeader;
71}
72
c23f7c32 73/// Module initialization hook
7faf2bdb 74void
9bc73deb 75httpHdrCcInitModule(void)
7faf2bdb 76{
ce394734 77 /* build lookup and accounting structures */
77da1817 78 for (int32_t i = 0; i < CC_ENUM_END; ++i) {
46cba5d3
FC
79 const HttpHeaderCcFields &f=CcAttrs[i];
80 assert(i == f.id); /* verify assumption: the id is the key into the array */
f2853dd9 81 const SBuf k(f.name);
46cba5d3 82 CcNameToIdMap[k]=f.id;
ce394734 83 }
de336bbe 84}
85
c23f7c32 86/// Module cleanup hook.
de336bbe 87void
9bc73deb 88httpHdrCcCleanModule(void)
de336bbe 89{
ce394734 90 // HdrCcNameToIdMap is self-cleaning
7faf2bdb 91}
92
ce394734
FC
93void
94HttpHdrCc::clear()
7faf2bdb 95{
7ebe76de 96 *this=HttpHdrCc();
7faf2bdb 97}
98
ce394734 99bool
7ebe76de 100HttpHdrCc::parse(const String & str)
7faf2bdb 101{
102 const char *item;
f53969cc 103 const char *p; /* '=' parameter */
7faf2bdb 104 const char *pos = NULL;
e6ccf245 105 http_hdr_cc_type type;
7faf2bdb 106 int ilen;
1b2e9616 107 int nlen;
7faf2bdb 108
7faf2bdb 109 /* iterate through comma separated list */
62e76326 110
ce394734 111 while (strListGetItem(&str, ',', &item, &ilen, &pos)) {
1b2e9616 112 /* isolate directive name */
62e76326 113
a38ec4b1
FC
114 if ((p = (const char *)memchr(item, '=', ilen)) && (p - item < ilen)) {
115 nlen = p - item;
116 ++p;
117 } else {
1b2e9616 118 nlen = ilen;
a38ec4b1 119 }
62e76326 120
121 /* find type */
f2853dd9 122 const CcNameToIdMap_t::const_iterator i=CcNameToIdMap.find(SBuf(item,nlen));
7ebe76de 123 if (i==CcNameToIdMap.end())
ce394734
FC
124 type=CC_OTHER;
125 else
126 type=i->second;
62e76326 127
aa62670a 128 // ignore known duplicate directives
f9517ad8 129 if (isSet(type)) {
aa62670a 130 if (type != CC_OTHER) {
e8466ea9 131 debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item << "' in '" << str << "'");
7ebe76de 132 ++CcAttrs[type].stat.repCount;
aa62670a
AR
133 continue;
134 }
62e76326 135 }
136
4ce6e3b5 137 /* special-case-parsing and attribute-setting */
62e76326 138 switch (type) {
139
140 case CC_MAX_AGE:
d74ad83f 141 if (!p || !httpHeaderParseInt(p, &max_age) || max_age < 0) {
bf8fe701 142 debugs(65, 2, "cc: invalid max-age specs near '" << item << "'");
4ce6e3b5 143 clearMaxAge();
1ba0611a 144 } else {
d74ad83f 145 setMask(type,true);
62e76326 146 }
62e76326 147 break;
148
149 case CC_S_MAXAGE:
d74ad83f 150 if (!p || !httpHeaderParseInt(p, &s_maxage) || s_maxage < 0) {
bf8fe701 151 debugs(65, 2, "cc: invalid s-maxage specs near '" << item << "'");
4ce6e3b5 152 clearSMaxAge();
d74ad83f
FC
153 } else {
154 setMask(type,true);
62e76326 155 }
62e76326 156 break;
157
158 case CC_MAX_STALE:
d74ad83f 159 if (!p || !httpHeaderParseInt(p, &max_stale) || max_stale < 0) {
bf8fe701 160 debugs(65, 2, "cc: max-stale directive is valid without value");
d74ad83f
FC
161 maxStale(MAX_STALE_ANY);
162 } else {
163 setMask(type,true);
62e76326 164 }
62e76326 165 break;
166
64f8c2cb 167 case CC_MIN_FRESH:
d74ad83f 168 if (!p || !httpHeaderParseInt(p, &min_fresh) || min_fresh < 0) {
64f8c2cb 169 debugs(65, 2, "cc: invalid min-fresh specs near '" << item << "'");
4ce6e3b5 170 clearMinFresh();
d74ad83f
FC
171 } else {
172 setMask(type,true);
64f8c2cb 173 }
64f8c2cb
AR
174 break;
175
65fd3895 176 case CC_STALE_IF_ERROR:
d74ad83f 177 if (!p || !httpHeaderParseInt(p, &stale_if_error) || stale_if_error < 0) {
65fd3895 178 debugs(65, 2, "cc: invalid stale-if-error specs near '" << item << "'");
4ce6e3b5 179 clearStaleIfError();
d74ad83f
FC
180 } else {
181 setMask(type,true);
65fd3895
AJ
182 }
183 break;
184
1259f9cf
AJ
185 case CC_PRIVATE: {
186 String temp;
187 if (!p) {
188 // Value parameter is optional.
189 private_.clean();
190 } else if (/* p &&*/ httpHeaderParseQuotedString(p, (ilen-nlen-1), &temp)) {
191 private_.append(temp);
192 } else {
193 debugs(65, 2, "cc: invalid private= specs near '" << item << "'");
194 }
195 // to be safe we ignore broken parameters, but always remember the 'private' part.
196 setMask(type,true);
197 }
198 break;
199
200 case CC_NO_CACHE: {
201 String temp;
202 if (!p) {
203 // On Requests, missing value parameter is expected syntax.
204 // On Responses, value parameter is optional.
205 setMask(type,true);
206 no_cache.clean();
207 } else if (/* p &&*/ httpHeaderParseQuotedString(p, (ilen-nlen-1), &temp)) {
208 // On Requests, a value parameter is invalid syntax.
209 // XXX: identify when parsing request header and dump err message here.
210 setMask(type,true);
211 no_cache.append(temp);
212 } else {
213 debugs(65, 2, "cc: invalid no-cache= specs near '" << item << "'");
214 }
215 }
216 break;
217
77da1817
A
218 case CC_PUBLIC:
219 Public(true);
220 break;
77da1817
A
221 case CC_NO_STORE:
222 noStore(true);
223 break;
224 case CC_NO_TRANSFORM:
225 noTransform(true);
226 break;
227 case CC_MUST_REVALIDATE:
228 mustRevalidate(true);
229 break;
230 case CC_PROXY_REVALIDATE:
231 proxyRevalidate(true);
232 break;
233 case CC_ONLY_IF_CACHED:
234 onlyIfCached(true);
235 break;
1b2e9616 236
4ce6e3b5 237 case CC_OTHER:
f9517ad8
FC
238 if (other.size())
239 other.append(", ");
1b2e9616 240
f9517ad8 241 other.append(item, ilen);
1b2e9616 242 break;
243
62e76326 244 default:
1b2e9616 245 /* note that we ignore most of '=' specs (RFCVIOLATION) */
62e76326 246 break;
247 }
7faf2bdb 248 }
62e76326 249
f9517ad8 250 return (mask != 0);
7faf2bdb 251}
252
7faf2bdb 253void
17802cf1 254HttpHdrCc::packInto(Packable * p) const
7faf2bdb 255{
2c8c98ad
FC
256 // optimization: if the mask is empty do nothing
257 if (mask==0)
258 return;
259
7faf2bdb 260 http_hdr_cc_type flag;
261 int pcount = 0;
4ce6e3b5 262 assert(p);
62e76326 263
e6ccf245 264 for (flag = CC_PUBLIC; flag < CC_ENUM_END; ++flag) {
4ce6e3b5 265 if (isSet(flag) && flag != CC_OTHER) {
62e76326 266
c397963f 267 /* print option name for all options */
d2a739f5 268 p->Printf((pcount ? ", %s": "%s") , CcAttrs[flag].name);
91274dd0 269
c397963f
FC
270 /* for all options having values, "=value" after the name */
271 switch (flag) {
272 case CC_MAX_AGE:
d2a739f5 273 p->Printf("=%d", (int) maxAge());
c397963f
FC
274 break;
275 case CC_S_MAXAGE:
d2a739f5 276 p->Printf("=%d", (int) sMaxAge());
c397963f
FC
277 break;
278 case CC_MAX_STALE:
279 /* max-stale's value is optional.
280 If we didn't receive it, don't send it */
281 if (maxStale()!=MAX_STALE_ANY)
d2a739f5 282 p->Printf("=%d", (int) maxStale());
c397963f
FC
283 break;
284 case CC_MIN_FRESH:
d2a739f5 285 p->Printf("=%d", (int) minFresh());
c397963f
FC
286 break;
287 default:
288 /* do nothing, directive was already printed */
289 break;
290 }
64f8c2cb 291
7ebe76de 292 ++pcount;
62e76326 293 }
7faf2bdb 294 }
1b2e9616 295
4ce6e3b5 296 if (other.size() != 0)
d2a739f5 297 p->Printf((pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH),
4ce6e3b5 298 SQUIDSTRINGPRINT(other));
7faf2bdb 299}
300
7faf2bdb 301void
302httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist)
303{
304 http_hdr_cc_type c;
305 assert(cc);
62e76326 306
e6ccf245 307 for (c = CC_PUBLIC; c < CC_ENUM_END; ++c)
f9517ad8 308 if (cc->isSet(c))
f30f7998 309 hist->count(c);
7faf2bdb 310}
311
312void
ced8def3 313httpHdrCcStatDumper(StoreEntry * sentry, int, double val, double, int count)
7faf2bdb 314{
f53969cc 315 extern const HttpHeaderStat *dump_stat; /* argh! */
7faf2bdb 316 const int id = (int) val;
317 const int valid_id = id >= 0 && id < CC_ENUM_END;
ce394734 318 const char *name = valid_id ? CcAttrs[id].name : "INVALID";
62e76326 319
7faf2bdb 320 if (count || valid_id)
62e76326 321 storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
322 id, name, count, xdiv(count, dump_stat->ccParsedCount));
7faf2bdb 323}
1ba0611a 324
9774b48e
FC
325#if !_USE_INLINE_
326#include "HttpHdrCc.cci"
327#endif
f53969cc 328