Index: cache_cf.c =================================================================== RCS file: /cvsroot/squid/squid/src/cache_cf.c,v retrieving revision 1.506 diff -u -r1.506 cache_cf.c --- cache_cf.c 14 Aug 2008 19:59:14 -0000 1.506 +++ cache_cf.c 27 Aug 2008 06:33:21 -0000 @@ -1853,6 +1853,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")) { p->options.no_netdb_exchange = 1; Index: cf.data.pre =================================================================== RCS file: /cvsroot/squid/squid/src/cf.data.pre,v retrieving revision 1.493 diff -u -r1.493 cf.data.pre --- cf.data.pre 27 Aug 2008 00:33:24 -0000 1.493 +++ cf.data.pre 27 Aug 2008 06:33:21 -0000 @@ -1513,6 +1513,10 @@ max-conn=n htcp htcp-oldsquid + htcp-no-clr + htcp-no-purge-clr + htcp-only-clr + htcp-forward-clr originserver userhash sourcehash @@ -1655,7 +1659,21 @@ use 'htcp-oldsquid' to send HTCP to old Squid versions You must also allow this Squid htcp_access and http_access in the peer Squid configuration. - + + 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. Index: client_side.c =================================================================== RCS file: /cvsroot/squid/squid/src/client_side.c,v retrieving revision 1.787 diff -u -r1.787 client_side.c --- client_side.c 17 Aug 2008 22:02:00 -0000 1.787 +++ client_side.c 27 Aug 2008 06:33:22 -0000 @@ -1027,6 +1027,9 @@ if (entry) { debug(33, 4) ("clientPurgeRequest: GET '%s'\n", storeUrl(entry)); +#if USE_HTCP + neighborsHtcpClear(entry, NULL, http->request, method_get, HTCP_CLR_PURGE); +#endif storeRelease(entry); status = HTTP_OK; } @@ -1034,6 +1037,9 @@ if (entry) { debug(33, 4) ("clientPurgeRequest: HEAD '%s'\n", storeUrl(entry)); +#if USE_HTCP + neighborsHtcpClear(entry, NULL, http->request, method_head, HTCP_CLR_PURGE); +#endif storeRelease(entry); status = HTTP_OK; } @@ -1043,6 +1049,9 @@ if (entry) { debug(33, 4) ("clientPurgeRequest: Vary GET '%s'\n", storeUrl(entry)); +#if USE_HTCP + neighborsHtcpClear(entry, NULL, http->request, method_get, HTCP_CLR_PURGE); +#endif storeRelease(entry); status = HTTP_OK; } @@ -1050,6 +1059,9 @@ if (entry) { debug(33, 4) ("clientPurgeRequest: Vary HEAD '%s'\n", storeUrl(entry)); +#if USE_HTCP + neighborsHtcpClear(entry, NULL, http->request, method_head, HTCP_CLR_PURGE); +#endif storeRelease(entry); status = HTTP_OK; } Index: enums.h =================================================================== RCS file: /cvsroot/squid/squid/src/enums.h,v retrieving revision 1.253 diff -u -r1.253 enums.h --- enums.h 17 Aug 2008 22:02:00 -0000 1.253 +++ enums.h 27 Aug 2008 06:33:22 -0000 @@ -807,4 +807,13 @@ FORWARDED_FOR_TRUNCATE } forwarded_for_mode; +#if USE_HTCP + +enum htcp_clr_reason { + HTCP_CLR_PURGE, + HTCP_CLR_INVALIDATION, +}; + +#endif + #endif /* SQUID_ENUMS_H */ Index: htcp.c =================================================================== RCS file: /cvsroot/squid/squid/src/htcp.c,v retrieving revision 1.58 diff -u -r1.58 htcp.c --- htcp.c 15 Aug 2008 04:56:00 -0000 1.58 +++ htcp.c 27 Aug 2008 06:33:22 -0000 @@ -129,6 +129,7 @@ int rr; int f1; int response; + int reason; u_num32 msg_id; htcpSpecifier S; htcpDetail D; @@ -196,7 +197,6 @@ static void htcpFreeSpecifier(htcpSpecifier * s); static void htcpFreeDetail(htcpDetail * s); static void htcpHandle(char *buf, int sz, struct sockaddr_in *from); -static void htcpHandleData(char *buf, int sz, struct sockaddr_in *from); static void htcpHandleMon(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from); static void htcpHandleNop(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from); static void htcpHandleSet(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from); @@ -207,6 +207,7 @@ static void htcpHandleTstRequest(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from); static void htcpHandleTstResponse(htcpDataHeader *, char *, int, struct sockaddr_in *); static StoreEntry *htcpCheckHit(const htcpSpecifier *); +static void htcpForwardClr(char *buf, int sz); static int old_squid_format = 0; @@ -339,6 +340,25 @@ } static ssize_t +htcpBuildClrOpData(char *buf, size_t buflen, htcpStuff * stuff) +{ + u_short reason; + + switch (stuff->rr) { + case RR_REQUEST: + debug(31, 3) ("htcpBuildClrOpData: RR_REQUEST\n"); + 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; @@ -349,7 +369,7 @@ off = htcpBuildTstOpData(buf + off, buflen, stuff); break; case HTCP_CLR: - /* nothing to be done */ + off = htcpBuildClrOpData(buf + off, buflen, stuff); break; default: assert(0); @@ -982,18 +1002,70 @@ } static void -htcpHandleData(char *buf, int sz, struct sockaddr_in *from) +htcpForwardClr(char *buf, int sz) +{ + peer *p; + int i; + + for (i = 0, p = Config.peers; i < Config.npeers; i++, p = p->next) { + if (!p->options.htcp) { + continue; + } + if (!p->options.htcp_forward_clr) { + continue; + } + + htcpSend(buf, sz, &p->in_addr); + } +} + +static void +htcpHandle(char *buf, int sz, struct sockaddr_in *from) { + htcpHeader htcpHdr; htcpDataHeader hdr; - if (sz < sizeof(htcpDataHeader)) { - debug(31, 1) ("htcpHandleData: msg size less than htcpDataHeader size\n"); + char *hbuf; + int hsz; + + if (sz < sizeof(htcpHeader)) { + debug(31, 1) ("htcpHandle: msg size less than htcpHeader size\n"); + 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; + debug(31, 3) ("htcpHandle: htcpHdr.length = %d\n", (int) htcpHdr.length); + debug(31, 3) ("htcpHandle: htcpHdr.major = %d\n", (int) htcpHdr.major); + debug(31, 3) ("htcpHandle: htcpHdr.minor = %d\n", (int) htcpHdr.minor); + if (sz != htcpHdr.length) { + debug(31, 1) ("htcpHandle: sz/%d != htcpHdr.length/%d from %s:%d\n", + sz, htcpHdr.length, + inet_ntoa(from->sin_addr), (int) ntohs(from->sin_port)); + return; + } + if (htcpHdr.major != 0) { + debug(31, 1) ("htcpHandle: Unknown major version %d from %s:%d\n", + htcpHdr.major, + inet_ntoa(from->sin_addr), (int) ntohs(from->sin_port)); + return; + } + + hbuf = buf + sizeof(htcpHeader); + hsz = sz - sizeof(htcpHeader); + + if (hsz < sizeof(htcpDataHeader)) { + debug(31, 1) ("htcpHandle: msg size less than htcpDataHeader size\n"); return; } if (!old_squid_format) { - xmemcpy(&hdr, buf, sizeof(hdr)); + 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; @@ -1004,48 +1076,49 @@ } hdr.length = ntohs(hdr.length); hdr.msg_id = ntohl(hdr.msg_id); - debug(31, 3) ("htcpHandleData: sz = %d\n", sz); - debug(31, 3) ("htcpHandleData: length = %d\n", (int) hdr.length); + debug(31, 3) ("htcpHandle: hsz = %d\n", hsz); + debug(31, 3) ("htcpHandle: length = %d\n", (int) hdr.length); if (hdr.opcode >= HTCP_END) { - debug(31, 1) ("htcpHandleData: client %s, opcode %d out of range\n", + debug(31, 1) ("htcpHandle: client %s, opcode %d out of range\n", inet_ntoa(from->sin_addr), (int) hdr.opcode); return; } - debug(31, 3) ("htcpHandleData: opcode = %d %s\n", + debug(31, 3) ("htcpHandle: opcode = %d %s\n", (int) hdr.opcode, htcpOpcodeStr[hdr.opcode]); - debug(31, 3) ("htcpHandleData: response = %d\n", (int) hdr.response); - debug(31, 3) ("htcpHandleData: F1 = %d\n", (int) hdr.F1); - debug(31, 3) ("htcpHandleData: RR = %d\n", (int) hdr.RR); - debug(31, 3) ("htcpHandleData: msg_id = %d\n", (int) hdr.msg_id); - if (sz < hdr.length) { - debug(31, 1) ("htcpHandleData: sz < hdr.length\n"); + debug(31, 3) ("htcpHandle: response = %d\n", (int) hdr.response); + debug(31, 3) ("htcpHandle: F1 = %d\n", (int) hdr.F1); + debug(31, 3) ("htcpHandle: RR = %d\n", (int) hdr.RR); + debug(31, 3) ("htcpHandle: msg_id = %d\n", (int) hdr.msg_id); + if (hsz < hdr.length) { + debug(31, 1) ("htcpHandle: hsz < hdr.length\n"); return; } /* * set sz = hdr.length so we ignore any AUTH fields following * the DATA. */ - sz = (int) hdr.length; - buf += sizeof(htcpDataHeader); - sz -= sizeof(htcpDataHeader); - debug(31, 3) ("htcpHandleData: sz = %d\n", sz); - htcpHexdump("htcpHandleData", buf, sz); + hsz = (int) hdr.length; + hbuf += sizeof(htcpDataHeader); + hsz -= sizeof(htcpDataHeader); + debug(31, 3) ("htcpHandle: hsz = %d\n", hsz); + htcpHexdump("htcpHandle", 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; @@ -1053,41 +1126,6 @@ } static void -htcpHandle(char *buf, int sz, struct sockaddr_in *from) -{ - htcpHeader htcpHdr; - if (sz < sizeof(htcpHeader)) { - debug(31, 1) ("htcpHandle: msg size less than htcpHeader size\n"); - 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; - debug(31, 3) ("htcpHandle: htcpHdr.length = %d\n", (int) htcpHdr.length); - debug(31, 3) ("htcpHandle: htcpHdr.major = %d\n", (int) htcpHdr.major); - debug(31, 3) ("htcpHandle: htcpHdr.minor = %d\n", (int) htcpHdr.minor); - if (sz != htcpHdr.length) { - debug(31, 1) ("htcpHandle: sz/%d != htcpHdr.length/%d from %s:%d\n", - sz, htcpHdr.length, - inet_ntoa(from->sin_addr), (int) ntohs(from->sin_port)); - return; - } - if (htcpHdr.major != 0) { - debug(31, 1) ("htcpHandle: Unknown major version %d from %s:%d\n", - htcpHdr.major, - inet_ntoa(from->sin_addr), (int) ntohs(from->sin_port)); - return; - } - buf += sizeof(htcpHeader); - sz -= sizeof(htcpHeader); - htcpHandleData(buf, sz, from); -} - -static void htcpRecv(int fd, void *data) { static char buf[8192]; @@ -1205,6 +1243,71 @@ debug(31, 3) ("htcpQuery: key (%p) %s\n", save_key, storeKeyText(save_key)); } +void +htcpClear(StoreEntry * e, const char *uri, request_t * req, method_t *method, peer * p, htcp_clr_reason reason) +{ + static char pkt[8192]; + ssize_t pktlen; + char vbuf[32]; + htcpStuff stuff; + HttpHeader hdr; + 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 *) method->string; + if (e == NULL || e->mem_obj == NULL) { + if (uri == NULL) { + return; + } + stuff.S.uri = xstrdup(uri); + } else { + stuff.S.uri = (char *) storeUrl(e); + } + stuff.S.version = vbuf; + if (reason != HTCP_CLR_INVALIDATION) { + httpBuildRequestHeader(req, req, e, &hdr, flags); + memBufDefInit(&mb); + packerToMemInit(&pa, &mb); + httpHeaderPackInto(&hdr, &pa); + httpHeaderClean(&hdr); + packerClean(&pa); + stuff.S.req_hdrs = mb.buf; + } + pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff); + if (reason != HTCP_CLR_INVALIDATION) { + memBufClean(&mb); + } + if (e == NULL) { + xfree(stuff.S.uri); + } + if (!pktlen) { + debug(31, 1) ("htcpQuery: 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. Index: http.c =================================================================== RCS file: /cvsroot/squid/squid/src/http.c,v retrieving revision 1.449 diff -u -r1.449 http.c --- http.c 17 Aug 2008 22:02:00 -0000 1.449 +++ http.c 27 Aug 2008 06:33:22 -0000 @@ -238,6 +238,9 @@ else pe = storeGetPublicByCode(e->mem_obj->url, METHOD_HEAD); if (pe != NULL && e != pe) { +#if USE_HTCP + neighborsHtcpClear(e, NULL, e->mem_obj->request, urlMethodGetKnownByCode(METHOD_HEAD), HTCP_CLR_INVALIDATION); +#endif storeRelease(pe); } if (forbidden) Index: neighbors.c =================================================================== RCS file: /cvsroot/squid/squid/src/neighbors.c,v retrieving revision 1.330 diff -u -r1.330 neighbors.c --- neighbors.c 15 Aug 2008 04:56:00 -0000 1.330 +++ neighbors.c 27 Aug 2008 06:33:22 -0000 @@ -478,7 +478,7 @@ debug(15, 3) ("neighborsUdpPing: reqnum = %d\n", reqnum); #if USE_HTCP - if (p->options.htcp) { + if (p->options.htcp && !p->options.htcp_only_clr) { debug(15, 3) ("neighborsUdpPing: sending HTCP query\n"); htcpQuery(entry, request, p); } else @@ -1327,8 +1327,18 @@ if (p->options.sourcehash) storeAppendPrintf(sentry, " sourcehash"); #if USE_HTCP - if (p->options.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) storeAppendPrintf(sentry, " no-netdb-exchange"); @@ -1513,4 +1523,28 @@ debug(15, 3) ("neighborsHtcpReply: e = %p\n", e); mem->ping_reply_callback(p, ntype, PROTO_HTCP, htcp, mem->ircb_data); } + +void +neighborsHtcpClear(StoreEntry *e, const char *uri, request_t *req, method_t *method, htcp_clr_reason reason) +{ + peer *p; + int i; + + debug(15, 1) ("neighborsHtcpClear: clear reason: %d\n", reason); + for (i = 0, p = Config.peers; i++ < Config.npeers; 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:%d\n", inet_ntoa(p->in_addr.sin_addr), ntohs(p->in_addr.sin_port)); + htcpClear(e, uri, req, method, p, reason); + } +} + #endif Index: protos.h =================================================================== RCS file: /cvsroot/squid/squid/src/protos.h,v retrieving revision 1.567 diff -u -r1.567 protos.h --- protos.h 15 Aug 2008 05:08:00 -0000 1.567 +++ protos.h 27 Aug 2008 06:33:22 -0000 @@ -688,6 +688,9 @@ extern void neighborsUdpAck(const cache_key *, icp_common_t *, const struct sockaddr_in *); extern void neighborAdd(const char *, const char *, int, int, int, int, int); extern void neighbors_init(void); +#if USE_HTCP +extern void neighborsHtcpClear(StoreEntry *, const char *, request_t *, method_t *, htcp_clr_reason); +#endif extern peer *peerFindByName(const char *); extern peer *peerFindByNameAndPort(const char *, unsigned short); extern peer *getDefaultParent(request_t * request); @@ -1257,6 +1260,7 @@ #if USE_HTCP extern void htcpInit(void); extern void htcpQuery(StoreEntry * e, request_t * req, peer * p); +extern void htcpClear(StoreEntry * e, const char *uri, request_t * req, method_t *, peer * p, htcp_clr_reason reason); extern void htcpSocketShutdown(void); extern void htcpSocketClose(void); #endif Index: store.c =================================================================== RCS file: /cvsroot/squid/squid/src/store.c,v retrieving revision 1.596 diff -u -r1.596 store.c --- store.c 15 Aug 2008 05:08:00 -0000 1.596 +++ store.c 27 Aug 2008 06:33:23 -0000 @@ -426,10 +426,28 @@ } e = storeGetPublic(url, method); if (e == NULL) { +#if USE_HTCP + if (m == METHOD_HEAD) { + method = urlMethodGetKnownByCode(METHOD_GET); + } + neighborsHtcpClear(NULL, url, req, method, HTCP_CLR_INVALIDATION); + if (m == METHOD_GET || m == METHOD_HEAD) { + get_or_head_sent = 1; + } +#endif continue; } debug(20, 5) ("storePurgeEntriesByUrl: purging %s %s\n", method->string, url); +#if USE_HTCP + if (m == METHOD_HEAD) { + method = urlMethodGetKnownByCode(METHOD_GET); + } + neighborsHtcpClear(e, url, req, method, HTCP_CLR_INVALIDATION); + if (m == METHOD_GET || m == METHOD_HEAD) { + get_or_head_sent = 1; + } +#endif storeRelease(e); } } Index: structs.h =================================================================== RCS file: /cvsroot/squid/squid/src/structs.h,v retrieving revision 1.567 diff -u -r1.567 structs.h --- structs.h 17 Aug 2008 22:02:00 -0000 1.567 +++ structs.h 27 Aug 2008 06:33:23 -0000 @@ -1506,6 +1506,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 Index: typedefs.h =================================================================== RCS file: /cvsroot/squid/squid/src/typedefs.h,v retrieving revision 1.164 diff -u -r1.164 typedefs.h --- typedefs.h 15 Aug 2008 04:56:01 -0000 1.164 +++ typedefs.h 27 Aug 2008 06:33:23 -0000 @@ -434,4 +434,11 @@ typedef void REFRESHCHECK(void *data, int fresh, const char *log); typedef struct _refresh_check_helper refresh_check_helper; + +#if USE_HTCP + +typedef enum htcp_clr_reason htcp_clr_reason; + +#endif + #endif /* SQUID_TYPEDEFS_H */