=== modified file 'compat/Makefile.am' --- compat/Makefile.am 2011-08-28 17:11:19 +0000 +++ compat/Makefile.am 2011-10-13 05:35:47 +0000 @@ -21,40 +21,42 @@ debug.cc \ debug.h \ drand48.h \ eui64_aton.h \ fdsetsize.h \ getaddrinfo.h \ getnameinfo.h \ GnuRegex.c \ GnuRegex.h \ inet_ntop.h \ inet_pton.h \ initgroups.h \ osdetect.h \ psignal.h \ shm.h \ stdio.h \ stdvarargs.h \ strnstr.cc \ strsep.h \ strtoll.h \ + strnrchr.h \ + strnrchr.c \ tempnam.h \ types.h \ unsafe.h \ valgrind.h \ xalloc.cc \ xalloc.h \ xis.h \ xstrerror.cc \ xstrerror.h \ xstring.cc \ xstring.h \ xstrto.cc \ xstrto.h \ \ os/aix.h \ os/dragonfly.h \ os/freebsd.h \ os/hpux.h \ os/linux.h \ os/macosx.h \ === added file 'compat/strnrchr.c' --- compat/strnrchr.c 1970-01-01 00:00:00 +0000 +++ compat/strnrchr.c 2011-10-13 05:35:47 +0000 @@ -0,0 +1,46 @@ +/* + * strnrchr.c + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + */ + +#include "config.h" +#include "strnrchr.h" + +const char * +strnrchr(const char *s, size_t slen, char c) +{ + const char *rv=NULL; + const char *l=s; + while (slen > 0 && *l != 0) { + if (*l==c) + rv=l; + ++l; + --slen; + } + return rv; +} === added file 'compat/strnrchr.h' --- compat/strnrchr.h 1970-01-01 00:00:00 +0000 +++ compat/strnrchr.h 2011-10-13 05:35:47 +0000 @@ -0,0 +1,43 @@ +/* + * strnrchr.h + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + */ + +#ifndef COMPAT_STRNRCHR_H_ +#define COMPAT_STRNRCHR_H_ + +#if HAVE_SYS_TYPES_H +#include +#endif + +/** + * look for the last occurrence of a character in a c-string with a set maximum length + */ +SQUIDCEXTERN const char *strnrchr(const char *s, size_t slen, char c); + +#endif /* COMPAT_STRNRCHR_H_ */ === modified file 'src/HttpHdrSc.cc' --- src/HttpHdrSc.cc 2010-11-02 00:49:51 +0000 +++ src/HttpHdrSc.cc 2011-10-30 19:02:42 +0000 @@ -1,407 +1,388 @@ /* * $Id$ * * DEBUG: section 90 HTTP Cache Control Header * AUTHOR: Alex Rousskov * Robert Collins (Surrogate-Control is derived from * Cache-Control). + * Francesco Chemolli (c++ refactoring) * * SQUID Web Proxy Cache http://www.squid-cache.org/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from * the Internet community; see the CONTRIBUTORS file for full * details. Many organizations have provided support for Squid's * development; see the SPONSORS file for full details. Squid is * Copyrighted (C) 2001 by the Regents of the University of * California; see the COPYRIGHT file for full details. Squid * incorporates software developed and/or copyrighted by other * sources; see the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #include "Store.h" #include "HttpHeader.h" #include "HttpHdrSc.h" +#if HAVE_CSTRING +#include +#endif + +#if HAVE_MAP +#include +#endif + +/* a row in the table used for parsing surrogate-control header and statistics */ +typedef struct { + const char *name; + http_hdr_sc_type id; + HttpHeaderFieldStat stat; +} HttpHeaderScFields; + /* this table is used for parsing surrogate control header */ +/* order must match that of enum http_hdr_sc_type. The constraint is verified at initialization time */ +//todo: implement constraint static const HttpHeaderFieldAttrs ScAttrs[SC_ENUM_END] = { {"no-store", (http_hdr_type)SC_NO_STORE}, - {"no-store-remote", (http_hdr_type)SC_NO_STORE_REMOTE}, {"max-age", (http_hdr_type)SC_MAX_AGE}, {"content", (http_hdr_type)SC_CONTENT}, {"Other,", (http_hdr_type)SC_OTHER} /* ',' will protect from matches */ }; HttpHeaderFieldInfo *ScFieldsInfo = NULL; http_hdr_sc_type &operator++ (http_hdr_sc_type &aHeader) { int tmp = (int)aHeader; aHeader = (http_hdr_sc_type)(++tmp); return aHeader; } int operator - (http_hdr_sc_type const &anSc, http_hdr_sc_type const &anSc2) { return (int)anSc - (int)anSc2; } -/* local prototypes */ -static int httpHdrScParseInit(HttpHdrSc * sc, const String * str); - /* module initialization */ void httpHdrScInitModule(void) { ScFieldsInfo = httpHeaderBuildFieldsInfo(ScAttrs, SC_ENUM_END); } void httpHdrScCleanModule(void) { httpHeaderDestroyFieldsInfo(ScFieldsInfo, SC_ENUM_END); ScFieldsInfo = NULL; } /* implementation */ -HttpHdrSc * -httpHdrScCreate(void) -{ - return new HttpHdrSc(); -} - /* creates an sc object from a 0-terminating string */ HttpHdrSc * -httpHdrScParseCreate(const String * str) +httpHdrScParseCreate(const String & str) { - HttpHdrSc *sc = httpHdrScCreate(); + HttpHdrSc *sc = new HttpHdrSc(); - if (!httpHdrScParseInit(sc, str)) { - httpHdrScDestroy(sc); + if (!sc->parse(&str)) { + delete sc; sc = NULL; } return sc; } /* parses a 0-terminating string and inits sc */ -static int -httpHdrScParseInit(HttpHdrSc * sc, const String * str) +bool +HttpHdrSc::parse(const String * str) { + HttpHdrSc * sc=this; const char *item; const char *p; /* '=' parameter */ const char *pos = NULL; const char *target = NULL; /* ;foo */ - const char *temp = NULL; /* temp buffer */ int type; int ilen, vlen; int initiallen; HttpHdrScTarget *sct; - assert(sc && str); + assert(str); /* iterate through comma separated list */ while (strListGetItem(str, ',', &item, &ilen, &pos)) { initiallen = ilen; vlen = 0; /* decrease ilen to still match the token for '=' statements */ if ((p = strchr(item, '=')) && (p - item < ilen)) { vlen = ilen - (p + 1 - item); ilen = p - item; p++; } /* decrease ilen to still match the token for ';' qualified non '=' statments */ else if ((p = strchr(item, ';')) && (p - item < ilen)) ilen = p++ - item; /* find type */ + /* TODO: use a type-safe map-based lookup */ type = httpHeaderIdByName(item, ilen, ScFieldsInfo, SC_ENUM_END); if (type < 0) { debugs(90, 2, "hdr sc: unknown control-directive: near '" << item << "' in '" << str << "'"); type = SC_OTHER; } /* Is this a targeted directive? */ - /* TODO sometime: implement a strnrchr that looks at a substring */ - temp = xstrndup (item, initiallen + 1); - - if (!((target = strrchr (temp, ';')) && !strchr (target, '"') && *(target + 1) != '\0')) + if (!((target = static_cast(memrchr (item, ';', initiallen+1))) && !strchr (target, '"') && *(target + 1) != '\0')) target = NULL; else ++target; - sct = httpHdrScFindTarget (sc, target); + sct = sc->findTarget(target); if (!sct) { - sct = httpHdrScTargetCreate (target); - dlinkAdd(sct, &sct->node, &sc->targets); + sct = new HttpHdrScTarget(target); + addTarget(sct); } - - safe_free (temp); - - if (EBIT_TEST(sct->mask, type)) { + if (sct->isSet(static_cast(type))) { if (type != SC_OTHER) debugs(90, 2, "hdr sc: ignoring duplicate control-directive: near '" << item << "' in '" << str << "'"); ScFieldsInfo[type].stat.repCount++; continue; } - /* update mask */ - EBIT_SET(sct->mask, type); - - /* post-processing special cases */ + /* process directives */ switch (type) { + case SC_NO_STORE: + sct->noStore(true); + break; - case SC_MAX_AGE: + case SC_NO_STORE_REMOTE: + sct->noStoreRemote(true); + break; - if (!p || !httpHeaderParseInt(p, &sct->max_age)) { + case SC_MAX_AGE: + int ma; + if (p && httpHeaderParseInt(p, &ma)) { + sct->maxAge(ma); + } else { debugs(90, 2, "sc: invalid max-age specs near '" << item << "'"); - sct->max_age = -1; - EBIT_CLR(sct->mask, type); + sct->clearMaxAge(); } - if ((p = strchr (p, '+'))) - if (!httpHeaderParseInt(++p, &sct->max_stale)) { + if ((p = strchr (p, '+'))) { + int ms; + ++p; //skip the + char + if (httpHeaderParseInt(p, &ms)) { + sct->maxStale(ms); + } else { debugs(90, 2, "sc: invalid max-stale specs near '" << item << "'"); - sct->max_stale = 0; + sct->clearMaxStale(); /* leave the max-age alone */ } - + } break; case SC_CONTENT: - if (!p || !httpHeaderParseQuotedString(p, vlen, &sct->content)) { + if ( p && httpHeaderParseQuotedString(p, vlen, &sct->content_)) { + sct->setMask(SC_CONTENT,true); // ugly but saves a copy + } else { debugs(90, 2, "sc: invalid content= quoted string near '" << item << "'"); - sct->content.clean(); - EBIT_CLR(sct->mask, type); + sct->clearContent(); } + case SC_OTHER: default: break; } } return sc->targets.head != NULL; } -void -httpHdrScDestroy(HttpHdrSc * sc) +HttpHdrSc::~HttpHdrSc() { - assert(sc); - - if (sc->targets.head) { - dlink_node *sct = sc->targets.head; + if (targets.head) { + dlink_node *sct = targets.head; while (sct) { - HttpHdrScTarget *t = (HttpHdrScTarget *)sct->data; + HttpHdrScTarget *t = static_cast(sct->data); sct = sct->next; - dlinkDelete (&t->node, &sc->targets); - httpHdrScTargetDestroy (t); + dlinkDelete (&t->node, &targets); + delete t; } } - - delete sc; } -HttpHdrSc * -httpHdrScDup(const HttpHdrSc * sc) + +HttpHdrSc::HttpHdrSc(const HttpHdrSc &sc) { - HttpHdrSc *dup; - dlink_node *node; - assert(sc); - node = sc->targets.head; - dup = httpHdrScCreate(); + dlink_node *node = sc.targets.head; while (node) { - HttpHdrScTarget *dupsct; - dupsct = httpHdrScTargetDup ((HttpHdrScTarget *)node->data); - dlinkAddTail (dupsct, &dupsct->node, &dup->targets); + HttpHdrScTarget *dupsct = new HttpHdrScTarget(*static_cast(node->data)); + addTargetAtTail(dupsct); node = node->next; } - - return dup; } void -httpHdrScTargetPackInto(const HttpHdrScTarget * sc, Packer * p) +HttpHdrScTarget::packInto(Packer * p) const { http_hdr_sc_type flag; int pcount = 0; - assert(sc && p); + assert (p); for (flag = SC_NO_STORE; flag < SC_ENUM_END; ++flag) { - if (EBIT_TEST(sc->mask, flag) && flag != SC_OTHER) { + if (isSet(flag) && flag != SC_OTHER) { /* print option name */ packerPrintf(p, (pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH), SQUIDSTRINGPRINT(ScFieldsInfo[flag].name)); /* handle options with values */ if (flag == SC_MAX_AGE) - packerPrintf(p, "=%d", (int) sc->max_age); + packerPrintf(p, "=%d", (int) max_age); if (flag == SC_CONTENT) - packerPrintf(p, "=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(sc->content)); + packerPrintf(p, "=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(content_)); pcount++; } } - if (sc->target.size()) - packerPrintf (p, ";" SQUIDSTRINGPH, SQUIDSTRINGPRINT(sc->target)); + if (hasTarget()) + packerPrintf (p, ";" SQUIDSTRINGPH, SQUIDSTRINGPRINT(target)); } void -httpHdrScPackInto(const HttpHdrSc * sc, Packer * p) +HttpHdrSc::packInto(Packer * p) const { dlink_node *node; - assert(sc && p); - node = sc->targets.head; + assert(p); + node = targets.head; while (node) { - httpHdrScTargetPackInto((HttpHdrScTarget *)node->data, p); + static_cast(node->data)->packInto(p); node = node->next; } } -void -httpHdrScJoinWith(HttpHdrSc * sc, const HttpHdrSc * new_sc) -{ - assert(sc && new_sc); -#if 0 - /* RC TODO: check that both have the same target */ - - if (sc->max_age < 0) - sc->max_age = new_sc->max_age; - - /* RC TODO: copy unique missing stringlist entries */ - cc->mask |= new_cc->mask; - -#endif -} - /* negative max_age will clean old max_Age setting */ void -httpHdrScSetMaxAge(HttpHdrSc * sc, char const *target, int max_age) +HttpHdrSc::setMaxAge(char const *target, int max_age) { - HttpHdrScTarget *sct; - assert(sc); - sct = httpHdrScFindTarget (sc, target); + HttpHdrScTarget *sct = findTarget(target); if (!sct) { - sct = httpHdrScTargetCreate (target); - dlinkAddTail (sct, &sct->node, &sc->targets); + sct = new HttpHdrScTarget(target); + dlinkAddTail (sct, &sct->node, &targets); } - httpHdrScTargetSetMaxAge(sct, max_age); + sct->maxAge(max_age); } void -httpHdrScUpdateStats(const HttpHdrSc * sc, StatHist * hist) +HttpHdrSc::updateStats(StatHist * hist) const { - dlink_node *sct; - assert(sc); - sct = sc->targets.head; + dlink_node *sct = targets.head; while (sct) { - httpHdrScTargetUpdateStats((HttpHdrScTarget *)sct->data, hist); + static_cast(sct->data)->updateStats(hist); sct = sct->next; } } void httpHdrScTargetStatDumper(StoreEntry * sentry, int idx, double val, double size, int count) { extern const HttpHeaderStat *dump_stat; /* argh! */ const int id = (int) val; const int valid_id = id >= 0 && id < SC_ENUM_END; const char *name = valid_id ? ScFieldsInfo[id].name.termedBuf() : "INVALID"; if (count || valid_id) storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n", id, name, count, xdiv(count, dump_stat->scParsedCount)); } void httpHdrScStatDumper(StoreEntry * sentry, int idx, double val, double size, int count) { extern const HttpHeaderStat *dump_stat; /* argh! */ const int id = (int) val; const int valid_id = id >= 0 && id < SC_ENUM_END; const char *name = valid_id ? ScFieldsInfo[id].name.termedBuf() : "INVALID"; if (count || valid_id) storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n", id, name, count, xdiv(count, dump_stat->scParsedCount)); } HttpHdrScTarget * -httpHdrScFindTarget (HttpHdrSc *sc, const char *target) +HttpHdrSc::findTarget(const char *target) { dlink_node *node; - assert (sc); - node = sc->targets.head; + node = targets.head; while (node) { HttpHdrScTarget *sct = (HttpHdrScTarget *)node->data; if (target && sct->target.defined() && !strcmp (target, sct->target.termedBuf())) return sct; else if (!target && sct->target.undefined()) return sct; node = node->next; } return NULL; } HttpHdrScTarget * -httpHdrScGetMergedTarget (HttpHdrSc *sc, const char *ourtarget) +HttpHdrSc::getMergedTarget(const char *ourtarget) { - HttpHdrScTarget *sctus = httpHdrScFindTarget (sc, ourtarget); - HttpHdrScTarget *sctgeneric = httpHdrScFindTarget (sc, NULL); + HttpHdrScTarget *sctus = findTarget(ourtarget); + HttpHdrScTarget *sctgeneric = findTarget(NULL); if (sctgeneric || sctus) { - HttpHdrScTarget *sctusable = httpHdrScTargetCreate (NULL); + HttpHdrScTarget *sctusable = new HttpHdrScTarget(NULL); if (sctgeneric) - httpHdrScTargetMergeWith (sctusable, sctgeneric); + sctusable->mergeWith(sctgeneric); if (sctus) - httpHdrScTargetMergeWith (sctusable, sctus); + sctusable->mergeWith(sctus); return sctusable; } return NULL; } === modified file 'src/HttpHdrSc.h' --- src/HttpHdrSc.h 2009-01-21 03:47:47 +0000 +++ src/HttpHdrSc.h 2011-10-13 20:01:32 +0000 @@ -26,45 +26,52 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #ifndef SQUID_HTTPHDRSURROGATECONTROL_H #define SQUID_HTTPHDRSURROGATECONTROL_H #include "dlink.h" #include "HttpHdrScTarget.h" /* http surogate control header field */ class HttpHdrSc { public: + bool parse(const String *str); + ~HttpHdrSc(); + HttpHdrSc(const HttpHdrSc &); + HttpHdrSc() {}; + void packInto(Packer * p) const; + void updateStats(StatHist *) const; + HttpHdrScTarget * getMergedTarget (const char *ourtarget); //todo: make const? + void setMaxAge(char const *target, int max_age); + void addTarget(HttpHdrScTarget *t) { + dlinkAdd(t, &t->node, &targets); + } + void addTargetAtTail(HttpHdrScTarget *t) { + dlinkAddTail (t, &t->node, &targets); + } + MEMPROXY_CLASS(HttpHdrSc); dlink_list targets; +private: + HttpHdrScTarget * findTarget (const char *target); + }; MEMPROXY_CLASS_INLINE(HttpHdrSc); /* Http Surrogate Control Header Field */ extern void httpHdrScStatDumper(StoreEntry * sentry, int idx, double val, double size, int count); extern void httpHdrScInitModule (void); extern void httpHdrScCleanModule (void); -extern HttpHdrSc *httpHdrScCreate(void); -extern HttpHdrSc *httpHdrScParseCreate(String const *); -extern void httpHdrScDestroy(HttpHdrSc * sc); -extern HttpHdrSc *httpHdrScDup(const HttpHdrSc * sc); -extern void httpHdrScPackInto(const HttpHdrSc * sc, Packer * p); -extern void httpHdrScJoinWith(HttpHdrSc *, const HttpHdrSc *); +extern HttpHdrSc *httpHdrScParseCreate(String const &); extern void httpHdrScSetMaxAge(HttpHdrSc *, char const *, int); -extern void httpHdrScUpdateStats(const HttpHdrSc *, StatHist *); -extern HttpHdrScTarget * httpHdrScFindTarget (HttpHdrSc *sc, const char *target); -extern HttpHdrScTarget * httpHdrScGetMergedTarget (HttpHdrSc *sc, const char *ourtarget); - -extern void httpHeaderPutSc(HttpHeader *hdr, const HttpHdrSc *sc); -extern HttpHdrSc *httpHeaderGetSc(const HttpHeader *hdr); #endif /* SQUID_HTTPHDRSURROGATECONTROL_H */ === modified file 'src/HttpHdrScTarget.cc' --- src/HttpHdrScTarget.cc 2009-01-31 18:23:44 +0000 +++ src/HttpHdrScTarget.cc 2011-10-30 19:03:36 +0000 @@ -21,131 +21,55 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #include "HttpHdrSc.h" -/* local prototypes */ - -/* module initialization */ - -/* implementation */ - -HttpHdrScTarget * -httpHdrScTargetCreate(char const *target) -{ - HttpHdrScTarget *sc = new HttpHdrScTarget(); - sc->max_age = -1; - /* max_stale is specified as 0 if not specified in the header */ - sc->target = target; - return sc; -} - -void -httpHdrScTargetDestroy(HttpHdrScTarget * sc) -{ - assert(sc); - sc->target.clean(); - sc->content.clean(); - delete sc; -} - -HttpHdrScTarget * -httpHdrScTargetDup(const HttpHdrScTarget * sc) -{ - HttpHdrScTarget *dup; - assert(sc); - dup = httpHdrScTargetCreate(sc->target.termedBuf()); - dup->mask = sc->mask; - dup->max_age = sc->max_age; - dup->content = sc->content; - return dup; -} - -/* union of two targets */ -void -httpHdrScTargetJoinWith(HttpHdrScTarget * sc, const HttpHdrScTarget * new_sc) -{ - assert(sc && new_sc); - /* TODO: check both targets are the same */ - - if (sc->max_age < 0) - sc->max_age = new_sc->max_age; - - if (sc->max_stale < new_sc->max_stale) - sc->max_stale = new_sc->max_stale; - - /* RC TODO: copy unique missing content stringlist entries */ - sc->mask |= new_sc->mask; -} - extern http_hdr_sc_type &operator++ (http_hdr_sc_type &aHeader); -extern int operator - (http_hdr_sc_type const &anSc, http_hdr_sc_type const &anSc2); /* copies non-extant fields from new_sc to this sc */ void -httpHdrScTargetMergeWith(HttpHdrScTarget * sc, const HttpHdrScTarget * new_sc) +HttpHdrScTarget::mergeWith(const HttpHdrScTarget * new_sc) { - http_hdr_sc_type c; - assert(sc && new_sc); + assert(new_sc); /* Don't touch the target - this is used to get the operations for a * single surrogate */ - for (c = SC_NO_STORE; c < SC_ENUM_END; ++c) - if (!EBIT_TEST(sc->mask, c) && EBIT_TEST(new_sc->mask,c)) { - EBIT_SET(sc->mask, c); + if (new_sc->hasNoStore()) + noStore(true); - switch (c) { + if (new_sc->hasNoStoreRemote()) + noStoreRemote(true); - case SC_MAX_AGE: - sc->max_age = new_sc->max_age; - sc->max_stale = new_sc->max_stale; - break; - - case SC_CONTENT: - assert (sc->content.size() == 0); - sc->content = new_sc->content; - break; - - default: - break; - } - } -} + if (new_sc->hasMaxAge() && !hasMaxAge()) { + maxAge(new_sc->maxAge()); + maxStale(new_sc->maxStale()); + } -/* negative max_age will clean old max_Age setting */ -void -httpHdrScTargetSetMaxAge(HttpHdrScTarget * sc, int max_age) -{ - assert(sc); - sc->max_age = max_age; + if (new_sc->hasContent() && !hasContent()) + Content(new_sc->content()); - if (max_age >= 0) - EBIT_SET(sc->mask, SC_MAX_AGE); - else - EBIT_CLR(sc->mask, SC_MAX_AGE); } void -httpHdrScTargetUpdateStats(const HttpHdrScTarget * sc, StatHist * hist) +HttpHdrScTarget::updateStats(StatHist * hist) const { http_hdr_sc_type c; - assert(sc); for (c = SC_NO_STORE; c < SC_ENUM_END; ++c) - if (EBIT_TEST(sc->mask, c)) + if (isSet(c)) statHistCount(hist, c); } === modified file 'src/HttpHdrScTarget.h' --- src/HttpHdrScTarget.h 2009-01-21 03:47:47 +0000 +++ src/HttpHdrScTarget.h 2011-10-30 19:03:36 +0000 @@ -24,53 +24,126 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #ifndef SQUID_HTTPHDRSURROGATECONTROLTARGET_H #define SQUID_HTTPHDRSURROGATECONTROLTARGET_H class Packer; class StoreEntry; /* for MEMPROXY_CLASS() macros */ #include "MemPool.h" /* for dlink_node */ #include "dlink.h" /* for String */ #include "SquidString.h" +/* for StatHist */ +#include "typedefs.h" -/** HTTP Surogate-Control: header field */ +/** Representation of HTTP Surogate-Control header field targeted directive + * + * \see HttpHdrSc + */ class HttpHdrScTarget { + friend class HttpHdrSc; public: + static const int MAX_AGE_UNSET=-1; + static const int MAX_STALE_UNSET=0; + + ///create a new target from a c-string. + explicit HttpHdrScTarget(const char *target_): + mask(0), max_age(MAX_AGE_UNSET), max_stale(MAX_STALE_UNSET),target(target_) {} + + /// copy-constructor + explicit HttpHdrScTarget(const HttpHdrScTarget &t): + mask(t.mask), max_age(t.max_age), max_stale(t.max_stale), + content_(t.content_), target(t.target) {} + + ///verify if the directive id is set for this target + bool isSet(http_hdr_sc_type id) const { + assert (id >= SC_NO_STORE && id < SC_ENUM_END); + return EBIT_TEST(mask,id); + } + + /* test/set/get/clear the no-store target directive */ + bool hasNoStore() const {return isSet(SC_NO_STORE); } + void noStore(bool v) { setMask(SC_NO_STORE,v); } + bool noStore() const { return isSet(SC_NO_STORE); } + void clearNoStore() { setMask(SC_NO_STORE, false); } + + /* test/set/get/clear the no-store-remote target directive */ + bool hasNoStoreRemote() const {return isSet(SC_NO_STORE_REMOTE); } + void noStoreRemote(bool v) { setMask(SC_NO_STORE_REMOTE,v); } + bool noStoreRemote() const { return isSet(SC_NO_STORE_REMOTE); } + void clearNoStoreRemote() { setMask(SC_NO_STORE_REMOTE, false); } + + /* test/set/get/clear the max-age target directive */ + bool hasMaxAge() const { return isSet(SC_MAX_AGE); } + void maxAge(int v) { + if (v >= 0) { //setting + setMask(SC_MAX_AGE,true); + max_age=v; + } else { + setMask(SC_MAX_AGE,false); + max_age=MAX_AGE_UNSET; + } + } + int maxAge() const { return max_age; } + void clearMaxAge() { setMask(SC_MAX_AGE,false); max_age=MAX_AGE_UNSET; } + + /* test/set/get/clear the max-stale target directive */ + bool hasMaxStale() const { return max_stale != MAX_STALE_UNSET; } + void maxStale(int v) { max_stale=v; } + int maxStale() const { return max_stale; } + void clearMaxStale() { max_stale=MAX_STALE_UNSET; } + + /* test/set/get/clear the content_ target directive */ + bool hasContent() const { return isSet(SC_CONTENT); } + void Content(const String &v) { + setMask(SC_CONTENT,true); + content_=v; + } + String content() const { return content_; } + void clearContent() { setMask(SC_CONTENT,false); content_.clean(); } + + /// check whether a target was actually set for this directive + bool hasTarget() const { return target.size() != 0; } + ///retrieve the directive's target + String Target() const { return target; } + + /// merge with another surrogate-control target + void mergeWith(const HttpHdrScTarget * new_sc); + + /// output this directive + void packInto (Packer *p) const; + + /// update the global statistics for Surrogate-Control targets + void updateStats(StatHist *) const; + MEMPROXY_CLASS(HttpHdrScTarget); - dlink_node node; +private: + + ///assert the existence of a directive. + /// for boolean directives, also sets it. + void setMask(http_hdr_sc_type id, bool newval) { + if (newval) EBIT_SET(mask,id); + else EBIT_CLR(mask,id); + } + + int mask; int max_age; int max_stale; - String content; + String content_; String target; + dlink_node node; }; MEMPROXY_CLASS_INLINE(HttpHdrScTarget); -/* Http Surrogate control header field 'targets' */ -extern HttpHdrScTarget * httpHdrScTargetCreate (const char *); -extern void httpHdrScTargetDestroy(HttpHdrScTarget *); -extern HttpHdrScTarget *httpHdrScTargetDup(const HttpHdrScTarget *); -extern void httpHdrScTargetPackInto(const HttpHdrScTarget *, Packer *); -extern void httpHdrScTargetSetMaxAge(HttpHdrScTarget *, int); -extern void httpHdrScTargetJoinWith(HttpHdrScTarget *, const HttpHdrScTarget *); -extern void httpHdrScTargetMergeWith(HttpHdrScTarget *, const HttpHdrScTarget *); -extern void httpHdrScTargetStatDumper(StoreEntry * sentry, int idx, double val, double size, int count); - -/* for StatHist */ -#include "typedefs.h" - -extern void httpHdrScTargetUpdateStats(const HttpHdrScTarget *, StatHist *); - - #endif /* SQUID_HTTPHDRSURROGATECONTROLTARGET_H */ === modified file 'src/HttpHeader.cc' --- src/HttpHeader.cc 2011-09-28 12:13:22 +0000 +++ src/HttpHeader.cc 2011-10-30 19:05:47 +0000 @@ -1192,41 +1192,41 @@ packerToMemInit(&p, &mb); range->packInto(&p); /* put */ addEntry(new HttpHeaderEntry(HDR_RANGE, NULL, mb.buf)); /* cleanup */ packerClean(&p); mb.clean(); } void HttpHeader::putSc(HttpHdrSc *sc) { MemBuf mb; Packer p; assert(sc); /* remove old directives if any */ delById(HDR_SURROGATE_CONTROL); /* pack into mb */ mb.init(); packerToMemInit(&p, &mb); - httpHdrScPackInto(sc, &p); + sc->packInto(&p); /* put */ addEntry(new HttpHeaderEntry(HDR_SURROGATE_CONTROL, NULL, mb.buf)); /* cleanup */ packerClean(&p); mb.clean(); } void HttpHeader::putWarning(const int code, const char *const text) { char buf[512]; snprintf(buf, sizeof(buf), "%i %s \"%s\"", code, visible_appname_string, text); putStr(HDR_WARNING, buf); } /* add extension header (these fields are not parsed/analyzed/joined, etc.) */ void HttpHeader::putExt(const char *name, const char *value) { assert(name && value); @@ -1349,46 +1349,46 @@ if ((e = findEntry(HDR_RANGE)) || (e = findEntry(HDR_REQUEST_RANGE))) { r = HttpHdrRange::ParseCreate(&e->value); httpHeaderNoteParsedEntry(e->id, e->value, !r); } return r; } HttpHdrSc * HttpHeader::getSc() const { if (!CBIT_TEST(mask, HDR_SURROGATE_CONTROL)) return NULL; String s; (void) getList(HDR_SURROGATE_CONTROL, &s); - HttpHdrSc *sc = httpHdrScParseCreate(&s); + HttpHdrSc *sc = httpHdrScParseCreate(s); - HttpHeaderStats[owner].ccParsedCount++; + ++HttpHeaderStats[owner].ccParsedCount; if (sc) - httpHdrScUpdateStats(sc, &HttpHeaderStats[owner].scTypeDistr); + sc->updateStats(&HttpHeaderStats[owner].scTypeDistr); httpHeaderNoteParsedEntry(HDR_SURROGATE_CONTROL, s, !sc); return sc; } HttpHdrContRange * HttpHeader::getContRange() const { HttpHdrContRange *cr = NULL; HttpHeaderEntry *e; if ((e = findEntry(HDR_CONTENT_RANGE))) { cr = httpHdrContRangeParseCreate(e->value.termedBuf()); httpHeaderNoteParsedEntry(e->id, e->value, !cr); } return cr; } === modified file 'src/HttpReply.cc' --- src/HttpReply.cc 2011-09-28 22:42:19 +0000 +++ src/HttpReply.cc 2011-10-04 22:01:48 +0000 @@ -391,41 +391,41 @@ content_type.limitInit(str, strcspn(str, ";\t ")); else content_type = String(); /* be sure to set expires after date and cache-control */ expires = hdrExpirationTime(); } /* sync this routine when you update HttpReply struct */ void HttpReply::hdrCacheClean() { content_type.clean(); if (cache_control) { delete cache_control; cache_control = NULL; } if (surrogate_control) { - httpHdrScDestroy(surrogate_control); + delete surrogate_control; surrogate_control = NULL; } if (content_range) { httpHdrContRangeDestroy(content_range); content_range = NULL; } } /* * Returns the body size of a HTTP response */ int64_t HttpReply::bodySize(const HttpRequestMethod& method) const { if (sline.version.major < 1) return -1; else if (method.id() == METHOD_HEAD) return 0; else if (sline.status == HTTP_OK) === modified file 'src/esi/Esi.cc' --- src/esi/Esi.cc 2011-05-13 08:13:01 +0000 +++ src/esi/Esi.cc 2011-10-30 19:03:36 +0000 @@ -2415,39 +2415,39 @@ CBDATA_INIT_TYPE_FREECB(esiOtherwise, esiSequence::Free); rv = (void *)cbdataAlloc (esiOtherwise); return rv; } void esiOtherwise::operator delete (void *address) { cbdataFree (address); } #endif /* TODO: implement surrogate targeting and control processing */ int esiEnableProcessing (HttpReply *rep) { int rv = 0; if (rep->surrogate_control) { - HttpHdrScTarget *sctusable = httpHdrScGetMergedTarget (rep->surrogate_control, - Config.Accel.surrogate_id); + HttpHdrScTarget *sctusable = + rep->surrogate_control->getMergedTarget(Config.Accel.surrogate_id); - if (!sctusable || sctusable->content.size() == 0) + if (!sctusable || sctusable->hasContent()) /* Nothing generic or targeted at us, or no * content processing requested */ return 0; - if (sctusable->content.pos("ESI/1.0") != NULL) + if (sctusable->content().pos("ESI/1.0") != NULL) rv = 1; - httpHdrScTargetDestroy (sctusable); + delete sctusable; } return rv; } #endif /* USE_SQUID_ESI == 1 */ === modified file 'src/http.cc' --- src/http.cc 2011-10-04 10:34:19 +0000 +++ src/http.cc 2011-10-13 18:24:55 +0000 @@ -277,68 +277,68 @@ * changed. */ if (e->mem_obj->request) pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_HEAD); else pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD); if (pe != NULL) { assert(e != pe); #if USE_HTCP neighborsHtcpClear(e, NULL, e->mem_obj->request, HttpRequestMethod(METHOD_HEAD), HTCP_CLR_INVALIDATION); #endif pe->release(); } } void HttpStateData::processSurrogateControl(HttpReply *reply) { if (request->flags.accelerated && reply->surrogate_control) { - HttpHdrScTarget *sctusable = httpHdrScGetMergedTarget(reply->surrogate_control, Config.Accel.surrogate_id); + HttpHdrScTarget *sctusable = reply->surrogate_control->getMergedTarget(Config.Accel.surrogate_id); if (sctusable) { - if (EBIT_TEST(sctusable->mask, SC_NO_STORE) || + if (sctusable->noStore() || (Config.onoff.surrogate_is_remote - && EBIT_TEST(sctusable->mask, SC_NO_STORE_REMOTE))) { + && sctusable->noStoreRemote())) { surrogateNoStore = true; entry->makePrivate(); } /* The HttpHeader logic cannot tell if the header it's parsing is a reply to an * accelerated request or not... * Still, this is an abstraction breach. - RC */ - if (sctusable->max_age != -1) { - if (sctusable->max_age < sctusable->max_stale) - reply->expires = reply->date + sctusable->max_age; + if (sctusable->hasMaxAge()) { + if (sctusable->maxAge() < sctusable->maxStale()) + reply->expires = reply->date + sctusable->maxAge(); else - reply->expires = reply->date + sctusable->max_stale; + reply->expires = reply->date + sctusable->maxStale(); /* And update the timestamps */ entry->timestampsSet(); } /* We ignore cache-control directives as per the Surrogate specification */ ignoreCacheControl = true; - httpHdrScTargetDestroy(sctusable); + delete sctusable; } } } int HttpStateData::cacheableReply() { HttpReply const *rep = finalReply(); HttpHeader const *hdr = &rep->header; const char *v; #if USE_HTTP_VIOLATIONS const refresh_t *R = NULL; /* This strange looking define first looks up the refresh pattern * and then checks if the specified flag is set. The main purpose * of this is to simplify the refresh pattern lookup and USE_HTTP_VIOLATIONS * condition */ #define REFRESH_OVERRIDE(flag) \