Index: squid/src/http.c =================================================================== --- squid.orig/src/http.c 2008-08-12 15:16:30.000000000 +1000 +++ squid/src/http.c 2008-08-12 15:16:40.000000000 +1000 @@ -53,9 +53,35 @@ static void httpMakePrivate(StoreEntry *); static void httpMakePublic(StoreEntry *); static int httpCachableReply(HttpStateData *); -static void httpMaybeRemovePublic(StoreEntry *, http_status); +static void httpMaybeRemovePublic(StoreEntry *, HttpReply *); static int peer_supports_connection_pinning(HttpStateData * httpState); +static int +httpUrlHostsMatch(const char *url1, const char *url2) +{ + const char *host1 = strchr(url1, ':'); + const char *host2 = strchr(url2, ':'); + + if (host1 && host2) { + do { + ++host1; + ++host2; + } while (*host1 == '/' && *host2 == '/'); + + if (!*host1) { + return (0); + } + + while (*host1 && *host1 != '/' && *host1 == *host2) { + ++host1; + ++host2; + } + return (*host1 == *host2); + } + + return (0); +} + static void httpStateFree(int fd, void *data) { @@ -133,14 +159,38 @@ } static void -httpMaybeRemovePublic(StoreEntry * e, http_status status) +httpRemovePublicByHeader(request_t *req, HttpReply *reply, http_hdr_type header) { + const char *url, *reqUrl; + char *absUrl; + + reqUrl = urlCanonical(req); + url = httpHeaderGetStr(&reply->header, header); + if (url != NULL) { + absUrl = urlAbsolute(req, url); + if (absUrl != NULL) { + url = absUrl; + } + if (httpUrlHostsMatch(url, reqUrl)) { + storePurgeEntriesByUrl(req, url); + } + if (absUrl != NULL) { + xfree(absUrl); + } + } +} + +static void +httpMaybeRemovePublic(StoreEntry * e, HttpReply *reply) +{ + int status; int remove = 0; int forbidden = 0; StoreEntry *pe; - method_t *method_get, *method_head; - method_get = urlMethodGetKnownByCode(METHOD_GET); - method_head = urlMethodGetKnownByCode(METHOD_HEAD); + request_t *req; + const char *reqUrl; + + status = reply->sline.status; switch (status) { case HTTP_OK: case HTTP_NON_AUTHORITATIVE_INFORMATION: @@ -161,13 +211,11 @@ break; #endif default: -#if QUESTIONABLE /* - * Any 2xx response should eject previously cached entities... + * Any "success" response should eject previously cached entities... */ - if (status >= 200 && status < 300) + if (status >= 200 && status < 400) remove = 1; -#endif break; } if (!remove && !forbidden) @@ -188,37 +236,21 @@ * changed. */ if (e->mem_obj->request) - pe = storeGetPublicByRequestMethod(e->mem_obj->request, method_head); + pe = storeGetPublicByRequestMethodCode(e->mem_obj->request, METHOD_HEAD); else - pe = storeGetPublic(e->mem_obj->url, method_head); + pe = storeGetPublicByCode(e->mem_obj->url, METHOD_HEAD); if (pe != NULL && e != pe) { storeRelease(pe); } if (forbidden) return; - switch (e->mem_obj->method->code) { - case METHOD_PUT: - case METHOD_DELETE: - case METHOD_PROPPATCH: - case METHOD_MKCOL: - case METHOD_MOVE: - case METHOD_BMOVE: - case METHOD_BDELETE: - /* - * Remove any cached GET object if it is beleived that the - * object may have changed as a result of other methods - */ - if (e->mem_obj->request) - pe = storeGetPublicByRequestMethod(e->mem_obj->request, method_get); - else - pe = storeGetPublic(e->mem_obj->url, method_get); - if (pe != NULL) { - assert(e != pe); - storeRelease(pe); - } - break; - default: - break; + if (e->mem_obj->method->flags.purges_all && status < 400) { + req = e->mem_obj->request; + reqUrl = urlCanonical(req); + debug(88, 5) ("httpMaybeRemovePublic: purging due to %s %s\n", req->method->string, reqUrl); + storePurgeEntriesByUrl(req, reqUrl); + httpRemovePublicByHeader(req, reply, HDR_LOCATION); + httpRemovePublicByHeader(req, reply, HDR_CONTENT_LOCATION); } } @@ -569,7 +601,7 @@ EBIT_SET(entry->flags, ENTRY_REVALIDATE); } if (neighbors_do_private_keys && !Config.onoff.collapsed_forwarding) - httpMaybeRemovePublic(entry, reply->sline.status); + httpMaybeRemovePublic(entry, reply); if (httpState->flags.keepalive) if (httpState->peer) httpState->peer->stats.n_keepalives_sent++; Index: squid/src/protos.h =================================================================== --- squid.orig/src/protos.h 2008-08-12 15:16:30.000000000 +1000 +++ squid/src/protos.h 2008-08-12 15:16:40.000000000 +1000 @@ -953,6 +953,7 @@ extern void storeAppend(StoreEntry *, const char *, int); extern void storeLockObjectDebug(StoreEntry *, const char *file, const int line); extern void storeRelease(StoreEntry *); +extern void storePurgeEntriesByUrl(request_t *req, const char *url); extern int storeUnlockObjectDebug(StoreEntry *, const char *file, const int line); extern const char *storeLookupUrl(const StoreEntry * e); #define storeLockObject(a) storeLockObjectDebug(a, __FILE__, __LINE__); @@ -1188,6 +1189,7 @@ extern void urlInitialize(void); extern request_t *urlParse(method_t *, char *); extern const char *urlCanonical(request_t *); +extern char *urlAbsolute(request_t *, const char *); extern char *urlRInternal(const char *host, u_short port, const char *dir, const char *name); extern char *urlInternal(const char *dir, const char *name); extern int matchDomainName(const char *host, const char *domain); Index: squid/src/store.c =================================================================== --- squid.orig/src/store.c 2008-08-12 15:16:30.000000000 +1000 +++ squid/src/store.c 2008-08-12 15:16:40.000000000 +1000 @@ -408,6 +408,36 @@ return e; } +void +storePurgeEntriesByUrl(request_t *req, const char *url) +{ + int m, get_or_head_sent; + method_t *method; + StoreEntry *e; + + debug(20, 5) ("storePurgeEntriesByUrl: purging %s\n", url); + get_or_head_sent = 0; + + for (m = METHOD_NONE; m < METHOD_OTHER; m++) { + method = urlMethodGetKnownByCode(m); + if (!method->flags.cachable) { + continue; + } + if ((m == METHOD_HEAD || m == METHOD_GET) && get_or_head_sent) { + continue; + } + + e = storeGetPublic(url, method); + if (e == NULL) { + continue; + } + + debug(20, 5) ("storePurgeEntriesByUrl: purging %s %s\n", + method->string, url); + storeRelease(e); + } +} + static int getKeyCounter(void) { Index: squid/src/url.c =================================================================== --- squid.orig/src/url.c 2008-08-12 15:16:30.000000000 +1000 +++ squid/src/url.c 2008-08-12 15:16:40.000000000 +1000 @@ -525,6 +525,70 @@ return (request->canonical = xstrdup(urlbuf)); } +char * +urlAbsolute(request_t *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->code == METHOD_CONNECT) { + return (NULL); + } + if (strchr(relUrl, ':') != NULL) { + return (NULL); + } + + if (req->protocol == PROTO_URN) { + snprintf(urlbuf, MAX_URL, "urn:%s", strBuf(req->urlpath)); + } 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->host, + portbuf, + relUrl + ); + } else { + path = xstrdup(strBuf(req->urlpath)); + 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->host, + 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->host, + portbuf, + path, + relUrl + ); + } + xfree(path); + } + } + + return (xstrdup(urlbuf)); +} /* * Eventually the request_t strings should be String entries which * have in-built length. Eventually we should just take a buffer and