This is a forward-port of the HTCP changes I made to squid 2.HEAD.

Changes include:

- Ability to send HTCP CLR requests when objects are invalidated or purged from
  the cache.
- Config logic to allow the following:
        - HTCP peers who ONLY receive CLR messages from us.
        - HTCP peers who NEVER receive CLR messages from us.
        - HTCP peers who NEVER receive CLR messages from us for PURGE requests.
        - HTCP peers who are forwarded CLR messages we receive.
- Code to support all of the above.
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: [EMAIL PROTECTED]
# target_branch: http://www.squid-cache.org/bzr/squid3/trunk/
# testament_sha1: 3d704808c3aaab7c5c9afbcbf4d51962a4097f25
# timestamp: 2008-09-18 12:57:08 +1000
# base_revision_id: [EMAIL PROTECTED]
#   cikogp3tfb08wpam
# 
# Begin patch
=== modified file 'src/Server.cc'
--- src/Server.cc	2008-09-03 01:00:39 +0000
+++ src/Server.cc	2008-09-18 02:55:19 +0000
@@ -46,7 +46,7 @@
 #endif
 
 // implemented in client_side_reply.cc until sides have a common parent
-extern void purgeEntriesByUrl(const char *url);
+extern void purgeEntriesByUrl(HttpRequest * req, const char *url);
 
 
 ServerStateData::ServerStateData(FwdState *theFwdState): AsyncJob("ServerStateData"),requestSender(NULL)
@@ -402,7 +402,7 @@
 
 // purges entries that match the value of a given HTTP [response] header
 static void
-purgeEntriesByHeader(const HttpRequest *req, const char *reqUrl, HttpMsg *rep, http_hdr_type hdr)
+purgeEntriesByHeader(HttpRequest *req, const char *reqUrl, HttpMsg *rep, http_hdr_type hdr)
 {
     const char *hdrUrl, *absUrl;
     
@@ -426,7 +426,7 @@
         return;
     }
     
-    purgeEntriesByUrl(hdrUrl);
+    purgeEntriesByUrl(req, hdrUrl);
     
     if (absUrl != NULL) {
         safe_free(absUrl);
@@ -448,7 +448,7 @@
    // XXX: should we use originalRequest() here?
    const char *reqUrl = urlCanonical(request);
    debugs(88, 5, "maybe purging due to " << RequestMethodStr(request->method) << ' ' << reqUrl);
-   purgeEntriesByUrl(reqUrl);
+   purgeEntriesByUrl(request, reqUrl);
    purgeEntriesByHeader(request, reqUrl, theFinalReply, HDR_LOCATION);
    purgeEntriesByHeader(request, reqUrl, theFinalReply, HDR_CONTENT_LOCATION);
 }

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2008-08-10 05:05:45 +0000
+++ src/cache_cf.cc	2008-09-01 02:43:20 +0000
@@ -1731,6 +1731,22 @@
         } else if (!strcasecmp(token, "htcp-oldsquid")) {
             p->options.htcp = 1;
             p->options.htcp_oldsquid = 1;
+        } else if (!strcasecmp(token, "htcp-no-clr")) {
+            if (p->options.htcp_only_clr)
+        	fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
+            p->options.htcp = 1;
+            p->options.htcp_no_clr = 1;
+        } else if (!strcasecmp(token, "htcp-no-purge-clr")) {
+            p->options.htcp = 1;
+            p->options.htcp_no_purge_clr = 1;
+        } else if (!strcasecmp(token, "htcp-only-clr")) {
+            if (p->options.htcp_no_clr)
+        	fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
+            p->options.htcp = 1;
+            p->options.htcp_only_clr = 1;
+        } else if (!strcasecmp(token, "htcp-forward-clr")) {
+            p->options.htcp = 1;
+            p->options.htcp_forward_clr = 1;
 #endif
 
         } else if (!strcasecmp(token, "no-netdb-exchange")) {

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2008-08-09 06:24:33 +0000
+++ src/cf.data.pre	2008-09-01 02:43:20 +0000
@@ -1585,6 +1585,10 @@
 		     max-conn=n
 		     htcp
 		     htcp-oldsquid
+		     htcp-no-clr
+		     htcp-no-purge-clr
+		     htcp-only-clr
+		     htcp-forward-clr
 		     originserver
 		     name=xxx
 		     forceddomain=name
@@ -1727,6 +1731,20 @@
 		     You MUST also set htcp_access expicitly. The default of
 		     deny all will prevent peer traffic.		     
 
+		     use 'htcp-no-clr' to send HTCP to the neighbor but without
+		     sending any CLR requests.  This cannot be used with
+		     htcp-only-clr.
+		
+		     use 'htcp-no-purge-clr' to send HTCP to the neighbor
+		     including CLRs but only when they do not result from
+		     PURGE requests.
+		
+		     use 'htcp-only-clr' to send HTCP to the neighbor but ONLY
+		     CLR requests.  This cannot be used with htcp-no-clr.
+		
+		     use 'htcp-forward-clr' to forward any HTCP CLR requests
+		     this proxy receives to the peer.
+
 		     'originserver' causes this parent peer to be contacted as
 		     a origin server. Meant to be used in accelerator setups.
 

=== modified file 'src/client_side_reply.cc'
--- src/client_side_reply.cc	2008-09-04 04:33:48 +0000
+++ src/client_side_reply.cc	2008-09-18 02:55:19 +0000
@@ -721,23 +721,39 @@
  * keys depend on vary headers.
  */
 void
-purgeEntriesByUrl(const char *url)
+purgeEntriesByUrl(HttpRequest * req, const char *url)
 {
+#if USE_HTCP
+    bool get_or_head_sent = false;
+#endif
+    
     for (HttpRequestMethod m(METHOD_NONE); m != METHOD_ENUM_END; ++m) {
         if (m.isCacheble()) {
             if (StoreEntry *entry = storeGetPublic(url, m)) {
                 debugs(88, 5, "purging " << RequestMethodStr(m) << ' ' << url);
+#if USE_HTCP
+                neighborsHtcpClear(entry, url, req, m, HTCP_CLR_INVALIDATION);
+                if (m == METHOD_GET || m == METHOD_HEAD) {
+                    get_or_head_sent = true;
+                }
+#endif
                 entry->release();
             }
         }
     }
+
+#if USE_HTCP
+    if (!get_or_head_sent) {
+        neighborsHtcpClear(NULL, url, req, HttpRequestMethod(METHOD_GET), HTCP_CLR_INVALIDATION);
+    }
+#endif
 }
 
 void 
 clientReplyContext::purgeAllCached()
 {
 	const char *url = urlCanonical(http->request);
-    purgeEntriesByUrl(url);
+    purgeEntriesByUrl(http->request, url);
 }
 
 void
@@ -851,6 +867,9 @@
     if (!newEntry->isNull()) {
         /* Release the cached URI */
         debugs(88, 4, "clientPurgeRequest: GET '" << newEntry->url() << "'" );
+#if USE_HTCP
+        neighborsHtcpClear(newEntry, NULL, http->request, HttpRequestMethod(METHOD_GET), HTCP_CLR_PURGE);
+#endif
         newEntry->release();
         purgeStatus = HTTP_OK;
     }
@@ -864,6 +883,9 @@
 {
     if (newEntry && !newEntry->isNull()) {
         debugs(88, 4, "clientPurgeRequest: HEAD '" << newEntry->url() << "'" );
+#if USE_HTCP
+        neighborsHtcpClear(newEntry, NULL, http->request, HttpRequestMethod(METHOD_HEAD), HTCP_CLR_PURGE);
+#endif
         newEntry->release();
         purgeStatus = HTTP_OK;
     }
@@ -876,6 +898,9 @@
 
         if (entry) {
             debugs(88, 4, "clientPurgeRequest: Vary GET '" << entry->url() << "'" );
+#if USE_HTCP
+            neighborsHtcpClear(entry, NULL, http->request, HttpRequestMethod(METHOD_GET), HTCP_CLR_PURGE);
+#endif
             entry->release();
             purgeStatus = HTTP_OK;
         }
@@ -884,6 +909,9 @@
 
         if (entry) {
             debugs(88, 4, "clientPurgeRequest: Vary HEAD '" << entry->url() << "'" );
+#if USE_HTCP
+            neighborsHtcpClear(entry, NULL, http->request, HttpRequestMethod(METHOD_HEAD), HTCP_CLR_PURGE);
+#endif
             entry->release();
             purgeStatus = HTTP_OK;
         }

=== modified file 'src/enums.h'
--- src/enums.h	2008-07-11 20:43:43 +0000
+++ src/enums.h	2008-09-01 05:27:59 +0000
@@ -545,4 +545,15 @@
     DISABLE_PMTU_TRANSPARENT
 };
 
+#if USE_HTCP
+/*
+ * This should be in htcp.h but because neighborsHtcpClear is defined in
+ * protos.h it has to be here.
+ */
+typedef enum {
+    HTCP_CLR_PURGE,
+    HTCP_CLR_INVALIDATION,
+} htcp_clr_reason;
+#endif
+
 #endif /* SQUID_ENUMS_H */

=== modified file 'src/htcp.cc'
--- src/htcp.cc	2008-09-08 23:52:06 +0000
+++ src/htcp.cc	2008-09-18 02:55:19 +0000
@@ -176,6 +176,7 @@
     int rr;
     int f1;
     int response;
+    int reason;
     u_int32_t msg_id;
     htcpSpecifier S;
     htcpDetail D;
@@ -248,8 +249,6 @@
 
 static void htcpHandle(char *buf, int sz, IPAddress &from);
 
-static void htcpHandleData(char *buf, int sz, IPAddress &from);
-
 static void htcpHandleMon(htcpDataHeader *, char *buf, int sz, IPAddress &from);
 
 static void htcpHandleNop(htcpDataHeader *, char *buf, int sz, IPAddress &from);
@@ -439,6 +438,26 @@
 }
 
 static ssize_t
+htcpBuildClrOpData(char *buf, size_t buflen, htcpStuff * stuff)
+{
+    u_short reason;
+    
+    switch (stuff->rr) {
+    case RR_REQUEST:
+        debugs(31, 3, "htcpBuildClrOpData: RR_REQUEST");
+        reason = htons((u_short)stuff->reason);
+        xmemcpy(buf, &reason, 2);
+        return htcpBuildSpecifier(buf + 2, buflen - 2, stuff) + 2;
+    case RR_RESPONSE:
+        break;
+    default:
+        fatal_dump("htcpBuildClrOpData: bad RR value");
+    }
+    
+    return 0;
+}
+
+static ssize_t
 htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff)
 {
     ssize_t off = 0;
@@ -451,7 +470,7 @@
         break;
 
     case HTCP_CLR:
-        /* nothing to be done */
+        off = htcpBuildClrOpData(buf + off, buflen, stuff);
         break;
 
     default:
@@ -1288,12 +1307,69 @@
 }
 
 static void
+htcpForwardClr(char *buf, int sz)
+{
+    peer *p;
+    
+    for (p = Config.peers; p; p = p->next) {
+        if (!p->options.htcp) {
+            continue;
+        }
+        if (!p->options.htcp_forward_clr) {
+            continue;
+        }
+        
+        htcpSend(buf, sz, p->in_addr);
+    }
+}
 
-htcpHandleData(char *buf, int sz, IPAddress &from)
+static void
+htcpHandle(char *buf, int sz, IPAddress &from)
 {
+    htcpHeader htcpHdr;
     htcpDataHeader hdr;
-
-    if ((size_t)sz < sizeof(htcpDataHeader))
+    char *hbuf;
+    int hsz;
+    assert (sz >= 0);
+
+    if ((size_t)sz < sizeof(htcpHeader))
+    {
+        debugs(31, 1, "htcpHandle: msg size less than htcpHeader size");
+        return;
+    }
+
+    htcpHexdump("htcpHandle", buf, sz);
+    xmemcpy(&htcpHdr, buf, sizeof(htcpHeader));
+    htcpHdr.length = ntohs(htcpHdr.length);
+
+    if (htcpHdr.minor == 0)
+        old_squid_format = 1;
+    else
+        old_squid_format = 0;
+
+    debugs(31, 3, "htcpHandle: htcpHdr.length = " << htcpHdr.length);
+    debugs(31, 3, "htcpHandle: htcpHdr.major = " << htcpHdr.major);
+    debugs(31, 3, "htcpHandle: htcpHdr.minor = " << htcpHdr.minor);
+
+    if (sz != htcpHdr.length)
+    {
+        debugs(31, 1, "htcpHandle: sz/" << sz << " != htcpHdr.length/" <<
+               htcpHdr.length << " from " << from );
+
+        return;
+    }
+
+    if (htcpHdr.major != 0)
+    {
+        debugs(31, 1, "htcpHandle: Unknown major version " << htcpHdr.major << " from " << from );
+
+        return;
+    }
+
+    hbuf = buf + sizeof(htcpHeader);
+    hsz = sz - sizeof(htcpHeader);
+
+    if ((size_t)hsz < sizeof(htcpDataHeader))
     {
         debugs(31, 1, "htcpHandleData: msg size less than htcpDataHeader size");
         return;
@@ -1301,11 +1377,10 @@
 
     if (!old_squid_format)
     {
-        xmemcpy(&hdr, buf, sizeof(hdr));
-    } else
-    {
+        xmemcpy(&hdr, hbuf, sizeof(hdr));
+    } else {
         htcpDataHeaderSquid hdrSquid;
-        xmemcpy(&hdrSquid, buf, sizeof(hdrSquid));
+        xmemcpy(&hdrSquid, hbuf, sizeof(hdrSquid));
         hdr.length = hdrSquid.length;
         hdr.opcode = hdrSquid.opcode;
         hdr.response = hdrSquid.response;
@@ -1317,11 +1392,10 @@
 
     hdr.length = ntohs(hdr.length);
     hdr.msg_id = ntohl(hdr.msg_id);
-    debugs(31, 3, "htcpHandleData: sz = " << sz);
+    debugs(31, 3, "htcpHandleData: hsz = " << hsz);
     debugs(31, 3, "htcpHandleData: length = " << hdr.length);
 
-    if (hdr.opcode >= HTCP_END)
-    {
+    if (hdr.opcode >= HTCP_END) {
         debugs(31, 1, "htcpHandleData: client " << from << ", opcode " << hdr.opcode << " out of range");
         return;
     }
@@ -1332,8 +1406,7 @@
     debugs(31, 3, "htcpHandleData: RR = " << hdr.RR);
     debugs(31, 3, "htcpHandleData: msg_id = " << hdr.msg_id);
 
-    if (sz < hdr.length)
-    {
+    if (hsz < hdr.length) {
         debugs(31, 1, "htcpHandleData: sz < hdr.length");
         return;
     }
@@ -1342,88 +1415,33 @@
      * set sz = hdr.length so we ignore any AUTH fields following
      * the DATA.
      */
-    sz = (int) hdr.length;
-
-    buf += sizeof(htcpDataHeader);
-
-    sz -= sizeof(htcpDataHeader);
-
-    debugs(31, 3, "htcpHandleData: sz = " << sz);
-
-    htcpHexdump("htcpHandleData", buf, sz);
-
-    switch (hdr.opcode)
-    {
-
+    hsz = (int) hdr.length;
+    hbuf += sizeof(htcpDataHeader);
+    hsz -= sizeof(htcpDataHeader);
+    debugs(31, 3, "htcpHandleData: hsz = " << hsz);
+
+    htcpHexdump("htcpHandleData", hbuf, hsz);
+
+    switch (hdr.opcode) {
     case HTCP_NOP:
-        htcpHandleNop(&hdr, buf, sz, from);
+        htcpHandleNop(&hdr, hbuf, hsz, from);
         break;
-
     case HTCP_TST:
-        htcpHandleTst(&hdr, buf, sz, from);
+        htcpHandleTst(&hdr, hbuf, hsz, from);
         break;
-
     case HTCP_MON:
-        htcpHandleMon(&hdr, buf, sz, from);
+        htcpHandleMon(&hdr, hbuf, hsz, from);
         break;
-
     case HTCP_SET:
-        htcpHandleSet(&hdr, buf, sz, from);
+        htcpHandleSet(&hdr, hbuf, hsz, from);
         break;
-
     case HTCP_CLR:
-        htcpHandleClr(&hdr, buf, sz, from);
+        htcpHandleClr(&hdr, hbuf, hsz, from);
+        htcpForwardClr(buf, sz);
         break;
-
     default:
-        return;
-    }
-}
-
-static void
-
-htcpHandle(char *buf, int sz, IPAddress &from)
-{
-    htcpHeader htcpHdr;
-    assert (sz >= 0);
-
-    if ((size_t)sz < sizeof(htcpHeader))
-    {
-        debugs(31, 1, "htcpHandle: msg size less than htcpHeader size");
-        return;
-    }
-
-    htcpHexdump("htcpHandle", buf, sz);
-    xmemcpy(&htcpHdr, buf, sizeof(htcpHeader));
-    htcpHdr.length = ntohs(htcpHdr.length);
-
-    if (htcpHdr.minor == 0)
-        old_squid_format = 1;
-    else
-        old_squid_format = 0;
-
-    debugs(31, 3, "htcpHandle: htcpHdr.length = " << htcpHdr.length);
-    debugs(31, 3, "htcpHandle: htcpHdr.major = " << htcpHdr.major);
-    debugs(31, 3, "htcpHandle: htcpHdr.minor = " << htcpHdr.minor);
-
-    if (sz != htcpHdr.length)
-    {
-        debugs(31, 1, "htcpHandle: sz/" << sz << " != htcpHdr.length/" <<
-               htcpHdr.length << " from " << from );
-
-        return;
-    }
-
-    if (htcpHdr.major != 0)
-    {
-        debugs(31, 1, "htcpHandle: Unknown major version " << htcpHdr.major << " from " << from );
-
-        return;
-    }
-
-    buf += sizeof(htcpHeader);
-    sz -= sizeof(htcpHeader);
-    htcpHandleData(buf, sz, from);
+        break;
+    }
 }
 
 static void
@@ -1525,51 +1543,31 @@
         return;
 
     old_squid_format = p->options.htcp_oldsquid;
-
     memset(&flags, '\0', sizeof(flags));
-
     snprintf(vbuf, sizeof(vbuf), "%d/%d",
              req->http_ver.major, req->http_ver.minor);
-
     stuff.op = HTCP_TST;
-
     stuff.rr = RR_REQUEST;
-
     stuff.f1 = 1;
-
     stuff.response = 0;
-
     stuff.msg_id = ++msg_id_counter;
-
     stuff.S.method = (char *) RequestMethodStr(req->method);
-
     stuff.S.uri = (char *) e->url();
-
     stuff.S.version = vbuf;
-
     HttpStateData::httpBuildRequestHeader(req, req, e, &hdr, flags);
-
     mb.init();
-
     packerToMemInit(&pa, &mb);
-
     hdr.packInto(&pa);
-
     hdr.clean();
-
     packerClean(&pa);
-
     stuff.S.req_hdrs = mb.buf;
-
     pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
-
     mb.clean();
-
     if (!pktlen) {
         debugs(31, 1, "htcpQuery: htcpBuildPacket() failed");
         return;
     }
-
+    
     htcpSend(pkt, (int) pktlen, p->in_addr);
 
     queried_id[stuff.msg_id % N_QUERIED_KEYS] = stuff.msg_id;
@@ -1579,6 +1577,75 @@
     debugs(31, 3, "htcpQuery: key (" << save_key << ") " << storeKeyText(save_key));
 }
 
+void
+htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &method, peer * p, htcp_clr_reason reason)
+{
+    static char pkt[8192];
+    ssize_t pktlen;
+    char vbuf[32];
+    htcpStuff stuff;
+    HttpHeader hdr(hoRequest);
+    Packer pa;
+    MemBuf mb;
+    http_state_flags flags;
+
+    if (htcpInSocket < 0)
+    	return;
+
+    old_squid_format = p->options.htcp_oldsquid;
+    memset(&flags, '\0', sizeof(flags));
+    snprintf(vbuf, sizeof(vbuf), "%d/%d",
+	req->http_ver.major, req->http_ver.minor);
+    stuff.op = HTCP_CLR;
+    stuff.rr = RR_REQUEST;
+    stuff.f1 = 0;
+    stuff.response = 0;
+    stuff.msg_id = ++msg_id_counter;
+    switch (reason) {
+    case HTCP_CLR_INVALIDATION:
+    	stuff.reason = 1;
+    	break;
+    default:
+    	stuff.reason = 0;
+    	break;
+    }
+    stuff.S.method = (char *) RequestMethodStr(req->method);
+    if (e == NULL || e->mem_obj == NULL) {
+    	if (uri == NULL) {
+            return;
+    	}
+    	stuff.S.uri = xstrdup(uri);
+    } else {
+    	stuff.S.uri = (char *) e->url();
+    }
+    stuff.S.version = vbuf;
+    if (reason != HTCP_CLR_INVALIDATION) {
+        HttpStateData::httpBuildRequestHeader(req, req, e, &hdr, flags);
+        mb.init();
+        packerToMemInit(&pa, &mb);
+        hdr.packInto(&pa);
+        hdr.clean();
+        packerClean(&pa);
+    	stuff.S.req_hdrs = mb.buf;
+        debug(31, 1) ("htcpClear: headers: %s\n", stuff.S.req_hdrs);
+    } else {
+        stuff.S.req_hdrs = NULL;
+    }
+    pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
+    if (reason != HTCP_CLR_INVALIDATION) {
+        mb.clean();
+    }
+    if (e == NULL) {
+    	xfree(stuff.S.uri);
+    }
+    if (!pktlen) {
+    	debug(31, 1) ("htcpClear: htcpBuildPacket() failed\n");
+    	return;
+    }
+    
+    htcpSend(pkt, (int) pktlen, p->in_addr);
+}
+
 /*
  * htcpSocketShutdown only closes the 'in' socket if it is
  * different than the 'out' socket.

=== modified file 'src/htcp.h'
--- src/htcp.h	2008-03-16 22:10:18 +0000
+++ src/htcp.h	2008-09-18 02:55:19 +0000
@@ -70,6 +70,9 @@
 SQUIDCEXTERN void htcpQuery(StoreEntry * e, HttpRequest * req, peer * p);
 
 /// \ingroup ServerProtocolHTCP
+SQUIDCEXTERN void htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &method, peer * p, htcp_clr_reason reason);
+
+/// \ingroup ServerProtocolHTCP
 SQUIDCEXTERN void htcpSocketShutdown(void);
 
 /// \ingroup ServerProtocolHTCP

=== modified file 'src/http.cc'
--- src/http.cc	2008-09-13 13:43:00 +0000
+++ src/http.cc	2008-09-18 02:55:19 +0000
@@ -274,6 +274,9 @@
 
     if (pe != NULL) {
         assert(e != pe);
+#if USE_HTCP
+        neighborsHtcpClear(e, NULL, e->mem_obj->request, e->mem_obj->method, HTCP_CLR_INVALIDATION);
+#endif
         pe->release();
     }
 
@@ -288,6 +291,9 @@
 
     if (pe != NULL) {
         assert(e != pe);
+#if USE_HTCP
+        neighborsHtcpClear(e, NULL, e->mem_obj->request, HttpRequestMethod(METHOD_HEAD), HTCP_CLR_INVALIDATION);
+#endif
         pe->release();
     }
 }

=== modified file 'src/neighbors.cc'
--- src/neighbors.cc	2008-07-18 11:24:16 +0000
+++ src/neighbors.cc	2008-09-18 02:55:19 +0000
@@ -672,8 +672,7 @@
         debugs(15, 3, "neighborsUdpPing: reqnum = " << reqnum);
 
 #if USE_HTCP
-
-        if (p->options.htcp) {
+        if (p->options.htcp && !p->options.htcp_only_clr) {
             debugs(15, 3, "neighborsUdpPing: sending HTCP query");
             htcpQuery(entry, request, p);
         } else
@@ -1591,10 +1590,16 @@
         storeAppendPrintf(sentry, " closest-only");
 
 #if USE_HTCP
-
     if (p->options.htcp)
         storeAppendPrintf(sentry, " htcp");
-
+	if (p->options.htcp_oldsquid)
+	    storeAppendPrintf(sentry, " htcp-oldsquid");
+	if (p->options.htcp_no_clr)
+	    storeAppendPrintf(sentry, " htcp-no-clr");
+	if (p->options.htcp_no_purge_clr)
+	    storeAppendPrintf(sentry, " htcp-no-purge-clr");
+	if (p->options.htcp_only_clr)
+	    storeAppendPrintf(sentry, " htcp-only-clr");
 #endif
 
     if (p->options.no_netdb_exchange)
@@ -1749,7 +1754,6 @@
 
 #if USE_HTCP
 void
-
 neighborsHtcpReply(const cache_key * key, htcpReplyData * htcp, const IPAddress &from)
 {
     StoreEntry *e = Store::Root().get(key);
@@ -1819,4 +1823,26 @@
     mem->ping_reply_callback(p, ntype, PROTO_HTCP, htcp, mem->ircb_data);
 }
 
+void
+neighborsHtcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &method, htcp_clr_reason reason)
+{
+    peer *p;
+    char buf[128];
+
+    debug(15, 1) ("neighborsHtcpClear: clear reason: %d\n", reason);
+    for (p = Config.peers; p; p = p->next) {
+        if (!p->options.htcp) {
+            continue;
+        }
+        if (p->options.htcp_no_clr) {
+            continue;
+        }
+        if (p->options.htcp_no_purge_clr && reason == HTCP_CLR_PURGE) {
+            continue;
+        }
+        debug(15, 1) ("neighborsHtcpClear: sending CLR to %s\n", p->in_addr.ToURL(buf, 128));
+        htcpClear(e, uri, req, method, p, reason);
+    }
+}
+
 #endif

=== modified file 'src/protos.h'
--- src/protos.h	2008-09-11 06:32:57 +0000
+++ src/protos.h	2008-09-18 02:55:19 +0000
@@ -385,6 +385,9 @@
 SQUIDCEXTERN void neighborsUdpAck(const cache_key *, icp_common_t *, const IPAddress &);
 SQUIDCEXTERN void neighborAdd(const char *, const char *, int, int, int, int, int);
 SQUIDCEXTERN void neighbors_init(void);
+#if USE_HTCP
+SQUIDCEXTERN void neighborsHtcpClear(StoreEntry *, const char *, HttpRequest *, const HttpRequestMethod &, htcp_clr_reason);
+#endif
 SQUIDCEXTERN peer *peerFindByName(const char *);
 SQUIDCEXTERN peer *peerFindByNameAndPort(const char *, unsigned short);
 SQUIDCEXTERN peer *getDefaultParent(HttpRequest * request);

=== modified file 'src/structs.h'
--- src/structs.h	2008-08-09 06:24:33 +0000
+++ src/structs.h	2008-09-01 02:43:20 +0000
@@ -925,6 +925,10 @@
 #if USE_HTCP
         unsigned int htcp:1;
         unsigned int htcp_oldsquid:1;
+        unsigned int htcp_no_clr:1;
+        unsigned int htcp_no_purge_clr:1;
+        unsigned int htcp_only_clr:1;
+        unsigned int htcp_forward_clr:1;
 #endif
         unsigned int no_netdb_exchange:1;
 #if DELAY_POOLS

# Begin bundle
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

Reply via email to