# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: benno@squid-cache.org-20080903044227-s1vsrpyb4mlbnvlf # target_branch: http://www.squid-cache.org/bzr/squid3/trunk/ # testament_sha1: 623f171d6e06626c28aa1dd5e02cf8b18daff6ca # timestamp: 2008-09-03 14:43:27 +1000 # base_revision_id: squid3@treenet.co.nz-20080828125715-\ # ejhnqdep2qm6qz0h # # Begin patch === modified file 'src/HttpRequestMethod.cc' --- src/HttpRequestMethod.cc 2008-06-20 04:43:01 +0000 +++ src/HttpRequestMethod.cc 2008-08-29 00:56:35 +0000 @@ -243,11 +243,16 @@ case METHOD_PURGE: return true; - /* all others */ + /* + * RFC 2616 sayeth, in section 13.10, final paragraph: + * A cache that passes through requests for methods it does not + * understand SHOULD invalidate any entities referred to by the + * Request-URI. + */ case METHOD_OTHER: default: - return false; // be conservative: we do not know some methods specs + return true; } - return false; // not reached + return true; // not reached, but just in case } === modified file 'src/Server.cc' --- src/Server.cc 2008-07-22 12:33:41 +0000 +++ src/Server.cc 2008-09-03 01:00:39 +0000 @@ -402,11 +402,35 @@ // purges entries that match the value of a given HTTP [response] header static void -purgeEntriesByHeader(const char *reqUrl, HttpMsg *rep, http_hdr_type hdr) +purgeEntriesByHeader(const HttpRequest *req, 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 - purgeEntriesByUrl(url); + const char *hdrUrl, *absUrl; + + absUrl = NULL; + hdrUrl = rep->header.getStr(hdr); + if (hdrUrl == NULL) { + return; + } + + /* + * If the URL is relative, make it absolute so we can find it. + * If it's absolute, make sure the host parts match to avoid DOS attacks + * as per RFC 2616 13.10. + */ + if (urlIsRelative(hdrUrl)) { + absUrl = urlMakeAbsolute(req, hdrUrl); + if (absUrl != NULL) { + hdrUrl = absUrl; + } + } else if (!sameUrlHosts(reqUrl, hdrUrl)) { + return; + } + + purgeEntriesByUrl(hdrUrl); + + if (absUrl != NULL) { + safe_free(absUrl); + } } // some HTTP methods should purge matching cache entries @@ -425,8 +449,8 @@ 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 === modified file 'src/protos.h' --- src/protos.h 2008-07-17 12:38:06 +0000 +++ src/protos.h 2008-09-03 04:40:31 +0000 @@ -638,6 +638,8 @@ SQUIDCEXTERN void urlInitialize(void); SQUIDCEXTERN HttpRequest *urlParse(const HttpRequestMethod&, char *, HttpRequest *request = NULL); SQUIDCEXTERN const char *urlCanonical(HttpRequest *); +SQUIDCEXTERN bool urlIsRelative(const char *); +SQUIDCEXTERN char *urlMakeAbsolute(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); === modified file 'src/url.cc' --- src/url.cc 2008-04-10 11:29:39 +0000 +++ src/url.cc 2008-09-03 04:42:27 +0000 @@ -533,6 +533,105 @@ } /* + * Test if a URL is relative. + * + * RFC 2396, Section 5 (Page 17) implies that in a relative URL, a '/' will + * appear before a ':'. + */ +bool +urlIsRelative(const char *url) +{ + const char *p; + + if (url == NULL) { + return (false); + } + if (*url == '\0') { + return (false); + } + + for (p = url; *p != '\0' && *p != ':' && *p != '/'; p++); + + if (*p == ':') { + return (false); + } + return (true); +} + +/* + * Convert a relative URL to an absolute URL using the context of a given + * request. + * + * It is assumed that you have already ensured that the URL is relative. + * + * If NULL is returned it is an indication that the method in use in the + * request does not distinguish between relative and absolute and you should + * use the url unchanged. + * + * If non-NULL is returned, it is up to the caller to free the resulting + * memory using safe_free(). + */ +char * +urlMakeAbsolute(const HttpRequest * req, const char *relUrl) +{ + + if (req->method.id() == METHOD_CONNECT) { + return (NULL); + } + + char *urlbuf = (char *)xmalloc(MAX_URL * sizeof(char)); + + if (req->protocol == PROTO_URN) { + snprintf(urlbuf, MAX_URL, "urn:%s", req->urlpath.buf()); + return (urlbuf); + } + + size_t urllen; + + if (req->port != urlDefaultPort(req->protocol)) { + urllen = snprintf(urlbuf, MAX_URL, "%s://%s%s%s:%d", + ProtocolStr[req->protocol], + req->login, + *req->login ? "@" : null_string, + req->GetHost(), + req->port + ); + } else { + urllen = snprintf(urlbuf, MAX_URL, "%s://%s%s%s", + ProtocolStr[req->protocol], + req->login, + *req->login ? "@" : null_string, + req->GetHost() + ); + } + + if (relUrl[0] == '/') { + strncpy(&urlbuf[urllen], relUrl, MAX_URL - urllen - 1); + } else { + const char *path = req->urlpath.buf(); + const char *last_slash = strrchr(path, '/'); + + if (last_slash == NULL) { + urlbuf[urllen++] = '/'; + strncpy(&urlbuf[urllen], relUrl, MAX_URL - urllen - 1); + } else { + last_slash++; + size_t pathlen = last_slash - path; + if (pathlen > MAX_URL - urllen - 1) { + pathlen = MAX_URL - urllen - 1; + } + strncpy(&urlbuf[urllen], path, pathlen); + urllen += pathlen; + if (urllen + 1 < MAX_URL) { + strncpy(&urlbuf[urllen], relUrl, MAX_URL - urllen - 1); + } + } + } + + return (urlbuf); +} + +/* * matchDomainName() compares a hostname with a domainname according * to the following rules: * # Begin bundle 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 UA==