# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: kinkie@squid-cache.org-20110926200540-q7upakd61d4bclly # target_branch: ../trunk/ # testament_sha1: 3c469cf92d953c74863320896098a0b52bf18c19 # timestamp: 2011-09-26 22:08:15 +0200 # base_revision_id: squid3@treenet.co.nz-20110918025418-\ # uoxqj1fxx199qsgb # # Begin patch === modified file 'src/HttpHdrCc.cc' --- src/HttpHdrCc.cc 2010-12-27 20:25:30 +0000 +++ src/HttpHdrCc.cc 2011-09-26 20:05:40 +0000 @@ -1,9 +1,6 @@ - /* - * $Id$ * * DEBUG: section 65 HTTP Cache Control Header - * AUTHOR: Alex Rousskov * * SQUID Web Proxy Cache http://www.squid-cache.org/ * ---------------------------------------------------------- @@ -36,28 +33,58 @@ #include "squid.h" #include "Store.h" #include "HttpHeader.h" - -/* this table is used for parsing cache control header */ -static const HttpHeaderFieldAttrs CcAttrs[CC_ENUM_END] = { - {"public", (http_hdr_type)CC_PUBLIC}, - - {"private", (http_hdr_type)CC_PRIVATE}, - {"no-cache", (http_hdr_type)CC_NO_CACHE}, - {"no-store", (http_hdr_type)CC_NO_STORE}, - {"no-transform", (http_hdr_type)CC_NO_TRANSFORM}, - {"must-revalidate", (http_hdr_type)CC_MUST_REVALIDATE}, - {"proxy-revalidate", (http_hdr_type)CC_PROXY_REVALIDATE}, - {"only-if-cached", (http_hdr_type)CC_ONLY_IF_CACHED}, - {"max-age", (http_hdr_type)CC_MAX_AGE}, - {"s-maxage", (http_hdr_type)CC_S_MAXAGE}, - {"max-stale", (http_hdr_type)CC_MAX_STALE}, - {"stale-if-error", (http_hdr_type)CC_STALE_IF_ERROR}, - {"min-fresh", (http_hdr_type)CC_MIN_FRESH}, - {"Other,", (http_hdr_type)CC_OTHER} /* ',' will protect from matches */ -}; - -HttpHeaderFieldInfo *CcFieldsInfo = NULL; - +#include "HttpHdrCc.h" + +#if HAVE_MAP +#include +#endif + +/** dumb char* /length combo for quick lookups. + * + * Data is not copied. + * Validity of the pointed-to storage is responsibility of the caller. + * */ +class strblob { + public: + strblob(const char * ptr, size_t len): thePtr(ptr), theLen(len) {} + bool operator==(strblob &s) const { return theLen==s.theLen && 0==strncmp(thePtr,s.thePtr,theLen); } + bool operator< ( const strblob &s2) const { return strncmp(thePtr,s2.thePtr,theLen) < 0; } + + private: + const char *thePtr; + size_t theLen; +}; + +/* a row in the table used for parsing cache control header and statistics */ +typedef struct { + const char *name; + http_hdr_cc_type id; + HttpHeaderFieldStat stat; +} HttpHeaderCcFields; + +/* order must match that of enum http_hdr_cc_type. The constraint is verified at initialization time */ +static HttpHeaderCcFields CcAttrs[CC_ENUM_END] = { + {"public", CC_PUBLIC}, + {"private", CC_PRIVATE}, + {"no-cache", CC_NO_CACHE}, + {"no-store", CC_NO_STORE}, + {"no-transform", CC_NO_TRANSFORM}, + {"must-revalidate", CC_MUST_REVALIDATE}, + {"proxy-revalidate", CC_PROXY_REVALIDATE}, + {"max-age", CC_MAX_AGE}, + {"s-maxage", CC_S_MAXAGE}, + {"max-stale", CC_MAX_STALE}, + {"min-fresh", CC_MIN_FRESH}, + {"only-if-cached", CC_ONLY_IF_CACHED}, + {"stale-if-error", CC_STALE_IF_ERROR}, + {"Other,", CC_OTHER} /* ',' will protect from matches */ +}; + +/// Map an header name to its type, to expedite parsing +typedef std::map CcNameToIdMap_t; +static CcNameToIdMap_t CcNameToIdMap; + +/// iterate over a table of http_header_cc_type structs http_hdr_cc_type &operator++ (http_hdr_cc_type &aHeader) { int tmp = (int)aHeader; @@ -66,52 +93,34 @@ } -/* local prototypes */ -static int httpHdrCcParseInit(HttpHdrCc * cc, const String * str); - - -/* module initialization */ - +/// Module initialization hook void httpHdrCcInitModule(void) { - CcFieldsInfo = httpHeaderBuildFieldsInfo(CcAttrs, CC_ENUM_END); + /* build lookup and accounting structures */ + for (int32_t i = 0;i < CC_ENUM_END; ++i) { + const HttpHeaderCcFields *f=&CcAttrs[i]; + assert(i == f->id); /* verify assumption: the id is the key into the array */ + const strblob k(f->name,strlen(f->name)); + CcNameToIdMap[k]=f->id; + } } +/// Module cleanup hook. void httpHdrCcCleanModule(void) { - httpHeaderDestroyFieldsInfo(CcFieldsInfo, CC_ENUM_END); - CcFieldsInfo = NULL; -} - -/* implementation */ - -HttpHdrCc * -httpHdrCcCreate(void) -{ - HttpHdrCc *cc = (HttpHdrCc *)memAllocate(MEM_HTTP_HDR_CC); - cc->max_age = cc->s_maxage = cc->max_stale = cc->min_fresh = -1; - return cc; -} - -/* creates an cc object from a 0-terminating string */ -HttpHdrCc * -httpHdrCcParseCreate(const String * str) -{ - HttpHdrCc *cc = httpHdrCcCreate(); - - if (!httpHdrCcParseInit(cc, str)) { - httpHdrCcDestroy(cc); - cc = NULL; - } - - return cc; -} - -/* parses a 0-terminating string and inits cc */ -static int -httpHdrCcParseInit(HttpHdrCc * cc, const String * str) + // HdrCcNameToIdMap is self-cleaning +} + +void +HttpHdrCc::clear() +{ + *this=HttpHdrCc(); +} + +bool +HttpHdrCc::parse(const String & str) { const char *item; const char *p; /* '=' parameter */ @@ -119,11 +128,11 @@ http_hdr_cc_type type; int ilen; int nlen; - assert(cc && str); + HttpHdrCc *cc=this; //TODO: remove after review /* iterate through comma separated list */ - while (strListGetItem(str, ',', &item, &ilen, &pos)) { + while (strListGetItem(&str, ',', &item, &ilen, &pos)) { /* isolate directive name */ if ((p = (const char *)memchr(item, '=', ilen)) && (p - item < ilen)) @@ -132,19 +141,18 @@ nlen = ilen; /* find type */ - type = (http_hdr_cc_type ) httpHeaderIdByName(item, nlen, - CcFieldsInfo, CC_ENUM_END); - - if (type < 0) { - debugs(65, 2, "hdr cc: unknown cache-directive: near '" << item << "' in '" << str << "'"); - type = CC_OTHER; - } + const strblob tmpstr(item,nlen); + const CcNameToIdMap_t::iterator i=CcNameToIdMap.find(tmpstr); + if (i==CcNameToIdMap.end()) + type=CC_OTHER; + else + type=i->second; // ignore known duplicate directives if (EBIT_TEST(cc->mask, type)) { if (type != CC_OTHER) { debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item << "' in '" << str << "'"); - CcFieldsInfo[type].stat.repCount++; + ++CcAttrs[type].stat.repCount; continue; } } else { @@ -155,11 +163,12 @@ switch (type) { case CC_MAX_AGE: - - if (!p || !httpHeaderParseInt(p, &cc->max_age)) { + int32_t ma; + if (!p || !httpHeaderParseInt(p, &ma)) { debugs(65, 2, "cc: invalid max-age specs near '" << item << "'"); - cc->max_age = -1; - EBIT_CLR(cc->mask, type); + cc->setMaxAge(MAX_AGE_UNSET); + } else { + cc->setMaxAge(ma); } break; @@ -168,8 +177,7 @@ if (!p || !httpHeaderParseInt(p, &cc->s_maxage)) { debugs(65, 2, "cc: invalid s-maxage specs near '" << item << "'"); - cc->s_maxage = -1; - EBIT_CLR(cc->mask, type); + cc->setSMaxAge(S_MAXAGE_UNSET); } break; @@ -178,7 +186,7 @@ if (!p || !httpHeaderParseInt(p, &cc->max_stale)) { debugs(65, 2, "cc: max-stale directive is valid without value"); - cc->max_stale = -1; + cc->setMaxStale(MAX_STALE_ALWAYS); } break; @@ -187,8 +195,7 @@ if (!p || !httpHeaderParseInt(p, &cc->min_fresh)) { debugs(65, 2, "cc: invalid min-fresh specs near '" << item << "'"); - cc->min_fresh = -1; - EBIT_CLR(cc->mask, type); + cc->setMinFresh(MIN_FRESH_UNSET); } break; @@ -196,8 +203,7 @@ case CC_STALE_IF_ERROR: if (!p || !httpHeaderParseInt(p, &cc->stale_if_error)) { debugs(65, 2, "cc: invalid stale-if-error specs near '" << item << "'"); - cc->stale_if_error = -1; - EBIT_CLR(cc->mask, type); + cc->setStaleIfError(STALE_IF_ERROR_UNSET); } break; @@ -216,32 +222,7 @@ } } - return cc->mask != 0; -} - -void -httpHdrCcDestroy(HttpHdrCc * cc) -{ - assert(cc); - - if (cc->other.defined()) - cc->other.clean(); - - memFree(cc, MEM_HTTP_HDR_CC); -} - -HttpHdrCc * -httpHdrCcDup(const HttpHdrCc * cc) -{ - HttpHdrCc *dup; - assert(cc); - dup = httpHdrCcCreate(); - dup->mask = cc->mask; - dup->max_age = cc->max_age; - dup->s_maxage = cc->s_maxage; - dup->max_stale = cc->max_stale; - dup->min_fresh = cc->min_fresh; - return dup; + return (cc->mask != 0); } void @@ -255,24 +236,23 @@ if (EBIT_TEST(cc->mask, flag) && flag != CC_OTHER) { /* print option name */ - packerPrintf(p, (pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH), - SQUIDSTRINGPRINT(CcFieldsInfo[flag].name)); + packerPrintf(p, (pcount ? ", %s": "%s") , CcAttrs[flag].name); /* handle options with values */ if (flag == CC_MAX_AGE) - packerPrintf(p, "=%d", (int) cc->max_age); + packerPrintf(p, "=%d", (int) cc->getMaxAge()); if (flag == CC_S_MAXAGE) - packerPrintf(p, "=%d", (int) cc->s_maxage); + packerPrintf(p, "=%d", (int) cc->getSMaxAge()); - if (flag == CC_MAX_STALE && cc->max_stale >= 0) - packerPrintf(p, "=%d", (int) cc->max_stale); + if (flag == CC_MAX_STALE && cc->getMaxStale() >= 0) + packerPrintf(p, "=%d", (int) cc->getMaxStale()); if (flag == CC_MIN_FRESH) - packerPrintf(p, "=%d", (int) cc->min_fresh); + packerPrintf(p, "=%d", (int) cc->getMinFresh()); - pcount++; + ++pcount; } } @@ -281,32 +261,6 @@ SQUIDSTRINGPRINT(cc->other)); } -/* negative max_age will clean old max_Age setting */ -void -httpHdrCcSetMaxAge(HttpHdrCc * cc, int max_age) -{ - assert(cc); - cc->max_age = max_age; - - if (max_age >= 0) - EBIT_SET(cc->mask, CC_MAX_AGE); - else - EBIT_CLR(cc->mask, CC_MAX_AGE); -} - -/* negative s_maxage will clean old s-maxage setting */ -void -httpHdrCcSetSMaxAge(HttpHdrCc * cc, int s_maxage) -{ - assert(cc); - cc->s_maxage = s_maxage; - - if (s_maxage >= 0) - EBIT_SET(cc->mask, CC_S_MAXAGE); - else - EBIT_CLR(cc->mask, CC_S_MAXAGE); -} - void httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist) { @@ -324,9 +278,13 @@ extern const HttpHeaderStat *dump_stat; /* argh! */ const int id = (int) val; const int valid_id = id >= 0 && id < CC_ENUM_END; - const char *name = valid_id ? CcFieldsInfo[id].name.termedBuf() : "INVALID"; + const char *name = valid_id ? CcAttrs[id].name : "INVALID"; if (count || valid_id) storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n", id, name, count, xdiv(count, dump_stat->ccParsedCount)); } + +#if !_USE_INLINE_ +#include "HttpHdrCc.cci" +#endif === added file 'src/HttpHdrCc.cci' --- src/HttpHdrCc.cci 1970-01-01 00:00:00 +0000 +++ src/HttpHdrCc.cci 2011-09-26 19:58:43 +0000 @@ -0,0 +1,122 @@ +/* + * + * DEBUG: section 65 HTTP Cache Control Header + * + * 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. + * + */ + + +void +HttpHdrCc::setMaxAge(int max_age_) +{ + + if (max_age_ >= 0) { + EBIT_SET(mask, CC_MAX_AGE); + max_age = max_age_; + } else { + EBIT_CLR(mask, CC_MAX_AGE); + max_age=MAX_AGE_UNSET; + } +} + +int32_t +HttpHdrCc::getMaxAge() const +{ + return max_age; +} + +void +HttpHdrCc::setSMaxAge(int32_t s_maxage) +{ + if (s_maxage >= 0) { + EBIT_SET(mask, CC_S_MAXAGE); + this->s_maxage=s_maxage; + } else { + EBIT_CLR(mask, CC_S_MAXAGE); + this->s_maxage=S_MAXAGE_UNSET; + } +} + +int32_t +HttpHdrCc::getSMaxAge() const +{ + return s_maxage; +} + +void +HttpHdrCc::setMaxStale(int32_t max_stale) +{ + if (max_stale>=0 || max_stale==MAX_STALE_ALWAYS) { + EBIT_SET(mask,CC_MAX_STALE); + this->max_stale=max_stale; + } else { + EBIT_CLR(mask, CC_MAX_STALE); + this->max_stale=MAX_STALE_UNSET; + } +} +int32_t +HttpHdrCc::getMaxStale() const +{ + return max_stale; +} + +void +HttpHdrCc::setStaleIfError(int32_t stale_if_error) +{ + if (stale_if_error >= 0) { + EBIT_SET(mask, CC_STALE_IF_ERROR); + this->stale_if_error=stale_if_error; + } else { + EBIT_CLR(mask, CC_STALE_IF_ERROR); + this->stale_if_error=STALE_IF_ERROR_UNSET; + } +} + +int32_t +HttpHdrCc::getStaleIfError() const +{ + return stale_if_error; +} + +void +HttpHdrCc::setMinFresh(int32_t min_fresh) +{ + if (min_fresh >= 0) { + EBIT_SET(mask, CC_MIN_FRESH); + this->min_fresh=min_fresh; + } else { + EBIT_CLR(mask, CC_MIN_FRESH); + this->min_fresh=STALE_IF_ERROR_UNSET; + } +} + +int32_t +HttpHdrCc::getMinFresh() const +{ + return min_fresh; +} === added file 'src/HttpHdrCc.h' --- src/HttpHdrCc.h 1970-01-01 00:00:00 +0000 +++ src/HttpHdrCc.h 2011-09-26 19:58:43 +0000 @@ -0,0 +1,96 @@ +/* + * HttpHdrCc.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 SQUID_HTTPHDRCC_H +#define SQUID_HTTPHDRCC_H + +#include "config.h" +#include "MemPool.h" +#include "SquidString.h" + +/** Http Cache-Control header representation + * + * Store and parse the Cache-Control HTTP header. + */ +class HttpHdrCc +{ + +public: + static const int32_t MAX_AGE_UNSET=-1; //max-age is unset + static const int32_t S_MAXAGE_UNSET=-1; //s-maxage is unset + static const int32_t MAX_STALE_UNSET=-1; //max-stale is unset + static const int32_t MAX_STALE_ALWAYS=-2; //max-stale is set to no value + static const int32_t STALE_IF_ERROR_UNSET=-1; //stale_if_error is unset + static const int32_t MIN_FRESH_UNSET=-1; //min_fresh is unset + + explicit HttpHdrCc() : + mask(0), max_age(MAX_AGE_UNSET), s_maxage(S_MAXAGE_UNSET), + max_stale(MAX_STALE_UNSET), stale_if_error(STALE_IF_ERROR_UNSET), + min_fresh(MIN_FRESH_UNSET) {} + + void clear(); + bool parse(const String & s); + + _SQUID_INLINE_ void setMaxAge(int32_t max_age); + _SQUID_INLINE_ int32_t getMaxAge() const; + + _SQUID_INLINE_ void setSMaxAge(int32_t s_maxage); + _SQUID_INLINE_ int32_t getSMaxAge() const; + + _SQUID_INLINE_ void setMaxStale(int32_t max_stale); + _SQUID_INLINE_ int32_t getMaxStale() const; + + _SQUID_INLINE_ void setStaleIfError(int32_t stale_if_error); + _SQUID_INLINE_ int32_t getStaleIfError() const; + + _SQUID_INLINE_ void setMinFresh(int32_t min_fresh); + _SQUID_INLINE_ int32_t getMinFresh() const; + + MEMPROXY_CLASS(HttpHdrCc); + + int32_t mask; +private: + int32_t max_age; + int32_t s_maxage; + int32_t max_stale; + int32_t stale_if_error; + int32_t min_fresh; +public: + String other; +}; + +MEMPROXY_CLASS_INLINE(HttpHdrCc); + +#if _USE_INLINE_ +#include "HttpHdrCc.cci" +#endif + +#endif /* SQUID_HTTPHDRCC_H */ === modified file 'src/HttpHeader.cc' --- src/HttpHeader.cc 2011-08-29 03:47:54 +0000 +++ src/HttpHeader.cc 2011-09-14 18:21:46 +0000 @@ -36,6 +36,7 @@ #include "squid.h" #include "base64.h" #include "HttpHdrContRange.h" +#include "HttpHdrCc.h" #include "HttpHdrSc.h" #include "HttpHeader.h" #include "MemBuf.h" @@ -1312,14 +1313,22 @@ { HttpHdrCc *cc; String s; + bool gotList; if (!CBIT_TEST(mask, HDR_CACHE_CONTROL)) return NULL; PROF_start(HttpHeader_getCc); - getList(HDR_CACHE_CONTROL, &s); - - cc = httpHdrCcParseCreate(&s); + gotList=getList(HDR_CACHE_CONTROL, &s); + + cc=new HttpHdrCc(); + if (!gotList) + return cc; + + if (!cc->parse(s)) { + delete cc; + cc = NULL; + } HttpHeaderStats[owner].ccParsedCount++; === modified file 'src/HttpReply.cc' --- src/HttpReply.cc 2011-07-16 15:21:48 +0000 +++ src/HttpReply.cc 2011-09-26 19:50:51 +0000 @@ -38,6 +38,7 @@ #include "Store.h" #include "HttpReply.h" #include "HttpHdrContRange.h" +#include "HttpHdrCc.h" #include "HttpHdrSc.h" #include "acl/FilledChecklist.h" #include "HttpRequest.h" @@ -330,21 +331,21 @@ if (cache_control) { if (date >= 0) { - if (cache_control->s_maxage >= 0) - return date + cache_control->s_maxage; + if (cache_control->getSMaxAge() != HttpHdrCc::S_MAXAGE_UNSET) + return date + cache_control->getSMaxAge(); - if (cache_control->max_age >= 0) - return date + cache_control->max_age; + if (cache_control->getMaxAge() != HttpHdrCc::MAX_AGE_UNSET) + return date + cache_control->getMaxAge(); } else { /* * Conservatively handle the case when we have a max-age * header, but no Date for reference? */ - if (cache_control->s_maxage >= 0) + if (cache_control->getSMaxAge() != HttpHdrCc::S_MAXAGE_UNSET) return squid_curtime; - if (cache_control->max_age >= 0) + if (cache_control->getMaxAge() != HttpHdrCc::MAX_AGE_UNSET) return squid_curtime; } } @@ -402,7 +403,7 @@ content_type.clean(); if (cache_control) { - httpHdrCcDestroy(cache_control); + delete cache_control; cache_control = NULL; } === modified file 'src/HttpRequest.cc' --- src/HttpRequest.cc 2011-08-04 03:21:06 +0000 +++ src/HttpRequest.cc 2011-09-14 18:21:46 +0000 @@ -37,6 +37,7 @@ #include "squid.h" #include "DnsLookupDetails.h" #include "HttpRequest.h" +#include "HttpHdrCc.h" #if USE_AUTH #include "auth/UserRequest.h" #endif @@ -145,7 +146,7 @@ header.clean(); if (cache_control) { - httpHdrCcDestroy(cache_control); + delete cache_control; cache_control = NULL; } === modified file 'src/Makefile.am' --- src/Makefile.am 2011-09-11 23:40:46 +0000 +++ src/Makefile.am 2011-09-16 18:33:19 +0000 @@ -342,6 +342,7 @@ HttpStatusCode.h \ HttpStatusLine.cc \ HttpStatusLine.h \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrRange.cc \ HttpHdrSc.cc \ @@ -1034,6 +1035,7 @@ cbdata.h \ ETag.cc \ HttpBody.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrContRange.cc \ HttpHdrContRange.h \ @@ -1093,7 +1095,7 @@ tests_testHttpReply_DEPENDENCIES= $(SQUID_CPPUNIT_LA) ## Tests for the ACLMaxUserIP class -## acl needs wordlist. wordlist needs MemBug +## acl needs wordlist. wordlist needs MemBuf ## MemBuf needs mem, MemBuf needs event, ## event needs cbdata. ## ACLMaxUserUP needs $(AUTH_LIBS) @@ -1129,6 +1131,7 @@ HttpHeaderTools.cc \ HttpHdrContRange.cc \ HttpHdrRange.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrSc.cc \ HttpHdrScTarget.cc \ @@ -1294,6 +1297,7 @@ HttpBody.cc \ HttpHeader.cc \ HttpHeaderTools.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrContRange.cc \ HttpHdrRange.cc \ @@ -1430,6 +1434,7 @@ fd.cc \ filemap.cc \ HttpBody.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrContRange.cc \ HttpHdrSc.cc \ @@ -1605,6 +1610,7 @@ HttpBody.cc \ HttpHeader.cc \ HttpHeaderTools.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrContRange.cc \ HttpHdrRange.cc \ @@ -1790,6 +1796,7 @@ HttpBody.cc \ HttpHeader.cc \ HttpHeaderTools.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrContRange.cc \ HttpHdrRange.cc \ @@ -1971,6 +1978,7 @@ $(HTCPSOURCE) \ http.cc \ HttpBody.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrContRange.cc \ HttpHdrRange.cc \ @@ -2196,6 +2204,7 @@ HttpBody.cc \ HttpHeader.cc \ HttpHeaderTools.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrContRange.cc \ HttpHdrRange.cc \ @@ -2328,6 +2337,7 @@ event.cc \ EventLoop.cc \ filemap.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrContRange.cc \ HttpHdrRange.cc \ @@ -2566,6 +2576,7 @@ MemBuf.cc \ HttpHdrContRange.cc \ Packer.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrSc.cc \ HttpHdrScTarget.cc \ @@ -2696,6 +2707,7 @@ MemBuf.cc \ HttpHdrContRange.cc \ Packer.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrSc.cc \ HttpHdrScTarget.cc \ @@ -2825,6 +2837,7 @@ MemBuf.cc \ HttpHdrContRange.cc \ Packer.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrSc.cc \ HttpHdrScTarget.cc \ @@ -2927,6 +2940,7 @@ $(HTCPSOURCE) \ http.cc \ HttpBody.cc \ + HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrContRange.cc \ HttpHdrRange.cc \ === modified file 'src/client_side_request.cc' --- src/client_side_request.cc 2011-09-04 18:28:39 +0000 +++ src/client_side_request.cc 2011-09-16 18:33:19 +0000 @@ -67,6 +67,7 @@ #include "compat/inet_pton.h" #include "fde.h" #include "format/Tokens.h" +#include "HttpHdrCc.h" #include "HttpReply.h" #include "HttpRequest.h" #include "ip/QosConfig.h" === modified file 'src/enums.h' --- src/enums.h 2011-07-16 04:00:55 +0000 +++ src/enums.h 2011-09-14 18:21:46 +0000 @@ -218,7 +218,6 @@ MEM_DLINK_NODE, MEM_DREAD_CTRL, MEM_DWRITE_Q, - MEM_HTTP_HDR_CC, MEM_HTTP_HDR_CONTENT_RANGE, MEM_MD5_DIGEST, MEM_NETDBENTRY, === modified file 'src/http.cc' --- src/http.cc 2011-08-30 15:04:30 +0000 +++ src/http.cc 2011-09-21 07:52:42 +0000 @@ -58,6 +58,7 @@ #include "http.h" #include "HttpControlMsg.h" #include "HttpHdrContRange.h" +#include "HttpHdrCc.h" #include "HttpHdrSc.h" #include "HttpHdrScTarget.h" #include "HttpReply.h" @@ -927,7 +928,8 @@ if (!ignoreCacheControl && rep->cache_control) { if (EBIT_TEST(rep->cache_control->mask, CC_PROXY_REVALIDATE) || EBIT_TEST(rep->cache_control->mask, CC_MUST_REVALIDATE) || - EBIT_TEST(rep->cache_control->mask, CC_S_MAXAGE)) + rep->cache_control->getSMaxAge() != HttpHdrCc::S_MAXAGE_UNSET + ) EBIT_SET(entry->flags, ENTRY_REVALIDATE); } @@ -1760,7 +1762,7 @@ HttpHdrCc *cc = hdr_in->getCc(); if (!cc) - cc = httpHdrCcCreate(); + cc = new HttpHdrCc(); #if 0 /* see bug 2330 */ /* Set no-cache if determined needed but not found */ @@ -1769,10 +1771,10 @@ #endif /* Add max-age only without no-cache */ - if (!EBIT_TEST(cc->mask, CC_MAX_AGE) && !EBIT_TEST(cc->mask, CC_NO_CACHE)) { + if (cc->getMaxAge()==HttpHdrCc::MAX_AGE_UNSET && !EBIT_TEST(cc->mask, CC_NO_CACHE)) { const char *url = entry ? entry->url() : urlCanonical(request); - httpHdrCcSetMaxAge(cc, getMaxAge(url)); + cc->setMaxAge(getMaxAge(url)); } @@ -1782,7 +1784,7 @@ hdr_out->putCc(cc); - httpHdrCcDestroy(cc); + delete cc; } /* maybe append Connection: keep-alive */ === modified file 'src/mem.cc' --- src/mem.cc 2011-08-10 15:54:51 +0000 +++ src/mem.cc 2011-09-16 18:33:19 +0000 @@ -453,7 +453,6 @@ memDataInit(MEM_DLINK_NODE, "dlink_node", sizeof(dlink_node), 10); memDataInit(MEM_DREAD_CTRL, "dread_ctrl", sizeof(dread_ctrl), 0); memDataInit(MEM_DWRITE_Q, "dwrite_q", sizeof(dwrite_q), 0); - memDataInit(MEM_HTTP_HDR_CC, "HttpHdrCc", sizeof(HttpHdrCc), 0); memDataInit(MEM_HTTP_HDR_CONTENT_RANGE, "HttpHdrContRange", sizeof(HttpHdrContRange), 0); memDataInit(MEM_NETDBENTRY, "netdbEntry", sizeof(netdbEntry), 0); memDataInit(MEM_NET_DB_NAME, "net_db_name", sizeof(net_db_name), 0); === modified file 'src/mime.cc' --- src/mime.cc 2011-01-28 07:58:53 +0000 +++ src/mime.cc 2011-09-14 18:21:46 +0000 @@ -34,6 +34,7 @@ */ #include "squid.h" +#include "HttpHdrCc.h" #include "Store.h" #include "StoreClient.h" #include "HttpReply.h" @@ -462,9 +463,9 @@ reply->setHeaders(HTTP_OK, NULL, mimeGetContentType(icon), sb.st_size, sb.st_mtime, -1); - reply->cache_control = httpHdrCcCreate(); + reply->cache_control = new HttpHdrCc(); - httpHdrCcSetMaxAge(reply->cache_control, 86400); + reply->cache_control->setMaxAge(86400); reply->header.putCc(reply->cache_control); === modified file 'src/protos.h' --- src/protos.h 2011-08-30 15:04:30 +0000 +++ src/protos.h 2011-09-16 18:33:19 +0000 @@ -237,13 +237,7 @@ /* Http Cache Control Header Field */ SQUIDCEXTERN void httpHdrCcInitModule(void); SQUIDCEXTERN void httpHdrCcCleanModule(void); -SQUIDCEXTERN HttpHdrCc *httpHdrCcCreate(void); -SQUIDCEXTERN HttpHdrCc *httpHdrCcParseCreate(const String * str); -SQUIDCEXTERN void httpHdrCcDestroy(HttpHdrCc * cc); -SQUIDCEXTERN HttpHdrCc *httpHdrCcDup(const HttpHdrCc * cc); SQUIDCEXTERN void httpHdrCcPackInto(const HttpHdrCc * cc, Packer * p); -SQUIDCEXTERN void httpHdrCcSetMaxAge(HttpHdrCc * cc, int max_age); -SQUIDCEXTERN void httpHdrCcSetSMaxAge(HttpHdrCc * cc, int s_maxage); SQUIDCEXTERN void httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist); void httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count); === modified file 'src/refresh.cc' --- src/refresh.cc 2011-09-12 00:31:13 +0000 +++ src/refresh.cc 2011-09-26 19:50:51 +0000 @@ -38,6 +38,7 @@ #endif #include "squid.h" +#include "HttpHdrCc.h" #include "mgr/Registration.h" #include "Store.h" #include "MemObject.h" @@ -267,14 +268,15 @@ if (request && !request->flags.ignore_cc) { const HttpHdrCc *const cc = request->cache_control; - if (cc && cc->min_fresh > 0) { + const int32_t minFresh=cc->getMinFresh(); + if (cc && minFresh!=HttpHdrCc::MIN_FRESH_UNSET) { debugs(22, 3, "\tage + min-fresh:\t" << age << " + " << - cc->min_fresh << " = " << age + cc->min_fresh); + minFresh << " = " << age + minFresh); debugs(22, 3, "\tcheck_time + min-fresh:\t" << check_time << " + " - << cc->min_fresh << " = " << - mkrfc1123(check_time + cc->min_fresh)); - age += cc->min_fresh; - check_time += cc->min_fresh; + << minFresh << " = " << + mkrfc1123(check_time + minFresh)); + age += minFresh; + check_time += minFresh; } } @@ -286,8 +288,8 @@ // stale-if-error requires any failure be passed thru when its period is over. if (request && entry->mem_obj && entry->mem_obj->getReply() && entry->mem_obj->getReply()->cache_control && - EBIT_TEST(entry->mem_obj->getReply()->cache_control->mask, CC_STALE_IF_ERROR) && - entry->mem_obj->getReply()->cache_control->stale_if_error < staleness) { + entry->mem_obj->getReply()->cache_control->getStaleIfError() != HttpHdrCc::STALE_IF_ERROR_UNSET && + entry->mem_obj->getReply()->cache_control->getStaleIfError() < staleness) { debugs(22, 3, "refreshCheck: stale-if-error period expired."); request->flags.fail_on_validation_err = 1; @@ -334,31 +336,31 @@ #endif if (NULL != cc) { - if (cc->max_age > -1) { + if (cc->getMaxAge() != HttpHdrCc::MAX_AGE_UNSET) { #if USE_HTTP_VIOLATIONS - if (R->flags.ignore_reload && cc->max_age == 0) { + if (R->flags.ignore_reload && cc->getMaxAge() == 0) { debugs(22, 3, "refreshCheck: MAYBE: client-max-age = 0 and ignore-reload"); } else #endif { - if (cc->max_age == 0) { + if (cc->getMaxAge() == 0) { debugs(22, 3, "refreshCheck: YES: client-max-age = 0"); return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE; } - if (age > cc->max_age) { + if (age > cc->getMaxAge()) { debugs(22, 3, "refreshCheck: YES: age > client-max-age"); return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE; } } } - if (EBIT_TEST(cc->mask, CC_MAX_STALE) && staleness > -1) { - if (cc->max_stale < 0) { + if (cc->getMaxStale()>=0 && staleness > -1) { + if (cc->getMaxStale()==HttpHdrCc::MAX_STALE_ALWAYS) { /* max-stale directive without a value */ debugs(22, 3, "refreshCheck: NO: max-stale wildcard"); return FRESH_REQUEST_MAX_STALE_ALL; - } else if (staleness < cc->max_stale) { + } else if (staleness < cc->getMaxStale()) { debugs(22, 3, "refreshCheck: NO: staleness < max-stale"); return FRESH_REQUEST_MAX_STALE_VALUE; } === modified file 'src/structs.h' --- src/structs.h 2011-09-11 22:21:35 +0000 +++ src/structs.h 2011-09-16 18:33:19 +0000 @@ -723,21 +723,6 @@ String value; /* field-value from HTTP/1.1 */ }; -/* http cache control header field */ - -class HttpHdrCc -{ - -public: - int mask; - int max_age; - int s_maxage; - int max_stale; - int stale_if_error; - int min_fresh; - String other; -}; - /* per field statistics */ class HttpHeaderFieldStat # Begin bundle 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