From: benno@jeamland.net <> Date: Thu, 28 Aug 2008 05:12:17 +0000 (+1000) Subject: RFC-compliant object invalidation behaviour. X-Git-Tag: SQUID_3_1_0_1~49^2~62^2~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3cbbd242fd449863c0fee22f0cf51c11217254c6;p=thirdparty%2Fsquid.git RFC-compliant object invalidation behaviour. - Switch the default from not purging if the method is unknown to purging if the method is unknown. - When purging URIs sourced from Location and Content-Location headers, make sure the URL is absolute before a) comparing it to see if hosts match and b) actually trying to find it in the store. --- diff --git a/src/HttpRequestMethod.cc b/src/HttpRequestMethod.cc index 8b05d813c5..5ac9323045 100644 --- a/src/HttpRequestMethod.cc +++ b/src/HttpRequestMethod.cc @@ -246,7 +246,7 @@ HttpRequestMethod::purgesOthers() const /* all others */ case METHOD_OTHER: default: - return false; // be conservative: we do not know some methods specs + return true; // RFC says to purge if we don't know the method } return false; // not reached diff --git a/src/Server.cc b/src/Server.cc index 935222c35a..3a2ecab9ef 100644 --- a/src/Server.cc +++ b/src/Server.cc @@ -402,11 +402,20 @@ sameUrlHosts(const char *url1, const char *url2) // purges entries that match the value of a given HTTP [response] header static void -purgeEntriesByHeader(const char *reqUrl, HttpMsg *rep, http_hdr_type hdr) -{ - if (const char *url = rep->header.getStr(hdr)) - if (sameUrlHosts(reqUrl, url)) // prevent purging DoS, per RFC 2616 +purgeEntriesByHeader(const HttpRequest *req, const char *reqUrl, HttpMsg *rep, http_hdr_type hdr) +{ + if (const char *url = rep->header.getStr(hdr)) { + const char *absUrl = urlAbsolute(req, url); + if (absUrl != NULL) { + url = absUrl; + } + if (sameUrlHosts(reqUrl, url)) { // prevent purging DoS, per RFC 2616 purgeEntriesByUrl(url); + } + if (absUrl != NULL) { + xfree((void *)absUrl); + } + } } // some HTTP methods should purge matching cache entries @@ -425,8 +434,8 @@ ServerStateData::maybePurgeOthers() const char *reqUrl = urlCanonical(request); debugs(88, 5, "maybe purging due to " << RequestMethodStr(request->method) << ' ' << reqUrl); purgeEntriesByUrl(reqUrl); - purgeEntriesByHeader(reqUrl, theFinalReply, HDR_LOCATION); - purgeEntriesByHeader(reqUrl, theFinalReply, HDR_CONTENT_LOCATION); + purgeEntriesByHeader(request, reqUrl, theFinalReply, HDR_LOCATION); + purgeEntriesByHeader(request, reqUrl, theFinalReply, HDR_CONTENT_LOCATION); } // called (usually by kids) when we have final (possibly adapted) reply headers diff --git a/src/protos.h b/src/protos.h index 313358bace..71f9fadee1 100644 --- a/src/protos.h +++ b/src/protos.h @@ -638,6 +638,7 @@ SQUIDCEXTERN protocol_t urlParseProtocol(const char *, const char *e = NULL); SQUIDCEXTERN void urlInitialize(void); SQUIDCEXTERN HttpRequest *urlParse(const HttpRequestMethod&, char *, HttpRequest *request = NULL); SQUIDCEXTERN const char *urlCanonical(HttpRequest *); +SQUIDCEXTERN const char *urlAbsolute(const HttpRequest *, const char *); SQUIDCEXTERN char *urlRInternal(const char *host, u_short port, const char *dir, const char *name); SQUIDCEXTERN char *urlInternal(const char *dir, const char *name); SQUIDCEXTERN int matchDomainName(const char *host, const char *domain); diff --git a/src/url.cc b/src/url.cc index 869ec4559b..8cdf775cdf 100644 --- a/src/url.cc +++ b/src/url.cc @@ -532,6 +532,70 @@ urlCanonicalClean(const HttpRequest * request) return buf; } +const char * +urlAbsolute(const HttpRequest * req, const char *relUrl) +{ + LOCAL_ARRAY(char, portbuf, 32); + LOCAL_ARRAY(char, urlbuf, MAX_URL); + char *path, *last_slash; + + if (relUrl == NULL) { + return (NULL); + } + if (req->method.id() == METHOD_CONNECT) { + return (NULL); + } + if (strchr(relUrl, ':') != NULL) { + return (NULL); + } + if (req->protocol == PROTO_URN) { + snprintf(urlbuf, MAX_URL, "urn:%s", req->urlpath.buf()); + } else { + portbuf[0] = '\0'; + if (req->port != urlDefaultPort(req->protocol)) { + snprintf(portbuf, 32, ":%d", req->port); + } + if (relUrl[0] == '/') { + snprintf(urlbuf, MAX_URL, "%s://%s%s%s%s%s", + ProtocolStr[req->protocol], + req->login, + *req->login ? "@" : null_string, + req->GetHost(), + portbuf, + relUrl + ); + } else { + path = xstrdup(req->urlpath.buf()); + last_slash = strrchr(path, '/'); + if (last_slash == NULL) { + snprintf(urlbuf, MAX_URL, "%s://%s%s%s%s/%s", + ProtocolStr[req->protocol], + req->login, + *req->login ? "@" : null_string, + req->GetHost(), + portbuf, + relUrl + ); + } else { + last_slash++; + *last_slash = '\0'; + snprintf(urlbuf, MAX_URL, "%s://%s%s%s%s%s%s", + ProtocolStr[req->protocol], + req->login, + *req->login ? "@" : null_string, + req->GetHost(), + portbuf, + path, + relUrl + ); + } + xfree(path); + } + } + + return (xstrdup(urlbuf)); +} + /* * matchDomainName() compares a hostname with a domainname according * to the following rules: