Address comments from Alex and Amos.
  
- Add some comments describing various function purposes.
- Remove some debugging debugs that had crept in.
- Use debugs() in preference to debug()().
- Adjust some debug levels.
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: [EMAIL PROTECTED]
# target_branch: http://www.squid-cache.org/bzr/squid3/trunk/
# testament_sha1: 6dd88f3b15c24a9224ca4a0a2010789f8a473373
# timestamp: 2008-09-22 10:54:17 +1000
# base_revision_id: [EMAIL PROTECTED]
#   l725z2vh1835mn1m
# 
# 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-09-20 09:43:40 +0000
+++ src/cf.data.pre	2008-09-22 00:04:12 +0000
@@ -1578,6 +1578,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
@@ -1720,6 +1724,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-20 05:00:47 +0000
+++ src/client_side_reply.cc	2008-09-22 00:04:12 +0000
@@ -719,23 +719,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
@@ -849,6 +865,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;
     }
@@ -862,6 +881,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;
     }
@@ -874,6 +896,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;
         }
@@ -882,6 +907,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-22 00:53:13 +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:
@@ -1287,13 +1306,82 @@
     htcpFreeSpecifier(s);
 }
 
+/*
+ * Forward a CLR request to all peers who have requested that CLRs be
+ * forwarded to them.
+ */
 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)
+/*
+ * Do the first pass of handling an HTCP message.  This used to be two
+ * separate functions, htcpHandle and htcpHandleData.  They were merged to
+ * allow for forwarding HTCP packets easily to other peers if desired.
+ *
+ * This function now works out what type of message we have received and then
+ * hands it off to other functions to break apart message-specific data.
+ */
+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 +1389,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 +1404,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 +1418,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 +1427,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 +1555,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;
@@ -1580,6 +1590,77 @@
 }
 
 /*
+ * Send an HTCP CLR message for a specified item to a given peer.
+ */
+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;
+    } 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) {
+    	debugs(31, 1, "htcpClear: htcpBuildPacket() failed");
+    	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-09-21 05:08:44 +0000
+++ src/neighbors.cc	2008-09-22 00:53:13 +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
@@ -1604,10 +1603,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)
@@ -1762,7 +1767,6 @@
 
 #if USE_HTCP
 void
-
 neighborsHtcpReply(const cache_key * key, htcpReplyData * htcp, const IPAddress &from)
 {
     StoreEntry *e = Store::Root().get(key);
@@ -1832,4 +1836,28 @@
     mem->ping_reply_callback(p, ntype, PROTO_HTCP, htcp, mem->ircb_data);
 }
 
+/*
+ * Send HTCP CLR messages to all peers configured to receive them.
+ */
+void
+neighborsHtcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &method, htcp_clr_reason reason)
+{
+    peer *p;
+    char buf[128];
+
+    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;
+        }
+        debugs(15, 3, "neighborsHtcpClear: sending CLR to " << 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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
QkOnYb/M

Reply via email to