# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: benno@squid-cache.org-20080903010039-2qt2xvtn0mseaiqu # target_branch: file:///home/benno/squid-work/squid3-repo/trunk/ # testament_sha1: bc594f5388639662dda35328f972e5eb73bdc3d4 # timestamp: 2008-09-03 11:03:59 +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-02 11:27:02 +0000 @@ -638,6 +638,8 @@ SQUIDCEXTERN void urlInitialize(void); SQUIDCEXTERN HttpRequest *urlParse(const HttpRequestMethod&, char *, HttpRequest *request = NULL); SQUIDCEXTERN const char *urlCanonical(HttpRequest *); +SQUIDCEXTERN int urlIsRelative(const char *); +SQUIDCEXTERN const 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 01:00:39 +0000 @@ -533,6 +533,100 @@ } /* + * Test if a URL is relative. + * + * RFC 2396, Section 5 (Page 17) implies that in a relative URL, a '/' will + * appear before a ':'. + */ +int +urlIsRelative(const char *url) +{ + const char *p; + + if (url == NULL) { + return (0); + } + if (*url == '\0') { + return (0); + } + + for (p = url; *p != '\0' && *p != ':' && *p != '/'; p++); + + if (*p == ':') { + return (0); + } + return (1); +} + +/* + * 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, you should use the original URL unchanged. + */ +const char * +urlMakeAbsolute(const HttpRequest * req, const char *relUrl) +{ + char *urlbuf; + const char *path, *last_slash; + size_t urllen, pathlen; + + if (req->method.id() == METHOD_CONNECT) { + return (NULL); + } + + urlbuf = (char *)xmalloc(MAX_URL * sizeof(char)); + + if (req->protocol == PROTO_URN) { + snprintf(urlbuf, MAX_URL, "urn:%s", req->urlpath.buf()); + return (urlbuf); + } + + 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 { + path = req->urlpath.buf(); + last_slash = strrchr(path, '/'); + if (last_slash == NULL) { + urlbuf[urllen++] = '/'; + strncpy(&urlbuf[urllen], relUrl, MAX_URL - urllen - 1); + } else { + last_slash++; + 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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