3 * DEBUG: section 90 HTTP Cache Control Header
4 * AUTHOR: Alex Rousskov
5 * Robert Collins (Surrogate-Control is derived from
7 * Francesco Chemolli (c++ refactoring)
9 * SQUID Web Proxy Cache http://www.squid-cache.org/
10 * ----------------------------------------------------------
12 * Squid is the result of efforts by numerous individuals from
13 * the Internet community; see the CONTRIBUTORS file for full
14 * details. Many organizations have provided support for Squid's
15 * development; see the SPONSORS file for full details. Squid is
16 * Copyrighted (C) 2001 by the Regents of the University of
17 * California; see the COPYRIGHT file for full details. Squid
18 * incorporates software developed and/or copyrighted by other
19 * sources; see the CREDITS file for full details.
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
38 #include "HttpHdrSc.h"
39 #include "HttpHeader.h"
40 #include "HttpHeaderFieldInfo.h"
41 #include "HttpHeaderFieldStat.h"
42 #include "HttpHeaderStat.h"
43 #include "HttpHeaderTools.h"
49 /* a row in the table used for parsing surrogate-control header and statistics */
53 HttpHeaderFieldStat stat
;
56 /* this table is used for parsing surrogate control header */
57 /* order must match that of enum http_hdr_sc_type. The constraint is verified at initialization time */
58 //todo: implement constraint
59 static const HttpHeaderFieldAttrs ScAttrs
[SC_ENUM_END
] = {
60 {"no-store", (http_hdr_type
)SC_NO_STORE
},
61 {"no-store-remote", (http_hdr_type
)SC_NO_STORE_REMOTE
},
62 {"max-age", (http_hdr_type
)SC_MAX_AGE
},
63 {"content", (http_hdr_type
)SC_CONTENT
},
64 {"Other,", (http_hdr_type
)SC_OTHER
} /* ',' will protect from matches */
67 HttpHeaderFieldInfo
*ScFieldsInfo
= NULL
;
69 http_hdr_sc_type
&operator++ (http_hdr_sc_type
&aHeader
)
71 int tmp
= (int)aHeader
;
72 aHeader
= (http_hdr_sc_type
)(++tmp
);
76 int operator - (http_hdr_sc_type
const &anSc
, http_hdr_sc_type
const &anSc2
)
78 return (int)anSc
- (int)anSc2
;
81 /* module initialization */
84 httpHdrScInitModule(void)
86 ScFieldsInfo
= httpHeaderBuildFieldsInfo(ScAttrs
, SC_ENUM_END
);
90 httpHdrScCleanModule(void)
92 httpHeaderDestroyFieldsInfo(ScFieldsInfo
, SC_ENUM_END
);
98 /* creates an sc object from a 0-terminating string */
100 httpHdrScParseCreate(const String
& str
)
102 HttpHdrSc
*sc
= new HttpHdrSc();
104 if (!sc
->parse(&str
)) {
112 /* parses a 0-terminating string and inits sc */
114 HttpHdrSc::parse(const String
* str
)
118 const char *p
; /* '=' parameter */
119 const char *pos
= NULL
;
120 const char *target
= NULL
; /* ;foo */
121 const char *temp
= NULL
; /* temp buffer */
125 HttpHdrScTarget
*sct
;
128 /* iterate through comma separated list */
130 while (strListGetItem(str
, ',', &item
, &ilen
, &pos
)) {
133 /* decrease ilen to still match the token for '=' statements */
135 if ((p
= strchr(item
, '=')) && (p
- item
< ilen
)) {
136 vlen
= ilen
- (p
+ 1 - item
);
141 /* decrease ilen to still match the token for ';' qualified non '=' statments */
142 else if ((p
= strchr(item
, ';')) && (p
- item
< ilen
)) {
148 /* TODO: use a type-safe map-based lookup */
149 type
= httpHeaderIdByName(item
, ilen
,
150 ScFieldsInfo
, SC_ENUM_END
);
153 debugs(90, 2, "hdr sc: unknown control-directive: near '" << item
<< "' in '" << str
<< "'");
157 /* Is this a targeted directive? */
158 /* TODO: remove the temporary useage and use memrchr and the information we have instead */
159 temp
= xstrndup (item
, initiallen
+ 1);
161 if (!((target
= strrchr (temp
, ';')) && !strchr (target
, '"') && *(target
+ 1) != '\0'))
166 sct
= sc
->findTarget(target
);
169 sct
= new HttpHdrScTarget(target
);
175 if (sct
->isSet(static_cast<http_hdr_sc_type
>(type
))) {
176 if (type
!= SC_OTHER
)
177 debugs(90, 2, "hdr sc: ignoring duplicate control-directive: near '" << item
<< "' in '" << str
<< "'");
179 ++ ScFieldsInfo
[type
].stat
.repCount
;
184 /* process directives */
190 case SC_NO_STORE_REMOTE
:
191 sct
->noStoreRemote(true);
196 if (p
&& httpHeaderParseInt(p
, &ma
)) {
199 if ((p
= strchr (p
, '+'))) {
201 ++p
; //skip the + char
202 if (httpHeaderParseInt(p
, &ms
)) {
205 debugs(90, 2, "sc: invalid max-stale specs near '" << item
<< "'");
206 sct
->clearMaxStale();
207 /* leave the max-age alone */
211 debugs(90, 2, "sc: invalid max-age specs near '" << item
<< "'");
220 if ( p
&& httpHeaderParseQuotedString(p
, vlen
, &sct
->content_
)) {
221 sct
->setMask(SC_CONTENT
,true); // ugly but saves a copy
223 debugs(90, 2, "sc: invalid content= quoted string near '" << item
<< "'");
234 return sc
->targets
.head
!= NULL
;
237 HttpHdrSc::~HttpHdrSc()
240 dlink_node
*sct
= targets
.head
;
243 HttpHdrScTarget
*t
= static_cast<HttpHdrScTarget
*>(sct
->data
);
245 dlinkDelete (&t
->node
, &targets
);
251 HttpHdrSc::HttpHdrSc(const HttpHdrSc
&sc
)
253 dlink_node
*node
= sc
.targets
.head
;
256 HttpHdrScTarget
*dupsct
= new HttpHdrScTarget(*static_cast<HttpHdrScTarget
*>(node
->data
));
257 addTargetAtTail(dupsct
);
263 HttpHdrScTarget::packInto(Packer
* p
) const
265 http_hdr_sc_type flag
;
269 for (flag
= SC_NO_STORE
; flag
< SC_ENUM_END
; ++flag
) {
270 if (isSet(flag
) && flag
!= SC_OTHER
) {
272 /* print option name */
273 packerPrintf(p
, (pcount
? ", " SQUIDSTRINGPH
: SQUIDSTRINGPH
),
274 SQUIDSTRINGPRINT(ScFieldsInfo
[flag
].name
));
276 /* handle options with values */
278 if (flag
== SC_MAX_AGE
)
279 packerPrintf(p
, "=%d", (int) max_age
);
281 if (flag
== SC_CONTENT
)
282 packerPrintf(p
, "=\"" SQUIDSTRINGPH
"\"", SQUIDSTRINGPRINT(content_
));
289 packerPrintf (p
, ";" SQUIDSTRINGPH
, SQUIDSTRINGPRINT(target
));
293 HttpHdrSc::packInto(Packer
* p
) const
300 static_cast<HttpHdrScTarget
*>(node
->data
)->packInto(p
);
305 /* negative max_age will clean old max_Age setting */
307 HttpHdrSc::setMaxAge(char const *target
, int max_age
)
309 HttpHdrScTarget
*sct
= findTarget(target
);
312 sct
= new HttpHdrScTarget(target
);
313 dlinkAddTail (sct
, &sct
->node
, &targets
);
316 sct
->maxAge(max_age
);
320 HttpHdrSc::updateStats(StatHist
* hist
) const
322 dlink_node
*sct
= targets
.head
;
325 static_cast<HttpHdrScTarget
*>(sct
->data
)->updateStats(hist
);
331 httpHdrScTargetStatDumper(StoreEntry
* sentry
, int idx
, double val
, double size
, int count
)
333 extern const HttpHeaderStat
*dump_stat
; /* argh! */
334 const int id
= (int) val
;
335 const int valid_id
= id
>= 0 && id
< SC_ENUM_END
;
336 const char *name
= valid_id
? ScFieldsInfo
[id
].name
.termedBuf() : "INVALID";
338 if (count
|| valid_id
)
339 storeAppendPrintf(sentry
, "%2d\t %-20s\t %5d\t %6.2f\n",
340 id
, name
, count
, xdiv(count
, dump_stat
->scParsedCount
));
344 httpHdrScStatDumper(StoreEntry
* sentry
, int idx
, double val
, double size
, int count
)
346 extern const HttpHeaderStat
*dump_stat
; /* argh! */
347 const int id
= (int) val
;
348 const int valid_id
= id
>= 0 && id
< SC_ENUM_END
;
349 const char *name
= valid_id
? ScFieldsInfo
[id
].name
.termedBuf() : "INVALID";
351 if (count
|| valid_id
)
352 storeAppendPrintf(sentry
, "%2d\t %-20s\t %5d\t %6.2f\n",
353 id
, name
, count
, xdiv(count
, dump_stat
->scParsedCount
));
357 HttpHdrSc::findTarget(const char *target
)
363 HttpHdrScTarget
*sct
= (HttpHdrScTarget
*)node
->data
;
365 if (target
&& sct
->target
.size() > 0 && !strcmp(target
, sct
->target
.termedBuf()))
367 else if (!target
&& sct
->target
.size() == 0)
377 HttpHdrSc::getMergedTarget(const char *ourtarget
)
379 HttpHdrScTarget
*sctus
= findTarget(ourtarget
);
380 HttpHdrScTarget
*sctgeneric
= findTarget(NULL
);
382 if (sctgeneric
|| sctus
) {
383 HttpHdrScTarget
*sctusable
= new HttpHdrScTarget(NULL
);
386 sctusable
->mergeWith(sctgeneric
);
389 sctusable
->mergeWith(sctus
);