--- src/htcp.c.bak	2005-06-04 16:51:25.000000000 +0000
+++ src/htcp.c	2005-09-30 19:02:16.120269621 +0000
@@ -322,6 +322,9 @@
     case HTCP_TST:
 	off = htcpBuildTstOpData(buf + off, buflen, stuff);
 	break;
+    case HTCP_CLR:
+	// nothing to be done
+	break;
     default:
 	assert(0);
 	break;
@@ -607,6 +610,33 @@
 }
 
 static void
+htcpClrReply(htcpDataHeader * dhdr, int purgeSucceeded, struct sockaddr_in *from)
+{
+    htcpStuff stuff;
+    char *pkt;
+    ssize_t pktlen;
+
+    /* If dhdr->F1 == 0, no response desired */
+    if (dhdr->F1 == 0)
+        return;
+    
+    memset(&stuff, '\0', sizeof(stuff));
+    stuff.op = HTCP_CLR;
+    stuff.rr = RR_RESPONSE;
+    stuff.f1 = 0;
+    stuff.response = purgeSucceeded ? 0 : 2;
+    debug(31, 3) ("htcpClrReply: response = %d\n", stuff.response);
+    stuff.msg_id = dhdr->msg_id;
+    pkt = htcpBuildPacket(&stuff, &pktlen);
+    if (pkt == NULL) {
+	debug(31, 0) ("htcpClrReply: htcpBuildPacket() failed\n");
+	return;
+    }
+    htcpSend(pkt, (int) pktlen, from);
+    xfree(pkt);
+}
+
+static void
 htcpHandleNop(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
 {
     debug(31, 3) ("htcpHandleNop: Unimplemented\n");
@@ -650,6 +680,69 @@
 }
 
 static void
+htcpClrStoreEntry(StoreEntry *e) {
+    debug(31, 4) ("htcpClrStoreEntry: Clearing store for entry: %s\n", storeUrl(e));
+    storeRelease(e);
+}
+
+static int
+htcpClrStore(const htcpSpecifier * s)
+{
+    request_t *request;
+    method_t method;
+    char *blk_end;
+    StoreEntry *e = NULL;
+
+    method = urlParseMethod(s->method);
+    /* Purge both HEAD and GET */
+    request = urlParse( ( method == METHOD_NONE ? METHOD_HEAD : method ),
+            s->uri);
+    
+    if (request == NULL) {
+        debug(31, 3) ("htcpClrStore: failed to parse URL\n");
+        return 0;
+    }
+
+    /* Parse request headers */
+    blk_end = s->req_hdrs + strlen(s->req_hdrs);
+    if (!httpHeaderParse(&request->header, s->req_hdrs, blk_end)) {
+        debug(31, 3) ("htcpClrStore: failed to parse request headers\n");
+        goto miss;
+    }
+
+    /* Lookup matching entries */
+    e = storeGetPublicByRequest(request);
+    if (e != NULL) {
+        /* At this point we have a hit */
+        htcpClrStoreEntry(e);
+        
+        if (method == METHOD_NONE) {
+            requestDestroy(request);
+
+            /* Both HEAD and GET entries can be present at the same time
+             * The previous purge hit could have been a HEAD, while another
+             * GET entry still exists. Do another specific GET purge.
+             */
+            request = urlParse( METHOD_GET, s->uri);
+            if (request != NULL
+                && (e = storeGetPublicByRequestMethod(request, METHOD_GET)) != NULL)
+                htcpClrStoreEntry(e);
+        }
+        
+        debug(31, 4) ("htcpClrStore: Cleared matching entries\n");
+        requestDestroy(request);
+        return 1;
+    } else {
+        debug(31, 4) ("htcpClrStore: No matching entry found\n");
+        goto miss;
+    }
+
+miss:
+    requestDestroy(request);
+    return 0;    
+}
+
+static void
 htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
 {
     debug(31, 3) ("htcpHandleTst: sz = %d\n", (int) sz);
@@ -741,6 +834,44 @@
 }
 
 static void
+htcpHandleClr(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
+{
+    /* buf[0/1] is reserved and reason */
+    int reason = buf[1] << 4;
+    debug(31, 3) ("htcpHandleClr: reason=%d\n", reason);
+    buf += 2;
+    sz -= 2;
+
+    /* buf should be a SPECIFIER */
+    htcpSpecifier *s;
+    if (sz == 0) {
+	debug(31, 4) ("htcpHandleClr: nothing to do\n");
+	return;
+    }
+    s = htcpUnpackSpecifier(buf, sz);
+    if (NULL == s) {
+	debug(31, 3) ("htcpHandleClr: htcpUnpackSpecifier failed\n");
+	return;
+    }
+    debug(31, 5) ("htcpHandleClr: %s %s %s\n",
+	s->method,
+	s->uri,
+	s->version);
+    debug(31, 5) ("htcpHandleClr: request headers: %s\n", s->req_hdrs);
+
+    /* Release objects from cache
+     * analog to clientPurgeRequest in client_side.c
+     */
+    if (htcpClrStore(s)) {      
+        htcpClrReply(hdr, 1, from); /* hit */
+    } else {
+        htcpClrReply(hdr, 0, from); /* miss */
+    }
+    
+    htcpFreeSpecifier(s);
+}
+
+static void
 htcpHandleData(char *buf, int sz, struct sockaddr_in *from)
 {
     htcpDataHeader hdr;
@@ -792,8 +923,7 @@
 	htcpHandleSet(&hdr, buf, sz, from);
 	break;
     case HTCP_CLR:
-	debug(31, 1) ("htcpHandleData: client %s, CLR not supported\n",
-	    inet_ntoa(from->sin_addr));
+	htcpHandleClr(&hdr, buf, sz, from);
 	break;
     default:
 	assert(0);
