]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/htcp.cc
transaction_initiator ACL for detecting various unusual transactions
[thirdparty/squid.git] / src / htcp.cc
index 4f4a0a9fcdaef1c0a843ae7d5ec695fc6820cd2e..7ebc44fcaf5942fdf6e0af7c1ed184bb74b1cc38 100644 (file)
@@ -1,36 +1,13 @@
-
 /*
- * DEBUG: section 31    Hypertext Caching Protocol
- * AUTHOR: Duane Wesssels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
  *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
+/* DEBUG: section 31    Hypertext Caching Protocol */
+
 #include "squid.h"
 #include "AccessLogEntry.h"
 #include "acl/Acl.h"
 #include "htcp.h"
 #include "http.h"
 #include "HttpRequest.h"
-#include "HttpStateFlags.h"
 #include "icmp/net_db.h"
 #include "ip/tools.h"
 #include "md5.h"
+#include "mem/forward.h"
 #include "MemBuf.h"
 #include "refresh.h"
 #include "SquidConfig.h"
@@ -70,10 +47,6 @@ typedef struct _htcpDataHeaderSquid htcpDataHeaderSquid;
 
 typedef struct _htcpAuthHeader htcpAuthHeader;
 
-typedef struct _htcpStuff htcpStuff;
-
-typedef struct _htcpDetail htcpDetail;
-
 struct _Countstr {
     uint16_t length;
     char *text;
@@ -113,31 +86,21 @@ struct _htcpDataHeader {
     uint16_t length;
 
 #if WORDS_BIGENDIAN
-uint8_t opcode:
-    4;
-uint8_t response:
-    4;
+    uint8_t opcode:4;
+    uint8_t response:4;
 #else
-uint8_t response:
-    4;
-uint8_t opcode:
-    4;
+    uint8_t response:4;
+    uint8_t opcode:4;
 #endif
 
 #if WORDS_BIGENDIAN
-uint8_t reserved:
-    6;
-uint8_t F1:
-    1;
-uint8_t RR:
-    1;
+    uint8_t reserved:6;
+    uint8_t F1:1;
+    uint8_t RR:1;
 #else
-uint8_t RR:
-    1;
-uint8_t F1:
-    1;
-uint8_t reserved:
-    6;
+    uint8_t RR:1;
+    uint8_t F1:1;
+    uint8_t reserved:6;
 #endif
 
     uint32_t msg_id;
@@ -156,40 +119,67 @@ struct _htcpAuthHeader {
     Countstr signature;
 };
 
-class htcpSpecifier : public StoreClient
+class htcpSpecifier : public RefCountable, public StoreClient
 {
+    MEMPROXY_CLASS(htcpSpecifier);
 
 public:
-    MEMPROXY_CLASS(htcpSpecifier);
+    typedef RefCount<htcpSpecifier> Pointer;
 
-    void created (StoreEntry *newEntry);
     void checkHit();
-    void checkedHit(StoreEntry *e);
+    void checkedHit(StoreEntry *);
+
+    void setFrom(Ip::Address &anIp) { from = anIp; }
+    void setDataHeader(htcpDataHeader *aDataHeader) {
+        dhdr = aDataHeader;
+    }
+
+    /* StoreClient API */
+    void created(StoreEntry *);
 
-    void setFrom(Ip::Address &from);
-    void setDataHeader(htcpDataHeader *);
-    const char *method;
-    char *uri;
-    char *version;
-    char *req_hdrs;
-    HttpRequest *request;
+public:
+    const char *method = nullptr;
+    char *uri = nullptr;
+    char *version = nullptr;
+    char *req_hdrs = nullptr;
+    size_t reqHdrsSz = 0; ///< size of the req_hdrs content
+    HttpRequest::Pointer request;
 
 private:
-    HttpRequest *checkHitRequest;
+    HttpRequest::Pointer checkHitRequest;
 
-    Ip::Address from; // was a ptr. return to such IFF needed. otherwise copy should do.
-    htcpDataHeader *dhdr;
+    Ip::Address from;
+    htcpDataHeader *dhdr = nullptr;
 };
 
-MEMPROXY_CLASS_INLINE(htcpSpecifier);
-
-struct _htcpDetail {
+class htcpDetail {
+    MEMPROXY_CLASS(htcpDetail);
+public:
+    htcpDetail() : resp_hdrs(nullptr), respHdrsSz(0), entity_hdrs(nullptr), entityHdrsSz(0), cache_hdrs(nullptr), cacheHdrsSz(0) {}
     char *resp_hdrs;
+    size_t respHdrsSz;
+
     char *entity_hdrs;
+    size_t entityHdrsSz;
+
     char *cache_hdrs;
+    size_t cacheHdrsSz;
 };
 
-struct _htcpStuff {
+class htcpStuff
+{
+public:
+    htcpStuff(uint32_t id, int o, int r, int f) :
+        op(o),
+        rr(r),
+        f1(f),
+        response(0),
+        reason(0),
+        msg_id(id)
+    {
+        memset(&D, 0, sizeof(D));
+    }
+
     int op;
     int rr;
     int f1;
@@ -248,32 +238,22 @@ static uint32_t queried_id[N_QUERIED_KEYS];
 static cache_key queried_keys[N_QUERIED_KEYS][SQUID_MD5_DIGEST_LENGTH];
 
 static Ip::Address queried_addr[N_QUERIED_KEYS];
-static MemAllocator *htcpDetailPool = NULL;
 
 static int old_squid_format = 0;
 
 static ssize_t htcpBuildPacket(char *buf, size_t buflen, htcpStuff * stuff);
-static htcpSpecifier *htcpUnpackSpecifier(char *buf, int sz);
 static htcpDetail *htcpUnpackDetail(char *buf, int sz);
 static ssize_t htcpBuildAuth(char *buf, size_t buflen);
-static ssize_t htcpBuildCountstr(char *buf, size_t buflen, const char *s);
+static ssize_t htcpBuildCountstr(char *buf, size_t buflen, const char *s, size_t len);
 static ssize_t htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff);
 static ssize_t htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff);
 static ssize_t htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff);
 static ssize_t htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff);
 static ssize_t htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff);
-static void htcpFreeSpecifier(htcpSpecifier * s);
-static void htcpFreeDetail(htcpDetail * s);
 
 static void htcpHandleMsg(char *buf, int sz, Ip::Address &from);
 
 static void htcpLogHtcp(Ip::Address &, int, LogTags, const char *);
-static void htcpHandleMon(htcpDataHeader *, char *buf, int sz, Ip::Address &from);
-
-static void htcpHandleNop(htcpDataHeader *, char *buf, int sz, Ip::Address &from);
-
-static void htcpHandleSet(htcpDataHeader *, char *buf, int sz, Ip::Address &from);
-
 static void htcpHandleTst(htcpDataHeader *, char *buf, int sz, Ip::Address &from);
 
 static void htcpRecv(int fd, void *data);
@@ -290,14 +270,12 @@ static void
 htcpHexdump(const char *tag, const char *s, int sz)
 {
 #if USE_HEXDUMP
-    int i;
-    int k;
     char hex[80];
     debugs(31, 3, "htcpHexdump " << tag);
-    memset(hex, '\0', 80);
+    memset(hex, '\0', sizeof(hex));
 
-    for (i = 0; i < sz; ++i) {
-        k = i % 16;
+    for (int i = 0; i < sz; ++i) {
+        int k = i % 16;
         snprintf(&hex[k * 3], 4, " %02x", (int) *(s + i));
 
         if (k < 15 && i < (sz - 1))
@@ -305,9 +283,8 @@ htcpHexdump(const char *tag, const char *s, int sz)
 
         debugs(31, 3, "\t" << hex);
 
-        memset(hex, '\0', 80);
+        memset(hex, '\0', sizeof(hex));
     }
-
 #endif
 }
 
@@ -330,25 +307,18 @@ htcpBuildAuth(char *buf, size_t buflen)
 }
 
 static ssize_t
-htcpBuildCountstr(char *buf, size_t buflen, const char *s)
+htcpBuildCountstr(char *buf, size_t buflen, const char *s, size_t len)
 {
-    uint16_t length;
-    size_t len;
     int off = 0;
 
     if (buflen - off < 2)
         return -1;
 
-    if (s)
-        len = strlen(s);
-    else
-        len = 0;
-
     debugs(31, 3, "htcpBuildCountstr: LENGTH = " << len);
 
     debugs(31, 3, "htcpBuildCountstr: TEXT = {" << (s ? s : "<NULL>") << "}");
 
-    length = htons((uint16_t) len);
+    uint16_t length = htons((uint16_t) len);
 
     memcpy(buf + off, &length, 2);
 
@@ -370,28 +340,28 @@ htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff)
 {
     ssize_t off = 0;
     ssize_t s;
-    s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.method);
+    s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.method, (stuff->S.method?strlen(stuff->S.method):0));
 
     if (s < 0)
         return s;
 
     off += s;
 
-    s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.uri);
+    s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.uri, (stuff->S.uri?strlen(stuff->S.uri):0));
 
     if (s < 0)
         return s;
 
     off += s;
 
-    s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.version);
+    s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.version, (stuff->S.version?strlen(stuff->S.version):0));
 
     if (s < 0)
         return s;
 
     off += s;
 
-    s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.req_hdrs);
+    s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.req_hdrs, stuff->S.reqHdrsSz);
 
     if (s < 0)
         return s;
@@ -408,21 +378,21 @@ htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff)
 {
     ssize_t off = 0;
     ssize_t s;
-    s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.resp_hdrs);
+    s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.resp_hdrs, stuff->D.respHdrsSz);
 
     if (s < 0)
         return s;
 
     off += s;
 
-    s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.entity_hdrs);
+    s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.entity_hdrs, stuff->D.entityHdrsSz);
 
     if (s < 0)
         return s;
 
     off += s;
 
-    s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.cache_hdrs);
+    s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.cache_hdrs, stuff->D.cacheHdrsSz);
 
     if (s < 0)
         return s;
@@ -445,9 +415,9 @@ htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff)
         debugs(31, 3, "htcpBuildTstOpData: RR_RESPONSE");
         debugs(31, 3, "htcpBuildTstOpData: F1 = " << stuff->f1);
 
-        if (stuff->f1)         /* cache miss */
+        if (stuff->f1)      /* cache miss */
             return 0;
-        else                   /* cache hit */
+        else            /* cache hit */
             return htcpBuildDetail(buf, buflen, stuff);
 
     default:
@@ -507,12 +477,11 @@ htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff)
     ssize_t off = 0;
     ssize_t op_data_sz;
     size_t hdr_sz = sizeof(htcpDataHeader);
-    htcpDataHeader hdr;
 
     if (buflen < hdr_sz)
         return -1;
 
-    off += hdr_sz;             /* skip! */
+    off += hdr_sz;      /* skip! */
 
     op_data_sz = htcpBuildOpData(buf + off, buflen - off, stuff);
 
@@ -523,33 +492,25 @@ htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff)
 
     debugs(31, 3, "htcpBuildData: hdr.length = " << off);
 
-    hdr.length = (uint16_t) off;
-
-    hdr.opcode = stuff->op;
-
-    hdr.response = stuff->response;
-
-    hdr.RR = stuff->rr;
-
-    hdr.F1 = stuff->f1;
-
-    hdr.msg_id = stuff->msg_id;
-
-    /* convert multi-byte fields */
-    hdr.length = htons(hdr.length);
-
-    hdr.msg_id = htonl(hdr.msg_id);
-
     if (!old_squid_format) {
+        htcpDataHeader hdr;
+        memset(&hdr, 0, sizeof(hdr));
+        /* convert multi-byte fields */
+        hdr.msg_id = htonl(stuff->msg_id);
+        hdr.length = htons(static_cast<uint16_t>(off));
+        hdr.opcode = stuff->op;
+        hdr.response = stuff->response;
+        hdr.RR = stuff->rr;
+        hdr.F1 = stuff->f1;
         memcpy(buf, &hdr, hdr_sz);
     } else {
         htcpDataHeaderSquid hdrSquid;
         memset(&hdrSquid, 0, sizeof(hdrSquid));
-        hdrSquid.length = hdr.length;
-        hdrSquid.opcode = hdr.opcode;
-        hdrSquid.response = hdr.response;
-        hdrSquid.F1 = hdr.F1;
-        hdrSquid.RR = hdr.RR;
+        hdrSquid.length = htons(static_cast<uint16_t>(off));
+        hdrSquid.opcode = stuff->op;
+        hdrSquid.response = stuff->response;
+        hdrSquid.F1 = stuff->f1;
+        hdrSquid.RR = stuff->rr;
         memcpy(buf, &hdrSquid, hdr_sz);
     }
 
@@ -608,53 +569,27 @@ htcpBuildPacket(char *buf, size_t buflen, htcpStuff * stuff)
 static void
 htcpSend(const char *buf, int len, Ip::Address &to)
 {
-    debugs(31, 3, HERE << to);
+    debugs(31, 3, to);
     htcpHexdump("htcpSend", buf, len);
 
-    if (comm_udp_sendto(htcpOutgoingConn->fd, to, buf, len) < 0)
-        debugs(31, 3, HERE << htcpOutgoingConn << " sendto: " << xstrerror());
-    else
+    if (comm_udp_sendto(htcpOutgoingConn->fd, to, buf, len) < 0) {
+        int xerrno = errno;
+        debugs(31, 3, htcpOutgoingConn << " sendto: " << xstrerr(xerrno));
+    } else
         ++statCounter.htcp.pkts_sent;
 }
 
-/*
- * STUFF FOR RECEIVING HTCP MESSAGES
- */
-
-void
-htcpSpecifier::setFrom(Ip::Address &aSocket)
-{
-    from = aSocket;
-}
-
-void
-htcpSpecifier::setDataHeader(htcpDataHeader *aDataHeader)
-{
-    dhdr = aDataHeader;
-}
-
-static void
-htcpFreeSpecifier(htcpSpecifier * s)
-{
-    HTTPMSGUNLOCK(s->request);
-
-    delete s;
-}
-
-static void
-htcpFreeDetail(htcpDetail * d)
-{
-    htcpDetailPool->freeOne(d);
-}
-
 /*
  * Unpack an HTCP SPECIFIER in place
  * This will overwrite any following AUTH block
  */
-static htcpSpecifier *
+// XXX: this needs to be turned into an Htcp1::Parser inheriting from Http1::RequestParser
+//   but with different first-line and block unpacking logic.
+static htcpSpecifier::Pointer
 htcpUnpackSpecifier(char *buf, int sz)
 {
-    htcpSpecifier *s = new htcpSpecifier;
+    static const htcpSpecifier::Pointer nil;
+    htcpSpecifier::Pointer s(new htcpSpecifier);
     HttpRequestMethod method;
 
     /* Find length of METHOD */
@@ -664,8 +599,7 @@ htcpUnpackSpecifier(char *buf, int sz)
 
     if (l > sz) {
         debugs(31, 3, "htcpUnpackSpecifier: failed to unpack METHOD");
-        htcpFreeSpecifier(s);
-        return NULL;
+        return nil;
     }
 
     /* Set METHOD */
@@ -680,8 +614,7 @@ htcpUnpackSpecifier(char *buf, int sz)
 
     if (l > sz) {
         debugs(31, 3, "htcpUnpackSpecifier: failed to unpack URI");
-        htcpFreeSpecifier(s);
-        return NULL;
+        return nil;
     }
 
     /* Add terminating null to METHOD */
@@ -700,8 +633,7 @@ htcpUnpackSpecifier(char *buf, int sz)
 
     if (l > sz) {
         debugs(31, 3, "htcpUnpackSpecifier: failed to unpack VERSION");
-        htcpFreeSpecifier(s);
-        return NULL;
+        return nil;
     }
 
     /* Add terminating null to URI */
@@ -720,8 +652,7 @@ htcpUnpackSpecifier(char *buf, int sz)
 
     if (l > sz) {
         debugs(31, 3, "htcpUnpackSpecifier: failed to unpack REQ-HDRS");
-        htcpFreeSpecifier(s);
-        return NULL;
+        return nil;
     }
 
     /* Add terminating null to URI */
@@ -732,6 +663,7 @@ htcpUnpackSpecifier(char *buf, int sz)
     s->req_hdrs = buf;
     buf += l;
     sz -= l;
+    s->reqHdrsSz = l;
     debugs(31, 6, "htcpUnpackSpecifier: REQ-HDRS (" << l << "/" << sz << ") '" << s->req_hdrs << "'");
 
     debugs(31, 3, "htcpUnpackSpecifier: " << sz << " bytes left");
@@ -743,16 +675,11 @@ htcpUnpackSpecifier(char *buf, int sz)
      */
     *buf = '\0';
 
-    /*
-     * Parse the request
-     */
-    method = HttpRequestMethod(s->method, NULL);
-
-    s->request = HttpRequest::CreateFromUrlAndMethod(s->uri, method == Http::METHOD_NONE ? HttpRequestMethod(Http::METHOD_GET) : method);
-
-    if (s->request)
-        HTTPMSGLOCK(s->request);
+    // Parse the request
+    method.HttpRequestMethodXXX(s->method);
 
+    const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initHtcp);
+    s->request = HttpRequest::FromUrl(s->uri, mx, method == Http::METHOD_NONE ? HttpRequestMethod(Http::METHOD_GET) : method);
     return s;
 }
 
@@ -763,7 +690,7 @@ htcpUnpackSpecifier(char *buf, int sz)
 static htcpDetail *
 htcpUnpackDetail(char *buf, int sz)
 {
-    htcpDetail *d = static_cast<htcpDetail *>(htcpDetailPool->alloc());
+    htcpDetail *d = new htcpDetail;
 
     /* Find length of RESP-HDRS */
     uint16_t l = ntohs(*(uint16_t *) buf);
@@ -772,15 +699,14 @@ htcpUnpackDetail(char *buf, int sz)
 
     if (l > sz) {
         debugs(31, 3, "htcpUnpackDetail: failed to unpack RESP_HDRS");
-        htcpFreeDetail(d);
+        delete d;
         return NULL;
     }
 
     /* Set RESP-HDRS */
     d->resp_hdrs = buf;
-
     buf += l;
-
+    d->respHdrsSz = l;
     sz -= l;
 
     /* Find length of ENTITY-HDRS */
@@ -790,7 +716,7 @@ htcpUnpackDetail(char *buf, int sz)
 
     if (l > sz) {
         debugs(31, 3, "htcpUnpackDetail: failed to unpack ENTITY_HDRS");
-        htcpFreeDetail(d);
+        delete d;
         return NULL;
     }
 
@@ -801,9 +727,8 @@ htcpUnpackDetail(char *buf, int sz)
     buf += 2;
 
     d->entity_hdrs = buf;
-
     buf += l;
-
+    d->entityHdrsSz = l;
     sz -= l;
 
     /* Find length of CACHE-HDRS */
@@ -813,7 +738,7 @@ htcpUnpackDetail(char *buf, int sz)
 
     if (l > sz) {
         debugs(31, 3, "htcpUnpackDetail: failed to unpack CACHE_HDRS");
-        htcpFreeDetail(d);
+        delete d;
         return NULL;
     }
 
@@ -824,9 +749,8 @@ htcpUnpackDetail(char *buf, int sz)
     buf += 2;
 
     d->cache_hdrs = buf;
-
     buf += l;
-
+    d->cacheHdrsSz = l;
     sz -= l;
 
     debugs(31, 3, "htcpUnpackDetail: " << sz << " bytes left");
@@ -842,13 +766,13 @@ htcpUnpackDetail(char *buf, int sz)
 }
 
 static bool
-htcpAccessAllowed(acl_access * acl, htcpSpecifier * s, Ip::Address &from)
+htcpAccessAllowed(acl_access * acl, const htcpSpecifier::Pointer &s, Ip::Address &from)
 {
     /* default deny if no access list present */
     if (!acl)
         return false;
 
-    ACLFilledChecklist checklist(acl, s->request, NULL);
+    ACLFilledChecklist checklist(acl, s->request.getRaw(), nullptr);
     checklist.src_addr = from;
     checklist.my_addr.setNoAddr();
     return (checklist.fastCheck() == ACCESS_ALLOWED);
@@ -857,52 +781,48 @@ htcpAccessAllowed(acl_access * acl, htcpSpecifier * s, Ip::Address &from)
 static void
 htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, Ip::Address &from)
 {
-    htcpStuff stuff;
     static char pkt[8192];
     HttpHeader hdr(hoHtcpReply);
-    MemBuf mb;
-    Packer p;
     ssize_t pktlen;
-    memset(&stuff, '\0', sizeof(stuff));
-    stuff.op = HTCP_TST;
-    stuff.rr = RR_RESPONSE;
-    stuff.f1 = 0;
+
+    htcpStuff stuff(dhdr->msg_id, HTCP_TST, RR_RESPONSE, 0);
     stuff.response = e ? 0 : 1;
     debugs(31, 3, "htcpTstReply: response = " << stuff.response);
-    stuff.msg_id = dhdr->msg_id;
 
     if (spec) {
-        mb.init();
-        packerToMemInit(&p, &mb);
         stuff.S.method = spec->method;
         stuff.S.uri = spec->uri;
         stuff.S.version = spec->version;
         stuff.S.req_hdrs = spec->req_hdrs;
+        stuff.S.reqHdrsSz = spec->reqHdrsSz;
         if (e)
-            hdr.putInt(HDR_AGE, (e->timestamp <= squid_curtime ? (squid_curtime - e->timestamp) : 0) );
+            hdr.putInt(Http::HdrType::AGE, (e->timestamp <= squid_curtime ? (squid_curtime - e->timestamp) : 0) );
         else
-            hdr.putInt(HDR_AGE, 0);
-        hdr.packInto(&p);
+            hdr.putInt(Http::HdrType::AGE, 0);
+        MemBuf mb;
+        mb.init();
+        hdr.packInto(&mb);
         stuff.D.resp_hdrs = xstrdup(mb.buf);
+        stuff.D.respHdrsSz = mb.contentSize();
         debugs(31, 3, "htcpTstReply: resp_hdrs = {" << stuff.D.resp_hdrs << "}");
         mb.reset();
-        hdr.reset();
+        hdr.clean();
 
         if (e && e->expires > -1)
-            hdr.putTime(HDR_EXPIRES, e->expires);
+            hdr.putTime(Http::HdrType::EXPIRES, e->expires);
 
-        if (e && e->lastmod > -1)
-            hdr.putTime(HDR_LAST_MODIFIED, e->lastmod);
+        if (e && e->lastModified() > -1)
+            hdr.putTime(Http::HdrType::LAST_MODIFIED, e->lastModified());
 
-        hdr.packInto(&p);
+        hdr.packInto(&mb);
 
         stuff.D.entity_hdrs = xstrdup(mb.buf);
+        stuff.D.entityHdrsSz = mb.contentSize();
 
         debugs(31, 3, "htcpTstReply: entity_hdrs = {" << stuff.D.entity_hdrs << "}");
 
         mb.reset();
-
-        hdr.reset();
+        hdr.clean();
 
 #if USE_ICMP
         if (char *host = urlHostname(spec->uri)) {
@@ -920,19 +840,22 @@ htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, Ip::Ad
         }
 #endif /* USE_ICMP */
 
-        hdr.packInto(&p);
+        hdr.packInto(&mb);
         stuff.D.cache_hdrs = xstrdup(mb.buf);
+        stuff.D.cacheHdrsSz = mb.contentSize();
         debugs(31, 3, "htcpTstReply: cache_hdrs = {" << stuff.D.cache_hdrs << "}");
         mb.clean();
         hdr.clean();
-        packerClean(&p);
     }
 
     pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
 
     safe_free(stuff.D.resp_hdrs);
+    stuff.D.respHdrsSz = 0;
     safe_free(stuff.D.entity_hdrs);
+    stuff.D.entityHdrsSz = 0;
     safe_free(stuff.D.cache_hdrs);
+    stuff.D.cacheHdrsSz = 0;
 
     if (!pktlen) {
         debugs(31, 3, "htcpTstReply: htcpBuildPacket() failed");
@@ -946,7 +869,6 @@ static void
 
 htcpClrReply(htcpDataHeader * dhdr, int purgeSucceeded, Ip::Address &from)
 {
-    htcpStuff stuff;
     static char pkt[8192];
     ssize_t pktlen;
 
@@ -955,20 +877,12 @@ htcpClrReply(htcpDataHeader * dhdr, int purgeSucceeded, Ip::Address &from)
     if (dhdr->F1 == 0)
         return;
 
-    memset(&stuff, '\0', sizeof(stuff));
-
-    stuff.op = HTCP_CLR;
-
-    stuff.rr = RR_RESPONSE;
-
-    stuff.f1 = 0;
+    htcpStuff stuff(dhdr->msg_id, HTCP_CLR, RR_RESPONSE, 0);
 
     stuff.response = purgeSucceeded ? 0 : 2;
 
     debugs(31, 3, "htcpClrReply: response = " << stuff.response);
 
-    stuff.msg_id = dhdr->msg_id;
-
     pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
 
     if (pktlen == 0) {
@@ -979,56 +893,44 @@ htcpClrReply(htcpDataHeader * dhdr, int purgeSucceeded, Ip::Address &from)
     htcpSend(pkt, (int) pktlen, from);
 }
 
-static void
-
-htcpHandleNop(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
-{
-    debugs(31, 3, "htcpHandleNop: Unimplemented");
-}
-
 void
 htcpSpecifier::checkHit()
 {
-    char *blk_end;
     checkHitRequest = request;
 
-    if (NULL == checkHitRequest) {
+    if (!checkHitRequest) {
         debugs(31, 3, "htcpCheckHit: NO; failed to parse URL");
         checkedHit(NullStoreEntry::getInstance());
         return;
     }
 
-    blk_end = req_hdrs + strlen(req_hdrs);
-
-    if (!checkHitRequest->header.parse(req_hdrs, blk_end)) {
+    if (!checkHitRequest->header.parse(req_hdrs, reqHdrsSz)) {
         debugs(31, 3, "htcpCheckHit: NO; failed to parse request headers");
-        delete checkHitRequest;
-        checkHitRequest = NULL;
+        checkHitRequest = nullptr;
         checkedHit(NullStoreEntry::getInstance());
         return;
     }
 
-    StoreEntry::getPublicByRequest(this, checkHitRequest);
+    StoreEntry::getPublicByRequest(this, checkHitRequest.getRaw());
 }
 
 void
-htcpSpecifier::created (StoreEntry *e)
+htcpSpecifier::created(StoreEntry *e)
 {
-    StoreEntry *hit=NULL;
-    assert (e);
+    StoreEntry *hit = nullptr;
 
-    if (e->isNull()) {
+    if (!e || e->isNull()) {
         debugs(31, 3, "htcpCheckHit: NO; public object not found");
     } else if (!e->validToSend()) {
         debugs(31, 3, "htcpCheckHit: NO; entry not valid to send" );
-    } else if (refreshCheckHTCP(e, checkHitRequest)) {
+    } else if (refreshCheckHTCP(e, checkHitRequest.getRaw())) {
         debugs(31, 3, "htcpCheckHit: NO; cached response is stale");
     } else {
         debugs(31, 3, "htcpCheckHit: YES!?");
         hit = e;
     }
 
-    checkedHit (hit);
+    checkedHit(hit);
 }
 
 static void
@@ -1039,32 +941,26 @@ htcpClrStoreEntry(StoreEntry * e)
 }
 
 static int
-htcpClrStore(const htcpSpecifier * s)
+htcpClrStore(const htcpSpecifier::Pointer &s)
 {
-    HttpRequest *request = s->request;
-    char *blk_end;
-    StoreEntry *e = NULL;
-    int released = 0;
-
-    if (request == NULL) {
+    HttpRequestPointer request(s->request);
+    if (!request) {
         debugs(31, 3, "htcpClrStore: failed to parse URL");
         return -1;
     }
 
     /* Parse request headers */
-    blk_end = s->req_hdrs + strlen(s->req_hdrs);
-
-    if (!request->header.parse(s->req_hdrs, blk_end)) {
+    if (!request->header.parse(s->req_hdrs, s->reqHdrsSz)) {
         debugs(31, 2, "htcpClrStore: failed to parse request headers");
         return -1;
     }
 
+    StoreEntry *e = nullptr;
+    int released = 0;
     /* Lookup matching entries. This matches both GET and HEAD */
-    while ((e = storeGetPublicByRequest(request)) != NULL) {
-        if (e != NULL) {
-            htcpClrStoreEntry(e);
-            ++released;
-        }
+    while ((e = storeGetPublicByRequest(request.getRaw()))) {
+        htcpClrStoreEntry(e);
+        ++released;
     }
 
     if (released) {
@@ -1089,8 +985,10 @@ htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
 }
 
 HtcpReplyData::HtcpReplyData() :
-        hit(0), hdr(hoHtcpReply), msg_id(0), version(0.0)
-{}
+    hit(0), hdr(hoHtcpReply), msg_id(0), version(0.0)
+{
+    memset(&cto, 0, sizeof(cto));
+}
 
 static void
 
@@ -1147,29 +1045,25 @@ htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from
         }
 
         if ((t = d->resp_hdrs))
-            htcpReply.hdr.parse(t, t + strlen(t));
+            htcpReply.hdr.parse(t, d->respHdrsSz);
 
         if ((t = d->entity_hdrs))
-            htcpReply.hdr.parse(t, t + strlen(t));
+            htcpReply.hdr.parse(t, d->entityHdrsSz);
 
         if ((t = d->cache_hdrs))
-            htcpReply.hdr.parse(t, t + strlen(t));
+            htcpReply.hdr.parse(t, d->cacheHdrsSz);
     }
 
     debugs(31, 3, "htcpHandleTstResponse: key (" << key << ") " << storeKeyText(key));
     neighborsHtcpReply(key, &htcpReply, from);
     htcpReply.hdr.clean();
 
-    if (d)
-        htcpFreeDetail(d);
+    delete d;
 }
 
 static void
 htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, Ip::Address &from)
 {
-    /* buf should be a SPECIFIER */
-    htcpSpecifier *s;
-
     if (sz == 0) {
         debugs(31, 3, "htcpHandleTst: nothing to do");
         return;
@@ -1178,10 +1072,10 @@ htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, Ip::Address &from
     if (dhdr->F1 == 0)
         return;
 
-    /* s is a new object */
-    s = htcpUnpackSpecifier(buf, sz);
+    /* buf should be a SPECIFIER */
+    htcpSpecifier::Pointer s(htcpUnpackSpecifier(buf, sz));
 
-    if (s == NULL) {
+    if (!s) {
         debugs(31, 3, "htcpHandleTstRequest: htcpUnpackSpecifier failed");
         htcpLogHtcp(from, dhdr->opcode, LOG_UDP_INVALID, dash_str);
         return;
@@ -1193,14 +1087,12 @@ htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, Ip::Address &from
     if (!s->request) {
         debugs(31, 3, "htcpHandleTstRequest: failed to parse request");
         htcpLogHtcp(from, dhdr->opcode, LOG_UDP_INVALID, dash_str);
-        htcpFreeSpecifier(s);
         return;
     }
 
     if (!htcpAccessAllowed(Config.accessList.htcp, s, from)) {
         debugs(31, 3, "htcpHandleTstRequest: Access denied");
         htcpLogHtcp(from, dhdr->opcode, LOG_UDP_DENIED, s->uri);
-        htcpFreeSpecifier(s);
         return;
     }
 
@@ -1213,34 +1105,17 @@ void
 htcpSpecifier::checkedHit(StoreEntry *e)
 {
     if (e) {
-        htcpTstReply(dhdr, e, this, from);             /* hit */
+        htcpTstReply(dhdr, e, this, from);      /* hit */
         htcpLogHtcp(from, dhdr->opcode, LOG_UDP_HIT, uri);
     } else {
-        htcpTstReply(dhdr, NULL, NULL, from);  /* cache miss */
+        htcpTstReply(dhdr, NULL, NULL, from);   /* cache miss */
         htcpLogHtcp(from, dhdr->opcode, LOG_UDP_MISS, uri);
     }
-
-    htcpFreeSpecifier(this);
-}
-
-static void
-
-htcpHandleMon(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
-{
-    debugs(31, 3, "htcpHandleMon: Unimplemented");
-}
-
-static void
-
-htcpHandleSet(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
-{
-    debugs(31, 3, "htcpHandleSet: Unimplemented");
 }
 
 static void
 htcpHandleClr(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
 {
-    htcpSpecifier *s;
     /* buf[0/1] is reserved and reason */
     int reason = buf[1] << 4;
     debugs(31, 2, "HTCP CLR reason: " << reason);
@@ -1255,9 +1130,9 @@ htcpHandleClr(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
         return;
     }
 
-    s = htcpUnpackSpecifier(buf, sz);
+    htcpSpecifier::Pointer s(htcpUnpackSpecifier(buf, sz));
 
-    if (NULL == s) {
+    if (!s) {
         debugs(31, 3, "htcpHandleClr: htcpUnpackSpecifier failed");
         htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str);
         return;
@@ -1266,14 +1141,12 @@ htcpHandleClr(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
     if (!s->request) {
         debugs(31, 3, "htcpHandleTstRequest: failed to parse request");
         htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str);
-        htcpFreeSpecifier(s);
         return;
     }
 
     if (!htcpAccessAllowed(Config.accessList.htcp_clr, s, from)) {
         debugs(31, 3, "htcpHandleClr: Access denied");
         htcpLogHtcp(from, hdr->opcode, LOG_UDP_DENIED, s->uri);
-        htcpFreeSpecifier(s);
         return;
     }
 
@@ -1287,20 +1160,18 @@ htcpHandleClr(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
     switch (htcpClrStore(s)) {
 
     case 1:
-        htcpClrReply(hdr, 1, from);    /* hit */
+        htcpClrReply(hdr, 1, from); /* hit */
         htcpLogHtcp(from, hdr->opcode, LOG_UDP_HIT, s->uri);
         break;
 
     case 0:
-        htcpClrReply(hdr, 0, from);    /* miss */
+        htcpClrReply(hdr, 0, from); /* miss */
         htcpLogHtcp(from, hdr->opcode, LOG_UDP_MISS, s->uri);
         break;
 
     default:
         break;
     }
-
-    htcpFreeSpecifier(s);
 }
 
 /*
@@ -1428,16 +1299,16 @@ htcpHandleMsg(char *buf, int sz, Ip::Address &from)
 
     switch (hdr.opcode) {
     case HTCP_NOP:
-        htcpHandleNop(&hdr, hbuf, hsz, from);
+        debugs(31, 3, "HTCP NOP not implemented");
         break;
     case HTCP_TST:
         htcpHandleTst(&hdr, hbuf, hsz, from);
         break;
     case HTCP_MON:
-        htcpHandleMon(&hdr, hbuf, hsz, from);
+        debugs(31, 3, "HTCP MON not implemented");
         break;
     case HTCP_SET:
-        htcpHandleSet(&hdr, hbuf, hsz, from);
+        debugs(31, 3, "HTCP SET not implemented");
         break;
     case HTCP_CLR:
         htcpHandleClr(&hdr, hbuf, hsz, from);
@@ -1449,7 +1320,7 @@ htcpHandleMsg(char *buf, int sz, Ip::Address &from)
 }
 
 static void
-htcpRecv(int fd, void *data)
+htcpRecv(int fd, void *)
 {
     static char buf[8192];
     int len;
@@ -1531,9 +1402,6 @@ htcpOpenPorts(void)
         debugs(31, DBG_IMPORTANT, "Sending HTCP messages from " << htcpOutgoingConn->local);
     }
 
-    if (!htcpDetailPool) {
-        htcpDetailPool = memPoolCreate("htcpDetail", sizeof(htcpDetail));
-    }
 }
 
 static void
@@ -1559,11 +1427,8 @@ htcpQuery(StoreEntry * e, HttpRequest * req, CachePeer * p)
     static char pkt[8192];
     ssize_t pktlen;
     char vbuf[32];
-    htcpStuff stuff;
     HttpHeader hdr(hoRequest);
-    Packer pa;
-    MemBuf mb;
-    HttpStateFlags flags;
+    Http::StateFlags flags;
 
     if (!Comm::IsConnOpen(htcpIncomingConn))
         return 0;
@@ -1572,21 +1437,17 @@ htcpQuery(StoreEntry * e, HttpRequest * req, CachePeer * p)
     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;
+
+    htcpStuff stuff(++msg_id_counter, HTCP_TST, RR_REQUEST, 1);
     SBuf sb = req->method.image();
     stuff.S.method = sb.c_str();
     stuff.S.uri = (char *) e->url();
     stuff.S.version = vbuf;
     HttpStateData::httpBuildRequestHeader(req, e, NULL, &hdr, flags);
+    MemBuf mb;
     mb.init();
-    packerToMemInit(&pa, &mb);
-    hdr.packInto(&pa);
+    hdr.packInto(&mb);
     hdr.clean();
-    packerClean(&pa);
     stuff.S.req_hdrs = mb.buf;
     pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
     mb.clean();
@@ -1610,16 +1471,14 @@ htcpQuery(StoreEntry * e, HttpRequest * req, CachePeer * p)
  * Send an HTCP CLR message for a specified item to a given CachePeer.
  */
 void
-htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &method, CachePeer * p, htcp_clr_reason reason)
+htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &, CachePeer * p, htcp_clr_reason reason)
 {
     static char pkt[8192];
     ssize_t pktlen;
     char vbuf[32];
-    htcpStuff stuff;
     HttpHeader hdr(hoRequest);
-    Packer pa;
     MemBuf mb;
-    HttpStateFlags flags;
+    Http::StateFlags flags;
 
     if (!Comm::IsConnOpen(htcpIncomingConn))
         return;
@@ -1628,19 +1487,11 @@ htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestM
     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:
+
+    htcpStuff stuff(++msg_id_counter, HTCP_CLR, RR_REQUEST, 0);
+    if (reason == HTCP_CLR_INVALIDATION)
         stuff.reason = 1;
-        break;
-    default:
-        stuff.reason = 0;
-        break;
-    }
+
     SBuf sb = req->method.image();
     stuff.S.method = sb.c_str();
     if (e == NULL || e->mem_obj == NULL) {
@@ -1655,10 +1506,8 @@ htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestM
     if (reason != HTCP_CLR_INVALIDATION) {
         HttpStateData::httpBuildRequestHeader(req, e, NULL, &hdr, flags);
         mb.init();
-        packerToMemInit(&pa, &mb);
-        hdr.packInto(&pa);
+        hdr.packInto(&mb);
         hdr.clean();
-        packerClean(&pa);
         stuff.S.req_hdrs = mb.buf;
     } else {
         stuff.S.req_hdrs = NULL;
@@ -1726,7 +1575,7 @@ static void
 htcpLogHtcp(Ip::Address &caddr, int opcode, LogTags logcode, const char *url)
 {
     AccessLogEntry::Pointer al = new AccessLogEntry;
-    if (LOG_TAG_NONE == logcode)
+    if (LOG_TAG_NONE == logcode.oldType)
         return;
     if (!Config.onoff.log_udp)
         return;
@@ -1734,6 +1583,8 @@ htcpLogHtcp(Ip::Address &caddr, int opcode, LogTags logcode, const char *url)
     al->url = url;
     al->cache.caddr = caddr;
     al->cache.code = logcode;
-    al->cache.msec = 0;
+    al->cache.trTime.tv_sec = 0;
+    al->cache.trTime.tv_usec = 0;
     accessLogLog(al, NULL);
 }
+