]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Remove Edge Side Include (ESI) protocol (#1905)
authorAmos Jeffries <yadij@users.noreply.github.com>
Sat, 21 Sep 2024 20:27:11 +0000 (20:27 +0000)
committerSquid Anubis <squid-anubis@squid-cache.org>
Sun, 22 Sep 2024 19:11:09 +0000 (19:11 +0000)
ESI feature has a number of bugs and security vulnerabilities.
It is also rarely used and a survey of active community members
has not revealed a need to keep maintaining this code.

63 files changed:
CREDITS
configure.ac
doc/Programming-Guide/03_MajorComponents.dox
doc/debug-sections.txt
doc/release-notes/release-7.sgml.in
lib/Makefile.am
lib/libTrie/Makefile.am [deleted file]
lib/libTrie/Trie.cc [deleted file]
lib/libTrie/Trie.h [deleted file]
lib/libTrie/TrieCharTransform.h [deleted file]
lib/libTrie/TrieNode.cc [deleted file]
lib/libTrie/TrieNode.h [deleted file]
lib/libTrie/test/Makefile.am [deleted file]
lib/libTrie/test/trie.cc [deleted file]
squid.dox
src/HttpHeader.cc
src/Makefile.am
src/Store.h
src/XactionInitiator.cc
src/XactionInitiator.h
src/cache_cf.cc
src/cf.data.pre
src/cf_gen_defines
src/client_side_reply.cc
src/client_side_request.cc
src/esi/Assign.cc [deleted file]
src/esi/Assign.h [deleted file]
src/esi/Attempt.h [deleted file]
src/esi/Context.cc [deleted file]
src/esi/Context.h [deleted file]
src/esi/Element.h [deleted file]
src/esi/Esi.cc [deleted file]
src/esi/Esi.h [deleted file]
src/esi/Except.h [deleted file]
src/esi/ExpatParser.cc [deleted file]
src/esi/ExpatParser.h [deleted file]
src/esi/Expression.cc [deleted file]
src/esi/Expression.h [deleted file]
src/esi/Include.cc [deleted file]
src/esi/Include.h [deleted file]
src/esi/Libxml2Parser.cc [deleted file]
src/esi/Libxml2Parser.h [deleted file]
src/esi/Literal.h [deleted file]
src/esi/Makefile.am [deleted file]
src/esi/Parser.cc [deleted file]
src/esi/Parser.h [deleted file]
src/esi/Segment.cc [deleted file]
src/esi/Segment.h [deleted file]
src/esi/Sequence.cc [deleted file]
src/esi/Sequence.h [deleted file]
src/esi/Var.h [deleted file]
src/esi/VarState.cc [deleted file]
src/esi/VarState.h [deleted file]
src/http.cc
src/http/RegisteredHeaders.h
src/main.cc
src/tests/stub_store.cc
test-suite/ESIExpressions.cc [deleted file]
test-suite/Makefile.am
test-suite/buildtests/layer-01-minimal.opts
test-suite/buildtests/layer-02-maximus.opts
test-suite/buildtests/layer-04-noauth-everything.opts
test-suite/buildtests/os-mingw.opts

diff --git a/CREDITS b/CREDITS
index 52ebd70e96d645559b3837ef3ff1267e2d04aa3f..d26f68ba0cfadd814aa243e16a0fd274565082c7 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1522,15 +1522,6 @@ src/auth/ntlm/smb_lm/:
 
 ==============================================================================
 
-src/esi/Libxml2Parser.cc,
-src/esi/Libxml2Parser.h:
-
- * The ESI Libxml2 parser is Copyright (c) 2004 by Joachim Bauch
- * http://www.joachim-bauch.de
- * mail@joachim-bauch.de
-
-==============================================================================
-
 src/external_acl.c:
 
  Copyright (C) 2002 MARA Systems AB, Sweden <info@marasystems.com>
index 285f05349e3813e6750e8971bb0081bb74b4adbe..19a5cbe7f85528bc526b9e4529b1ae15269a517d 100644 (file)
@@ -817,38 +817,6 @@ AC_ARG_ENABLE(delay-pools,
 dnl disable generic/common adaptation support by default
 squid_opt_use_adaptation=no
 
-AH_TEMPLATE([USE_SQUID_ESI],[whether to enable ESI processing])
-AC_ARG_ENABLE(esi,[
-  AS_HELP_STRING([--enable-esi],
-                 [Enable ESI for accelerators. ESI requires expat or xml2 library.
-                  Enabling ESI will cause squid reverse proxies to be capable
-                  of the Edge Acceleration Specification (www.esi.org).])
-],[
-  SQUID_DEFINE_BOOL(USE_SQUID_ESI,$enable_esi)
-])
-AC_MSG_NOTICE([Enable ESI processor: ${enable_esi:=no (auto)}])
-
-# ESI support libraries: expat
-SQUID_AUTO_LIB(expat,[ESI expat library],[LIBEXPAT])
-SQUID_CHECK_LIB_WORKS(expat,[
-  PKG_CHECK_MODULES([LIBEXPAT],[expat],[:],[:])
-  CPPFLAGS="$LIBEXPAT_CFLAGS $CPPFLAGS"
-  AC_CHECK_HEADERS(expat.h)
-])
-
-# ESI support libraries: xml2
-SQUID_AUTO_LIB(xml2,[ESI xml2 library],[LIBXML2])
-SQUID_CHECK_LIB_WORKS(xml2,[
-  PKG_CHECK_MODULES([LIBXML2],[libxml-2.0],[:],[:])
-  CPPFLAGS="$LIBXML2_CFLAGS $CPPFLAGS"
-  AC_CHECK_HEADERS(libxml/parser.h libxml/HTMLparser.h libxml/HTMLtree.h)
-])
-
-AS_IF([test "x$enable_esi" = "xyes" -a "x$LIBXML2_LIBS" = "x" -a "x$LIBEXPAT_LIBS" = "x"],[
-  AC_MSG_ERROR([ESI processor requires libxml2 or libexpat])
-])
-AM_CONDITIONAL(ENABLE_ESI,[test "x$enable_esi" = "xyes"])
-
 AC_ARG_ENABLE(icap-client,
   AS_HELP_STRING([--disable-icap-client],[Disable the ICAP client.]),[
   SQUID_YESNO([$enableval],[--enable-icap-client])
@@ -2519,8 +2487,6 @@ AC_CONFIG_FILES([
        errors/Makefile
        icons/Makefile
        lib/Makefile
-       lib/libTrie/Makefile
-       lib/libTrie/test/Makefile
        lib/ntlmauth/Makefile
        lib/rfcnb/Makefile
        lib/smblib/Makefile
@@ -2587,7 +2553,6 @@ AC_CONFIG_FILES([
        src/DiskIO/IpcIo/Makefile
        src/DiskIO/Mmapped/Makefile
        src/error/Makefile
-       src/esi/Makefile
        src/eui/Makefile
        src/format/Makefile
        src/fs/Makefile
index ce6a6606c9729a9078c957b13c6f7fe42df47c79..f52ae3d93184de260bc23c9dea42f3f0962a79a8 100644 (file)
@@ -338,11 +338,4 @@ TODO: get RFCs linked from ietf
        see (http://squid.nlanr.net/Squid/urn-support.html) URN Support in Squid
        .
 
-\section ESI ESI
-\par
-       ESI is an implementation of Edge Side Includes (http://www.esi.org).
-       ESI is implemented as a client side stream and a small
-       modification to client_side_reply.c to check whether
-       ESI should be inserted into the reply stream or not.
-
  */
index 892042ae2c73143ebc0b6e25235d1cb6f3402765..3fdfd0e16a322cc220affbcf1f5566b3e52f6d84 100644 (file)
@@ -138,8 +138,6 @@ section 83    TLS Server/Peer negotiation
 section 83    TLS session management
 section 84    Helper process maintenance
 section 85    Client-side Request Routines
-section 86    ESI Expressions
-section 86    ESI processing
 section 87    Client-side Stream routines.
 section 88    Client-side Reply Routines
 section 89    EUI-48 Lookup
index e3150e65ffefd8ec7c5fb2076ff1000e0033ad63..f33c9992d670d82678e92f624baa6e0021f284bb 100644 (file)
@@ -199,6 +199,9 @@ This section gives an account of those changes in three categories:
 <sect1>Removed directives<label id="removeddirectives">
 <p>
 <descrip>
+       <tag>esi_parser</tag>
+       <p>Edge Side Includes (ESI) protocol is no longer supported natively.
+
        <tag>mcast_miss_addr</tag>
        <p>The corresponding code has not built for many years, indicating that the
        feature is unused.
@@ -257,9 +260,7 @@ This section gives an account of those changes in three categories:
 <sect1>Changes to existing options<label id="modifiedoptions">
 <p>
 <descrip>
-       <tag>--disable-esi</tag>
-       <p>The ESI feature is now disabled by default.
-          Use <em>--enable-esi</em> if needed.
+       <p>No build options have changed behaviour in this version.
 
 </descrip>
 </p>
@@ -270,9 +271,18 @@ This section gives an account of those changes in three categories:
        <tag>--enable-cachemgr-hostname=</tag>
        <p>The <em>cachemgr.cgi</em> tool this option relates to has been removed.
 
+       <tag>--enable-esi</tag>
+       <p>Edge Side Includes (ESI) protocol is no longer supported natively.
+
+       <tag>--without-expat</tag>
+       <p>The ESI feature using libexpat has been removed.
+
        <tag>--without-gnugss</tag>
        <p>Renamed to <em>--without-gss</em>.
 
+       <tag>--without-xml2</tag>
+       <p>The ESI feature using libxml2 has been removed.
+
        <tag>CPPFLAGS=-DHEADERS_LOG</tag>
        <p>The code enabled by this preprocessor macro has not built for many
           years, indicating that the feature is unused.
index 0c09a0e57d81a94d27e7fb3adc03fd94ceda7c39..6bec8df867aec004cb22b17f160102e2dc7c0f83 100644 (file)
@@ -10,9 +10,6 @@ include $(top_srcdir)/src/Common.am
 SUBDIRS=
 EXTRA_DIST=
 
-if ENABLE_ESI
-SUBDIRS += libTrie
-endif
 if ENABLE_SNMP
 SUBDIRS += snmplib
 endif
diff --git a/lib/libTrie/Makefile.am b/lib/libTrie/Makefile.am
deleted file mode 100644 (file)
index cbd016b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-## Copyright (C) 1996-2023 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.
-##
-
-include $(top_srcdir)/src/Common.am
-
-SUBDIRS = . test
-
-noinst_LIBRARIES = libTrie.a
-
-noinst_HEADERS = Trie.h TrieNode.h TrieCharTransform.h
-
-libTrie_a_SOURCES = \
-       Trie.cc \
-       Trie.h \
-       TrieCharTransform.h \
-       TrieNode.cc \
-       TrieNode.h
diff --git a/lib/libTrie/Trie.cc b/lib/libTrie/Trie.cc
deleted file mode 100644 (file)
index fe22224..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#include "squid.h"
-#include "Trie.h"
-#include "TrieCharTransform.h"
-#include "TrieNode.h"
-
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-Trie::Trie(TrieCharTransform *aTransform) : head(nullptr), transform(aTransform)
-{}
-
-Trie::~Trie()
-{
-    delete head;
-    delete transform;
-}
-
-bool
-Trie::add(char const *aString, size_t theLength, void *privatedata)
-{
-    if (!privatedata)
-        return false;
-
-    if (head) {
-        if (find(aString, theLength))
-            return false;
-
-        return head->add(aString, theLength, privatedata, transform);
-    }
-
-    head = new TrieNode;
-
-    return head->add(aString, theLength, privatedata, transform);
-}
-
diff --git a/lib/libTrie/Trie.h b/lib/libTrie/Trie.h
deleted file mode 100644 (file)
index 7d6b888..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#ifndef SQUID_LIB_LIBTRIE_TRIE_H
-#define SQUID_LIB_LIBTRIE_TRIE_H
-
-#include "TrieNode.h"
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-class TrieCharTransform;
-
-/* TODO: parameterize this to be more generic -
-* i.e. M-ary internal node sizes etc
-*/
-
-class Trie
-{
-
-public:
-    Trie(TrieCharTransform *aTransform = nullptr);
-    ~Trie();
-    Trie (Trie const &);
-    Trie &operator= (Trie const &);
-
-    /* Find an exact match in the trie.
-    * If found, return the private data.
-    * If not found, return NULL.
-    */
-    inline void *find (char const *, size_t);
-    /* find any element of the trie in the buffer from the
-    * beginning thereof
-    */
-    inline void *findPrefix (char const *, size_t);
-
-    /* Add a string.
-    * returns false if the string is already
-    * present or cannot be added.
-    */
-
-    bool add(char const *, size_t, void *);
-
-private:
-    TrieNode *head;
-
-    /* transfor each 8 bits in the element */
-    TrieCharTransform *transform;
-};
-
-void *
-Trie::find (char const *aString, size_t theLength)
-{
-    if (head)
-        return head->find (aString, theLength, transform, false);
-
-    return nullptr;
-}
-
-void *
-Trie::findPrefix (char const *aString, size_t theLength)
-{
-    if (head)
-        return head->find (aString, theLength, transform, true);
-
-    return nullptr;
-}
-
-#endif /* SQUID_LIB_LIBTRIE_TRIE_H */
-
diff --git a/lib/libTrie/TrieCharTransform.h b/lib/libTrie/TrieCharTransform.h
deleted file mode 100644 (file)
index 62048e9..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#ifndef SQUID_LIB_LIBTRIE_TRIECHARTRANSFORM_H
-#define SQUID_LIB_LIBTRIE_TRIECHARTRANSFORM_H
-
-/* This is an internal header for libTrie.
- * libTrie provides both limited C and full C++
- * bindings.
- * libTrie itself is written in C++.
- * For C bindings see Trie.h
- */
-
-/* C bindings */
-#ifndef   __cplusplus
-
-/* C++ bindings */
-#else
-#include <cctype>
-#include <sys/types.h>
-#include <utility>
-
-/* TODO: parameterize this to be more generic -
-* i.e. M-ary internal node sizes etc
-*/
-
-class TrieCharTransform
-{
-
-public:
-    virtual ~TrieCharTransform() {}
-
-    virtual char operator () (char const) const = 0;
-};
-
-class TrieCaseless : public TrieCharTransform
-{
-    char operator () (char const aChar) const override {return tolower(aChar);}
-};
-
-#endif /* __cplusplus */
-
-#endif /* SQUID_LIB_LIBTRIE_TRIECHARTRANSFORM_H */
-
diff --git a/lib/libTrie/TrieNode.cc b/lib/libTrie/TrieNode.cc
deleted file mode 100644 (file)
index d417e0f..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#include "squid.h"
-#include "TrieCharTransform.h"
-#include "TrieNode.h"
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-TrieNode::TrieNode() : _privateData(nullptr)
-{
-    for (int i = 0; i < 256; ++i)
-        internal[i] = nullptr;
-}
-
-TrieNode::~TrieNode()
-{
-    for (int i = 0; i < 256; ++i)
-        delete internal[i];
-}
-
-/* as for find */
-bool
-TrieNode::add(char const *aString, size_t theLength, void *privatedata, TrieCharTransform *transform)
-{
-    /* We trust that privatedata and existent keys have already been checked */
-
-    if (theLength) {
-        const unsigned char index = transform ? (*transform)(*aString): *aString;
-
-        if (!internal[index])
-            internal[index] = new TrieNode;
-
-        return internal[index]->add(aString + 1, theLength - 1, privatedata, transform);
-    } else {
-        /* terminal node */
-
-        if (_privateData)
-            return false;
-
-        _privateData = privatedata;
-
-        return true;
-    }
-}
-
diff --git a/lib/libTrie/TrieNode.h b/lib/libTrie/TrieNode.h
deleted file mode 100644 (file)
index bbbb656..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#ifndef SQUID_LIB_LIBTRIE_TRIENODE_H
-#define SQUID_LIB_LIBTRIE_TRIENODE_H
-
-#include "TrieCharTransform.h"
-
-#include <sys/types.h>
-#include <utility>
-
-/* TODO: parameterize this to be more generic -
-* i.e. M-ary internal node sizes etc
-*/
-
-class TrieNode
-{
-
-public:
-    TrieNode();
-    ~TrieNode();
-    TrieNode(TrieNode const &);
-    TrieNode &operator= (TrieNode const &);
-
-    /* Find a string.
-    * If found, return the private data.
-    * If not found, return NULL.
-    */
-    inline void *find (char const *, size_t, TrieCharTransform *, bool const prefix) const;
-
-    /* Add a string.
-    * returns false if the string is already
-    * present or can't be added.
-    */
-
-    bool add (char const *, size_t, void *, TrieCharTransform *);
-
-private:
-    /* 256-way Trie */
-    /* The char index into internal is an
-    * 8-bit prefix to a string in the trie.
-    * internal[0] is the terminal node for
-    * a string and may not be used
-    */
-    TrieNode * internal[256];
-
-    /* If a string ends here, non NULL */
-    void *_privateData;
-};
-
-/* recursive. TODO? make iterative */
-void *
-TrieNode::find (char const *aString, size_t theLength, TrieCharTransform *transform, bool const prefix) const
-{
-    if (theLength) {
-        int index = -1;
-        unsigned char pos = transform ? (*transform) (*aString) : *aString;
-
-        if (internal[pos])
-            index = pos;
-
-        if (index > -1) {
-            void *result;
-            result = internal[index]->find(aString + 1, theLength - 1, transform, prefix);
-
-            if (result)
-                return result;
-        }
-
-        if (prefix)
-            return _privateData;
-
-        return nullptr;
-    } else {
-        /* terminal node */
-        return _privateData;
-    }
-}
-#endif /* SQUID_LIB_LIBTRIE_TRIENODE_H */
-
diff --git a/lib/libTrie/test/Makefile.am b/lib/libTrie/test/Makefile.am
deleted file mode 100644 (file)
index 9cc4182..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-## Copyright (C) 1996-2023 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.
-##
-
-include $(top_srcdir)/src/Common.am
-
-AM_CPPFLAGS += -I$(top_srcdir)/include
-
-TESTS += trie
-
-check_PROGRAMS += trie
-
-trie_SOURCES = trie.cc
-trie_LDADD = $(top_builddir)/lib/libTrie/libTrie.a
diff --git a/lib/libTrie/test/trie.cc b/lib/libTrie/test/trie.cc
deleted file mode 100644 (file)
index cd6baeb..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#include "squid.h"
-#include "libTrie/Trie.h"
-#include "libTrie/TrieCharTransform.h"
-
-#include <iostream>
-
-static bool
-CaseSensitiveCheck()
-{
-    Trie aTrie;
-
-    if (!aTrie.add ("User-Agent", 10, (void *)1)) {
-        std::cerr << "Could not add User-Agent" << std::endl;
-        return 1;
-    }
-
-    if (aTrie.add ("User-Agent", 10, (void *)2)) {
-        std::cerr << "Could add duplicate User-Agent" << std::endl;
-        return 1;
-    }
-
-    if (!aTrie.add ("Alphabet", 8, (void *)3)) {
-        std::cerr << "Could not add Alphabet" << std::endl;
-        return 1;
-    }
-
-    if (!aTrie.add ("Uprefix", 8, (void *)3)) {
-        std::cerr << "Could not add Uprefix" << std::endl;
-        return 1;
-    }
-
-    if (aTrie.find ("User-Agent", 10) != (void *)1) {
-        std::cerr << "Could not find User-Agent" << std::endl;
-        return 1;
-    }
-
-    if (aTrie.find ("user-agent", 10) == (void *)1) {
-        std::cerr << "found user-agent" << std::endl;
-        return 1;
-    }
-
-    if (aTrie.findPrefix("User-AgentFoo", 13) != (void *)1) {
-        std::cerr << "Could not find User prefix" << std::endl;
-        return 1;
-    }
-
-    if (aTrie.findPrefix("user-agentFoo", 13) == (void *)1) {
-        std::cerr << "found user prefix" << std::endl;
-        return 1;
-    }
-
-    return 0;
-}
-
-static bool
-CaseInsensitiveCheck()
-{
-    Trie aTrie(new TrieCaseless);
-
-    if (!aTrie.add ("User-Agent", 10, (void *)1)) {
-        std::cerr << "Could not add User-Agent" << std::endl;
-        return 1;
-    }
-
-    if (aTrie.add ("user-agent", 10, (void *)2)) {
-        std::cerr << "Could add duplicate User-Agent" << std::endl;
-        return 1;
-    }
-
-    if (!aTrie.add ("Alphabet", 8, (void *)3)) {
-        std::cerr << "Could not add Alphabet" << std::endl;
-        return 1;
-    }
-
-    if (!aTrie.add ("uprefix", 8, (void *)3)) {
-        std::cerr << "Could not add uprefix" << std::endl;
-        return 1;
-    }
-
-    if (aTrie.find ("User-Agent", 10) != (void *)1) {
-        std::cerr << "Could not find User-Agent" << std::endl;
-        return 1;
-    }
-
-    if (aTrie.find ("user-agent", 10) != (void *)1) {
-        std::cerr << "Could not find user-agent" << std::endl;
-        return 1;
-    }
-
-    if (aTrie.findPrefix("User-AgentFoo", 13) != (void *)1) {
-        std::cerr << "Could not find User prefix" << std::endl;
-        return 1;
-    }
-
-    if (aTrie.findPrefix("user-agentFoo", 13) != (void *)1) {
-        std::cerr << "Could not find user prefix" << std::endl;
-        return 1;
-    }
-
-    return 0;
-}
-
-int main (int, char **)
-{
-    if (CaseSensitiveCheck()) {
-        std::cerr << "Case sensitive check failure." << std::endl;
-        return 1;
-    }
-
-    if (CaseInsensitiveCheck()) {
-        std::cerr << "Case in-sensitive check failure." << std::endl;
-        return 1;
-    }
-
-    return 0;
-}
-
index add40573edabf08389d57ea6813b36983e882964..2b7f0a96c2cb6d39adca3315b9a8b8cf44602735 100644 (file)
--- a/squid.dox
+++ b/squid.dox
@@ -849,7 +849,6 @@ EXCLUDE_SYMLINKS       = NO
 
 EXCLUDE_PATTERNS       = */CVS/* \
                          */.git* \
-                         */lib/libTrie/* \
                          */libltdl/* \
                          */Programming-Guide/html/* \
                          */Programming-guide/dyn/* \
@@ -2096,7 +2095,6 @@ PREDEFINED             = __cplusplus \
                          USE_QOS_TOS \
                          USE_SELECT \
                          USE_SOLARIS_KRB5 \
-                         USE_SQUID_ESI \
                          USE_SQUID_EUI \
                          USE_SSL_CRTD \
                          USE_OPENSSL \
index a251328c3dfac126f66c20b082d6def4e7df25b6..0dffc9c858c9dd86396ade0b202bc4663d92f0d2 100644 (file)
@@ -945,7 +945,7 @@ void
 HttpHeader::addVia(const AnyP::ProtocolVersion &ver, const HttpHeader *from)
 {
     // TODO: do not add Via header for messages where Squid itself
-    // generated the message (i.e., Downloader or ESI) there should be no Via header added at all.
+    // generated the message (i.e., Downloader) there should be no Via header added at all.
 
     if (Config.onoff.via) {
         SBuf buf;
index 9ad4612190401240b6b480737afa99665b03f67a..cfd26b3186764baa23a1cdb06e27b97aea5b4188 100644 (file)
@@ -85,17 +85,6 @@ if ENABLE_ADAPTATION
 SUBDIRS += adaptation
 endif
 
-if ENABLE_ESI
-SUBDIRS += esi
-ESI_LIBS = \
-       esi/libesi.la \
-       $(top_builddir)/lib/libTrie/libTrie.a \
-       $(LIBEXPAT_LIBS) \
-       $(LIBXML2_LIBS)
-else
-ESI_LIBS =
-endif
-
 DELAY_POOL_ALL_SOURCE = \
        BandwidthBucket.cc \
        BandwidthBucket.h \
@@ -544,7 +533,6 @@ squid_LDADD = \
        $(CRYPTLIB) \
        $(REGEXLIB) \
        $(ADAPTATION_LIBS) \
-       $(ESI_LIBS) \
        html/libhtml.la \
        $(SNMP_LIBS) \
        mem/libmem.la \
@@ -1987,7 +1975,6 @@ tests_testHttpRange_LDADD = \
        format/libformat.la \
        $(REPL_OBJS) \
        $(ADAPTATION_LIBS) \
-       $(ESI_LIBS) \
        $(SSL_LIBS) \
        ipc/libipc.la \
        dns/libdns.la \
@@ -2385,7 +2372,6 @@ tests_testHttpRequest_LDADD = \
        debug/libdebug.la \
        $(REPL_OBJS) \
        $(ADAPTATION_LIBS) \
-       $(ESI_LIBS) \
        $(top_builddir)/lib/libmisccontainers.la \
        $(top_builddir)/lib/libmiscencoding.la \
        $(top_builddir)/lib/libmiscutil.la \
@@ -2672,7 +2658,6 @@ tests_testCacheManager_LDADD = \
        format/libformat.la \
        $(REPL_OBJS) \
        $(ADAPTATION_LIBS) \
-       $(ESI_LIBS) \
        $(SSL_LIBS) \
        anyp/libanyp.la \
        ipc/libipc.la \
index f00028a17622b2430beae0c2eb4cb159efa5ca6b..1e603073f178e0d1867d5e4387bbcfc3b3cc7663 100644 (file)
 #include "StoreIOBuffer.h"
 #include "StoreStats.h"
 
-#if USE_SQUID_ESI
-#include "esi/Element.h"
-#endif
-
 #include <ostream>
 
 class AsyncCall;
@@ -253,10 +249,7 @@ public:
 
     void *operator new(size_t byteCount);
     void operator delete(void *address);
-#if USE_SQUID_ESI
 
-    ESIElement::Pointer cachedESITree;
-#endif
     int64_t objectLen() const { return mem().object_sz; }
     int64_t contentLen() const { return objectLen() - mem().baseReply().hdr_sz; }
 
index 73a257d0da39c164452ee48495c41afde381b2d1..6f7cd6acb27a29640af81ec1942ced086717b2b7 100644 (file)
@@ -22,7 +22,6 @@ XactionInitiator::ParseInitiators(const char *name)
         {"client", initClient},
         {"peer-pool", initPeerPool},
         {"certificate-fetching", initCertFetcher},
-        {"esi", initEsi},
         {"cache-digest", initCacheDigest},
         {"server", initServer},
         {"htcp", initHtcp},
index a2dd22994ad3af105d7c9e5a8b3604119cc1f0ed..371f4476e80948b697c0289f573f29775e5ec6f4 100644 (file)
@@ -18,7 +18,6 @@ public:
         initClient = 1 << 0, ///< HTTP or FTP client
         initPeerPool = 1 << 1, ///< PeerPool manager
         initCertFetcher = 1 << 2, ///< Missing intermediate certificates fetching code
-        initEsi = 1 << 3, ///< ESI processing code
         initCacheDigest = 1 << 4, ///< Cache Digest fetching code
         initHtcp = 1<< 5, ///< HTCP client
         initIcp = 1 << 6, ///< the ICP/neighbors subsystem
@@ -48,7 +47,7 @@ public:
 
     /// internally generated requests
     static Initiators InternalInitiators() {
-        return initPeerPool | initCertFetcher | initEsi | initCacheDigest | initIcp | initIcmp | initIpc | initAdaptation | initIcon | initPeerMcast;
+        return initPeerPool | initCertFetcher | initCacheDigest | initIcp | initIcmp | initIpc | initAdaptation | initIcon | initPeerMcast;
     }
 
     /// all initiators
index 90875f9bdde386c639ab13508c8bab0b01c5f90c..34bf9c43bbfc79b52888474b4ddbf48e233ffb3f 100644 (file)
@@ -87,9 +87,6 @@
 #include "ssl/Config.h"
 #include "ssl/support.h"
 #endif
-#if USE_SQUID_ESI
-#include "esi/Parser.h"
-#endif
 #if SQUID_SNMP
 #include "snmp.h"
 #endif
index b90076188ae9bf83a0a7e19fe217826868e84f5d..1c0d2583738fef5a8a9d8a505c9f1cec057518cf 100644 (file)
@@ -181,6 +181,14 @@ DOC_START
        This option is not yet supported by Squid-3.
 DOC_END
 
+# Options removed in 7.x
+NAME: esi_parser
+TYPE: obsolete
+DOC_START
+       Remove this line. Squid no longer supports this feature.
+DOC_END
+
+
 # Options removed in 6.x
 NAME: announce_file
 TYPE: obsolete
@@ -1491,7 +1499,6 @@ ENDIF
          # Matches transaction's initiator [fast]
          #
          # Supported initiators are:
-         #  esi: matches transactions fetching ESI resources
          #  certificate-fetching: matches transactions fetching
          #     a missing intermediate TLS certificate
          #  cache-digest: matches transactions fetching Cache Digests
@@ -4994,7 +5001,7 @@ DOC_START
                        as a forwarding attempt. Pure cache hits log zero, but cache hits
                        that triggered HTTP cache revalidation log the number of attempts
                        made when sending an internal revalidation request. DNS, ICMP,
-                       ICP, HTCP, ESI, ICAP, eCAP, helper, and other secondary requests
+                       ICP, HTCP, ICAP, eCAP, helper, and other secondary requests
                        sent by Squid as a part of a master transaction do not increment
                        the counter logged for the received request.
 
@@ -6755,9 +6762,6 @@ DOC_START
        In reverse proxy environments it might be desirable to honor
        shorter object lifetimes. It is most likely better to make
        your server return a meaningful Last-Modified header however.
-
-       In ESI environments where page fragments often have short
-       lifetimes, this will often be best set to 0.
 DOC_END
 
 NAME: store_avg_object_size
@@ -7639,20 +7643,6 @@ DOC_START
        Set this to on to have squid behave as a remote surrogate.
 DOC_END
 
-NAME: esi_parser
-IFDEF: USE_SQUID_ESI
-COMMENT: libxml2|expat
-TYPE: string
-LOC: ESIParser::Type
-DEFAULT: auto
-DEFAULT_DOC: Selects libxml2 if available at ./configure time or libexpat otherwise.
-DOC_START
-       Selects the XML parsing library to use when interpreting responses with
-       Edge Side Includes.
-
-       To disable ESI handling completely, ./configure Squid with --disable-esi.
-DOC_END
-
 COMMENT_START
  DELAY POOL PARAMETERS
  -----------------------------------------------------------------------------
index 406159f59c0e8d1519ebafc6de6b52ba55251b96..1cb8b71f9cc6fdea767e0dac35b994cb8f3813c1 100644 (file)
@@ -43,7 +43,6 @@ BEGIN {
        define["USE_LOADABLE_MODULES"]="--enable-shared"
        define["USE_OPENSSL"]="--with-openssl"
        define["USE_QOS_TOS"]="--enable-zph-qos"
-       define["USE_SQUID_ESI"]="--enable-esi"
        define["USE_SQUID_EUI"]="--enable-eui"
        define["USE_SSL_CRTD"]="--enable-ssl-crtd"
        define["USE_UNLINKD"]="--enable-unlinkd"
index db7d80d78c546821744fada7a487c445c00d3624..620c83d8f2b7de565e820f72777753a456bdc396 100644 (file)
@@ -43,9 +43,6 @@
 #if USE_DELAY_POOLS
 #include "DelayPools.h"
 #endif
-#if USE_SQUID_ESI
-#include "esi/Esi.h"
-#endif
 
 #include <memory>
 
@@ -1899,18 +1896,6 @@ clientReplyContext::processReplyAccessResult(const Acl::Answer &accessAllowed)
            (int) body_size << " bytes after " << reply->hdr_sz <<
            " bytes of headers");
 
-#if USE_SQUID_ESI
-
-    if (http->flags.accel && reply->sline.status() != Http::scForbidden &&
-            !alwaysAllowResponse(reply->sline.status()) &&
-            esiEnableProcessing(reply)) {
-        debugs(88, 2, "Enabling ESI processing for " << http->uri);
-        clientStreamInsertHead(&http->client_stream, esiStreamRead,
-                               esiProcessStream, esiStreamDetach, esiStreamStatus, nullptr);
-    }
-
-#endif
-
     if (http->request->method == Http::METHOD_HEAD) {
         /* do not forward body for HEAD replies */
         body_size = 0;
index 64084fc452922718e5f939431a9ba28b6f6f5fd1..c7778253e911d0ae33c4932f71aa59d0b580d3cf 100644 (file)
@@ -924,9 +924,7 @@ clientCheckPinning(ClientHttpRequest * http)
     HttpHeader *req_hdr = &request->header;
     ConnStateData *http_conn = http->getConn();
 
-    /* Internal requests such as those from ESI includes may be without
-     * a client connection
-     */
+    // Internal requests may be without a client connection
     if (!http_conn)
         return;
 
diff --git a/src/esi/Assign.cc b/src/esi/Assign.cc
deleted file mode 100644 (file)
index 35c09d7..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#include "squid.h"
-
-/* MS Visual Studio Projects are monolithic, so we need the following
- * #if to exclude the ESI code from compile process when not needed.
- */
-#if (USE_SQUID_ESI == 1)
-
-#include "esi/Assign.h"
-#include "esi/Context.h"
-#include "esi/Sequence.h"
-#include "HttpReply.h"
-
-ESIAssign::~ESIAssign()
-{
-    if (value)
-        delete value;
-}
-
-ESIAssign::ESIAssign (ESIAssign const &old) : parent (nullptr), varState (nullptr), name (old.name), value (old.value ? new ESIVariableExpression (*old.value): nullptr), variable (nullptr), unevaluatedVariable(old.unevaluatedVariable)
-{}
-
-ESIAssign::ESIAssign (esiTreeParentPtr aParent, int attrcount, char const **attr, ESIContext *aContext) : parent (aParent), varState (nullptr), name(), value (nullptr), variable (nullptr), unevaluatedVariable()
-{
-    /* TODO: grab content IFF no value was specified */
-    assert (aContext);
-
-    for (int i = 0; i < attrcount && attr[i]; i += 2) {
-        if (!strcmp(attr[i],"name")) {
-            /* the variables name is ...  */
-            debugs(86, 5, "ESIAssign::ESIAssign: Variable name '" << attr[i+1] << "'");
-            /* If there are duplicate name attributes, we simply use the
-             * last one
-             */
-            name = attr[i+1];
-        } else if (!strcmp(attr[i],"value")) {
-            /* short form assignment:  */
-            debugs(86, 5, "ESIAssign::ESIAssign: Unevaluated variable '" << attr[i+1] << "'");
-            /* Again, if there are duplicate attributes, we use the last */
-            unevaluatedVariable = attr[i+1];
-        } else {
-            /* ignore mistyped attributes. TODO:? error on these for user feedback - config parameter needed
-             */
-        }
-    }
-
-    varState = cbdataReference(aContext->varState);
-}
-
-void
-ESIAssign::evaluateVariable()
-{
-    if (variable.getRaw())
-        variable->process (false);
-
-    variable = nullptr;
-
-    if (unevaluatedVariable.size()) {
-        varState->feedData(unevaluatedVariable.rawBuf(), unevaluatedVariable.size());
-        char const *result = varState->extractChar ();
-
-        /* Consider activating this, when we want to evaluate variables to a
-         * value
-         */
-        // setTestResult(ESIExpression::Evaluate (expression));
-
-        value = new ESIVariableExpression (result);
-
-        safe_free (result);
-    }
-}
-
-void
-ESIAssign::provideData (ESISegment::Pointer data, ESIElement * source)
-{
-    assert (source == variable.getRaw());
-    char *result = data->listToChar();
-    unevaluatedVariable = result;
-    safe_free (result);
-}
-
-esiProcessResult_t
-ESIAssign::process (int)
-{
-    assert (varState);
-
-    if (!value)
-        evaluateVariable();
-
-    if (!value)
-        return ESI_PROCESS_COMPLETE;
-
-    varState->addVariable (name.rawBuf(), name.size(), value);
-
-    value = nullptr;
-
-    debugs(86, 5, "ESIAssign: Processed " << this);
-
-    return ESI_PROCESS_COMPLETE;
-}
-
-void
-ESIAssign::render(ESISegment::Pointer)
-{}
-
-ESIAssign::Pointer
-ESIAssign::makeCacheable() const
-{
-    ESIAssign *result = new ESIAssign (*this);
-
-    if (variable.getRaw())
-        result->variable = variable->makeCacheable();
-
-    return result;
-}
-
-ESIAssign::Pointer
-ESIAssign::makeUsable(esiTreeParentPtr aParent, ESIVarState &aVarState) const
-{
-    ESIAssign *result = new ESIAssign (*this);
-    result->parent = aParent;
-    result->varState = cbdataReference(&aVarState);
-
-    if (variable.getRaw())
-        result->variable = variable->makeUsable(result, aVarState);
-
-    return result;
-}
-
-void
-ESIAssign::finish()
-{
-    cbdataReferenceDone(varState);
-
-    if (parent.getRaw())
-        parent = nullptr;
-}
-
-bool
-ESIAssign::addElement(ESIElement::Pointer anElement)
-{
-    /* we have a value, drop the element on the floor */
-
-    if (unevaluatedVariable.size())
-        return true;
-
-    if (!variable.getRaw())
-        variable = new esiSequence (this, false);
-
-    return variable->addElement (anElement);
-}
-
-ESIVariableExpression::~ESIVariableExpression()
-{}
-
-ESIVariableExpression::ESIVariableExpression (String const &aString) : expression (aString)
-{}
-
-void
-ESIVariableExpression::eval (ESIVarState &state, char const *, char const *) const
-{
-    /* XXX: Implement evaluation of the expression */
-    ESISegment::ListAppend (state.getOutput(), expression.rawBuf(), expression.size());
-}
-
-#endif /* USE_SQUID_ESI == 1 */
-
diff --git a/src/esi/Assign.h b/src/esi/Assign.h
deleted file mode 100644 (file)
index 1665622..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#ifndef SQUID_SRC_ESI_ASSIGN_H
-#define SQUID_SRC_ESI_ASSIGN_H
-
-#include "esi/Element.h"
-#include "esi/VarState.h"
-#include "SquidString.h"
-
-/** This is a variable that is itself an expression */
-class ESIVariableExpression : public ESIVarState::Variable
-{
-public:
-    ~ESIVariableExpression() override;
-    ESIVariableExpression (String const &value);
-    void eval (ESIVarState &state, char const *, char const *) const override;
-
-private:
-    String expression;
-};
-
-class ESIContext;
-
-class ESIAssign : public ESIElement
-{
-    MEMPROXY_CLASS(ESIAssign);
-
-public:
-    ESIAssign (esiTreeParentPtr, int, const char **, ESIContext *);
-    ESIAssign (ESIAssign const &);
-    ESIAssign &operator=(ESIAssign const &);
-    ~ESIAssign() override;
-    esiProcessResult_t process (int dovars) override;
-    void render(ESISegment::Pointer) override;
-    bool addElement(ESIElement::Pointer) override;
-    void provideData (ESISegment::Pointer data, ESIElement * source) override;
-    Pointer makeCacheable() const override;
-    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const override;
-    void finish() override;
-
-private:
-    void evaluateVariable();
-    esiTreeParentPtr parent;
-    ESIVarState *varState;
-    String name;
-    ESIVariableExpression * value;
-    ESIElement::Pointer variable;
-    String unevaluatedVariable;
-};
-
-#endif /* SQUID_SRC_ESI_ASSIGN_H */
-
diff --git a/src/esi/Attempt.h b/src/esi/Attempt.h
deleted file mode 100644 (file)
index 1865210..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#ifndef SQUID_SRC_ESI_ATTEMPT_H
-#define SQUID_SRC_ESI_ATTEMPT_H
-
-#include "esi/Element.h"
-#include "esi/Sequence.h"
-
-struct esiAttempt : public esiSequence {
-    esiAttempt(esiTreeParentPtr aParent) : esiSequence (aParent) {}
-};
-
-#endif /* SQUID_SRC_ESI_ATTEMPT_H */
-
diff --git a/src/esi/Context.cc b/src/esi/Context.cc
deleted file mode 100644 (file)
index a85d1f1..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#include "squid.h"
-
-/* MS Visual Studio Projects are monolithic, so we need the following
- * #if to exclude the ESI code from compile process when not needed.
- */
-#if (USE_SQUID_ESI == 1)
-
-#include "client_side_request.h"
-#include "esi/Context.h"
-#include "http/Stream.h"
-#include "Store.h"
-
-void
-ESIContext::updateCachedAST()
-{
-    assert (http);
-    assert (http->storeEntry());
-
-    if (hasCachedAST()) {
-        debugs(86, 5, "ESIContext::updateCachedAST: not updating AST cache for entry " <<
-               http->storeEntry() << " from ESI Context " << this <<
-               " as there is already a cached AST.");
-
-        return;
-    }
-
-    ESIElement::Pointer treeToCache = tree->makeCacheable();
-    debugs(86, 5, "ESIContext::updateCachedAST: Updating AST cache for entry " <<
-           http->storeEntry() << " with current value " <<
-           http->storeEntry()->cachedESITree.getRaw() << " to new value " <<
-           treeToCache.getRaw());
-
-    if (http->storeEntry()->cachedESITree.getRaw())
-        http->storeEntry()->cachedESITree->finish();
-
-    http->storeEntry()->cachedESITree = treeToCache;
-
-    treeToCache = nullptr;
-}
-
-bool
-ESIContext::hasCachedAST() const
-{
-    assert (http);
-    assert (http->storeEntry());
-
-    if (http->storeEntry()->cachedESITree.getRaw()) {
-        debugs(86, 5, "ESIContext::hasCachedAST: " << this <<
-               " - Cached AST present in store entry " << http->storeEntry() << ".");
-        return true;
-    } else {
-        debugs(86, 5, "ESIContext::hasCachedAST: " << this <<
-               " - Cached AST not present in store entry " << http->storeEntry() << ".");
-        return false;
-    }
-}
-
-void
-ESIContext::getCachedAST()
-{
-    if (cachedASTInUse)
-        return;
-
-    assert (hasCachedAST());
-
-    assert (varState);
-
-    parserState.popAll();
-
-    tree = http->storeEntry()->cachedESITree->makeUsable (this, *varState);
-
-    cachedASTInUse = true;
-}
-
-void
-ESIContext::setErrorMessage(char const *anError)
-{
-    if (!errormessage)
-        errormessage = xstrdup(anError);
-}
-
-#endif /* USE_SQUID_ESI == 1 */
-
diff --git a/src/esi/Context.h b/src/esi/Context.h
deleted file mode 100644 (file)
index 73d1e86..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#ifndef SQUID_SRC_ESI_CONTEXT_H
-#define SQUID_SRC_ESI_CONTEXT_H
-
-#include "clientStream.h"
-#include "error/forward.h"
-#include "esi/Element.h"
-#include "esi/Esi.h"
-#include "esi/Parser.h"
-#include "http/forward.h"
-#include "http/StatusCode.h"
-#include "HttpReply.h"
-
-class ESIVarState;
-class ClientHttpRequest;
-
-/* ESIContext */
-
-class ESIContext : public esiTreeParent, public ESIParserClient
-{
-    CBDATA_CLASS(ESIContext);
-
-public:
-    typedef RefCount<ESIContext> Pointer;
-    ESIContext() :
-        thisNode(nullptr),
-        http(nullptr),
-        errorpage(ERR_NONE),
-        errorstatus(Http::scNone),
-        errormessage(nullptr),
-        rep(nullptr),
-        outbound_offset(0),
-        readpos(0),
-        pos(0),
-        varState(nullptr),
-        cachedASTInUse(false),
-        reading_(true),
-        processing(false) {
-        memset(&flags, 0, sizeof(flags));
-    }
-
-    ~ESIContext() override;
-
-    enum esiKick_t {
-        ESI_KICK_FAILED,
-        ESI_KICK_PENDING,
-        ESI_KICK_SENT,
-        ESI_KICK_INPROGRESS
-    };
-
-    /* when esi processing completes */
-    void provideData(ESISegment::Pointer, ESIElement *source) override;
-    void fail (ESIElement *source, char const*anError = nullptr) override;
-    void startRead();
-    void finishRead();
-    bool reading() const;
-    void setError();
-    void setErrorMessage(char const *);
-
-    void addStackElement (ESIElement::Pointer element);
-    void addLiteral (const char *s, int len);
-
-    void finishChildren ();
-
-    clientStreamNode *thisNode; /* our stream node */
-    /* the request we are processing. HMM: cbdataReferencing this will result
-     * in a circular reference, so we don't. Note: we are automatically freed
-     * when it is, so that's ok. */
-    ClientHttpRequest *http;
-
-    struct {
-        unsigned int passthrough:1;
-        unsigned int oktosend:1;
-        unsigned int finished:1;
-
-        /* an error has occurred, send full body replies
-         * regardless. Note that we don't fail midstream
-         * because we buffer until we can not fail
-         */
-        unsigned int error:1;
-
-        unsigned int finishedtemplate:1; /* we've read the entire template */
-        unsigned int clientwantsdata:1; /* we need to satisfy a read request */
-        unsigned int kicked:1; /* note on reentering the kick routine */
-        unsigned int detached:1; /* our downstream has detached */
-    } flags;
-
-    err_type errorpage; /* if we error what page to use */
-    Http::StatusCode errorstatus; /* if we error, what code to return */
-    char *errormessage; /* error to pass to error page */
-    HttpReplyPointer rep; /* buffered until we pass data downstream */
-    ESISegment::Pointer buffered; /* unprocessed data - for whatever reason */
-    ESISegment::Pointer incoming;
-    /* processed data we are waiting to send, or for
-     * potential errors to be resolved
-     */
-    ESISegment::Pointer outbound;
-    ESISegment::Pointer outboundtail; /* our write segment */
-    /* the offset to the next character to send -
-     * non zero if we haven't sent the entire segment
-     * for some reason
-     */
-    size_t outbound_offset;
-    int64_t readpos; /* the logical position we are reading from */
-    int64_t pos; /* the logical position of outbound_offset in the data stream */
-
-    class ParserState
-    {
-
-    public:
-        ESIElement::Pointer stack[ESI_STACK_DEPTH_LIMIT]; /* a stack of esi elements that are open */
-        int stackdepth; /* self explanatory */
-        ESIParser::Pointer theParser;
-        ESIElement::Pointer top();
-        void init (ESIParserClient *);
-        bool inited() const;
-        ParserState();
-        void freeResources();
-        void popAll();
-        unsigned int parsing:1; /* libexpat is not reentrant on the same context */
-
-    private:
-        bool inited_;
-    }
-    parserState; // TODO: refactor this to somewhere else
-
-    ESIVarState *varState;
-    ESIElement::Pointer tree;
-
-    esiKick_t kick ();
-    RefCount<ESIContext> cbdataLocker;
-    bool failed() const {return flags.error != 0;}
-
-    bool cachedASTInUse;
-
-private:
-    void fail ();
-    void freeResources();
-    void fixupOutboundTail();
-    void trimBlanks();
-    size_t send ();
-    bool reading_;
-    void appendOutboundData(ESISegment::Pointer theData);
-    esiProcessResult_t process ();
-    void parse();
-    void parseOneBuffer();
-    void updateCachedAST();
-    bool hasCachedAST() const;
-    void getCachedAST();
-    void start(const char *el, const char **attr, size_t attrCount) override;
-    void end(const char *el) override;
-    void parserDefault (const char *s, int len) override;
-    void parserComment (const char *s) override;
-    bool processing;
-};
-
-#endif /* SQUID_SRC_ESI_CONTEXT_H */
-
diff --git a/src/esi/Element.h b/src/esi/Element.h
deleted file mode 100644 (file)
index 65dc8ff..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#ifndef SQUID_SRC_ESI_ELEMENT_H
-#define SQUID_SRC_ESI_ELEMENT_H
-
-#include "base/RefCount.h"
-#include "debug/Stream.h"
-#include "esi/Segment.h"
-
-#include <vector>
-
-typedef enum {
-    ESI_PROCESS_COMPLETE = 0,
-    ESI_PROCESS_PENDING_WONTFAIL = 1,
-    ESI_PROCESS_PENDING_MAYFAIL = 2,
-    ESI_PROCESS_FAILED = 3
-} esiProcessResult_t;
-
-class ESIElement;
-
-struct esiTreeParent : public RefCountable {
-    virtual void provideData (ESISegment::Pointer /* data  */, ESIElement * /* source */ ) {
-        /* make abstract when all functionality complete */
-        assert (0);
-    }
-
-    virtual void fail(ESIElement * /* source */, char const * /* reason */ = nullptr) {}
-
-    ~esiTreeParent() override {}
-};
-
-typedef RefCount<esiTreeParent> esiTreeParentPtr;
-
-class ESIVarState;
-
-class ESIElement : public esiTreeParent
-{
-
-public:
-    typedef RefCount<ESIElement> Pointer;
-
-    /* the types we have */
-    enum ESIElementType_t {
-        ESI_ELEMENT_NONE,
-        ESI_ELEMENT_INCLUDE,
-        ESI_ELEMENT_COMMENT,
-        ESI_ELEMENT_REMOVE,
-        ESI_ELEMENT_TRY,
-        ESI_ELEMENT_ATTEMPT,
-        ESI_ELEMENT_EXCEPT,
-        ESI_ELEMENT_VARS,
-        ESI_ELEMENT_CHOOSE,
-        ESI_ELEMENT_WHEN,
-        ESI_ELEMENT_OTHERWISE,
-        ESI_ELEMENT_ASSIGN
-    };
-    static ESIElementType_t IdentifyElement (const char *);
-    virtual bool addElement(ESIElement::Pointer) {
-        /* Don't accept children */
-        debugs(86,5, "ESIElement::addElement: Failed for " << this);
-        return false;
-    }
-
-    virtual void render (ESISegment::Pointer) = 0;
-    /* process this element */
-    virtual esiProcessResult_t process(int) {
-        debugs(86,5, "esiProcessComplete: Processed " << this);
-        return ESI_PROCESS_COMPLETE;
-    }
-
-    virtual bool mayFail() const {
-        return true;
-    }
-
-    virtual Pointer makeCacheable() const = 0;
-    virtual Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const = 0;
-
-    /* The top level no longer needs this element */
-    virtual void finish() = 0;
-};
-
-/// ESI protocol types and operators
-namespace Esi {
-
-/// an ordered set of ESI elements
-typedef std::vector<ESIElement::Pointer> Elements;
-
-} // namespace Esi
-
-/// Call finish() and set to nil the given element. Element may already be nil.
-/// When element is part of a set, use pos to indicate position/ID
-/// for debugging.
-extern void FinishAnElement(ESIElement::Pointer &, int pos = -1);
-
-// for all elements call finish() and set Pointer to nil
-extern void FinishAllElements(Esi::Elements &);
-
-#endif /* SQUID_SRC_ESI_ELEMENT_H */
-
diff --git a/src/esi/Esi.cc b/src/esi/Esi.cc
deleted file mode 100644 (file)
index 5933922..0000000
+++ /dev/null
@@ -1,2260 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#include "squid.h"
-
-/* MS Visual Studio Projects are monolithic, so we need the following
- * #if to exclude the ESI code from compile process when not needed.
- */
-#if (USE_SQUID_ESI == 1)
-
-#include "client_side.h"
-#include "client_side_request.h"
-#include "clientStream.h"
-#include "comm/Connection.h"
-#include "errorpage.h"
-#include "esi/Assign.h"
-#include "esi/Attempt.h"
-#include "esi/Context.h"
-#include "esi/Element.h"
-#include "esi/Esi.h"
-#include "esi/Except.h"
-#include "esi/Expression.h"
-#include "esi/Segment.h"
-#include "esi/VarState.h"
-#include "FadingCounter.h"
-#include "fatal.h"
-#include "http/Stream.h"
-#include "HttpHdrSc.h"
-#include "HttpHdrScTarget.h"
-#include "HttpReply.h"
-#include "HttpRequest.h"
-#include "ip/Address.h"
-#include "log/forward.h"
-#include "MemBuf.h"
-#include "SquidConfig.h"
-
-/* quick reference on behaviour here.
- * The ESI specification 1.0 requires the ESI processor to be able to
- * return an error code at any point in the processing. To that end
- * we buffer the incoming esi body until we know we will be able to
- * satisfy the request. At that point we start streaming the queued
- * data downstream.
- *
- */
-
-class ESIStreamContext;
-
-/* TODO: split this out into separate files ? */
-/* Parsing: quick and dirty. ESI files are not valid XML, so a generic
- * XML parser is not much use. Also we need a push parser not a pull
- * parser, so LibXML is out.
- *
- * Interpreter methods:
- * Render: May only ever be called after Process returns PROCESS_COMPLETE.
- * Renders the resulting content into a ESISegment chain.
- * Process: returns the status of the node.
- * COMPLETE - processing is complete, rendering may staret
- * PENDING_WONTFAIL - process is incomplete, but the element *will*
- *   be able to be rendered given time.
- * PENDING_MAYFAIL - processing is incomplete, and the element *may*
- *   fail to be able to rendered.
- * FAILED - processing failed, return an error to the client.
- */
-
-/*
- * NOT TODO: esi:inline - out of scope.
- */
-
-/* make comparisons with refcount pointers easy */
-static bool
-operator == (ESIElement const *lhs, ESIElement::Pointer const &rhs)
-{
-    return lhs == rhs.getRaw();
-}
-
-typedef ESIContext::esiKick_t esiKick_t;
-
-/* some core operators */
-
-class esiComment : public ESIElement
-{
-    MEMPROXY_CLASS(esiComment);
-
-public:
-    ~esiComment() override;
-    esiComment();
-    Pointer makeCacheable() const override;
-    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const override;
-
-    void render(ESISegment::Pointer) override;
-    void finish() override;
-};
-
-#include "esi/Literal.h"
-
-#include "esi/Sequence.h"
-
-#include "esi/Include.h"
-
-/* esiRemove */
-
-class esiRemove : public ESIElement
-{
-    MEMPROXY_CLASS(esiRemove);
-
-public:
-    esiRemove() : ESIElement() {}
-    ~esiRemove() override {}
-
-    void render(ESISegment::Pointer) override;
-    bool addElement (ESIElement::Pointer) override;
-    Pointer makeCacheable() const override;
-    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const override;
-    void finish() override {}
-};
-
-class esiTry : public ESIElement
-{
-    MEMPROXY_CLASS(esiTry);
-
-public:
-    esiTry(esiTreeParentPtr aParent);
-    ~esiTry() override;
-
-    void render(ESISegment::Pointer) override;
-    bool addElement (ESIElement::Pointer) override;
-    void fail(ESIElement *, char const * = nullptr) override;
-    esiProcessResult_t process (int dovars) override;
-    void provideData (ESISegment::Pointer data, ESIElement * source) override;
-    Pointer makeCacheable() const override;
-    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const override;
-
-    ESIElement::Pointer attempt;
-    ESIElement::Pointer except;
-
-    struct {
-        unsigned int attemptok:1; /* the attempt branch process correctly */
-        unsigned int exceptok:1; /* likewise */
-        unsigned int attemptfailed:1; /* The attempt branch failed */
-        unsigned int exceptfailed:1; /* the except branch failed */
-    } flags;
-    void finish() override;
-
-private:
-    void notifyParent();
-    esiTreeParentPtr parent;
-    ESISegment::Pointer exceptbuffer;
-    esiTry (esiTry const &);
-    esiProcessResult_t bestAttemptRV() const;
-};
-
-#include "esi/Var.h"
-
-class esiChoose : public ESIElement
-{
-    MEMPROXY_CLASS(esiChoose);
-
-public:
-    esiChoose(const esiTreeParentPtr &);
-    ~esiChoose() override;
-
-    void render(ESISegment::Pointer) override;
-    bool addElement (ESIElement::Pointer) override;
-    void fail(ESIElement *, char const * = nullptr) override;
-    esiProcessResult_t process (int dovars) override;
-
-    void provideData (ESISegment::Pointer data, ESIElement *source) override;
-    void makeCachableElements(esiChoose const &old);
-    void makeUsableElements(esiChoose const &old, ESIVarState &);
-    Pointer makeCacheable() const override;
-    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const override;
-    void NULLUnChosen();
-
-    Esi::Elements elements;
-    int chosenelement;
-    ESIElement::Pointer otherwise;
-    void finish() override;
-
-private:
-    esiChoose(esiChoose const &);
-    esiTreeParentPtr parent;
-    void checkValidSource (ESIElement::Pointer source) const;
-    void selectElement();
-};
-
-class esiWhen : public esiSequence
-{
-    MEMPROXY_CLASS(esiWhen);
-
-public:
-    esiWhen(esiTreeParentPtr aParent, int attributes, const char **attr, ESIVarState *);
-    ~esiWhen() override;
-    Pointer makeCacheable() const override;
-    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const override;
-
-    bool testsTrue() const { return testValue;}
-
-    void setTestResult(bool aBool) {testValue = aBool;}
-
-private:
-    esiWhen (esiWhen const &);
-    bool testValue;
-    char const *unevaluatedExpression;
-    ESIVarState *varState;
-    void evaluate();
-};
-
-struct esiOtherwise : public esiSequence {
-    esiOtherwise(esiTreeParentPtr aParent) : esiSequence (aParent) {}
-};
-
-CBDATA_CLASS_INIT(ESIContext);
-
-void ESIContext::startRead()
-{
-    assert (!reading_);
-    reading_ = true;
-}
-
-void ESIContext::finishRead()
-{
-    assert (reading_);
-    reading_ = false;
-}
-
-bool ESIContext::reading() const
-{
-    return reading_;
-}
-
-ESIStreamContext::ESIStreamContext() : finished(false), include (nullptr), localbuffer (new ESISegment), buffer (nullptr)
-{}
-
-/* Local functions */
-/* ESIContext */
-static ESIContext *ESIContextNew(HttpReply *, clientStreamNode *, ClientHttpRequest *);
-
-void
-ESIContext::setError()
-{
-    errorpage = ERR_ESI;
-    errorstatus = Http::scInternalServerError;
-    flags.error = 1;
-}
-
-void
-ESIContext::appendOutboundData(ESISegment::Pointer theData)
-{
-    if (!outbound.getRaw()) {
-        outbound = theData;
-        outboundtail = outbound;
-    } else {
-        assert (outboundtail->next.getRaw() == nullptr);
-        outboundtail->next = theData;
-    }
-
-    fixupOutboundTail();
-    debugs(86, 9, "ESIContext::appendOutboundData: outbound " << outbound.getRaw());
-}
-
-void
-ESIContext::provideData (ESISegment::Pointer theData, ESIElement * source)
-{
-    debugs(86, 5, "ESIContext::provideData: " << this << " " << theData.getRaw() << " " << source);
-    /* No callbacks permitted after finish() called on the tree */
-    assert (tree.getRaw());
-    assert (source == tree);
-    appendOutboundData(theData);
-    trimBlanks();
-
-    if (!processing)
-        send();
-}
-
-void
-ESIContext::fail(ESIElement *, char const *anError)
-{
-    setError();
-    setErrorMessage (anError);
-    fail ();
-    send ();
-}
-
-void
-ESIContext::fixupOutboundTail()
-{
-    /* TODO: fixup thisNode outboundtail dross a little */
-
-    if (outboundtail.getRaw())
-        outboundtail = outboundtail->tail();
-}
-
-esiKick_t
-ESIContext::kick ()
-{
-    if (flags.kicked) {
-        debugs(86, 5, "esiKick: Re-entered whilst in progress");
-        // return ESI_KICK_INPROGRESS;
-    } else
-        ++flags.kicked;
-
-    if (flags.detached)
-        /* we've been detached from - we can't do anything more */
-        return ESI_KICK_FAILED;
-
-    /* Something has occurred. Process any remaining nodes */
-    if (!flags.finished)
-        /* Process some of our data */
-        switch (process ()) {
-
-        case ESI_PROCESS_COMPLETE:
-            debugs(86, 5, "esiKick: esiProcess OK");
-            break;
-
-        case ESI_PROCESS_PENDING_WONTFAIL:
-            debugs(86, 5, "esiKick: esiProcess PENDING OK");
-            break;
-
-        case ESI_PROCESS_PENDING_MAYFAIL:
-            debugs(86, 5, "esiKick: esiProcess PENDING UNKNOWN");
-            break;
-
-        case ESI_PROCESS_FAILED:
-            debugs(86, 2, "esiKick: esiProcess " << this << " FAILED");
-            /* this can not happen - processing can't fail until we have data,
-             * and when we come here we have sent data to the client
-             */
-
-            if (pos == 0)
-                fail ();
-
-            --flags.kicked;
-
-            return ESI_KICK_FAILED;
-        }
-
-    /* Render if we can to get maximal sent data */
-    assert (tree.getRaw() || flags.error);
-
-    if (!flags.finished && !outbound.getRaw()) {
-        outboundtail = new ESISegment;
-        outbound = outboundtail;
-    }
-
-    if (!flags.error && !flags.finished)
-        tree->render(outboundtail);
-
-    if (!flags.finished)
-        fixupOutboundTail();
-
-    /* Is there data to send? */
-    if (send ()) {
-        /* some data was sent. we're finished until the next read */
-        --flags.kicked;
-        return ESI_KICK_SENT;
-    }
-
-    --flags.kicked;
-    /* nothing to send */
-    return flags.error ? ESI_KICK_FAILED : ESI_KICK_PENDING;
-}
-
-/* request from downstream for more data
- */
-void
-esiStreamRead (clientStreamNode *thisNode, ClientHttpRequest *http)
-{
-    clientStreamNode *next;
-    /* Test preconditions */
-    assert (thisNode != nullptr);
-    assert (cbdataReferenceValid (thisNode));
-    /* we are not in the chain until ESI is detected on a data callback */
-    assert (thisNode->node.prev != nullptr);
-    assert (thisNode->node.next != nullptr);
-
-    ESIContext::Pointer context = dynamic_cast<ESIContext *>(thisNode->data.getRaw());
-    assert (context.getRaw() != nullptr);
-
-    if (context->flags.passthrough) {
-        /* passthru mode - read into supplied buffers */
-        next = thisNode->next();
-        clientStreamRead (thisNode, http, next->readBuffer);
-        return;
-    }
-
-    context->flags.clientwantsdata = 1;
-    debugs(86, 5, "esiStreamRead: Client now wants data");
-
-    /* Ok, not passing through */
-
-    switch (context->kick ()) {
-
-    case ESIContext::ESI_KICK_FAILED:
-    /* this can not happen - processing can't fail until we have data,
-     * and when we come here we have sent data to the client
-     */
-
-    case ESIContext::ESI_KICK_SENT:
-
-    case ESIContext::ESI_KICK_INPROGRESS:
-        return;
-
-    case ESIContext::ESI_KICK_PENDING:
-        break;
-    }
-
-    /* Nothing to send */
-
-    if (context->flags.oktosend && (context->flags.finishedtemplate
-                                    || context->cachedASTInUse) &&
-            ! context->flags.finished) {
-        /* we've started sending, finished reading, but not finished
-         * processing. stop here, a callback will resume the stream
-         * flow
-         */
-        debugs(86, 5, "esiStreamRead: Waiting for async resume of esi processing");
-        return;
-    }
-
-    if (context->flags.oktosend && context->flags.finished && context->outbound.getRaw()) {
-        debugs(86, 5, "all processing complete, but outbound data still buffered");
-        assert (!context->flags.clientwantsdata);
-        /* client MUST be processing the last reply */
-        return;
-    }
-
-    if (context->flags.oktosend && context->flags.finished) {
-        StoreIOBuffer tempBuffer;
-        assert (!context->outbound.getRaw());
-        /* We've finished processing, and there is no more data buffered */
-        debugs(86, 5, "Telling recipient EOF on READ");
-        clientStreamCallback (thisNode, http, nullptr, tempBuffer);
-        return;
-    }
-
-    if (context->reading())
-        return;
-
-    /* no data that is ready to send, and still reading? well, lets get some */
-    /* secure a buffer */
-    if (!context->incoming.getRaw()) {
-        /* create a new buffer segment */
-        context->buffered = new ESISegment;
-        context->incoming = context->buffered;
-    }
-
-    assert (context->incoming.getRaw() && context->incoming->len != HTTP_REQBUF_SZ);
-    {
-        StoreIOBuffer tempBuffer;
-        tempBuffer.offset =  context->readpos;
-        tempBuffer.length = context->incoming->len - HTTP_REQBUF_SZ;
-        tempBuffer.data = &context->incoming->buf[context->incoming->len];
-        context->startRead();
-        clientStreamRead (thisNode, http, tempBuffer);
-    }
-}
-
-clientStream_status_t
-esiStreamStatus (clientStreamNode *thisNode, ClientHttpRequest *http)
-{
-    /* Test preconditions */
-    assert (thisNode != nullptr);
-    assert (cbdataReferenceValid (thisNode));
-    /* we are not in the chain until ESI is detected on a data callback */
-    assert (thisNode->node.prev != nullptr);
-    assert (thisNode->node.next != nullptr);
-
-    ESIContext::Pointer context = dynamic_cast<ESIContext *>(thisNode->data.getRaw());
-    assert (context.getRaw() != nullptr);
-
-    if (context->flags.passthrough)
-        return clientStreamStatus (thisNode, http);
-
-    if (context->flags.oktosend && context->flags.finished &&
-            !(context->outbound.getRaw() && context->outbound_offset < context->outbound->len)) {
-        debugs(86, 5, "Telling recipient EOF on STATUS");
-        return STREAM_UNPLANNED_COMPLETE; /* we don't know lengths in advance */
-    }
-
-    /* ?? RC: we can't be aborted / fail ? */
-    return STREAM_NONE;
-}
-
-static int
-esiAlwaysPassthrough(Http::StatusCode sline)
-{
-    int result;
-
-    switch (sline) {
-
-    case Http::scContinue: /* Should never reach us... but squid needs to alter to accommodate this */
-
-    case Http::scSwitchingProtocols: /* Ditto */
-
-    case Http::scProcessing: /* Unknown - some extension */
-
-    case Http::scNoContent: /* no body, no esi */
-
-    case Http::scNotModified: /* ESI does not affect assembled page headers, so 304s are valid */
-        result = 1;
-        /* unreached */
-        break;
-
-    default:
-        result = 0;
-    }
-
-    return result;
-}
-
-void
-ESIContext::trimBlanks()
-{
-    /* trim leading empty buffers ? */
-
-    while (outbound.getRaw() && outbound->next.getRaw() && !outbound->len) {
-        debugs(86, 5, "ESIContext::trimBlanks: " << this <<
-               " skipping segment " << outbound.getRaw());
-        outbound = outbound->next;
-    }
-
-    if (outboundtail.getRaw())
-        assert (outbound.getRaw());
-}
-
-/* Send data downstream
- * Returns 0 if nothing was sent. Non-zero if data was sent.
- */
-size_t
-ESIContext::send ()
-{
-    debugs(86, 5, "ESIContext::send: this=" << this);
-    /* send any processed data */
-
-    trimBlanks();
-
-    if (!flags.clientwantsdata) {
-        debugs(86, 5, "ESIContext::send: Client does not want data - not sending anything");
-        return 0;
-    }
-
-    if (tree.getRaw() && tree->mayFail()) {
-        debugs(86, 5, "ESIContext::send: Tree may fail. Not sending.");
-        return 0;
-    } else
-        flags.oktosend = 1;
-
-    if (!(rep || (outbound.getRaw() &&
-                  outbound->len && (outbound_offset <= outbound->len)))) {
-        debugs(86, 5, "ESIContext::send: Nothing to send.");
-        return 0;
-    }
-
-    debugs(86, 5, "ESIContext::send: Sending something...");
-    /* Yes! Send it without asking for more upstream */
-    /* memcopying because the client provided the buffer */
-    /* TODO: skip data until pos == next->readoff; */
-    assert (thisNode->data == this);
-    clientStreamNode *next = thisNode->next();
-    ESIContext *templock = cbdataReference (this);
-    size_t len = 0;
-
-    if (outbound.getRaw())
-        len = min (next->readBuffer.length, outbound->len - outbound_offset);
-
-    /* prevent corruption on range requests, even though we don't support them yet */
-    assert (pos == next->readBuffer.offset);
-
-    /* We must send data or a reply */
-    assert (len != 0 || rep != nullptr);
-
-    if (len) {
-        memcpy(next->readBuffer.data, &outbound->buf[outbound_offset], len);
-
-        if (len + outbound_offset == outbound->len) {
-            ESISegment::Pointer temp = outbound->next;
-            /* remove the used buffer */
-            outbound_offset = 0;
-            outbound = temp;
-        }
-
-        pos += len;
-
-        if (!outbound.getRaw())
-            outboundtail = nullptr;
-
-        trimBlanks();
-    }
-
-    flags.clientwantsdata = 0;
-    debugs(86, 5, "ESIContext::send: this=" << this << " Client no longer wants data ");
-    /* Deal with re-entrancy */
-    HttpReplyPointer temprep = rep;
-    rep = nullptr; /* freed downstream */
-
-    if (temprep && varState)
-        varState->buildVary(temprep.getRaw());
-
-    {
-        StoreIOBuffer tempBuffer;
-        tempBuffer.length = len;
-        tempBuffer.offset = pos - len;
-        tempBuffer.data = next->readBuffer.data;
-        clientStreamCallback (thisNode, http, temprep.getRaw(), tempBuffer);
-    }
-
-    if (len == 0)
-        len = 1; /* tell the caller we sent something (because we sent headers */
-
-    cbdataReferenceDone (templock);
-
-    debugs (86,5,"ESIContext::send: this=" << this << " sent " << len);
-
-    return len;
-}
-
-void
-ESIContext::finishChildren()
-{
-    if (tree.getRaw())
-        tree->finish();
-
-    tree = nullptr;
-}
-
-/* Detach event from a client Stream */
-void
-esiStreamDetach (clientStreamNode *thisNode, ClientHttpRequest *http)
-{
-    /* if we have pending callbacks, tell them we're done. */
-    /* test preconditions */
-    assert (thisNode != nullptr);
-    assert (cbdataReferenceValid (thisNode));
-    ESIContext::Pointer context = dynamic_cast<ESIContext *>(thisNode->data.getRaw());
-    assert (context.getRaw() != nullptr);
-    /* detach from the stream */
-    clientStreamDetach (thisNode,http);
-    /* if we have pending callbacks (from subincludes), tell them we're done. */
-    context->thisNode = nullptr;
-    context->flags.detached = 1;
-    context->finishChildren();
-    /* HACK for parser stack not being emptied */
-    context->parserState.stack[0] = nullptr;
-    /* allow refcount logic to trigger */
-    context->cbdataLocker = nullptr;
-}
-
-/* Process incoming data for ESI tags */
-/* ESI TODO: Long term: we should have a framework to parse html/xml and
- * callback to a set of processors like thisNode, to prevent multiple parsing
- * overhead. More thoughts on thisNode: We have to parse multiple times, because
- * the output of one processor may create a very different tree. What we could
- * do is something like DOM and pass that down to a final renderer. This is
- * getting into web server territory though...
- *
- * Preconditions:
- *   This is not the last node in the stream.
- *   ESI processing has been enabled.
- *   There is context data or a reply structure
- */
-void
-esiProcessStream (clientStreamNode *thisNode, ClientHttpRequest *http, HttpReply *rep, StoreIOBuffer receivedData)
-{
-    /* test preconditions */
-    assert (thisNode != nullptr);
-    /* ESI TODO: handle thisNode rather than asserting - it should only ever
-     * happen if we cause an abort and the callback chain
-     * loops back to here, so we can simply return. However, that itself
-     * shouldn't happen, so it stays as an assert for now. */
-    assert (cbdataReferenceValid (thisNode));
-    /*
-     * if data is NULL thisNode is the first entrance. If rep is also NULL,
-     * something is wrong.
-     * */
-    assert (thisNode->data.getRaw() != nullptr || rep);
-    assert (thisNode->node.next != nullptr);
-
-    if (!thisNode->data.getRaw())
-        /* setup ESI context from reply headers */
-        thisNode->data = ESIContextNew(rep, thisNode, http);
-
-    ESIContext::Pointer context = dynamic_cast<ESIContext *>(thisNode->data.getRaw());
-
-    assert (context.getRaw() != nullptr);
-
-    context->finishRead();
-
-    /* Skipping all ESI processing. All remaining data gets untouched.
-     * Mainly used when an error or other non-ESI processable entity
-     * has been detected to prevent ESI processing the error body
-     */
-    if (context->flags.passthrough) {
-        clientStreamCallback (thisNode, http, rep, receivedData);
-        return;
-    }
-
-    debugs(86, 3, "esiProcessStream: Processing thisNode " << thisNode <<
-           " context " << context.getRaw() << " offset " <<
-           (int) receivedData.offset << " length " <<
-           (unsigned int)receivedData.length);
-
-    /* once we finish the template, we *cannot* return here */
-    assert (!context->flags.finishedtemplate);
-    assert (!context->cachedASTInUse);
-
-    /* Can we generate any data ?*/
-
-    if (receivedData.data) {
-        /* Increase our buffer area with incoming data */
-        assert (receivedData.length <= HTTP_REQBUF_SZ);
-        assert (thisNode->readBuffer.offset == receivedData.offset);
-        debugs (86,5, "esiProcessStream found " << receivedData.length << " bytes of body data at offset " << receivedData.offset);
-        /* secure the data for later use */
-
-        if (!context->incoming.getRaw()) {
-            /* create a new buffer segment */
-            debugs(86, 5, "esiProcessStream: Setting up incoming buffer");
-            context->buffered = new ESISegment;
-            context->incoming = context->buffered;
-        }
-
-        if (receivedData.data != &context->incoming->buf[context->incoming->len]) {
-            /* We have to copy the data out because we didn't supply thisNode buffer */
-            size_t space = HTTP_REQBUF_SZ - context->incoming->len;
-            size_t len = min (space, receivedData.length);
-            debugs(86, 5, "Copying data from " << receivedData.data << " to " <<
-                   &context->incoming->buf[context->incoming->len] <<
-                   " because our buffer was not used");
-
-            memcpy(&context->incoming->buf[context->incoming->len], receivedData.data, len);
-            context->incoming->len += len;
-
-            if (context->incoming->len == HTTP_REQBUF_SZ) {
-                /* append another buffer */
-                context->incoming->next = new ESISegment;
-                context->incoming = context->incoming->next;
-            }
-
-            if (len != receivedData.length) {
-                /* capture the remnants */
-                memcpy(context->incoming->buf, &receivedData.data[len], receivedData.length - len);
-                context->incoming->len = receivedData.length - len;
-            }
-
-            /* and note where we are up to */
-            context->readpos += receivedData.length;
-        } else {
-            /* update our position counters, and if needed assign a new buffer */
-            context->incoming->len += receivedData.length;
-            assert (context->incoming->len <= HTTP_REQBUF_SZ);
-
-            if (context->incoming->len > HTTP_REQBUF_SZ * 3 / 4) {
-                /* allocate a new buffer - to stop us asking for ridiculously small amounts */
-                context->incoming->next = new ESISegment;
-                context->incoming = context->incoming->next;
-            }
-
-            context->readpos += receivedData.length;
-        }
-    }
-
-    /* EOF / Read error /  aborted entry */
-    if (rep == nullptr && receivedData.data == nullptr && receivedData.length == 0 && !context->flags.finishedtemplate) {
-        /* TODO: get stream status to test the entry for aborts */
-        /* else flush the esi processor */
-        debugs(86, 5, "esiProcess: " << context.getRaw() << " Finished reading upstream data");
-        /* This is correct */
-        context->flags.finishedtemplate = 1;
-    }
-
-    switch (context->kick()) {
-
-    case ESIContext::ESI_KICK_FAILED:
-        /* thisNode can not happen - processing can't fail until we have data,
-         * and when we come here we have sent data to the client
-         */
-        return;
-
-    case ESIContext::ESI_KICK_SENT:
-
-    case ESIContext::ESI_KICK_INPROGRESS:
-        return;
-
-    case ESIContext::ESI_KICK_PENDING:
-        break;
-    }
-
-    /* ok.. no data sent, try to pull more data in from upstream.
-     * TODO: Don't try thisNode if we have finished reading the template
-     */
-    if (!context->flags.finishedtemplate && !context->reading()
-            && !context->cachedASTInUse) {
-        StoreIOBuffer tempBuffer;
-        assert (context->incoming.getRaw() && context->incoming->len < HTTP_REQBUF_SZ);
-        tempBuffer.offset = context->readpos;
-        tempBuffer.length =  HTTP_REQBUF_SZ - context->incoming->len;
-        tempBuffer.data = &context->incoming->buf[context->incoming->len];
-        context->startRead();
-        clientStreamRead (thisNode, http, tempBuffer);
-        return;
-    }
-
-    debugs(86, 3, "esiProcessStream: no data to send, no data to read, awaiting a callback");
-}
-
-ESIContext::~ESIContext()
-{
-    freeResources ();
-    /* Not freed by freeresources because esi::fail needs it */
-    safe_free (errormessage);
-    debugs(86, 3, "ESIContext::~ESIContext: Freed " << this);
-}
-
-ESIContext *
-ESIContextNew (HttpReply *rep, clientStreamNode *thisNode, ClientHttpRequest *http)
-{
-    assert (rep);
-    ESIContext *rv = new ESIContext;
-    rv->rep = rep;
-    rv->cbdataLocker = rv;
-
-    if (esiAlwaysPassthrough(rep->sline.status())) {
-        rv->flags.passthrough = 1;
-    } else {
-        /* remove specific headers for ESI to prevent
-         * downstream cache confusion */
-        HttpHeader *hdr = &rep->header;
-        hdr->delById(Http::HdrType::ACCEPT_RANGES);
-        hdr->delById(Http::HdrType::ETAG);
-        hdr->delById(Http::HdrType::CONTENT_LENGTH);
-        hdr->delById(Http::HdrType::CONTENT_MD5);
-        rv->tree = new esiSequence (rv, true);
-        rv->thisNode = thisNode;
-        rv->http = http;
-        rv->flags.clientwantsdata = 1;
-        rv->varState = new ESIVarState (&http->request->header, http->uri);
-        debugs(86, 5, "ESIContextNew: Client wants data (always created during reply cycle");
-    }
-
-    debugs(86, 5, "ESIContextNew: Create context " << rv);
-    return rv;
-}
-
-ESIElement::ESIElementType_t
-ESIElement::IdentifyElement (const char *el)
-{
-    int offset = 0;
-    assert (el);
-
-    if (strlen (el) < 5)
-        return ESI_ELEMENT_NONE;
-
-    if (!strncmp (el, "esi:", 4))
-        offset = 4;
-    else if (!strncmp (el, "http://www.edge-delivery.org/esi/1.0|", 37))
-        offset = 37;
-    else
-        return ESI_ELEMENT_NONE;
-
-    if (!strncmp (el + offset, "otherwise", 9))
-        return ESI_ELEMENT_OTHERWISE;
-
-    if (!strncmp (el + offset, "comment", 7))
-        return ESI_ELEMENT_COMMENT;
-
-    if (!strncmp (el + offset, "include", 7))
-        return ESI_ELEMENT_INCLUDE;
-
-    if (!strncmp (el + offset, "attempt", 7))
-        return ESI_ELEMENT_ATTEMPT;
-
-    if (!strncmp (el + offset, "assign", 6))
-        return ESI_ELEMENT_ASSIGN;
-
-    if (!strncmp (el + offset, "remove", 6))
-        return ESI_ELEMENT_REMOVE;
-
-    if (!strncmp (el + offset, "except", 6))
-        return ESI_ELEMENT_EXCEPT;
-
-    if (!strncmp (el + offset, "choose", 6))
-        return ESI_ELEMENT_CHOOSE;
-
-    if (!strncmp (el + offset, "vars", 4))
-        return ESI_ELEMENT_VARS;
-
-    if (!strncmp (el + offset, "when", 4))
-        return ESI_ELEMENT_WHEN;
-
-    if (!strncmp (el + offset, "try", 3))
-        return ESI_ELEMENT_TRY;
-
-    return ESI_ELEMENT_NONE;
-}
-
-ESIElement::Pointer
-ESIContext::ParserState::top()
-{
-    return stack[stackdepth-1];
-}
-
-ESIContext::ParserState::ParserState() :
-    stackdepth(0),
-    parsing(0),
-    inited_(false)
-{}
-
-bool
-ESIContext::ParserState::inited() const
-{
-    return inited_;
-}
-
-void
-ESIContext::addStackElement (ESIElement::Pointer element)
-{
-    /* Put on the stack to allow skipping of 'invalid' markup */
-
-    // throw an error if the stack location would be invalid
-    if (parserState.stackdepth >= ESI_STACK_DEPTH_LIMIT)
-        throw Esi::Error("ESI Too many nested elements");
-    if (parserState.stackdepth < 0)
-        throw Esi::Error("ESI elements stack error, probable error in ESI template");
-
-    assert (!failed());
-    debugs(86, 5, "ESIContext::addStackElement: About to add ESI Node " << element.getRaw());
-
-    if (!parserState.top()->addElement(element)) {
-        throw Esi::Error("ESIContext::addStackElement failed, probable error in ESI template");
-    } else {
-        /* added ok, push onto the stack */
-        parserState.stack[parserState.stackdepth] = element;
-        ++parserState.stackdepth;
-    }
-}
-
-void
-ESIContext::start(const char *el, const char **attr, size_t attrCount)
-{
-    int i;
-    unsigned int ellen = strlen (el);
-    char localbuf [HTTP_REQBUF_SZ];
-    ESIElement::Pointer element;
-    int specifiedattcount = attrCount * 2;
-    char *position;
-    Must(ellen < sizeof(localbuf)); /* prevent unexpected overruns. */
-
-    debugs(86, 5, "ESIContext::Start: element '" << el << "' with " << specifiedattcount << " tags");
-
-    if (failed())
-        /* waiting for expat to finish the buffer we gave it */
-        return;
-
-    switch (ESIElement::IdentifyElement (el)) {
-
-    case ESIElement::ESI_ELEMENT_NONE:
-        /* Spit out elements we aren't interested in */
-        localbuf[0] = '<';
-        localbuf[1] = '\0';
-        xstrncpy(&localbuf[1], el, sizeof(localbuf) - 2);
-        position = localbuf + strlen (localbuf);
-
-        for (i = 0; i < specifiedattcount && attr[i]; i += 2) {
-            Must(static_cast<size_t>(position - localbuf) < sizeof(localbuf) - 1);
-            *position = ' ';
-            ++position;
-            /* TODO: handle thisNode gracefully */
-            xstrncpy(position, attr[i], sizeof(localbuf) - (position - localbuf));
-            position += strlen (position);
-            Must(static_cast<size_t>(position - localbuf) < sizeof(localbuf) - 2);
-            *position = '=';
-            ++position;
-            *position = '\"';
-            ++position;
-            const char *chPtr = attr[i + 1];
-            char ch;
-            while ((ch = *chPtr++) != '\0') {
-                if (ch == '\"') {
-                    Must(static_cast<size_t>(position - localbuf) < sizeof(localbuf) - 6);
-                    xstrncpy(position, "&quot;", sizeof(localbuf) - (position-localbuf));
-                    position += 6;
-                } else {
-                    Must(static_cast<size_t>(position - localbuf) < sizeof(localbuf) - 1);
-                    *position = ch;
-                    ++position;
-                }
-            }
-            Must(static_cast<size_t>(position - localbuf) < sizeof(localbuf) - 1);
-            *position = '\"';
-            ++position;
-        }
-
-        Must(static_cast<size_t>(position - localbuf) < sizeof(localbuf) - 2);
-        *position = '>';
-        ++position;
-        *position = '\0';
-
-        addLiteral (localbuf, position - localbuf);
-        debugs(86, 5, "esi stack depth " << parserState.stackdepth);
-        return;
-        break;
-
-    case ESIElement::ESI_ELEMENT_COMMENT:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new esiComment ();
-        break;
-
-    case ESIElement::ESI_ELEMENT_INCLUDE:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new ESIInclude (parserState.top().getRaw(), specifiedattcount, attr, this);
-        break;
-
-    case ESIElement::ESI_ELEMENT_REMOVE:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new esiRemove();
-        break;
-
-    case ESIElement::ESI_ELEMENT_TRY:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new esiTry (parserState.top().getRaw());
-        break;
-
-    case ESIElement::ESI_ELEMENT_ATTEMPT:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new esiAttempt (parserState.top().getRaw());
-        break;
-
-    case ESIElement::ESI_ELEMENT_EXCEPT:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new esiExcept (parserState.top().getRaw());
-        break;
-
-    case ESIElement::ESI_ELEMENT_VARS:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new ESIVar (parserState.top().getRaw());
-        break;
-
-    case ESIElement::ESI_ELEMENT_CHOOSE:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new esiChoose (parserState.top().getRaw());
-        break;
-
-    case ESIElement::ESI_ELEMENT_WHEN:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new esiWhen (parserState.top().getRaw(), specifiedattcount, attr, varState);
-        break;
-
-    case ESIElement::ESI_ELEMENT_OTHERWISE:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new esiOtherwise (parserState.top().getRaw());
-        break;
-
-    case ESIElement::ESI_ELEMENT_ASSIGN:
-        /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new ESIAssign (parserState.top().getRaw(), specifiedattcount, attr, this);
-        break;
-    }
-
-    addStackElement(element);
-
-    debugs(86, 5, "esi stack depth " << parserState.stackdepth);
-
-}  /* End of start handler */
-
-void
-ESIContext::end(const char *el)
-{
-    unsigned int ellen = strlen (el);
-    char localbuf [HTTP_REQBUF_SZ];
-    char *position;
-
-    if (flags.error)
-        /* waiting for expat to finish the buffer we gave it */
-        return;
-
-    switch (ESIElement::IdentifyElement (el)) {
-
-    case ESIElement::ESI_ELEMENT_NONE:
-        Must(ellen < sizeof(localbuf) - 3); /* prevent unexpected overruns. */
-        /* Add elements we aren't interested in */
-        localbuf[0] = '<';
-        localbuf[1] = '/';
-        xstrncpy(&localbuf[2], el, sizeof(localbuf) - 3);
-        position = localbuf + strlen (localbuf);
-        *position = '>';
-        ++position;
-        *position = '\0';
-        addLiteral (localbuf, position - localbuf);
-        break;
-
-    case ESIElement::ESI_ELEMENT_COMMENT:
-
-    case ESIElement::ESI_ELEMENT_INCLUDE:
-
-    case ESIElement::ESI_ELEMENT_REMOVE:
-
-    case ESIElement::ESI_ELEMENT_TRY:
-
-    case ESIElement::ESI_ELEMENT_ATTEMPT:
-
-    case ESIElement::ESI_ELEMENT_EXCEPT:
-
-    case ESIElement::ESI_ELEMENT_VARS:
-
-    case ESIElement::ESI_ELEMENT_CHOOSE:
-
-    case ESIElement::ESI_ELEMENT_WHEN:
-
-    case ESIElement::ESI_ELEMENT_OTHERWISE:
-
-    case ESIElement::ESI_ELEMENT_ASSIGN:
-        /* pop of the stack */
-        parserState.stack[--parserState.stackdepth] = nullptr;
-        break;
-    }
-}  /* End of end handler */
-
-void
-ESIContext::parserDefault (const char *s, int len)
-{
-    if (failed())
-        return;
-
-    /* handle any skipped data */
-    addLiteral (s, len);
-}
-
-void
-ESIContext::parserComment (const char *s)
-{
-    if (failed())
-        return;
-
-    if (!strncmp(s, "esi",3)) {
-        debugs(86, 5, "ESIContext::parserComment: ESI <!-- block encountered");
-        ESIParser::Pointer tempParser = ESIParser::NewParser (this);
-
-        /* wrap the comment in some tags */
-
-        if (!tempParser->parse("<div>", 5,0) ||
-                !tempParser->parse(s + 3, strlen(s) - 3, 0) ||
-                !tempParser->parse("</div>",6,1)) {
-            debugs(86, DBG_CRITICAL, "ERROR: ESIContext::parserComment: Parsing fragment '" << s + 3 << "' failed.");
-            setError();
-            char tempstr[1024];
-            snprintf(tempstr, 1023, "ESIContext::parserComment: Parse error at line %ld:\n%s\n",
-                     tempParser->lineNumber(),
-                     tempParser->errorString());
-            debugs(86, DBG_CRITICAL, "" << tempstr << "");
-
-            setErrorMessage(tempstr);
-        }
-
-        debugs(86, 5, "ESIContext::parserComment: ESI <!-- block parsed");
-        return;
-    } else {
-        char localbuf [HTTP_REQBUF_SZ];
-        unsigned int len;
-        debugs(86, 5, "ESIContext::parserComment: Regenerating comment block");
-        len = strlen (s);
-
-        if (len > sizeof (localbuf) - 9) {
-            debugs(86, DBG_CRITICAL, "ESIContext::parserComment: Truncating long comment");
-            len = sizeof (localbuf) - 9;
-        }
-
-        xstrncpy(localbuf, "<!--", 5);
-        xstrncpy(localbuf + 4, s, len + 1);
-        xstrncpy(localbuf + 4 + len, "-->", 4);
-        addLiteral (localbuf,len + 7);
-    }
-}
-
-void
-ESIContext::addLiteral (const char *s, int len)
-{
-    /* handle any skipped data */
-    assert (len);
-    debugs(86, 5, "literal length is " << len);
-    /* give a literal to the current element */
-    ESIElement::Pointer element (new esiLiteral (this, s, len));
-
-    if (!parserState.top()->addElement(element))
-        throw Esi::Error("ESIContext::addLiteral failed, probable error in ESI template");
-}
-
-void
-ESIContext::ParserState::init(ESIParserClient *userData)
-{
-    theParser = ESIParser::NewParser (userData);
-    inited_ = true;
-}
-
-void
-ESIContext::parseOneBuffer()
-{
-    assert (buffered.getRaw());
-
-    debugs (86,9,"ESIContext::parseOneBuffer: " << buffered->len << " bytes");
-    bool lastBlock = buffered->next.getRaw() == nullptr && flags.finishedtemplate ? true : false;
-
-    if (! parserState.theParser->parse(buffered->buf, buffered->len, lastBlock)) {
-        setError();
-        char tempstr[1024];
-        snprintf (tempstr, 1023, "esiProcess: Parse error at line %ld:\n%s\n",
-                  parserState.theParser->lineNumber(),
-                  parserState.theParser->errorString());
-        debugs(86, DBG_CRITICAL, "" << tempstr << "");
-
-        setErrorMessage(tempstr);
-
-        assert (flags.error);
-
-        return;
-    }
-
-    if (flags.error) {
-        setError();
-        return;
-    }
-
-    ESISegment::Pointer temp = buffered;
-    buffered = temp->next;
-}
-
-void
-ESIContext::parse()
-{
-    if (!parserState.stackdepth) {
-        debugs(86, 5, "empty parser stack, inserting the top level node");
-        assert (tree.getRaw());
-        parserState.stack[parserState.stackdepth] = tree;
-        ++parserState.stackdepth;
-    }
-
-    if (rep && !parserState.inited())
-        parserState.init(this);
-
-    /* we have data */
-    if (buffered.getRaw()) {
-        parserState.parsing = 1;
-        /* we don't keep any data around */
-
-        try {
-            while (buffered.getRaw() && !flags.error)
-                parseOneBuffer();
-
-        } catch (Esi::ErrorDetail &errMsg) { // XXX: non-const for c_str()
-            // level-2: these are protocol/syntax errors from upstream
-            debugs(86, 2, "WARNING: ESI syntax error: " << errMsg);
-            setError();
-            setErrorMessage(errMsg.c_str());
-
-        } catch (...) {
-            // DBG_IMPORTANT because these are local issues the admin needs to fix
-            static FadingCounter logEntries; // TODO: set horizon less than infinity
-            if (logEntries.count(1) < 100)
-                debugs(86, DBG_IMPORTANT, "ERROR: ESI parser: " << CurrentException);
-            setError();
-            setErrorMessage("ESI parser error");
-        }
-
-        /* Tel the read code to allocate a new buffer */
-        incoming = nullptr;
-
-        parserState.parsing = 0;
-    }
-}
-
-esiProcessResult_t
-ESIContext::process ()
-{
-    /* parsing:
-     * read through buffered, skipping plain text, and skipping any
-     * <...> entry that is not an <esi: entry.
-     * when it's found, hand an esiLiteral of the preceding data to our current
-     * context
-     */
-
-    if (parserState.parsing) {
-        /* in middle of parsing - finish here */
-        return ESI_PROCESS_PENDING_MAYFAIL;
-    }
-
-    assert (flags.finished == 0);
-
-    assert (!flags.error);
-
-    if (!hasCachedAST())
-        parse();
-    else if (!flags.finishedtemplate)
-        getCachedAST();
-
-    if (flags.error) {
-        debugs(86, 5, "ESIContext::process: Parsing failed");
-        finishChildren ();
-        parserState.popAll();
-        return ESI_PROCESS_FAILED;
-    }
-
-    if (!flags.finishedtemplate && !incoming.getRaw() && !cachedASTInUse) {
-        buffered = new ESISegment;
-        incoming = buffered;
-    }
-
-    if (!flags.finishedtemplate && !cachedASTInUse) {
-        return ESI_PROCESS_PENDING_MAYFAIL;
-    }
-
-    assert (flags.finishedtemplate || cachedASTInUse);
-    updateCachedAST();
-    /* ok, we've done all we can with the data. What can we process now?
-     */
-    {
-        esiProcessResult_t status;
-        processing = true;
-        status = tree->process(0);
-        processing = false;
-
-        switch (status) {
-
-        case ESI_PROCESS_COMPLETE:
-            debugs(86, 5, "esiProcess: tree Processed OK");
-            break;
-
-        case ESI_PROCESS_PENDING_WONTFAIL:
-            debugs(86, 5, "esiProcess: tree Processed PENDING OK");
-            break;
-
-        case ESI_PROCESS_PENDING_MAYFAIL:
-            debugs(86, 5, "esiProcess: tree Processed PENDING UNKNOWN");
-            break;
-
-        case ESI_PROCESS_FAILED:
-            debugs(86, DBG_CRITICAL, "ERROR: esiProcess: tree Processed FAILED");
-            setError();
-
-            setErrorMessage("esiProcess: ESI template Processing failed.");
-            return ESI_PROCESS_FAILED;
-
-            break;
-        }
-
-        if (status != ESI_PROCESS_PENDING_MAYFAIL && (flags.finishedtemplate || cachedASTInUse)) {
-            /* We've read the entire template, and no nodes will
-             * return failure
-             */
-            debugs(86, 5, "esiProcess, request will succeed");
-            flags.oktosend = 1;
-        }
-
-        if (status == ESI_PROCESS_COMPLETE
-                && (flags.finishedtemplate || cachedASTInUse)) {
-            /* we've finished all processing. Render and send. */
-            debugs(86, 5, "esiProcess, processing complete");
-            flags.finished = 1;
-        }
-
-        return status; /* because we have no callbacks */
-    }
-}
-
-void
-ESIContext::ParserState::freeResources()
-{
-    theParser = nullptr;
-    inited_ = false;
-}
-
-void
-ESIContext::ParserState::popAll()
-{
-    while (stackdepth)
-        stack[--stackdepth] = nullptr;
-}
-
-void
-ESIContext::freeResources ()
-{
-    debugs(86, 5, "Freeing for this=" << this);
-
-    rep = nullptr; // refcounted
-
-    finishChildren ();
-
-    if (parserState.inited()) {
-        parserState.freeResources();
-    }
-
-    parserState.popAll();
-    ESISegmentFreeList (buffered);
-    ESISegmentFreeList (outbound);
-    ESISegmentFreeList (outboundtail);
-    delete varState;
-    varState=nullptr;
-    /* don't touch incoming, it's a pointer into buffered anyway */
-}
-
-ErrorState *clientBuildError(err_type, Http::StatusCode, char const *, const ConnStateData *, HttpRequest *, const AccessLogEntryPointer &);
-
-/* This can ONLY be used before we have sent *any* data to the client */
-void
-ESIContext::fail ()
-{
-    debugs(86, 5, "ESIContext::fail: this=" << this);
-    /* check preconditions */
-    assert (pos == 0);
-    /* cleanup current state */
-    freeResources ();
-    /* Stop altering thisNode request */
-    flags.oktosend = 1;
-    flags.finished = 1;
-    /* don't honour range requests - for errors we send it all */
-    flags.error = 1;
-    /* create an error object */
-    // XXX: with the in-direction on remote IP. does the http->getConn()->clientConnection exist?
-    const auto err = clientBuildError(errorpage, errorstatus, nullptr, http->getConn(), http->request, http->al);
-    err->err_msg = errormessage;
-    errormessage = nullptr;
-    rep = err->BuildHttpReply();
-    // XXX: Leaking err!
-    assert (rep->body.hasContent());
-    size_t errorprogress = rep->body.contentSize();
-    /* Tell esiSend where to start sending from */
-    outbound_offset = 0;
-    /* copy the membuf from the reply to outbound */
-
-    while (errorprogress < (size_t)rep->body.contentSize()) {
-        appendOutboundData(new ESISegment);
-        errorprogress += outboundtail->append(rep->body.content() + errorprogress, rep->body.contentSize() - errorprogress);
-    }
-
-    /* the esiCode now thinks that the error is the outbound,
-     * and all processing has finished. */
-    /* Send as much as we can */
-    send ();
-
-    /* don't cancel anything. The stream nodes will clean up after
-     * themselves when the reply is freed - and we don't know what to
-     * clean anyway.
-     */
-}
-
-/* Implementation of ESIElements */
-
-/* esiComment */
-esiComment::~esiComment()
-{
-    debugs(86, 5, "esiComment::~esiComment " << this);
-}
-
-esiComment::esiComment()
-{}
-
-void
-esiComment::finish()
-{}
-
-void
-esiComment::render(ESISegment::Pointer output)
-{
-    /* Comments do nothing dude */
-    debugs(86, 5, "esiCommentRender: Rendering comment " << this << " into " << output.getRaw());
-}
-
-ESIElement::Pointer
-esiComment::makeCacheable() const
-{
-    debugs(86, 5, "esiComment::makeCacheable: returning NULL");
-    return nullptr;
-}
-
-ESIElement::Pointer
-esiComment::makeUsable(esiTreeParentPtr, ESIVarState &) const
-{
-    fatal ("esiComment::Usable: unreachable code!\n");
-    return nullptr;
-}
-
-/* esiLiteral */
-esiLiteral::~esiLiteral()
-{
-    debugs(86, 5, "esiLiteral::~esiLiteral: " << this);
-    ESISegmentFreeList (buffer);
-    cbdataReferenceDone (varState);
-}
-
-esiLiteral::esiLiteral(ESISegment::Pointer aSegment) :
-    buffer(aSegment),
-    varState(nullptr)
-{
-    /* Nothing to do */
-    flags.donevars = 1;
-}
-
-void
-esiLiteral::finish()
-{}
-
-/* precondition: the buffer chain has at least start + length bytes of data
- */
-esiLiteral::esiLiteral(ESIContext *context, const char *s, int numberOfCharacters)
-{
-    assert (s);
-    flags.donevars = 0;
-    buffer = new ESISegment;
-    ESISegment::Pointer local = buffer;
-    size_t start = 0;
-    int remainingCharacters = numberOfCharacters;
-
-    while (remainingCharacters > 0) {
-        if (local->len == sizeof (local->buf)) {
-            local->next = new ESISegment;
-            local=local->next;
-        }
-
-        size_t len = local->append (&s[start], remainingCharacters);
-        start += len;
-        remainingCharacters -= len;
-    }
-
-    varState = cbdataReference(context->varState);
-}
-
-void
-esiLiteral::render (ESISegment::Pointer output)
-{
-    debugs(86, 9, "esiLiteral::render: Rendering " << this);
-    /* append the entire chain */
-    assert (output->next.getRaw() == nullptr);
-    output->next = buffer;
-    buffer = nullptr;
-}
-
-esiProcessResult_t
-esiLiteral::process (int dovars)
-{
-    if (flags.donevars)
-        return ESI_PROCESS_COMPLETE;
-
-    if (dovars) {
-        ESISegment::Pointer temp = buffer;
-        /* Ensure variable state is clean */
-
-        while (temp.getRaw()) {
-            varState->feedData(temp->buf,temp->len);
-            temp = temp->next;
-        }
-
-        /* free the pre-processed content */
-        ESISegmentFreeList (buffer);
-
-        buffer = varState->extractList ();
-    }
-
-    flags.donevars = 1;
-    return ESI_PROCESS_COMPLETE;
-}
-
-esiLiteral::esiLiteral(esiLiteral const &old) : buffer (old.buffer->cloneList()),
-    varState (nullptr)
-{
-    flags.donevars = 0;
-}
-
-ESIElement::Pointer
-esiLiteral::makeCacheable() const
-{
-    return new esiLiteral (*this);
-}
-
-ESIElement::Pointer
-esiLiteral::makeUsable(esiTreeParentPtr, ESIVarState &newVarState) const
-{
-    debugs(86, 5, "esiLiteral::makeUsable: Creating usable literal");
-    esiLiteral * result = new esiLiteral (*this);
-    result->varState = cbdataReference (&newVarState);
-    return result;
-}
-
-/* esiRemove */
-void
-esiRemove::render(ESISegment::Pointer)
-{
-    /* Removes do nothing dude */
-    debugs(86, 5, "esiRemoveRender: Rendering remove " << this);
-}
-
-/* Accept non-ESI children */
-bool
-esiRemove::addElement (ESIElement::Pointer element)
-{
-    if (!dynamic_cast<esiLiteral*>(element.getRaw())) {
-        debugs(86, 5, "esiRemoveAdd: Failed for " << this);
-        return false;
-    }
-
-    return true;
-}
-
-ESIElement::Pointer
-esiRemove::makeCacheable() const
-{
-    debugs(86, 5, "esiRemove::makeCacheable: Returning NULL");
-    return nullptr;
-}
-
-ESIElement::Pointer
-esiRemove::makeUsable(esiTreeParentPtr, ESIVarState &) const
-{
-    fatal ("esiRemove::Usable: unreachable code!\n");
-    return nullptr;
-}
-
-/* esiTry */
-esiTry::~esiTry()
-{
-    debugs(86, 5, "esiTry::~esiTry " << this);
-}
-
-esiTry::esiTry(esiTreeParentPtr aParent) :
-    parent(aParent),
-    exceptbuffer(nullptr)
-{
-    memset(&flags, 0, sizeof(flags));
-}
-
-void
-esiTry::render(ESISegment::Pointer output)
-{
-    /* Try renders from it's children */
-    assert (attempt.getRaw());
-    assert (except.getRaw());
-    debugs(86, 5, "esiTryRender: Rendering Try " << this);
-
-    if (flags.attemptok) {
-        attempt->render(output);
-    } else if (flags.exceptok) {
-        /* prerendered */
-
-        if (exceptbuffer.getRaw())
-            ESISegment::ListTransfer(exceptbuffer, output);
-        else
-            except->render(output);
-    } else
-        debugs(86, 5, "esiTryRender: Neither except nor attempt succeeded?!?");
-}
-
-/* Accept attempt and except only */
-bool
-esiTry::addElement(ESIElement::Pointer element)
-{
-    debugs(86, 5, "esiTryAdd: Try " << this << " adding element " <<
-           element.getRaw());
-
-    if (dynamic_cast<esiLiteral*>(element.getRaw())) {
-        /* Swallow whitespace */
-        debugs(86, 5, "esiTryAdd: Try " << this << " skipping whitespace " << element.getRaw());
-        return true;
-    }
-
-    if (dynamic_cast<esiAttempt*>(element.getRaw())) {
-        if (attempt.getRaw()) {
-            debugs(86, DBG_IMPORTANT, "ERROR: esiTryAdd: Failed for " << this << " - try already has an attempt node (section 3.4)");
-            return false;
-        }
-
-        attempt = element;
-        return true;
-    }
-
-    if (dynamic_cast<esiExcept*>(element.getRaw())) {
-        if (except.getRaw()) {
-            debugs(86, DBG_IMPORTANT, "ERROR: esiTryAdd: Failed for " << this << " - try already has an except node (section 3.4)");
-            return false;
-        }
-
-        except = element;
-        return true;
-    }
-
-    debugs(86, DBG_IMPORTANT, "ERROR: esiTryAdd: Failed to add element " << element.getRaw() << " to try " << this << ", incorrect element type (see section 3.4)");
-    return false;
-}
-
-esiProcessResult_t
-esiTry::bestAttemptRV() const
-{
-    if (flags.attemptfailed)
-        return ESI_PROCESS_COMPLETE;
-    else
-        return ESI_PROCESS_PENDING_MAYFAIL;
-}
-
-esiProcessResult_t
-esiTry::process (int dovars)
-{
-    esiProcessResult_t rv = ESI_PROCESS_PENDING_MAYFAIL;
-
-    if (!attempt.getRaw()) {
-        debugs(86, DBG_CRITICAL, "ERROR: esiTryProcess: Try has no attempt element - ESI template is invalid (section 3.4)");
-        return ESI_PROCESS_FAILED;
-    }
-
-    if (!except.getRaw()) {
-        debugs(86, DBG_CRITICAL, "ERROR: esiTryProcess: Try has no except element - ESI template is invalid (section 3.4)");
-        return ESI_PROCESS_FAILED;
-    }
-
-    if (!flags.attemptfailed)
-        /* Try the attempt branch */
-        switch ((rv = attempt->process(dovars))) {
-
-        case ESI_PROCESS_COMPLETE:
-            debugs(86, 5, "esiTryProcess: attempt Processed OK");
-            flags.attemptok = 1;
-            return ESI_PROCESS_COMPLETE;
-
-        case ESI_PROCESS_PENDING_WONTFAIL:
-            debugs(86, 5, "esiTryProcess: attempt Processed PENDING OK");
-            /* We're not done yet, but don't need to test except */
-            return ESI_PROCESS_PENDING_WONTFAIL;
-
-        case ESI_PROCESS_PENDING_MAYFAIL:
-            debugs(86, 5, "eseSequenceProcess: element Processed PENDING UNKNOWN");
-            break;
-
-        case ESI_PROCESS_FAILED:
-            debugs(86, 5, "esiSequenceProcess: element Processed FAILED");
-            flags.attemptfailed = 1;
-            break;
-        }
-
-    /* attempt is either MAYFAIL or FAILED */
-    if (flags.exceptok)
-        return bestAttemptRV();
-
-    /* query except to see if it has a definite result */
-    if (!flags.exceptfailed)
-        /* Try the except branch */
-        switch (except->process(dovars)) {
-
-        case ESI_PROCESS_COMPLETE:
-            debugs(86, 5, "esiTryProcess: except Processed OK");
-            flags.exceptok = 1;
-            return bestAttemptRV();
-
-        case ESI_PROCESS_PENDING_WONTFAIL:
-            debugs(86, 5, "esiTryProcess: attempt Processed PENDING OK");
-            /* We're not done yet, but can't fail */
-            return ESI_PROCESS_PENDING_WONTFAIL;
-
-        case ESI_PROCESS_PENDING_MAYFAIL:
-            debugs(86, 5, "eseSequenceProcess: element Processed PENDING UNKNOWN");
-            /* The except branch fail fail */
-            return ESI_PROCESS_PENDING_MAYFAIL;
-
-        case ESI_PROCESS_FAILED:
-            debugs(86, 5, "esiSequenceProcess: element Processed FAILED");
-            flags.exceptfailed = 1;
-            break;
-        }
-
-    if (flags.exceptfailed && flags.attemptfailed)
-        return ESI_PROCESS_FAILED;
-
-    /* one of attempt or except returned PENDING MAYFAIL */
-    return ESI_PROCESS_PENDING_MAYFAIL;
-}
-
-void
-esiTry::notifyParent()
-{
-    if (flags.attemptfailed) {
-        if (flags.exceptok) {
-            parent->provideData (exceptbuffer, this);
-            exceptbuffer = nullptr;
-        } else if (flags.exceptfailed || except.getRaw() == nullptr) {
-            parent->fail (this, "esi:try - except claused failed, or no except clause found");
-        }
-    }
-
-    /* nothing to do when except fails and attempt hasn't */
-}
-
-void
-esiTry::fail(ESIElement *source, char const *anError)
-{
-    assert (source);
-    assert (source == attempt || source == except);
-    debugs(86, 5, "esiTry::fail: this=" << this << ", source=" << source << ", message=" << anError);
-
-    if (source == except) {
-        flags.exceptfailed = 1;
-    } else {
-        flags.attemptfailed = 1;
-    }
-
-    notifyParent();
-}
-
-void
-esiTry::provideData (ESISegment::Pointer data, ESIElement* source)
-{
-    if (source == attempt) {
-        flags.attemptok = 1;
-        parent->provideData (data, this);
-    } else if (source == except) {
-        flags.exceptok = 1;
-        assert (exceptbuffer == nullptr);
-        ESISegment::ListTransfer (data, exceptbuffer);
-        notifyParent();
-    }
-}
-
-esiTry::esiTry(esiTry const &)
-{
-    attempt = nullptr;
-    except  = nullptr;
-    flags.attemptok = 0;
-    flags.exceptok = 0;
-    flags.attemptfailed = 0;
-    flags.exceptfailed = 0;
-    parent = nullptr;
-    exceptbuffer = nullptr;
-}
-
-ESIElement::Pointer
-esiTry::makeCacheable() const
-{
-    debugs(86, 5, "esiTry::makeCacheable: making cachable Try from " << this);
-    esiTry *resultT = new esiTry (*this);
-    ESIElement::Pointer result = resultT;
-
-    if (attempt.getRaw())
-        resultT->attempt = attempt->makeCacheable();
-
-    if (except.getRaw())
-        resultT->except  = except->makeCacheable();
-
-    return result;
-}
-
-ESIElement::Pointer
-esiTry::makeUsable(esiTreeParentPtr newParent, ESIVarState &newVarState) const
-{
-    debugs(86, 5, "esiTry::makeUsable: making usable Try from " << this);
-    esiTry *resultT = new esiTry (*this);
-    ESIElement::Pointer result = resultT;
-
-    resultT->parent = newParent;
-
-    if (attempt.getRaw())
-        resultT->attempt = attempt->makeUsable(resultT, newVarState);
-
-    if (except.getRaw())
-        resultT->except  = except->makeUsable(resultT, newVarState);
-
-    return result;
-}
-
-void
-esiTry::finish()
-{
-    parent = nullptr;
-
-    if (attempt.getRaw())
-        attempt->finish();
-
-    attempt = nullptr;
-
-    if (except.getRaw())
-        except->finish();
-
-    except = nullptr;
-}
-
-/* esiChoose */
-esiChoose::~esiChoose()
-{
-    debugs(86, 5, "esiChoose::~esiChoose " << this);
-    FinishAllElements(elements); // finish if not already done
-}
-
-esiChoose::esiChoose(const esiTreeParentPtr & aParent) :
-    elements(),
-    chosenelement(-1),
-    parent(aParent)
-{}
-
-void
-esiChoose::render(ESISegment::Pointer output)
-{
-    /* append all processed elements, and trim processed and rendered elements */
-    assert (output->next == nullptr);
-    assert (elements.size() || otherwise.getRaw());
-    debugs(86, 5, "esiChooseRender: rendering");
-
-    if (chosenelement >= 0)
-        elements[chosenelement]->render(output);
-    else if (otherwise.getRaw())
-        otherwise->render(output);
-}
-
-bool
-esiChoose::addElement(ESIElement::Pointer element)
-{
-    /* add an element to the output list */
-
-    if (dynamic_cast<esiLiteral*>(element.getRaw())) {
-        /* Swallow whitespace */
-        debugs(86, 5, "esiChooseAdd: Choose " << this << " skipping whitespace " << element.getRaw());
-        return true;
-    }
-
-    /* Some elements require specific parents */
-    if (!(dynamic_cast<esiWhen*>(element.getRaw()) || dynamic_cast<esiOtherwise*>(element.getRaw()))) {
-        debugs(86, DBG_CRITICAL, "ERROR: esiChooseAdd: invalid child node for esi:choose (section 3.3)");
-        return false;
-    }
-
-    if (dynamic_cast<esiOtherwise*>(element.getRaw())) {
-        if (otherwise.getRaw()) {
-            debugs(86, DBG_CRITICAL, "esiChooseAdd: only one otherwise node allowed for esi:choose (section 3.3)");
-            return false;
-        }
-
-        otherwise = element;
-    } else {
-        elements.push_back (element);
-
-        debugs (86,3, "esiChooseAdd: Added a new element, elements = " << elements.size());
-
-        if (chosenelement == -1) {
-            const esiWhen * topElement=dynamic_cast<esiWhen *>(element.getRaw());
-            if (topElement && topElement->testsTrue()) {
-                chosenelement = elements.size() - 1;
-                debugs (86,3, "esiChooseAdd: Chose element " << elements.size());
-            }
-        }
-    }
-
-    return true;
-}
-
-void
-esiChoose::selectElement()
-{
-    if (chosenelement > -1)
-        return;
-
-    for (size_t counter = 0; counter < elements.size(); ++counter) {
-        const esiWhen *el = dynamic_cast<esiWhen *>(elements[counter].getRaw());
-        if (el && el->testsTrue()) {
-            chosenelement = counter;
-            debugs (86,3, "esiChooseAdd: Chose element " << counter + 1);
-            return;
-        }
-    }
-}
-
-// TODO: make ESIElement destructor call finish() instead so it is
-//       a) only called when an element ref-count is 0, and
-//       b) caller can elements.clear() instead of doing this
-void
-FinishAnElement(ESIElement::Pointer &element, int pos)
-{
-    if (element)
-        element->finish();
-
-    debugs(86, 5, "setting index " << pos << ", pointer " << (void*)element.getRaw() << " to nil");
-    element = nullptr;
-}
-
-void
-FinishAllElements(Esi::Elements &elements)
-{
-    int pos = 0;
-    for (auto &element : elements)
-        FinishAnElement(element, pos++);
-}
-
-void
-esiChoose::finish()
-{
-    FinishAllElements(elements);
-
-    if (otherwise.getRaw())
-        otherwise->finish();
-
-    otherwise = nullptr;
-    parent = nullptr;
-}
-
-void
-esiChoose::NULLUnChosen()
-{
-    if (chosenelement >= 0) {
-        if (otherwise.getRaw())
-            otherwise->finish();
-
-        otherwise = nullptr;
-
-        int pos = 0;
-        for (auto &element : elements) {
-            if (pos != chosenelement)
-                FinishAnElement(element, pos++);
-        }
-
-    } else if (otherwise.getRaw()) {
-        FinishAllElements(elements);
-    }
-}
-
-esiProcessResult_t
-esiChoose::process (int dovars)
-{
-    /* process as much of the list as we can, stopping only on
-     * failures
-     */
-    /* We MUST have a when clause */
-    NULLUnChosen();
-
-    if (!elements.size()) {
-        parent->fail(this);
-
-        if (otherwise.getRaw())
-            otherwise->finish();
-
-        otherwise = nullptr;
-
-        parent = nullptr;
-
-        return ESI_PROCESS_FAILED;
-    }
-
-    if (chosenelement >= 0) {
-        return elements[chosenelement]->process(dovars);
-    } else if (otherwise.getRaw())
-        return otherwise->process(dovars);
-    else
-        return ESI_PROCESS_COMPLETE;
-}
-
-void
-esiChoose::checkValidSource (ESIElement::Pointer source) const
-{
-    if (!elements.size())
-        fatal ("invalid callback = no when clause\n");
-
-    if (chosenelement >= 0)
-        assert (source == elements[chosenelement]);
-    else if (otherwise.getRaw())
-        assert (source == otherwise);
-    else
-        fatal ("esiChoose::checkValidSource: invalid callback - no elements chosen\n");
-}
-
-void
-esiChoose::fail(ESIElement * source, char const *anError)
-{
-    checkValidSource (source);
-    FinishAllElements(elements);
-
-    if (otherwise.getRaw())
-        otherwise->finish();
-
-    otherwise = nullptr;
-
-    parent->fail(this, anError);
-
-    parent = nullptr;
-}
-
-void
-esiChoose::provideData (ESISegment::Pointer data, ESIElement*source)
-{
-    checkValidSource (source);
-    parent->provideData (data, this);
-}
-
-esiChoose::esiChoose(esiChoose const &old) : chosenelement(-1), otherwise (nullptr), parent (nullptr)
-{
-    for (size_t counter = 0; counter < old.elements.size(); ++counter) {
-        ESIElement::Pointer newElement = old.elements[counter]->makeCacheable();
-
-        if (newElement.getRaw())
-            assert (addElement(newElement));
-    }
-}
-
-void
-esiChoose::makeCachableElements(esiChoose const &old)
-{
-    for (size_t counter = 0; counter < old.elements.size(); ++counter) {
-        ESIElement::Pointer newElement = old.elements[counter]->makeCacheable();
-
-        if (newElement.getRaw())
-            assert (addElement(newElement));
-    }
-}
-
-void
-esiChoose::makeUsableElements(esiChoose const &old, ESIVarState &newVarState)
-{
-    for (size_t counter = 0; counter < old.elements.size(); ++counter) {
-        ESIElement::Pointer newElement = old.elements[counter]->makeUsable (this, newVarState);
-
-        if (newElement.getRaw())
-            assert (addElement(newElement));
-    }
-}
-
-ESIElement::Pointer
-esiChoose::makeCacheable() const
-{
-    esiChoose *resultC = new esiChoose (*this);
-    ESIElement::Pointer result = resultC;
-    resultC->makeCachableElements(*this);
-
-    if (otherwise.getRaw())
-        resultC->otherwise = otherwise->makeCacheable();
-
-    return result;
-}
-
-ESIElement::Pointer
-esiChoose::makeUsable(esiTreeParentPtr newParent, ESIVarState &newVarState) const
-{
-    esiChoose *resultC = new esiChoose (*this);
-    ESIElement::Pointer result = resultC;
-    resultC->parent = newParent;
-    resultC->makeUsableElements(*this, newVarState);
-    resultC->selectElement();
-
-    if (otherwise.getRaw())
-        resultC->otherwise = otherwise->makeUsable(resultC, newVarState);
-
-    return result;
-}
-
-/* esiWhen */
-esiWhen::esiWhen(esiTreeParentPtr aParent, int attrcount, const char **attr,ESIVarState *aVar) :
-    esiSequence(aParent),
-    testValue(false),
-    unevaluatedExpression(nullptr),
-    varState(nullptr)
-{
-    char const *expression = nullptr;
-
-    for (int loopCounter = 0; loopCounter < attrcount && attr[loopCounter]; loopCounter += 2) {
-        if (!strcmp(attr[loopCounter],"test")) {
-            /* evaluate test */
-            debugs(86, 5, "esiWhen::esiWhen: Evaluating '" << attr[loopCounter+1] << "'");
-            /* TODO: warn the user instead of asserting */
-            assert (expression == nullptr);
-            expression = attr[loopCounter+1];
-        } else {
-            /* ignore mistyped attributes.
-             * TODO:? error on these for user feedback - config parameter needed
-             */
-            debugs(86, DBG_IMPORTANT, "Found misttyped attribute on ESI When clause");
-        }
-    }
-
-    /* No expression ? default is not matching */
-    if (!expression)
-        return;
-
-    unevaluatedExpression = xstrdup(expression);
-
-    varState = cbdataReference (aVar);
-
-    evaluate();
-}
-
-esiWhen::~esiWhen()
-{
-    safe_free (unevaluatedExpression);
-
-    cbdataReferenceDone(varState);
-}
-
-void
-esiWhen::evaluate()
-{
-    if (!unevaluatedExpression)
-        return;
-
-    assert(varState);
-
-    varState->feedData(unevaluatedExpression, strlen (unevaluatedExpression));
-
-    char const *expression = varState->extractChar ();
-
-    setTestResult(ESIExpression::Evaluate (expression));
-
-    safe_free (expression);
-}
-
-esiWhen::esiWhen(esiWhen const &old) :
-    esiSequence(old),
-    testValue(false),
-    unevaluatedExpression(nullptr),
-    varState(nullptr)
-{
-    if (old.unevaluatedExpression)
-        unevaluatedExpression = xstrdup(old.unevaluatedExpression);
-}
-
-ESIElement::Pointer
-esiWhen::makeCacheable() const
-{
-    return new esiWhen(*this);
-}
-
-ESIElement::Pointer
-esiWhen::makeUsable(esiTreeParentPtr newParent, ESIVarState &newVarState) const
-{
-    esiWhen *resultW = new esiWhen (*this);
-    ESIElement::Pointer result = resultW;
-    resultW->parent = newParent;
-    resultW->makeUsableElements(*this, newVarState);
-    resultW->varState = cbdataReference (&newVarState);
-    resultW->evaluate();
-    return result;
-}
-
-/* TODO: implement surrogate targeting and control processing */
-int
-esiEnableProcessing (HttpReply *rep)
-{
-    int rv = 0;
-
-    if (rep->surrogate_control) {
-        HttpHdrScTarget *sctusable =
-            rep->surrogate_control->getMergedTarget(Config.Accel.surrogate_id);
-
-        // found something targeted at us
-        if (sctusable &&
-                sctusable->hasContent() &&
-                sctusable->content().pos("ESI/1.0")) {
-            rv = 1;
-        }
-
-        delete sctusable;
-    }
-
-    return rv;
-}
-
-#endif /* USE_SQUID_ESI == 1 */
-
diff --git a/src/esi/Esi.h b/src/esi/Esi.h
deleted file mode 100644 (file)
index 47a73a0..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#ifndef SQUID_SRC_ESI_ESI_H
-#define SQUID_SRC_ESI_ESI_H
-
-#include "clientStream.h"
-#include "sbuf/SBuf.h"
-
-#if !defined(ESI_STACK_DEPTH_LIMIT)
-#define ESI_STACK_DEPTH_LIMIT 20
-#endif
-
-/* ESI.c */
-extern CSR esiStreamRead;
-extern CSCB esiProcessStream;
-extern CSD esiStreamDetach;
-extern CSS esiStreamStatus;
-int esiEnableProcessing (HttpReply *);
-
-namespace Esi
-{
-
-typedef SBuf ErrorDetail;
-/// prepare an Esi::ErrorDetail for throw on ESI parser internal errors
-inline Esi::ErrorDetail Error(const char *msg) { return ErrorDetail(msg); }
-
-} // namespace Esi
-
-#endif /* SQUID_SRC_ESI_ESI_H */
-
diff --git a/src/esi/Except.h b/src/esi/Except.h
deleted file mode 100644 (file)
index 3dfa6cc..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#ifndef SQUID_SRC_ESI_EXCEPT_H
-#define SQUID_SRC_ESI_EXCEPT_H
-
-#include "esi/Element.h"
-#include "esi/Sequence.h"
-
-/* esiExcept */
-
-class esiExcept : public esiSequence
-{
-
-public:
-    esiExcept(esiTreeParentPtr aParent) : esiSequence (aParent) {}
-};
-
-#endif /* SQUID_SRC_ESI_EXCEPT_H */
-
diff --git a/src/esi/ExpatParser.cc b/src/esi/ExpatParser.cc
deleted file mode 100644 (file)
index 5b1a925..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#include "squid.h"
-
-#if USE_SQUID_ESI && HAVE_LIBEXPAT
-
-#include "base/RunnersRegistry.h"
-#include "esi/ExpatParser.h"
-
-#include <memory>
-
-namespace Esi
-{
-
-class ExpatRr : public RegisteredRunner
-{
-public:
-    void finalizeConfig() override
-    {
-        registration.reset(new ESIParser::Register("expat", &ESIExpatParser::NewParser));
-    }
-
-private:
-    std::unique_ptr<ESIParser::Register> registration;
-};
-
-}
-
-DefineRunnerRegistratorIn(Esi, ExpatRr);
-
-EsiParserDefinition(ESIExpatParser);
-
-ESIExpatParser::ESIExpatParser(ESIParserClient *aClient) : theClient (aClient)
-{
-    /* TODO: grab the document encoding from the headers */
-    p = XML_ParserCreateNS(nullptr,'|');
-    XML_SetUserData (myParser(), static_cast<void *>(this));
-    XML_SetElementHandler(myParser(), Start, End);
-    XML_SetDefaultHandler(myParser(), Default);
-    XML_SetCommentHandler(myParser(), Comment);
-    XML_UseParserAsHandlerArg(myParser());
-}
-
-ESIExpatParser::~ESIExpatParser()
-{
-    XML_ParserFree (myParser());
-    p = nullptr;
-}
-
-void
-ESIExpatParser::Start(void *data,const XML_Char *el, const char **attr)
-{
-    XML_Parser parser = static_cast<XML_Parser>(data);
-    ESIExpatParser *me = (ESIExpatParser *)XML_GetUserData(parser);
-    me->theClient->start (el, attr, XML_GetSpecifiedAttributeCount (parser));
-}
-
-void
-ESIExpatParser::End(void *data,const XML_Char *el)
-{
-    XML_Parser parser = static_cast<XML_Parser>(data);
-    ESIExpatParser *me = (ESIExpatParser *)XML_GetUserData(parser);
-    me->theClient->end (el);
-}
-
-void
-ESIExpatParser::Default(void *data, const XML_Char *s, int len)
-{
-    XML_Parser parser = static_cast<XML_Parser>(data);
-    ESIExpatParser *me = (ESIExpatParser *)XML_GetUserData(parser);
-    me->theClient->parserDefault (s, len);
-}
-
-void
-ESIExpatParser::Comment(void *data, const XML_Char *s)
-{
-    XML_Parser parser = static_cast<XML_Parser>(data);
-    ESIExpatParser *me = (ESIExpatParser *)XML_GetUserData(parser);
-    me->theClient->parserComment (s);
-}
-
-bool
-ESIExpatParser::parse(char const *dataToParse, size_t const lengthOfData, bool const endOfStream)
-{
-    return XML_Parse(myParser(), dataToParse, lengthOfData, endOfStream);
-}
-
-long int
-ESIExpatParser::lineNumber() const
-{
-    return (long int)XML_GetCurrentLineNumber(myParser());
-}
-
-char const *
-ESIExpatParser::errorString() const
-{
-    return XML_ErrorString(XML_GetErrorCode(myParser()));
-}
-
-#endif /* USE_SQUID_ESI */
-
diff --git a/src/esi/ExpatParser.h b/src/esi/ExpatParser.h
deleted file mode 100644 (file)
index a039898..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#ifndef SQUID_SRC_ESI_EXPATPARSER_H
-#define SQUID_SRC_ESI_EXPATPARSER_H
-
-#if USE_SQUID_ESI && HAVE_LIBEXPAT
-
-#include "esi/Parser.h"
-
-#if HAVE_EXPAT_H
-#include <expat.h>
-#endif
-
-class ESIExpatParser : public ESIParser
-{
-
-public:
-    ESIExpatParser(ESIParserClient *);
-    ~ESIExpatParser() override;
-
-    /** \retval true    on success */
-    bool parse(char const *dataToParse, size_t const lengthOfData, bool const endOfStream) override;
-
-    long int lineNumber() const override;
-    char const * errorString() const override;
-
-    EsiParserDeclaration;
-
-private:
-    /** our parser */
-    mutable XML_Parser p;
-    static void Start(void *data, const XML_Char *el, const char **attr);
-    static void End(void *data, const XML_Char *el);
-    static void Default (void *data, const XML_Char *s, int len);
-    static void Comment (void *data, const XML_Char *s);
-    XML_Parser &myParser() const {return p;}
-
-    ESIParserClient *theClient;
-};
-
-#endif /* USE_SQUID_ESI */
-
-#endif /* SQUID_SRC_ESI_EXPATPARSER_H */
-
diff --git a/src/esi/Expression.cc b/src/esi/Expression.cc
deleted file mode 100644 (file)
index f34d2fc..0000000
+++ /dev/null
@@ -1,1049 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#include "squid.h"
-#include "debug/Stream.h"
-#include "esi/Esi.h"
-#include "esi/Expression.h"
-
-#include <cerrno>
-#include <cmath>
-
-/* stack precedence rules:
- * before pushing an operator onto the stack, the
- * top 2 elements are checked. if either has a higher
- * or equal precedence than the current operator, they
- * are evaluated.
- * Start of expression has 5 precedence,
- * end of expression has 0 precedence
- * literal has 1 as does expression results
- * | has 2
- * & has 3
- * ! has 4
- * == != < > <= >= has 5
- * ( has 5
- * ) has 0
- */
-
-typedef struct _stackmember stackmember;
-
-typedef int evaluate(stackmember * stack, int *depth, int whereAmI,
-                     stackmember * candidate);
-
-typedef enum {
-    ESI_EXPR_INVALID,
-    ESI_EXPR_LITERAL,
-    ESI_EXPR_OR,
-    ESI_EXPR_AND,
-    ESI_EXPR_NOT,
-    ESI_EXPR_START,
-    ESI_EXPR_END,
-    ESI_EXPR_EQ,
-    ESI_EXPR_NOTEQ,
-    ESI_EXPR_LESS,
-    ESI_EXPR_LESSEQ,
-    ESI_EXPR_MORE,
-    ESI_EXPR_MOREEQ,
-    ESI_EXPR_EXPR           /* the result of an expr PRI 1 */
-} evaltype;
-
-typedef enum {
-    ESI_LITERAL_STRING,
-    ESI_LITERAL_FLOAT,
-    ESI_LITERAL_INT,
-    ESI_LITERAL_BOOL,
-    ESI_LITERAL_INVALID
-} literalhint;
-
-struct _stackmember {
-    evaluate *eval = nullptr;
-    union Value {
-        char *string;
-        double floating;
-        int integral;
-        Value() { memset(this, 0, sizeof(*this)); }
-    } value;
-    literalhint valuestored = ESI_LITERAL_INVALID;
-    evaltype valuetype = ESI_EXPR_INVALID;
-    int precedence = 0;
-};
-
-static void cleanmember(stackmember *);
-static void stackpop(stackmember * s, int *depth);
-
-void
-cleanmember(stackmember * s)
-{
-    if (s->valuetype == ESI_EXPR_LITERAL
-            && s->valuestored == ESI_LITERAL_STRING) {
-        safe_free(s->value.string);
-        s->value.string = nullptr;
-    }
-
-}
-
-void
-stackpop(stackmember * s, int *depth)
-{
-    if (!(*depth)--)
-        return;
-
-    cleanmember(&s[*depth]);
-}
-
-static void
-stackpush(stackmember *stack, stackmember &item, int *depth)
-{
-    if (*depth < 0)
-        throw Esi::Error("ESIExpression stack has negative size");
-    if (*depth >= ESI_STACK_DEPTH_LIMIT)
-        throw Esi::Error("ESIExpression stack is full, cannot push");
-
-    stack[(*depth)++] = item;
-}
-
-static evaluate evalnegate;
-static evaluate evalliteral;
-static evaluate evalor;
-static evaluate evaland;
-static evaluate evallesseq;
-static evaluate evallessthan;
-static evaluate evalmoreeq;
-static evaluate evalmorethan;
-static evaluate evalequals;
-static evaluate evalnotequals;
-static evaluate evalstartexpr;
-static evaluate evalendexpr;
-static evaluate evalexpr;
-static void dumpstack(stackmember * stack, int depth);
-static int addmember(stackmember * stack, int *stackdepth,
-                     stackmember * candidate);
-static int membercompare(stackmember a, stackmember b);
-static char const *trim(char const *s);
-static stackmember getsymbol(const char *s, char const **endptr);
-
-/* -2 = failed to compate
- * -1 = a less than b
- * 0 = a equal b
- * 2 - a more than b
- */
-int
-membercompare(stackmember a, stackmember b)
-{
-    /* we can compare: sub expressions to sub expressions ,
-     * literals to literals
-     */
-
-    if (!((a.valuetype == ESI_EXPR_LITERAL && b.valuetype == ESI_EXPR_LITERAL &&
-            a.valuestored != ESI_LITERAL_INVALID && b.valuestored != ESI_LITERAL_INVALID) ||
-            (a.valuetype == ESI_EXPR_EXPR && b.valuetype == ESI_EXPR_EXPR)))
-        return -2;
-
-    if (a.valuetype == ESI_EXPR_EXPR) {
-        if (a.value.integral == b.value.integral)
-            return 0;
-        else
-            return 1;
-    } else if (a.valuestored == ESI_LITERAL_STRING) {
-        if (b.valuestored == ESI_LITERAL_STRING) {
-            int i =strcmp(a.value.string, b.value.string);
-
-            if (i < 0)
-                return -1;
-
-            if (i > 0)
-                return 1;
-
-            return 0;
-        } else {
-            /* TODO: numeric to string conversion ? */
-            debugs(86, DBG_IMPORTANT, "strcmp with non-string");
-            return -2;
-        }
-    } else if (a.valuestored == ESI_LITERAL_FLOAT) {
-        if (b.valuestored == ESI_LITERAL_INT) {
-            if (fabs(a.value.floating - b.value.integral) < 0.00001)
-                return 0;
-            else if (a.value.floating < b.value.integral)
-                return -1;
-            else
-                return 1;
-        } else if (b.valuestored == ESI_LITERAL_FLOAT) {
-            if (a.value.floating == b.value.floating)
-                return 0;
-            else if (a.value.floating < b.value.floating)
-                return -1;
-            else
-                return 1;
-        } else {
-            /* TODO: attempt numeric converson again? */
-            debugs(86, DBG_IMPORTANT, "floatcomp with non float or int");
-            return -2;
-        }
-    } else if (a.valuestored == ESI_LITERAL_INT) {
-        if (b.valuestored == ESI_LITERAL_INT) {
-            if (a.value.integral == b.value.integral)
-                return 0;
-            else if (a.value.integral < b.value.integral)
-                return -1;
-            else
-                return 1;
-        } else if (b.valuestored == ESI_LITERAL_FLOAT) {
-            if (fabs(a.value.integral - b.value.floating) < 0.00001)
-                return 0;
-            else if (a.value.integral < b.value.floating)
-                return -1;
-            else
-                return 1;
-        } else {
-            /* TODO: attempt numeric converson again? */
-            debugs(86, DBG_IMPORTANT, "intcomp vs non float non int");
-            return -2;
-        }
-    }
-
-    return -2;
-}
-
-/* return 0 on success, 1 on failure */
-int
-evalnegate(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
-{
-    if (whereAmI != *depth - 2)
-        /* invalid stack */
-        return 1;
-
-    if (whereAmI < 0)
-        throw Esi::Error("negate expression location too small");
-    if (*depth >= ESI_STACK_DEPTH_LIMIT)
-        throw Esi::Error("negate expression too complex");
-
-    if (stack[whereAmI + 1].valuetype != ESI_EXPR_EXPR)
-        /* invalid operand */
-        return 1;
-
-    /* copy down */
-    --(*depth);
-
-    stack[whereAmI] = stack[(*depth)];
-
-    cleanmember(candidate);
-
-    if (stack[whereAmI].value.integral == 1)
-        stack[whereAmI].value.integral = 0;
-    else
-        stack[whereAmI].value.integral = 1;
-
-    return 0;
-}
-
-int
-evalliteral(stackmember * /* stack */, int * /* depth */, int /* whereAmI */, stackmember * /* candidate */)
-{
-    debugs(86, DBG_IMPORTANT, "attempt to evaluate a literal");
-    /* literals can't be evaluated */
-    return 1;
-}
-
-int
-evalexpr(stackmember * /* stack */, int * /* depth */, int /* whereAmI */, stackmember * /* candidate */)
-{
-    debugs(86, DBG_IMPORTANT, "attempt to evaluate a sub-expression result");
-    /* sub-scpr's can't be evaluated */
-    return 1;
-}
-
-int
-evalor(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
-{
-    int rv;
-    stackmember srv;
-
-    if (*depth < 3)
-        /* Not enough operands */
-        return 1;
-
-    if (whereAmI != *depth - 2)
-        /* invalid stack */
-        return 1;
-
-    if (stack[whereAmI + 1].valuetype != ESI_EXPR_EXPR ||
-            stack[whereAmI - 1].valuetype != ESI_EXPR_EXPR)
-        /* invalid operand */
-        return 1;
-
-    rv = stack[whereAmI - 1].value.integral || stack[whereAmI + 1].value.integral;
-
-    stackpop(stack, depth);      /* arg rhs */
-
-    stackpop(stack, depth);      /* me */
-
-    stackpop(stack, depth);      /* arg lhs */
-
-    srv.valuetype = ESI_EXPR_EXPR;
-
-    srv.eval = evalliteral;
-
-    srv.valuestored = ESI_LITERAL_BOOL;
-
-    srv.value.integral = rv ? 1 : 0;
-
-    srv.precedence = 1;
-
-    stackpush(stack, srv, depth);
-
-    /* we're out of way, try adding now */
-    if (!addmember(stack, depth, candidate))
-        /* Something wrong upstream */
-        return 1;
-
-    return 0;
-}
-
-int
-evaland(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
-{
-    int rv;
-    stackmember srv;
-
-    if (*depth < 3)
-        /* Not enough operands */
-        return 1;
-
-    if (whereAmI != *depth - 2)
-        /* invalid stack */
-        return 1;
-
-    if (stack[whereAmI + 1].valuetype != ESI_EXPR_EXPR ||
-            stack[whereAmI - 1].valuetype != ESI_EXPR_EXPR)
-        /* invalid operand */
-        return 1;
-
-    rv = stack[whereAmI - 1].value.integral && stack[whereAmI + 1].value.integral;
-
-    stackpop(stack, depth);      /* arg rhs */
-
-    stackpop(stack, depth);      /* me */
-
-    stackpop(stack, depth);      /* arg lhs */
-
-    srv.valuetype = ESI_EXPR_EXPR;
-
-    srv.eval = evalexpr;
-
-    srv.valuestored = ESI_LITERAL_BOOL;
-
-    srv.value.integral = rv ? 1 : 0;
-
-    srv.precedence = 1;
-
-    stackpush(stack, srv, depth);
-
-    /* we're out of way, try adding now */
-    if (!addmember(stack, depth, candidate))
-        /* Something wrong upstream */
-        return 1;
-
-    return 0;
-}
-
-int
-evallesseq(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
-{
-    int rv;
-    stackmember srv;
-
-    if (*depth < 3)
-        /* Not enough operands */
-        return 1;
-
-    if (whereAmI != *depth - 2)
-        /* invalid stack */
-        return 1;
-
-    rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]);
-
-    if (rv == -2)
-        /* invalid comparison */
-        return 1;
-
-    stackpop(stack, depth);      /* arg rhs */
-
-    stackpop(stack, depth);      /* me */
-
-    stackpop(stack, depth);      /* arg lhs */
-
-    srv.valuetype = ESI_EXPR_EXPR;
-
-    srv.eval = evalexpr;
-
-    srv.valuestored = ESI_LITERAL_BOOL;
-
-    srv.value.integral = rv <= 0 ? 1 : 0;
-
-    srv.precedence = 1;
-
-    stackpush(stack, srv, depth);
-
-    /* we're out of way, try adding now */
-    if (!addmember(stack, depth, candidate))
-        /* Something wrong upstream */
-        return 1;
-
-    /*  debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
-    return 0;
-
-}
-
-int
-evallessthan(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
-{
-    int rv;
-    stackmember srv;
-
-    if (*depth < 3)
-        /* Not enough operands */
-        return 1;
-
-    if (whereAmI != *depth - 2)
-        /* invalid stack */
-        return 1;
-
-    rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]);
-
-    if (rv == -2)
-        /* invalid comparison */
-        return 1;
-
-    stackpop(stack, depth);      /* arg rhs */
-
-    stackpop(stack, depth);      /* me */
-
-    stackpop(stack, depth);      /* arg lhs */
-
-    srv.valuetype = ESI_EXPR_EXPR;
-
-    srv.eval = evalexpr;
-
-    srv.valuestored = ESI_LITERAL_BOOL;
-
-    srv.value.integral = rv < 0 ? 1 : 0;
-
-    srv.precedence = 1;
-
-    stackpush(stack, srv, depth);
-
-    /* we're out of way, try adding now */
-    if (!addmember(stack, depth, candidate))
-        /* Something wrong upstream */
-        return 1;
-
-    /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
-    return 0;
-
-}
-
-int
-evalmoreeq(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
-{
-    int rv;
-    stackmember srv;
-
-    if (*depth < 3)
-        /* Not enough operands */
-        return 1;
-
-    if (whereAmI != *depth - 2)
-        /* invalid stack */
-        return 1;
-
-    rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]);
-
-    if (rv == -2)
-        /* invalid comparison */
-        return 1;
-
-    stackpop(stack, depth);      /* arg rhs */
-
-    stackpop(stack, depth);      /* me */
-
-    stackpop(stack, depth);      /* arg lhs */
-
-    srv.valuetype = ESI_EXPR_EXPR;
-
-    srv.eval = evalexpr;
-
-    srv.valuestored = ESI_LITERAL_BOOL;
-
-    srv.value.integral = rv >= 0 ? 1 : 0;
-
-    srv.precedence = 1;
-
-    stackpush(stack, srv, depth);
-
-    /* we're out of way, try adding now */
-    if (!addmember(stack, depth, candidate))
-        /* Something wrong upstream */
-        return 1;
-
-    /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
-    return 0;
-
-}
-
-int
-evalmorethan(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
-{
-    int rv;
-    stackmember srv;
-
-    if (*depth < 3)
-        /* Not enough operands */
-        return 1;
-
-    if (whereAmI != *depth - 2)
-        /* invalid stack */
-        return 1;
-
-    rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]);
-
-    if (rv == -2)
-        /* invalid comparison */
-        return 1;
-
-    stackpop(stack, depth); /* arg rhs */
-
-    stackpop(stack, depth); /* me */
-
-    stackpop(stack, depth); /* arg lhs */
-
-    srv.valuetype = ESI_EXPR_EXPR;
-
-    srv.eval = evalexpr;
-
-    srv.valuestored = ESI_LITERAL_BOOL;
-
-    srv.value.integral = rv > 0 ? 1 : 0;
-
-    srv.precedence = 1;
-
-    stackpush(stack, srv, depth);
-
-    /* we're out of way, try adding now */
-    if (!addmember(stack, depth, candidate))
-        /* Something wrong upstream */
-        return 1;
-
-    /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
-    return 0;
-
-}
-
-int
-evalequals(stackmember * stack, int *depth, int whereAmI,
-           stackmember * candidate)
-{
-    int rv;
-    stackmember srv;
-
-    if (*depth < 3)
-        /* Not enough operands */
-        return 1;
-
-    if (whereAmI != *depth - 2)
-        /* invalid stack */
-        return 1;
-
-    rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]);
-
-    if (rv == -2)
-        /* invalid comparison */
-        return 1;
-
-    stackpop(stack, depth); /* arg rhs */
-
-    stackpop(stack, depth); /* me */
-
-    stackpop(stack, depth); /* arg lhs */
-
-    srv.valuetype = ESI_EXPR_EXPR;
-
-    srv.eval = evalexpr;
-
-    srv.valuestored = ESI_LITERAL_BOOL;
-
-    srv.value.integral = rv ? 0 : 1;
-
-    srv.precedence = 1;
-
-    stackpush(stack, srv, depth);
-
-    /* we're out of way, try adding now */
-    if (!addmember(stack, depth, candidate))
-        /* Something wrong upstream */
-        return 1;
-
-    /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
-    return 0;
-}
-
-int
-evalnotequals(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
-{
-    int rv;
-    stackmember srv;
-
-    if (*depth < 3)
-        /* Not enough operands */
-        return 1;
-
-    if (whereAmI != *depth - 2)
-        /* invalid stack */
-        return 1;
-
-    rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]);
-
-    if (rv == -2)
-        /* invalid comparison */
-        return 1;
-
-    stackpop(stack, depth); /* arg rhs */
-
-    stackpop(stack, depth); /* me */
-
-    stackpop(stack, depth); /* arg lhs */
-
-    srv.valuetype = ESI_EXPR_EXPR;
-
-    srv.eval = evalexpr;
-
-    srv.valuestored = ESI_LITERAL_BOOL;
-
-    srv.value.integral = rv ? 1 : 0;
-
-    srv.precedence = 1;
-
-    stackpush(stack, srv, depth);
-
-    /* we're out of way, try adding now */
-    if (!addmember(stack, depth, candidate))
-        /* Something wrong upstream */
-        return 1;
-
-    /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
-    return 0;
-}
-
-int
-evalstartexpr(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
-{
-    /* debugs(86, DBG_IMPORTANT, "?("); */
-
-    if (whereAmI != *depth - 2)
-        /* invalid stack */
-        return 1;
-
-    /* Only valid when RHS is an end bracket */
-    if (candidate->valuetype != ESI_EXPR_END)
-        return 1;
-
-    --(*depth);
-
-    stack[whereAmI] = stack[(*depth)];
-
-    cleanmember(candidate);
-
-    return 0;
-}
-
-int
-evalendexpr(stackmember * /* stack */, int * /* depth */, int /* whereAmI */, stackmember * /* candidate */)
-{
-    /* Can't evaluate ) brackets */
-    return 1;
-}
-
-char const *
-trim(char const *s)
-{
-    while (*s == ' ')
-        ++s;
-
-    return s;
-}
-
-stackmember
-getsymbol(const char *s, char const **endptr)
-{
-    stackmember rv;
-    char *end;
-    char const *origs = s;
-    /* trim whitespace */
-    s = trim(s);
-    rv.eval = nullptr;     /* A literal */
-    rv.valuetype = ESI_EXPR_INVALID;
-    rv.valuestored = ESI_LITERAL_INVALID;
-    rv.precedence = 1; /* A literal */
-
-    if (('0' <= *s && *s <= '9') || *s == '-') {
-        size_t length = strspn(s, "0123456789.");
-        char const *point;
-
-        if ((point = strchr(s, '.')) && point - s < (ssize_t)length) {
-            /* floating point */
-            errno=0; /* reset errno */
-            rv.value.floating = strtod(s, &end);
-
-            if (s == end || errno) {
-                /* Couldn't convert to float */
-                debugs(86, DBG_IMPORTANT, "ERROR: failed to convert '" << s << "' to float ");
-                *endptr = origs;
-            } else {
-                debugs(86,6, "found " << rv.value.floating << " of length " << end - s);
-                *endptr = end;
-                rv.eval = evalliteral;
-                rv.valuestored = ESI_LITERAL_FLOAT;
-                rv.valuetype = ESI_EXPR_LITERAL;
-                rv.precedence = 1;
-            }
-        } else {
-            /* INT */
-            errno=0; /* reset errno */
-            rv.value.integral = strtol(s, &end, 0);
-
-            if (s == end || errno) {
-                /* Couldn't convert to int */
-                debugs(86, DBG_IMPORTANT, "ERROR: failed to convert '" << s << "' to int ");
-                *endptr = origs;
-            } else {
-                debugs(86,6, "found " << rv.value.integral << " of length " << end - s);
-                *endptr = end;
-                rv.eval = evalliteral;
-                rv.valuestored = ESI_LITERAL_INT;
-                rv.valuetype = ESI_EXPR_LITERAL;
-                rv.precedence = 1;
-            }
-        }
-    } else if ('!' == *s) {
-        if ('=' == *(s + 1)) {
-            debugs(86, 6, "found !=");
-            *endptr = s + 2;
-            rv.eval = evalnotequals;
-            rv.valuetype = ESI_EXPR_NOTEQ;
-            rv.precedence = 5;
-        } else {
-            debugs(86, 6, "found !");
-            *endptr = s + 1;
-            rv.valuetype = ESI_EXPR_NOT;
-            rv.precedence = 4;
-            rv.eval = evalnegate;
-        }
-    } else if ('\'' == *s) {
-        char const *t = s + 1;
-        debugs(86, 6, "found \'");
-
-        while (*t != '\'' && *t)
-            ++t;
-
-        if (!*t) {
-            debugs(86, DBG_IMPORTANT, "ERROR: missing end \' in '" << s << "'");
-            *endptr = origs;
-        } else {
-            *endptr = t + 1;
-            /* Special case for zero length strings */
-
-            if (t - s - 1)
-                rv.value.string = xstrndup(s + 1, t - (s + 1) + 1);
-            else
-                rv.value.string = static_cast<char *>(xcalloc(1,1));
-
-            rv.eval = evalliteral;
-
-            rv.valuestored = ESI_LITERAL_STRING;
-
-            rv.valuetype = ESI_EXPR_LITERAL;
-
-            rv.precedence = 1;
-
-            debugs(86, 6, "found  string '" << rv.value.string << "'");
-        }
-    } else if ('(' == *s) {
-        debugs(86, 6, "found subexpr start");
-        *endptr = s + 1;
-        rv.valuetype = ESI_EXPR_START;
-        rv.precedence = 5;
-        rv.eval = evalstartexpr;
-    } else if (')' == *s) {
-        debugs(86, 6, "found subexpr end");
-        *endptr = s + 1;
-        rv.valuetype = ESI_EXPR_END;
-        rv.precedence = 0;
-        rv.eval = evalendexpr;
-    } else if ('&' == *s) {
-        debugs(86, 6, "found AND");
-        *endptr = s + 1;
-        rv.valuetype = ESI_EXPR_AND;
-        rv.precedence = 3;
-        rv.eval = evaland;
-    } else if ('|' == *s) {
-        debugs(86, 6, "found OR");
-        *endptr = s + 1;
-        rv.valuetype = ESI_EXPR_OR;
-        rv.precedence = 2;
-        rv.eval = evalor;
-    } else if ('=' == *s) {
-        if ('=' == *(s + 1)) {
-            debugs(86, 6, "found equals");
-            *endptr = s + 2;
-            rv.valuetype = ESI_EXPR_EQ;
-            rv.precedence = 5;
-            rv.eval = evalequals;
-        } else {
-            debugs(86, DBG_IMPORTANT, "ERROR: invalid expr '" << s << "'");
-            *endptr = origs;
-        }
-    } else if ('<' == *s) {
-        if ('=' == *(s + 1)) {
-            debugs(86, 6, "found less-equals");
-            *endptr = s + 2;
-            rv.valuetype = ESI_EXPR_LESSEQ;
-            rv.precedence = 5;
-            rv.eval = evallesseq;
-        } else {
-            debugs(86, 6, "found less than");
-            *endptr = s + 1;
-            rv.valuetype = ESI_EXPR_LESS;
-            rv.precedence = 5;
-            rv.eval = evallessthan;
-        }
-    } else if ('>' == *s) {
-        if ('=' == *(s + 1)) {
-            debugs(86, 6, "found more-equals");
-            *endptr = s + 2;
-            rv.valuetype = ESI_EXPR_MOREEQ;
-            rv.precedence = 5;
-            rv.eval = evalmoreeq;
-        } else {
-            debugs(86, 6, "found more than");
-            *endptr = s + 1;
-            rv.valuetype = ESI_EXPR_MORE;
-            rv.precedence = 5;
-            rv.eval = evalmorethan;
-        }
-    } else if (!strncmp(s, "false", 5)) {
-        debugs(86, 5, "getsymbol: found variable result 'false'");
-        *endptr = s + 5;
-        rv.valuetype = ESI_EXPR_EXPR;
-        rv.valuestored = ESI_LITERAL_BOOL;
-        rv.value.integral = 0;
-        rv.precedence = 1;
-        rv.eval = evalexpr;
-    } else if (!strncmp(s, "true", 4)) {
-        debugs(86, 5, "getsymbol: found variable result 'true'");
-        *endptr = s + 4;
-        rv.valuetype = ESI_EXPR_EXPR;
-        rv.valuestored = ESI_LITERAL_BOOL;
-        rv.value.integral = 1;
-        rv.precedence = 1;
-        rv.eval = evalexpr;
-    } else {
-        debugs(86, DBG_IMPORTANT, "ERROR: invalid expr '" << s << "'");
-        *endptr = origs;
-    }
-
-    return rv;
-}
-
-static void
-printLiteral(std::ostream &os, const stackmember &s)
-{
-    switch (s.valuestored) {
-
-    case ESI_LITERAL_INVALID:
-        os << " Invalid ";
-        break;
-
-    case ESI_LITERAL_FLOAT:
-        os << s.value.floating;
-        break;
-
-    case ESI_LITERAL_STRING:
-        os << '\'' << s.value.string << '\'';
-        break;
-
-    case ESI_LITERAL_INT:
-        os << s.value.integral;
-        break;
-
-    case ESI_LITERAL_BOOL:
-        os << (s.value.integral ? "true" : "false");
-    }
-}
-
-static std::ostream &
-operator <<(std::ostream &os, const stackmember &s)
-{
-    switch (s.valuetype) {
-
-    case ESI_EXPR_INVALID:
-        os << " Invalid ";
-        break;
-
-    case ESI_EXPR_LITERAL:
-        printLiteral(os, s);
-        break;
-
-    case ESI_EXPR_EXPR:
-        os << (s.value.integral ? "true" : "false");
-        break;
-
-    case ESI_EXPR_OR:
-        os << "|";
-        break;
-
-    case ESI_EXPR_AND:
-        os << "&";
-        break;
-
-    case ESI_EXPR_NOT:
-        os << "!";
-        break;
-
-    case ESI_EXPR_START:
-        os << "(";
-        break;
-
-    case ESI_EXPR_END:
-        os << ")";
-        break;
-
-    case ESI_EXPR_EQ:
-        os << "==";
-        break;
-
-    case ESI_EXPR_NOTEQ:
-        os << "!=";
-        break;
-
-    case ESI_EXPR_LESS:
-        os << "<";
-        break;
-
-    case ESI_EXPR_LESSEQ:
-        os << "<=";
-        break;
-
-    case ESI_EXPR_MORE:
-        os << ">";
-        break;
-
-    case ESI_EXPR_MOREEQ:
-        os << ">=";
-        break;
-    }
-
-    return os;
-}
-
-void
-dumpstack(stackmember * stack, int depth)
-{
-    if (depth) {
-        std::ostringstream buf;
-        for (int i = 0; i < depth; ++i)
-            buf << stack[i];
-        debugs(86,1, buf.str());
-    }
-}
-
-int
-addmember(stackmember * stack, int *stackdepth, stackmember * candidate)
-{
-    if (candidate->valuetype != ESI_EXPR_LITERAL && *stackdepth > 1) {
-        /* !(!(a==b))) is why that's safe */
-        /* strictly less than until we unwind */
-
-        if (*stackdepth >= ESI_STACK_DEPTH_LIMIT)
-            throw Esi::Error("ESI expression too complex to add member");
-
-        if (candidate->precedence < stack[*stackdepth - 1].precedence ||
-                candidate->precedence < stack[*stackdepth - 2].precedence) {
-            /* must be an operator */
-
-            if (stack[*stackdepth - 2].valuetype == ESI_EXPR_LITERAL ||
-                    stack[*stackdepth - 2].valuetype == ESI_EXPR_INVALID ||
-                    stack[*stackdepth - 2].eval(stack, stackdepth,
-                                                *stackdepth - 2, candidate)) {
-                /* cleanup candidate and stack */
-                dumpstack(stack, *stackdepth);
-                cleanmember(candidate);
-                debugs(86, DBG_IMPORTANT, "ERROR: invalid expression");
-                return 0;
-            }
-        } else {
-            stackpush(stack, *candidate, stackdepth);
-        }
-    } else if (candidate->valuetype != ESI_EXPR_INVALID)
-        stackpush(stack, *candidate, stackdepth);
-
-    return 1;
-}
-
-int
-ESIExpression::Evaluate(char const *s)
-{
-    stackmember stack[ESI_STACK_DEPTH_LIMIT];
-    int stackdepth = 0;
-    char const *end;
-
-    while (*s) {
-        stackmember candidate = getsymbol(s, &end);
-
-        if (candidate.valuetype != ESI_EXPR_INVALID) {
-            assert(s != end);
-
-            if (!addmember(stack, &stackdepth, &candidate)) {
-                return 0;
-            }
-
-            s = end;
-        } else {
-            assert (s == end);
-            debugs(86, DBG_IMPORTANT, "ERROR: failed parsing expression");
-            return 0;
-        }
-    }
-
-    if (stackdepth > 1) {
-        stackmember rv;
-        rv.valuetype = ESI_EXPR_INVALID;
-        rv.precedence = 0;
-
-        if (stack[stackdepth - 2].
-                eval(stack, &stackdepth, stackdepth - 2, &rv)) {
-            /* special case - leading operator failed */
-            debugs(86, DBG_IMPORTANT, "ERROR: invalid expression");
-            return 0;
-        }
-    }
-
-    if (stackdepth == 0) {
-        /* Empty expression - evaluate to false */
-        return 0;
-    }
-
-    /* if we hit here, we think we have a valid result */
-    assert(stackdepth == 1);
-
-    assert(stack[0].valuetype == ESI_EXPR_EXPR);
-
-    return stack[0].value.integral ? 1 : 0;
-}
-
diff --git a/src/esi/Expression.h b/src/esi/Expression.h
deleted file mode 100644 (file)
index 409c006..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#ifndef SQUID_SRC_ESI_EXPRESSION_H
-#define SQUID_SRC_ESI_EXPRESSION_H
-
-class ESIExpression
-{
-
-public:
-    static int Evaluate (char const *);
-};
-
-#endif /* SQUID_SRC_ESI_EXPRESSION_H */
-
diff --git a/src/esi/Include.cc b/src/esi/Include.cc
deleted file mode 100644 (file)
index efd6759..0000000
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#include "squid.h"
-
-#if USE_SQUID_ESI
-
-#include "client_side.h"
-#include "client_side_request.h"
-#include "esi/Include.h"
-#include "esi/VarState.h"
-#include "fatal.h"
-#include "http/Stream.h"
-#include "HttpReply.h"
-#include "log/access_log.h"
-
-CBDATA_CLASS_INIT (ESIStreamContext);
-
-/* other */
-static CSCB esiBufferRecipient;
-static CSD esiBufferDetach;
-/* esiStreamContext */
-static ESIStreamContext *ESIStreamContextNew (ESIIncludePtr);
-
-/* ESI TO CONSIDER:
- * 1. retry failed upstream requests
- */
-
-/* Detach from a buffering stream
- */
-void
-esiBufferDetach (clientStreamNode *node, ClientHttpRequest *http)
-{
-    /* Detach ourselves */
-    clientStreamDetach (node, http);
-}
-
-/**
- * Write a chunk of data to a client 'socket'.
- * If the reply is present, send the reply headers down the wire too.
- *
- * Pre-condition:
- *   The request is an internal ESI subrequest.
- *   data context is not NULL
- *   There are no more entries in the stream chain.
- *   The caller is responsible for creation and deletion of the Reply headers.
- *
- \note
- * Bug 975, bug 1566 : delete rep; 2006/09/02: TS, #975
- *
- * This was causing double-deletes. Its possible that not deleting
- * it here will cause memory leaks, but if so, this delete should
- * not be reinstated or it will trigger bug #975 again - RBC 20060903
- */
-void
-esiBufferRecipient (clientStreamNode *node, ClientHttpRequest *http, HttpReply *rep, StoreIOBuffer receivedData)
-{
-    /* Test preconditions */
-    assert (node != nullptr);
-    /* ESI TODO: handle thisNode rather than asserting
-     * - it should only ever happen if we cause an
-     * abort and the callback chain loops back to
-     * here, so we can simply return. However, that
-     * itself shouldn't happen, so it stays as an
-     * assert for now. */
-    assert (cbdataReferenceValid (node));
-    assert (node->node.next == nullptr);
-    assert (http->getConn() == nullptr);
-
-    ESIStreamContext::Pointer esiStream = dynamic_cast<ESIStreamContext *>(node->data.getRaw());
-    assert (esiStream.getRaw() != nullptr);
-    /* If segments become more flexible, ignore thisNode */
-    assert (receivedData.length <= sizeof(esiStream->localbuffer->buf));
-    assert (!esiStream->finished);
-
-    debugs (86,5, "rep " << rep << " body " << receivedData.data << " len " << receivedData.length);
-    assert (node->readBuffer.offset == receivedData.offset || receivedData.length == 0);
-
-    /* trivial case */
-
-    if (http->out.offset != 0) {
-        assert(rep == nullptr);
-    } else {
-        if (rep) {
-            if (rep->sline.status() != Http::scOkay) {
-                rep = nullptr;
-                esiStream->include->includeFail (esiStream);
-                esiStream->finished = 1;
-                httpRequestFree (http);
-                return;
-            }
-
-            rep = nullptr;
-        }
-    }
-
-    if (receivedData.data && receivedData.length) {
-        http->out.offset += receivedData.length;
-
-        if (receivedData.data >= esiStream->localbuffer->buf &&
-                receivedData.data < &esiStream->localbuffer->buf[sizeof(esiStream->localbuffer->buf)]) {
-            /* original static buffer */
-
-            if (receivedData.data != esiStream->localbuffer->buf) {
-                /* But not the start of it */
-                memmove(esiStream->localbuffer->buf, receivedData.data, receivedData.length);
-            }
-
-            esiStream->localbuffer->len = receivedData.length;
-        } else {
-            assert (esiStream->buffer.getRaw() != nullptr);
-            esiStream->buffer->len = receivedData.length;
-        }
-    }
-
-    /* EOF / Read error /  aborted entry */
-    if (rep == nullptr && receivedData.data == nullptr && receivedData.length == 0) {
-        /* TODO: get stream status to test the entry for aborts */
-        debugs(86, 5, "Finished reading upstream data in subrequest");
-        esiStream->include->subRequestDone (esiStream, true);
-        esiStream->finished = 1;
-        httpRequestFree (http);
-        return;
-    }
-
-    switch (clientStreamStatus (node, http)) {
-
-    case STREAM_UNPLANNED_COMPLETE:
-    case STREAM_COMPLETE: /* ok */
-        debugs(86, 3, "ESI subrequest finished OK");
-        esiStream->include->subRequestDone (esiStream, true);
-        esiStream->finished = 1;
-        httpRequestFree (http);
-        return;
-
-    case STREAM_FAILED:
-        debugs(86, DBG_IMPORTANT, "ERROR: ESI subrequest failed transfer");
-        esiStream->include->includeFail (esiStream);
-        esiStream->finished = 1;
-        httpRequestFree (http);
-        return;
-
-    case STREAM_NONE: {
-        StoreIOBuffer tempBuffer;
-
-        if (!esiStream->buffer.getRaw()) {
-            esiStream->buffer = esiStream->localbuffer;
-        }
-
-        esiStream->buffer = esiStream->buffer->tail();
-
-        if (esiStream->buffer->len) {
-            esiStream->buffer->next = new ESISegment;
-            esiStream->buffer = esiStream->buffer->next;
-        }
-
-        tempBuffer.offset = http->out.offset;
-        tempBuffer.length = sizeof (esiStream->buffer->buf);
-        tempBuffer.data = esiStream->buffer->buf;
-        /* now just read into 'buffer' */
-        clientStreamRead (node, http, tempBuffer);
-        debugs(86, 5, "Requested more data for ESI subrequest");
-    }
-
-    break;
-
-    default:
-        fatal ("Hit unreachable code in esiBufferRecipient\n");
-    }
-
-}
-
-/* esiStream functions */
-ESIStreamContext::~ESIStreamContext()
-{
-    freeResources();
-}
-
-void
-ESIStreamContext::freeResources()
-{
-    debugs(86, 5, "Freeing stream context resources.");
-    buffer = nullptr;
-    localbuffer = nullptr;
-    include = nullptr;
-}
-
-ESIStreamContext *
-ESIStreamContextNew (ESIIncludePtr include)
-{
-    ESIStreamContext *rv = new ESIStreamContext;
-    rv->include = include;
-    return rv;
-}
-
-/* ESIInclude */
-ESIInclude::~ESIInclude()
-{
-    debugs(86, 5, "ESIInclude::Free " << this);
-    ESISegmentFreeList (srccontent);
-    ESISegmentFreeList (altcontent);
-    cbdataReferenceDone (varState);
-    safe_free (srcurl);
-    safe_free (alturl);
-}
-
-void
-ESIInclude::finish()
-{
-    parent = nullptr;
-}
-
-ESIElement::Pointer
-ESIInclude::makeCacheable() const
-{
-    return new ESIInclude (*this);
-}
-
-ESIElement::Pointer
-ESIInclude::makeUsable(esiTreeParentPtr newParent, ESIVarState &newVarState) const
-{
-    ESIInclude *resultI = new ESIInclude (*this);
-    ESIElement::Pointer result = resultI;
-    resultI->parent = newParent;
-    resultI->varState = cbdataReference (&newVarState);
-
-    if (resultI->srcurl)
-        resultI->src = ESIStreamContextNew (resultI);
-
-    if (resultI->alturl)
-        resultI->alt = ESIStreamContextNew (resultI);
-
-    return result;
-}
-
-ESIInclude::ESIInclude(ESIInclude const &old) :
-    varState(nullptr),
-    srcurl(nullptr),
-    alturl(nullptr),
-    parent(nullptr),
-    started(false),
-    sent(false)
-{
-    memset(&flags, 0, sizeof(flags));
-    flags.onerrorcontinue = old.flags.onerrorcontinue;
-
-    if (old.srcurl)
-        srcurl = xstrdup(old.srcurl);
-
-    if (old.alturl)
-        alturl = xstrdup(old.alturl);
-}
-
-void
-ESIInclude::prepareRequestHeaders(HttpHeader &tempheaders, ESIVarState *vars)
-{
-    tempheaders.update(&vars->header());
-    tempheaders.removeHopByHopEntries();
-}
-
-void
-ESIInclude::Start (ESIStreamContext::Pointer stream, char const *url, ESIVarState *vars)
-{
-    if (!stream.getRaw())
-        return;
-
-    HttpHeader tempheaders(hoRequest);
-
-    prepareRequestHeaders(tempheaders, vars);
-
-    /* Ensure variable state is clean */
-    vars->feedData(url, strlen (url));
-
-    /* tempUrl is eaten by the request */
-    char const *tempUrl = vars->extractChar ();
-
-    debugs(86, 5, "ESIIncludeStart: Starting subrequest with url '" << tempUrl << "'");
-    const auto mx = MasterXaction::MakePortless<XactionInitiator::initEsi>();
-    if (clientBeginRequest(Http::METHOD_GET, tempUrl, esiBufferRecipient, esiBufferDetach, stream, &tempheaders, stream->localbuffer->buf, HTTP_REQBUF_SZ, mx)) {
-        debugs(86, DBG_CRITICAL, "ERROR: starting new ESI subrequest failed");
-    }
-
-    tempheaders.clean();
-}
-
-ESIInclude::ESIInclude(esiTreeParentPtr aParent, int attrcount, char const **attr, ESIContext *aContext) :
-    varState(nullptr),
-    srcurl(nullptr),
-    alturl(nullptr),
-    parent(aParent),
-    started(false),
-    sent(false)
-{
-    assert (aContext);
-    memset(&flags, 0, sizeof(flags));
-
-    for (int i = 0; i < attrcount && attr[i]; i += 2) {
-        if (!strcmp(attr[i],"src")) {
-            /* Start a request for thisNode url */
-            debugs(86, 5, "ESIIncludeNew: Requesting source '" << attr[i+1] << "'");
-
-            /* TODO: don't assert on thisNode, ignore the duplicate */
-            assert (src.getRaw() == nullptr);
-            src = ESIStreamContextNew (this);
-            assert (src.getRaw() != nullptr);
-            srcurl = xstrdup(attr[i+1]);
-        } else if (!strcmp(attr[i],"alt")) {
-            /* Start a secondary request for thisNode url */
-            /* TODO: make a config parameter to wait on requesting alt's
-             * for the src to fail
-             */
-            debugs(86, 5, "ESIIncludeNew: Requesting alternate '" << attr[i+1] << "'");
-
-            assert (alt.getRaw() == nullptr); /* TODO: fix? */
-            alt = ESIStreamContextNew (this);
-            assert (alt.getRaw() != nullptr);
-            alturl = xstrdup(attr[i+1]);
-        } else if (!strcmp(attr[i],"onerror")) {
-            if (!strcmp(attr[i+1], "continue")) {
-                flags.onerrorcontinue = 1;
-            } else {
-                /* ignore mistyped attributes */
-                debugs(86, DBG_IMPORTANT, "ERROR: invalid value for onerror='" << attr[i+1] << "'");
-            }
-        } else {
-            /* ignore mistyped attributes. TODO:? error on these for user feedback - config parameter needed
-             */
-        }
-    }
-
-    varState = cbdataReference(aContext->varState);
-}
-
-void
-ESIInclude::start()
-{
-    /* prevent freeing ourselves */
-    ESIIncludePtr foo(this);
-
-    if (started)
-        return;
-
-    started = true;
-
-    if (src.getRaw()) {
-        Start (src, srcurl, varState);
-        Start (alt, alturl, varState);
-    } else {
-        alt = nullptr;
-
-        debugs(86, DBG_IMPORTANT, "ESIIncludeNew: esi:include with no src attributes");
-
-        flags.failed = 1;
-    }
-}
-
-void
-ESIInclude::render(ESISegment::Pointer output)
-{
-    if (sent)
-        return;
-
-    ESISegment::Pointer myout;
-
-    debugs(86, 5, "ESIIncludeRender: Rendering include " << this);
-
-    assert (flags.finished || (flags.failed && flags.onerrorcontinue));
-
-    if (flags.failed && flags.onerrorcontinue) {
-        return;
-    }
-
-    /* Render the content */
-    if (srccontent.getRaw()) {
-        myout = srccontent;
-        srccontent = nullptr;
-    } else if (altcontent.getRaw()) {
-        myout = altcontent;
-        altcontent = nullptr;
-    } else
-        fatal ("ESIIncludeRender called with no content, and no failure!\n");
-
-    assert (output->next == nullptr);
-
-    output->next = myout;
-
-    sent = true;
-}
-
-esiProcessResult_t
-ESIInclude::process(int)
-{
-    /* Prevent refcount race leading to free */
-    Pointer me (this);
-    start();
-    debugs(86, 5, "ESIIncludeRender: Processing include " << this);
-
-    if (flags.failed) {
-        if (flags.onerrorcontinue)
-            return ESI_PROCESS_COMPLETE;
-        else
-            return ESI_PROCESS_FAILED;
-    }
-
-    if (!flags.finished) {
-        if (flags.onerrorcontinue)
-            return ESI_PROCESS_PENDING_WONTFAIL;
-        else
-            return ESI_PROCESS_PENDING_MAYFAIL;
-    }
-
-    return ESI_PROCESS_COMPLETE;
-}
-
-void
-ESIInclude::includeFail (ESIStreamContext::Pointer stream)
-{
-    subRequestDone (stream, false);
-}
-
-bool
-ESIInclude::dataNeeded() const
-{
-    return !(flags.finished || flags.failed);
-}
-
-void
-ESIInclude::subRequestDone (ESIStreamContext::Pointer stream, bool success)
-{
-    if (!dataNeeded())
-        return;
-
-    if (stream == src) {
-        debugs(86, 3, "ESIInclude::subRequestDone: " << srcurl);
-
-        if (success) {
-            /* copy the lead segment */
-            debugs(86, 3, "ESIIncludeSubRequestDone: Src OK - include PASSED.");
-            assert (!srccontent.getRaw());
-            ESISegment::ListTransfer (stream->localbuffer, srccontent);
-            /* we're done! */
-            flags.finished = 1;
-        } else {
-            /* Fail if there is no alt being retrieved */
-            debugs(86, 3, "ESIIncludeSubRequestDone: Src FAILED");
-
-            if (!(alt.getRaw() || altcontent.getRaw())) {
-                debugs(86, 3, "ESIIncludeSubRequestDone: Include FAILED - No ALT");
-                flags.failed = 1;
-            } else if (altcontent.getRaw()) {
-                debugs(86, 3, "ESIIncludeSubRequestDone: Include PASSED - ALT already Complete");
-                /* ALT was already retrieved, we are done */
-                flags.finished = 1;
-            }
-        }
-
-        src = nullptr;
-    } else if (stream == alt) {
-        debugs(86, 3, "ESIInclude::subRequestDone: " << alturl);
-
-        if (success) {
-            debugs(86, 3, "ESIIncludeSubRequestDone: ALT OK.");
-            /* copy the lead segment */
-            assert (!altcontent.getRaw());
-            ESISegment::ListTransfer (stream->localbuffer, altcontent);
-            /* we're done! */
-
-            if (!(src.getRaw() || srccontent.getRaw())) {
-                /* src already failed, kick ESI processor */
-                debugs(86, 3, "ESIIncludeSubRequestDone: Include PASSED - SRC already failed.");
-                flags.finished = 1;
-            }
-        } else {
-            if (!(src.getRaw() || srccontent.getRaw())) {
-                debugs(86, 3, "ESIIncludeSubRequestDone: ALT FAILED, Include FAILED - SRC already failed");
-                /* src already failed */
-                flags.failed = 1;
-            }
-        }
-
-        alt = nullptr;
-    } else {
-        fatal ("ESIIncludeSubRequestDone: non-owned stream found!\n");
-    }
-
-    if (flags.finished || flags.failed) {
-        /* Kick ESI Processor */
-        debugs (86, 5, "ESIInclude " << this <<
-                " SubRequest " << stream.getRaw() <<
-                " completed, kicking processor , status " <<
-                (flags.finished ? "OK" : "FAILED"));
-        /* There is a race condition - and we have no reproducible test case -
-         * during a subrequest the parent will get set to NULL, which is not
-         * meant to be possible. Rather than killing squid, we let it leak
-         * memory but complain in the log.
-         *
-         * Someone wanting to debug this could well start by running squid with
-         * a hardware breakpoint set to this location.
-         * Its probably due to parent being set to null - by a call to
-         * 'this.finish' while the subrequest is still not completed.
-         */
-        if (parent.getRaw() == nullptr) {
-            debugs(86, DBG_CRITICAL, "ERROR: Squid Bug #951: ESIInclude::subRequestDone: Sub request completed "
-                   "after finish() called and parent unlinked. Unable to "
-                   "continue handling the request, and may be memory leaking. "
-                   "See http://www.squid-cache.org/bugs/show_bug.cgi?id=951 - we "
-                   "are looking for a reproducible test case. This will require "
-                   "an ESI template with includes, probably with alt-options, "
-                   "and we're likely to need traffic dumps to allow us to "
-                   "reconstruct the exact tcp handling sequences to trigger this "
-                   "rather elusive bug.");
-            return;
-        }
-        assert (parent.getRaw());
-
-        if (!flags.failed) {
-            sent = true;
-            parent->provideData (srccontent.getRaw() ? srccontent:altcontent,this);
-
-            if (srccontent.getRaw())
-                srccontent = nullptr;
-            else
-                altcontent = nullptr;
-        } else if (flags.onerrorcontinue) {
-            /* render nothing but inform of completion */
-
-            if (!sent) {
-                sent = true;
-                parent->provideData (new ESISegment, this);
-            } else
-                assert (0);
-        } else
-            parent->fail(this, "esi:include could not be completed.");
-    }
-}
-
-#endif /* USE_SQUID_ESI */
-
diff --git a/src/esi/Include.h b/src/esi/Include.h
deleted file mode 100644 (file)
index 5830952..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#ifndef SQUID_SRC_ESI_INCLUDE_H
-#define SQUID_SRC_ESI_INCLUDE_H
-
-#include "esi/Context.h"
-#include "esi/Element.h"
-#include "esi/Segment.h"
-#include "HttpHeader.h"
-
-class ESIInclude;
-typedef RefCount<ESIInclude> ESIIncludePtr;
-
-class ESIStreamContext : public RefCountable
-{
-    CBDATA_CLASS(ESIStreamContext);
-
-public:
-    typedef RefCount<ESIStreamContext> Pointer;
-    ESIStreamContext();
-    ~ESIStreamContext() override;
-    void freeResources();
-    int finished;
-    ESIIncludePtr include;
-    ESISegment::Pointer localbuffer;
-    ESISegment::Pointer buffer;
-};
-
-class ESIInclude : public ESIElement
-{
-    MEMPROXY_CLASS(ESIInclude);
-
-public:
-    ESIInclude(esiTreeParentPtr, int attributes, const char **attr, ESIContext *);
-    ~ESIInclude() override;
-    void render(ESISegment::Pointer) override;
-    esiProcessResult_t process (int dovars) override;
-    Pointer makeCacheable() const override;
-    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const override;
-    void subRequestDone (ESIStreamContext::Pointer, bool);
-
-    struct {
-        unsigned int onerrorcontinue:1; /* on error return zero data */
-        unsigned int failed:1; /* Failed to process completely */
-        unsigned int finished:1; /* Finished getting subrequest data */
-    } flags;
-    ESIStreamContext::Pointer src;
-    ESIStreamContext::Pointer alt;
-    ESISegment::Pointer srccontent;
-    ESISegment::Pointer altcontent;
-    ESIVarState *varState;
-    char *srcurl, *alturl;
-    void includeFail(ESIStreamContext::Pointer);
-    void finish() override;
-
-private:
-    void Start (ESIStreamContext::Pointer, char const *, ESIVarState *);
-    esiTreeParentPtr parent;
-    void start();
-    bool started;
-    bool sent;
-    ESIInclude(ESIInclude const &);
-    bool dataNeeded() const;
-    void prepareRequestHeaders(HttpHeader &tempheaders, ESIVarState *vars);
-};
-
-#endif /* SQUID_SRC_ESI_INCLUDE_H */
-
diff --git a/src/esi/Libxml2Parser.cc b/src/esi/Libxml2Parser.cc
deleted file mode 100644 (file)
index 236a374..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-/*
- * The ESI Libxml2 parser is Copyright (c) 2004 by Joachim Bauch
- * http://www.joachim-bauch.de
- * mail@joachim-bauch.de
- */
-
-#include "squid.h"
-
-#if USE_SQUID_ESI && HAVE_LIBXML2
-
-#include "base/RunnersRegistry.h"
-#include "esi/Libxml2Parser.h"
-
-#include <memory>
-
-namespace Esi
-{
-
-class Libxml2Rr : public RegisteredRunner
-{
-public:
-    void finalizeConfig() override
-    {
-        registration.reset(new ESIParser::Register("libxml2", &ESILibxml2Parser::NewParser));
-    }
-
-private:
-    std::unique_ptr<ESIParser::Register> registration;
-};
-
-}
-
-DefineRunnerRegistratorIn(Esi, Libxml2Rr);
-
-// the global document that will store the resolved entity
-// definitions
-static htmlDocPtr entity_doc = nullptr;
-
-EsiParserDefinition(ESILibxml2Parser);
-
-// the SAX callback functions
-static void
-esi_startElementSAXFunc(void * ctx, const xmlChar * name, const xmlChar ** atts)
-{
-    int count=0;
-    xmlChar **tmp = (xmlChar **)atts;
-
-    while (tmp && *tmp != nullptr) {
-        ++count;
-        ++tmp;
-    }
-
-    // we increased on every key and value
-    count /= 2;
-
-    ESILibxml2Parser *p = (ESILibxml2Parser *)ctx;
-
-    p->getClient()->start((const char *)name, (const char **)atts, count);
-}
-
-static void
-esi_endElementSAXFunc(void *ctx, const xmlChar *name)
-{
-    ESILibxml2Parser *p = (ESILibxml2Parser *)ctx;
-    p->getClient()->end((const char *)name);
-}
-
-static void
-esi_commentSAXFunc(void *ctx, const xmlChar *value)
-{
-    ESILibxml2Parser *p = (ESILibxml2Parser *)ctx;
-    p->getClient()->parserComment((const char *)value);
-}
-
-static void
-esi_charactersSAXFunc(void *ctx, const xmlChar *ch, int len)
-{
-    ESILibxml2Parser *p = (ESILibxml2Parser *)ctx;
-    p->getClient()->parserDefault((const char *)ch, len);
-}
-
-static xmlEntityPtr
-esi_getEntitySAXFunc(void * /* ctx */, const xmlChar *name)
-{
-    xmlEntityPtr res = xmlGetDocEntity(entity_doc, name);
-
-    if (res == nullptr) {
-        const htmlEntityDesc *ent = htmlEntityLookup(name);
-
-        if (ent != nullptr) {
-            char tmp[32];
-            snprintf(tmp, 32, "&#%d;", ent->value);
-            res = xmlAddDocEntity(entity_doc, (const xmlChar *)name, XML_INTERNAL_GENERAL_ENTITY, nullptr, nullptr, (const xmlChar *)tmp);
-        }
-    }
-
-    return res;
-}
-
-ESILibxml2Parser::ESILibxml2Parser(ESIParserClient *aClient) : theClient (aClient)
-{
-    xmlSAXHandler sax;
-    xmlInitParser();
-    memset(&sax, 0, sizeof(sax));
-    sax.startElement = esi_startElementSAXFunc;
-    sax.endElement = esi_endElementSAXFunc;
-    sax.comment = esi_commentSAXFunc;
-    sax.characters = esi_charactersSAXFunc;
-    sax.getEntity = esi_getEntitySAXFunc;
-
-    /* TODO: grab the document encoding from the headers */
-    parser = xmlCreatePushParserCtxt(&sax, static_cast<void *>(this), nullptr, 0, nullptr);
-
-    if (entity_doc == nullptr)
-        entity_doc = htmlNewDoc(nullptr, nullptr);
-}
-
-ESILibxml2Parser::~ESILibxml2Parser()
-{
-    xmlFreeParserCtxt(parser);
-    parser = nullptr;
-}
-
-bool
-ESILibxml2Parser::parse(char const *dataToParse, size_t const lengthOfData, bool const endOfStream)
-{
-    return (xmlParseChunk(parser, dataToParse, lengthOfData, endOfStream) == 0);
-}
-
-long int
-ESILibxml2Parser::lineNumber() const
-{
-    return (long int)xmlSAX2GetLineNumber(parser);
-}
-
-char const *
-ESILibxml2Parser::errorString() const
-{
-    const auto error = xmlGetLastError();
-
-    if (error == nullptr)
-        return nullptr;
-
-    return error->message;
-}
-
-#endif /* USE_SQUID_ESI */
-
diff --git a/src/esi/Libxml2Parser.h b/src/esi/Libxml2Parser.h
deleted file mode 100644 (file)
index f1f9179..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-/*
- * The ESI Libxml2 parser is Copyright (c) 2004 by Joachim Bauch
- * http://www.joachim-bauch.de
- * mail@joachim-bauch.de
- */
-
-#ifndef SQUID_SRC_ESI_LIBXML2PARSER_H
-#define SQUID_SRC_ESI_LIBXML2PARSER_H
-
-#if USE_SQUID_ESI && HAVE_LIBXML2
-
-#include "esi/Parser.h"
-// workaround for definition of "free" that prevents include of
-// parser.h from libxml2 without errors
-#ifdef free
-#define OLD_FREE free
-#undef free
-#endif
-
-#if __clang__
-// workaround for clang complaining of unknown attributes in libxml2 on fedora22
-#ifdef LIBXML_ATTR_ALLOC_SIZE
-#undef LIBXML_ATTR_ALLOC_SIZE
-#endif
-#define LIBXML_ATTR_ALLOC_SIZE(x)
-#endif /* __clang__ */
-
-#if HAVE_LIBXML_PARSER_H
-#include <libxml/parser.h>
-#endif
-#if HAVE_LIBXML_HTMLPARSER_H
-#include <libxml/HTMLparser.h>
-#endif
-#if HAVE_LIBXML_HTMLTREE_H
-#include <libxml/HTMLtree.h>
-#endif
-
-#ifdef OLD_FREE
-#define free OLD_FREE
-#endif
-
-class ESILibxml2Parser : public ESIParser
-{
-
-public:
-    ESILibxml2Parser(ESIParserClient *);
-    ~ESILibxml2Parser() override;
-    /* true on success */
-    bool parse(char const *dataToParse, size_t const lengthOfData, bool const endOfStream) override;
-    long int lineNumber() const override;
-    char const * errorString() const override;
-
-    ESIParserClient *getClient() { return theClient; }
-
-    EsiParserDeclaration;
-
-private:
-    mutable xmlParserCtxtPtr parser; /* our parser */
-
-    ESIParserClient *theClient;
-};
-
-#endif /* USE_SQUID_ESI */
-
-#endif /* SQUID_SRC_ESI_LIBXML2PARSER_H */
-
diff --git a/src/esi/Literal.h b/src/esi/Literal.h
deleted file mode 100644 (file)
index 7326784..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#ifndef SQUID_SRC_ESI_LITERAL_H
-#define SQUID_SRC_ESI_LITERAL_H
-
-#include "esi/Element.h"
-
-class ESIContext;
-
-class esiLiteral : public ESIElement
-{
-    MEMPROXY_CLASS(esiLiteral);
-
-public:
-    esiLiteral(ESISegment::Pointer);
-    esiLiteral(ESIContext *, const char *s, int len);
-    ~esiLiteral() override;
-
-    void render(ESISegment::Pointer) override;
-    esiProcessResult_t process (int dovars) override;
-    Pointer makeCacheable() const override;
-    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const override;
-    /* optimise copies away later */
-    ESISegment::Pointer buffer;
-
-    struct {
-        unsigned int donevars:1;
-    } flags;
-
-    ESIVarState *varState;
-    void finish() override;
-
-private:
-    esiLiteral(esiLiteral const &);
-};
-
-#endif /* SQUID_SRC_ESI_LITERAL_H */
-
diff --git a/src/esi/Makefile.am b/src/esi/Makefile.am
deleted file mode 100644 (file)
index 3c73fcd..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-## Copyright (C) 1996-2023 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.
-##
-
-include $(top_srcdir)/src/Common.am
-
-noinst_LTLIBRARIES = libesi.la
-
-ESI_PARSER_SOURCES =
-
-if ENABLE_LIBEXPAT
-ESI_PARSER_SOURCES += \
-       ExpatParser.cc \
-       ExpatParser.h
-endif
-
-if ENABLE_LIBXML2
-ESI_PARSER_SOURCES += \
-       Libxml2Parser.cc \
-       Libxml2Parser.h
-endif
-
-libesi_la_SOURCES = \
-       $(ESI_PARSER_SOURCES) \
-       Assign.cc \
-       Assign.h \
-       Attempt.h \
-       Context.cc \
-       Context.h \
-       Element.h \
-       Esi.cc \
-       Esi.h \
-       Except.h \
-       Expression.cc \
-       Expression.h \
-       Include.cc \
-       Include.h \
-       Literal.h \
-       Parser.cc \
-       Parser.h \
-       Segment.cc \
-       Segment.h \
-       Sequence.cc \
-       Sequence.h \
-       Var.h \
-       VarState.cc \
-       VarState.h
diff --git a/src/esi/Parser.cc b/src/esi/Parser.cc
deleted file mode 100644 (file)
index a0a21c9..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#include "squid.h"
-#include "debug/Stream.h"
-#include "esi/Parser.h"
-#include "fatal.h"
-
-char *ESIParser::Type = nullptr;
-ESIParser::Register *ESIParser::Parser = nullptr;
-
-std::list<ESIParser::Register *> &
-ESIParser::GetRegistry()
-{
-    static std::list<ESIParser::Register *> parsers;
-    return parsers;
-}
-
-ESIParser::Pointer
-ESIParser::NewParser(ESIParserClient *aClient)
-{
-    if (!Parser) {
-        // if esi_parser is configured, use that
-        const char *selectParserName = Type;
-        if (!selectParserName || strcasecmp(selectParserName, "auto") == 0) {
-#if HAVE_LIBXML2
-            // libxml2 is the more secure. prefer when possible
-            selectParserName = "libxml2";
-#else
-            // expat is more widely available
-            selectParserName = "expat";
-#endif
-        }
-
-        for (auto *p : GetRegistry()) {
-            if (p && strcasecmp(p->name, selectParserName) == 0)
-                Parser = p;
-        }
-
-        if (!Parser)
-            fatalf("Unknown ESI Parser type '%s'", selectParserName);
-        debugs(86, 2, "selected ESI parser: " << Parser->name);
-    }
-
-    return (Parser->newParser)(aClient);
-}
-
-ESIParser::Register::Register(const char *_name, ESIParser::Pointer (*_newParser)(ESIParserClient *aClient)) : name(_name), newParser(_newParser)
-{
-    ESIParser::GetRegistry().emplace_back(this);
-}
-
-ESIParser::Register::~Register()
-{
-    ESIParser::GetRegistry().remove(this);
-}
-
diff --git a/src/esi/Parser.h b/src/esi/Parser.h
deleted file mode 100644 (file)
index 5153581..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#ifndef SQUID_SRC_ESI_PARSER_H
-#define SQUID_SRC_ESI_PARSER_H
-
-#include "base/RefCount.h"
-
-#include <list>
-
-class ESIParserClient
-{
-public:
-    virtual void start(const char *el, const char **attr, size_t attrCount) = 0;
-    virtual void end(const char *el) = 0;
-    virtual void parserDefault (const char *s, int len) =0;
-    virtual void parserComment (const char *s) = 0;
-    virtual ~ESIParserClient() {};
-};
-
-class ESIParser : public RefCountable
-{
-public:
-    class Register;
-    typedef RefCount<ESIParser> Pointer;
-
-    static void registerParser(const char *name, Pointer (*new_func)(ESIParserClient *aClient));
-    static Pointer NewParser(ESIParserClient *aClient);
-    static char *Type;
-
-    /**
-     \retval true      on success
-     \retval false     on what?
-     */
-    virtual bool parse(char const *dataToParse, size_t const lengthOfData, bool const endOfStream) = 0;
-
-    virtual long int lineNumber() const =0;
-    virtual char const * errorString() const =0;
-
-protected:
-    ESIParser() {};
-
-private:
-    static Register *Parser;
-    static std::list<Register *> & GetRegistry();
-};
-
-class ESIParser::Register
-{
-
-public:
-    Register(const char *_name, ESIParser::Pointer (*_newParser)(ESIParserClient *aClient));
-    ~Register();
-
-    const char *name;
-    ESIParser::Pointer (*newParser)(ESIParserClient *aClient);
-};
-
-#define EsiParserDefinition(ThisClass) \
-    ESIParser::Pointer ThisClass::NewParser(ESIParserClient *aClient) \
-    { \
-    return new ThisClass (aClient); \
-    }
-
-#define EsiParserDeclaration \
-    static ESIParser::Pointer NewParser(ESIParserClient *aClient)
-
-#endif /* SQUID_SRC_ESI_PARSER_H */
-
diff --git a/src/esi/Segment.cc b/src/esi/Segment.cc
deleted file mode 100644 (file)
index f606572..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#include "squid.h"
-#include "debug/Stream.h"
-#include "esi/Segment.h"
-#include "SquidString.h"
-
-CBDATA_CLASS_INIT(ESISegment);
-
-void
-ESISegmentFreeList (ESISegment::Pointer &head)
-{
-    while (head.getRaw()) {
-        ESISegment::Pointer temp = head;
-        head = head->next;
-        temp->next = nullptr;
-    }
-}
-
-size_t
-ESISegment::space() const
-{
-    assert (len <= sizeof(buf));
-    return sizeof (buf) - len;
-}
-
-void
-ESISegment::adsorbList (ESISegment::Pointer from)
-{
-    assert (next.getRaw() == nullptr);
-    assert (from.getRaw() != nullptr);
-    /* prevent worst case */
-    assert (!(len == 0 && from->len == space() ));
-    Pointer copyFrom = from;
-
-    while (copyFrom.getRaw() && space() >= copyFrom->len) {
-        assert (append (copyFrom) == copyFrom->len);
-        copyFrom = copyFrom->next;
-    }
-
-    next = copyFrom;
-}
-
-void
-ESISegment::ListTransfer (ESISegment::Pointer &from, ESISegment::Pointer &to)
-{
-    if (!to.getRaw()) {
-        to = from;
-        from = nullptr;
-        return;
-    }
-
-    ESISegment::Pointer temp = to->tail();
-    temp->adsorbList (from);
-    from = nullptr;
-}
-
-size_t
-ESISegment::listLength() const
-{
-    size_t result = 0;
-    ESISegment const* temp = this;
-
-    while (temp) {
-        result += temp->len;
-        temp = temp->next.getRaw();
-    }
-
-    return result;
-}
-
-char *
-ESISegment::listToChar() const
-{
-    size_t length = listLength();
-    char *rv = (char *)xmalloc (length + 1);
-    assert (rv);
-    rv [length] = '\0';
-
-    ESISegment::Pointer temp = this;
-    size_t pos = 0;
-
-    while (temp.getRaw()) {
-        memcpy(&rv[pos], temp->buf, temp->len);
-        pos += temp->len;
-        temp = temp->next;
-    }
-
-    return rv;
-}
-
-void
-ESISegment::listAppend (char const *s, size_t length)
-{
-    assert (next.getRaw() == nullptr);
-    ESISegment::Pointer output = this;
-    /* copy the string to output */
-    size_t pos=0;
-
-    while (pos < length) {
-        if (output->space() == 0) {
-            assert (output->next.getRaw() == nullptr);
-            output->next = new ESISegment;
-            output = output->next;
-        }
-
-        pos += output->append(s + pos, length - pos);
-    }
-}
-
-void
-ESISegment::ListAppend (ESISegment::Pointer &head, char const *s, size_t len)
-{
-    if (!head.getRaw())
-        head = new ESISegment;
-
-    head->tail()->listAppend (s, len);
-}
-
-/* XXX: if needed, make this iterative */
-ESISegment::Pointer
-ESISegment::cloneList () const
-{
-    ESISegment::Pointer result = new ESISegment (*this);
-    result->next = next.getRaw() ? next->cloneList() : nullptr;
-    return result;
-}
-
-size_t
-ESISegment::append(char const *appendBuffer, size_t appendLength)
-{
-    size_t toCopy = min(appendLength, space());
-    memcpy(&buf[len], appendBuffer, toCopy);
-    len += toCopy;
-    return toCopy;
-}
-
-size_t
-ESISegment::append(ESISegment::Pointer from)
-{
-    return append (from->buf, from->len);
-}
-
-ESISegment const *
-ESISegment::tail() const
-{
-    ESISegment const *result = this;
-
-    while (result->next.getRaw())
-        result = result->next.getRaw();
-
-    return result;
-}
-
-ESISegment *
-ESISegment::tail()
-{
-    ESISegment::Pointer result = this;
-
-    while (result->next.getRaw())
-        result = result->next;
-
-    return result.getRaw();
-}
-
-ESISegment::ESISegment(ESISegment const &old) : len (0), next(nullptr)
-{
-    append (old.buf, old.len);
-}
-
-void
-ESISegment::dumpToLog() const
-{
-    ESISegment::Pointer temp = this;
-
-    while (temp.getRaw()) {
-        temp->dumpOne();
-        temp = temp->next;
-    }
-}
-
-void
-ESISegment::dumpOne() const
-{
-    String temp;
-    temp.assign(buf, len);
-    debugs(86, 9, "ESISegment::dumpOne: \"" << temp << "\"");
-}
-
diff --git a/src/esi/Segment.h b/src/esi/Segment.h
deleted file mode 100644 (file)
index 74226ba..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#ifndef SQUID_SRC_ESI_SEGMENT_H
-#define SQUID_SRC_ESI_SEGMENT_H
-
-/* TODO: Factor the store memory segment management into a reusable code block
- * or perhaps use membuffers here?
- */
-
-#include "base/RefCount.h"
-#include "cbdata.h"
-#include "http/forward.h"
-#include "SquidString.h"
-
-class ESISegment : public RefCountable
-{
-    CBDATA_CLASS(ESISegment);
-
-public:
-    typedef RefCount<ESISegment> Pointer;
-    static void ListAppend (Pointer &, char const *, size_t);
-    static void ListTransfer (Pointer &from, Pointer &to);
-
-    ESISegment() : len(0), next(nullptr) {*buf = 0;}
-    ESISegment(ESISegment const &);
-    ~ESISegment() override {}
-
-    ESISegment::Pointer cloneList() const;
-    char *listToChar() const;
-    void listAppend (char const *s, size_t length);
-    void adsorbList (ESISegment::Pointer from);
-    size_t space() const;
-
-    char buf[HTTP_REQBUF_SZ];
-    size_t len; /* how much data has been pushed into this */
-    Pointer next;
-    size_t append(char const *, size_t);
-    size_t append (Pointer);
-    ESISegment const *tail() const;
-    ESISegment *tail();
-    void dumpToLog() const;
-
-private:
-    size_t listLength()const;
-    void dumpOne() const;
-};
-
-void ESISegmentFreeList (ESISegment::Pointer &head);
-
-#endif /* SQUID_SRC_ESI_SEGMENT_H */
-
diff --git a/src/esi/Sequence.cc b/src/esi/Sequence.cc
deleted file mode 100644 (file)
index bf899aa..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#include "squid.h"
-#include "debug/Stream.h"
-#include "fatal.h"
-
-/* MS Visual Studio Projects are monolithic, so we need the following
- * #if to exclude the ESI code from compile process when not needed.
- */
-#if (USE_SQUID_ESI == 1)
-
-#include "esi/Attempt.h"
-#include "esi/Except.h"
-#include "esi/Literal.h"
-#include "esi/Sequence.h"
-
-class esiExcept;
-
-esiSequence::~esiSequence ()
-{
-    debugs(86, 5, "esiSequence::~esiSequence " << this);
-    FinishAllElements(elements); // finish if not already done
-}
-
-esiSequence::esiSequence(esiTreeParentPtr aParent, bool incrementalFlag) :
-    elements(),
-    processedcount(0),
-    parent(aParent),
-    mayFail_(true),
-    failed(false),
-    provideIncrementalData(incrementalFlag),
-    processing(false),
-    processingResult(ESI_PROCESS_COMPLETE),
-    nextElementToProcess_(0)
-{
-    memset(&flags, 0, sizeof(flags));
-}
-
-size_t
-esiSequence::nextElementToProcess() const
-{
-    return nextElementToProcess_;
-}
-
-void
-esiSequence::nextElementToProcess(size_t const &aSizeT)
-{
-    nextElementToProcess_ = aSizeT;
-}
-
-bool
-esiSequence::finishedProcessing() const
-{
-    return nextElementToProcess() >= elements.size();
-}
-
-bool
-esiSequence::mayFail () const
-{
-    if (failed)
-        return true;
-
-    return mayFail_;
-}
-
-void
-esiSequence::wontFail()
-{
-    assert (!failed);
-    mayFail_ = false;
-}
-
-void
-esiSequence::render(ESISegment::Pointer output)
-{
-    /* append all processed elements, and trim processed
-     * and rendered elements
-     */
-    assert (output->next == nullptr);
-    debugs (86,5, "esiSequenceRender: rendering " << processedcount << " elements");
-
-    for (size_t i = 0; i < processedcount; ++i) {
-        elements[i]->render(output);
-        FinishAnElement(elements[i], i);
-        // TODO: pass an "ESISegment **" ?
-        output = output->tail();
-    }
-
-    // prune completed elements
-    elements.erase(elements.begin(), elements.begin() + processedcount);
-    processedcount = 0;
-    assert (output->next == nullptr);
-}
-
-void
-esiSequence::finish()
-{
-    debugs(86, 5, "esiSequence::finish: " << this << " is finished");
-    FinishAllElements(elements);
-    parent = nullptr;
-}
-
-void
-esiSequence::provideData (ESISegment::Pointer data, ESIElement *source)
-{
-    ESIElement::Pointer lockthis = this;
-
-    if (processing)
-        debugs(86, 5, "esiSequence::provideData: " << this << " data provided during processing");
-    debugs(86, 5, "esiSequence::provideData " << this << " " << data.getRaw() << " " << source);
-
-    /* when data is provided, the element *must* be completed */
-    /* XXX: when the callback model is complete,
-     * we can introduce 'finished'. And then this rule can be
-     * relaxed
-     */
-    /* find the index */
-    int index = elementIndex (source);
-
-    assert (index >= 0);
-
-    /* remove the current node */
-    FinishAnElement(elements[index], index);
-
-    /* create a literal */
-    esiLiteral *temp = new esiLiteral (data);
-
-    /* insert the literal */
-    elements[index] = temp;
-
-    /* XXX: TODO push any pushable data upwards */
-    /* fail() not done */
-    if (processing)
-        return;
-
-    assert (process (flags.dovars) != ESI_PROCESS_FAILED);
-}
-
-bool
-esiSequence::addElement (ESIElement::Pointer element)
-{
-    /* add an element to the output list */
-    /* Some elements require specific parents */
-
-    if (dynamic_cast<esiAttempt*>(element.getRaw()) ||
-            dynamic_cast<esiExcept*>(element.getRaw())) {
-        debugs(86, DBG_CRITICAL, "esiSequenceAdd: misparented Attempt or Except element (section 3.4)");
-        return false;
-    }
-
-    /* Tie literals together for efficiency */
-    if (elements.size() && dynamic_cast<esiLiteral*>(element.getRaw()) &&
-            dynamic_cast<esiLiteral*>(elements[elements.size() - 1].getRaw())) {
-        debugs(86, 5, "esiSequenceAdd: tying Literals " <<
-               elements[elements.size() - 1].getRaw() << " and " <<
-               element.getRaw() << " together");
-
-        ESISegment::ListTransfer (((esiLiteral *)element.getRaw())->buffer,
-                                  ((esiLiteral *)elements[elements.size() - 1].getRaw())->buffer);
-        return true;
-    }
-
-    elements.push_back(element);
-    debugs (86,3, "esiSequenceAdd: Added a new element, elements = " << elements.size());
-    return true;
-}
-
-int
-esiSequence::elementIndex(ESIElement::Pointer anElement) const
-{
-    for (size_t i = 0; i < elements.size(); ++i)
-        if (elements[i] == anElement)
-            return i;
-
-    return -1;
-}
-
-void
-esiSequence::processStep(int dovars)
-{
-    size_t elementToProcess = nextElementToProcess();
-    nextElementToProcess(elementToProcess + 1);
-    esiProcessResult_t tempResult = processOne(dovars, elementToProcess);
-
-    if (processingResult < tempResult) {
-        debugs(86, 5, "esiSequence::process: processingResult was " << processingResult << ", increasing to " << tempResult);
-        processingResult = tempResult;
-    }
-}
-
-esiProcessResult_t
-esiSequence::processOne(int dovars, size_t index)
-{
-    debugs (86,5, "esiSequence::process " << this << " about to process element[" << index << "] " << elements[index].getRaw());
-
-    switch (elements[index]->process(dovars)) {
-
-    case ESI_PROCESS_COMPLETE:
-        debugs(86, 5, "esiSequenceProcess: " << this << " element " << elements[index].getRaw() << " Processed OK");
-
-        if (index == processedcount)
-            /* another completely ready */
-            ++processedcount;
-
-        return ESI_PROCESS_COMPLETE;
-
-    case ESI_PROCESS_PENDING_WONTFAIL:
-        debugs(86, 5, "esiSequenceProcess: element Processed PENDING OK");
-
-        return ESI_PROCESS_PENDING_WONTFAIL;
-
-    case ESI_PROCESS_PENDING_MAYFAIL:
-        debugs(86, 5, "eseSequenceProcess: element Processed PENDING UNKNOWN");
-
-        return ESI_PROCESS_PENDING_MAYFAIL;
-
-    case ESI_PROCESS_FAILED:
-        debugs(86, 5, "esiSequenceProcess: element Processed FAILED");
-
-        return ESI_PROCESS_FAILED;
-
-    default:
-        fatal ("unexpected code in esiSequence::processOne\n");
-
-        return ESI_PROCESS_FAILED;
-    }
-}
-
-esiProcessResult_t
-esiSequence::process (int inheritedVarsFlag)
-{
-    debugs(86, 5, "esiSequence::process: " << this << " processing");
-
-    if (processing) {
-        debugs(86, 5, "esiSequence::process: " << this <<
-               " reentry attempt during processing");
-    }
-
-    /* process as much of the list as we can, stopping only on
-     * failures
-     */
-    if (!processing || processedcount == 0)
-        processingResult = ESI_PROCESS_COMPLETE;
-
-    int dovars = inheritedVarsFlag;
-
-    if (flags.dovars)
-        dovars = 1;
-
-    debugs(86, 5, "esiSequence::process: Processing " << this << " with" <<
-           (dovars ? "" : "out") << " variable processing");
-
-    processing = true;
-
-    nextElementToProcess(processedcount);
-
-    while (!finishedProcessing()) {
-        processStep(dovars);
-
-        if (!processing)
-            return processingResult;
-
-        if (processingResult == ESI_PROCESS_FAILED) {
-            FinishAllElements(elements);
-            failed = true;
-            parent = nullptr;
-            processing = false;
-            return processingResult;
-        }
-    }
-
-    assert (processingResult != ESI_PROCESS_COMPLETE || processedcount == elements.size());
-
-    if (processingResult == ESI_PROCESS_COMPLETE || processingResult == ESI_PROCESS_PENDING_WONTFAIL)
-        wontFail();
-
-    if (processedcount == elements.size() || provideIncrementalData) {
-        ESISegment::Pointer temp(new ESISegment);
-        render (temp);
-
-        if (temp->next.getRaw() || temp->len)
-            parent->provideData(temp, this);
-        else
-            ESISegmentFreeList (temp);
-    }
-
-    /* Depends on full parsing before processing */
-    if (processedcount == elements.size())
-        parent = nullptr;
-
-    debugs(86, 5, "esiSequence::process: " << this << " completed");
-
-    processing = false;
-
-    return processingResult;
-}
-
-void
-esiSequence::fail(ESIElement * /* source */, char const *anError)
-{
-    failed = true;
-
-    if (processing) {
-        debugs(86, 5, "esiSequence::fail: " << this << " failure callback during processing");
-        return;
-    }
-
-    debugs(86, 5, "esiSequence::fail: " << this << " has failed.");
-    parent->fail (this, anError);
-    FinishAllElements(elements);
-    parent = nullptr;
-}
-
-esiSequence::esiSequence(esiSequence const &old) :
-    processedcount(0),
-    parent(nullptr),
-    mayFail_(old.mayFail_),
-    failed(old.failed),
-    provideIncrementalData(old.provideIncrementalData),
-    processing(false),
-    processingResult(ESI_PROCESS_COMPLETE),
-    nextElementToProcess_(0)
-{
-    flags.dovars = old.flags.dovars;
-}
-
-void
-esiSequence::makeCachableElements(esiSequence const &old)
-{
-    for (size_t counter = 0; counter < old.elements.size(); ++counter) {
-        ESIElement::Pointer newElement = old.elements[counter]->makeCacheable();
-
-        if (newElement.getRaw())
-            assert (addElement(newElement));
-    }
-}
-
-void
-esiSequence::makeUsableElements(esiSequence const &old, ESIVarState &newVarState)
-{
-    for (size_t counter = 0; counter < old.elements.size(); ++counter) {
-        ESIElement::Pointer newElement = old.elements[counter]->makeUsable (this, newVarState);
-
-        if (newElement.getRaw())
-            assert (addElement(newElement));
-    }
-}
-
-ESIElement::Pointer
-esiSequence::makeCacheable() const
-{
-    debugs(86, 5, "esiSequence::makeCacheable: Making cachable sequence from " << this);
-    assert (processedcount == 0);
-    assert (!failed);
-
-    if (elements.size() == 0) {
-        debugs(86, 5, "esiSequence::makeCacheable: No elements in sequence " << this << ", returning NULL");
-        return nullptr;
-    }
-
-    esiSequence * resultS = new esiSequence (*this);
-    ESIElement::Pointer result = resultS;
-    resultS->makeCachableElements(*this);
-    debugs(86, 5, "esiSequence::makeCacheable: " << this << " created " << result.getRaw());
-    return result;
-}
-
-ESIElement::Pointer
-esiSequence::makeUsable(esiTreeParentPtr newParent, ESIVarState &newVarState) const
-{
-    debugs(86, 5, "esiSequence::makeUsable: Creating usable Sequence");
-    assert (processedcount == 0);
-    assert (!failed);
-
-    if (elements.size() == 0) {
-        debugs(86, 5, "esiSequence::makeUsable: No elements in sequence " << this << ", returning NULL");
-        return nullptr;
-    }
-
-    esiSequence * resultS = new esiSequence (*this);
-    ESIElement::Pointer result = resultS;
-    resultS->parent = newParent;
-    resultS->makeUsableElements(*this, newVarState);
-    return result;
-}
-
-#endif /* USE_SQUID_ESI == 1 */
-
diff --git a/src/esi/Sequence.h b/src/esi/Sequence.h
deleted file mode 100644 (file)
index 8fe4ea8..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#ifndef SQUID_SRC_ESI_SEQUENCE_H
-#define SQUID_SRC_ESI_SEQUENCE_H
-
-#include "esi/Element.h"
-#include "mem/forward.h"
-
-/* esiSequence */
-
-class esiSequence : public ESIElement
-{
-    MEMPROXY_CLASS(esiSequence);
-
-public:
-    esiSequence(esiTreeParentPtr, bool = false);
-    ~esiSequence() override;
-
-    void render(ESISegment::Pointer) override;
-    bool addElement (ESIElement::Pointer) override;
-    esiProcessResult_t process (int dovars) override;
-    void provideData (ESISegment::Pointer, ESIElement*) override;
-    bool mayFail () const override;
-    void wontFail();
-    void fail(ESIElement *, char const *anError = nullptr) override;
-    void makeCachableElements(esiSequence const &old);
-    Pointer makeCacheable() const override;
-    void makeUsableElements(esiSequence const &old, ESIVarState &);
-    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const override;
-
-    Esi::Elements elements; /* unprocessed or rendered nodes */
-    size_t processedcount;
-
-    struct {
-        unsigned int dovars:1; /* for esiVar */
-    } flags;
-    void finish() override;
-
-protected:
-    esiSequence(esiSequence const &);
-    esiTreeParentPtr parent;
-
-private:
-    int elementIndex (ESIElement::Pointer anElement) const;
-    bool mayFail_;
-    bool failed;
-    esiProcessResult_t processOne(int, size_t);
-    bool const provideIncrementalData;
-    bool processing;
-    esiProcessResult_t processingResult;
-    size_t nextElementToProcess_;
-    size_t nextElementToProcess() const;
-    void nextElementToProcess(size_t const &);
-    bool finishedProcessing() const;
-    void processStep(int dovars);
-};
-
-#endif /* SQUID_SRC_ESI_SEQUENCE_H */
-
diff --git a/src/esi/Var.h b/src/esi/Var.h
deleted file mode 100644 (file)
index aad6d2b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#ifndef SQUID_SRC_ESI_VAR_H
-#define SQUID_SRC_ESI_VAR_H
-
-#include "esi/Element.h"
-#include "esi/Sequence.h"
-
-/* esiVar */
-
-class ESIVar:public esiSequence
-{
-
-public:
-    ESIVar(esiTreeParentPtr aParent) : esiSequence (aParent) {
-        flags.dovars = 1;
-    }
-};
-
-#endif /* SQUID_SRC_ESI_VAR_H */
-
diff --git a/src/esi/VarState.cc b/src/esi/VarState.cc
deleted file mode 100644 (file)
index 2f48272..0000000
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI processing */
-
-#include "squid.h"
-#include "esi/VarState.h"
-#include "fatal.h"
-#include "HttpReply.h"
-
-char const *ESIVariableUserAgent::esiUserOs[]= {
-    "WIN",
-    "MAC",
-    "UNIX",
-    "OTHER"
-};
-
-char const * esiBrowsers[]= {"MSIE",
-                             "MOZILLA",
-                             "OTHER"
-                            };
-
-CBDATA_CLASS_INIT(ESIVarState);
-
-void
-ESIVarState::Variable::eval(ESIVarState &state, char const *, char const *found_default) const
-{
-    /* No-op. We swallow it */
-
-    if (found_default)
-        ESISegment::ListAppend (state.getOutput(), found_default, strlen (found_default));
-}
-
-void
-ESIVarState::hostUsed()
-{
-    flags.host = 1;
-}
-
-void
-ESIVarState::cookieUsed()
-{
-    flags.cookie = 1;
-}
-
-void
-ESIVarState::languageUsed()
-{
-    flags.language = 1;
-}
-
-void
-ESIVarState::refererUsed()
-{
-    flags.referer = 1;
-}
-
-void
-ESIVarState::useragentUsed()
-{
-    flags.useragent = 1;
-}
-
-HttpHeader &
-ESIVarState::header()
-{
-    return hdr;
-}
-
-ESISegment::Pointer &
-ESIVarState::getOutput()
-{
-    return output;
-}
-
-char const *
-ESIVariableQuery::queryString() const
-{
-    return query_string;
-}
-
-struct _query_elem const *
-ESIVariableQuery::queryVector() const {
-    return query;
-}
-
-size_t const &
-ESIVariableQuery::queryElements() const
-{
-    return query_elements;
-}
-
-void
-ESIVarState::feedData (const char *buf, size_t len)
-{
-    /* TODO: if needed - tune to skip segment iteration */
-    debugs (86,6, "esiVarState::feedData: accepting " << len << " bytes");
-    ESISegment::ListAppend (input, buf, len);
-}
-
-ESISegment::Pointer
-ESIVarState::extractList()
-{
-    doIt();
-    ESISegment::Pointer rv = output;
-    output = nullptr;
-    debugs(86, 6, "ESIVarStateExtractList: Extracted list");
-    return rv;
-}
-
-char *
-ESIVarState::extractChar ()
-{
-    if (!input.getRaw())
-        fatal ("Attempt to extract variable state with no data fed in \n");
-
-    doIt();
-
-    char *rv = output->listToChar();
-
-    ESISegmentFreeList (output);
-
-    debugs(86, 6, "ESIVarStateExtractList: Extracted char");
-
-    return rv;
-}
-
-ESIVarState::~ESIVarState()
-{
-    // freeResources
-    input = nullptr;
-    ESISegmentFreeList(output);
-    hdr.clean();
-
-    while (!variablesForCleanup.empty()) {
-        delete variablesForCleanup.back();
-        variablesForCleanup.pop_back();
-    }
-
-    delete defaultVariable;
-}
-
-char *
-ESIVariableUserAgent::getProductVersion (char const *s)
-{
-    char const *t;
-    int len;
-    t = strchr(s, '/');
-
-    if (!t || !*(++t))
-        return xstrdup("");
-
-    len = strcspn(t, " \r\n()<>@,;:\\\"/[]?={}");
-
-    return xstrndup(t, len + 1);
-}
-
-ESIVariableQuery::ESIVariableQuery(char const *uri) : query (nullptr), query_sz (0), query_elements (0), query_string (nullptr)
-{
-    /* Count off the query elements */
-    char const *query_start = strchr (uri, '?');
-
-    if (query_start && query_start[1] != '\0' ) {
-        unsigned int n;
-        query_string = xstrdup(query_start + 1);
-        query_elements = 1;
-        char const *query_pos = query_start + 1;
-
-        while ((query_pos = strchr(query_pos, '&'))) {
-            ++query_elements;
-            ++query_pos;
-        }
-
-        query = static_cast<_query_elem *>(memAllocBuf(query_elements * sizeof(struct _query_elem), &query_sz));
-        memset(query, 0, query_sz);
-        query_pos = query_start + 1;
-        n = 0;
-
-        while (query_pos) {
-            char const *next = strchr(query_pos, '&');
-            char const *div = strchr(query_pos, '=');
-
-            if (next)
-                ++next;
-
-            assert (n < query_elements);
-
-            if (!div)
-                div = next;
-
-            if (!(div - query_pos + 1))
-                /* zero length between & and = or & and & */
-                continue;
-
-            query[n].var = xstrndup(query_pos, div - query_pos + 1) ;
-
-            if (div == next) {
-                query[n].val = xstrdup("");
-            } else {
-                query[n].val = xstrndup(div + 1, next - div - 1);
-            }
-
-            query_pos = next;
-            ++n;
-        }
-    } else {
-        query_string = xstrdup("");
-    }
-
-    if (query) {
-        unsigned int n = 0;
-        debugs(86, 6, "esiVarStateNew: Parsed Query string: '" << uri << "'");
-
-        while (n < query_elements) {
-            debugs(86, 6, "esiVarStateNew: Parsed Query element " << n + 1 << " '" << query[n].var << "'='" << query[n].val << "'");
-            ++n;
-        }
-    }
-}
-
-ESIVariableQuery::~ESIVariableQuery()
-{
-    if (query) {
-        unsigned int i;
-
-        for (i = 0; i < query_elements; ++i) {
-            safe_free(query[i].var);
-            safe_free(query[i].val);
-        }
-
-        memFreeBuf (query_sz, query);
-    }
-
-    safe_free (query_string);
-}
-
-ESIVarState::ESIVarState(HttpHeader const *aHeader, char const *uri) :
-    output(nullptr),
-    hdr(hoReply)
-{
-    memset(&flags, 0, sizeof(flags));
-
-    /* TODO: only grab the needed headers */
-    /* Note that as we pass these through to included requests, we
-     * cannot trim them */
-    hdr.append(aHeader);
-
-    /* populate our variables trie with the available variables.
-     * Additional ones can be added during the parsing.
-     * If there is a lazy evaluation approach to this, consider it!
-     */
-    defaultVariable = new Variable;
-    addVariable ("HTTP_ACCEPT_LANGUAGE", 20, new ESIVariableLanguage);
-    addVariable ("HTTP_COOKIE", 11, new ESIVariableCookie);
-    addVariable ("HTTP_HOST", 9, new ESIVariableHost);
-    addVariable ("HTTP_REFERER", 12, new ESIVariableReferer);
-    addVariable ("HTTP_USER_AGENT", 15, new ESIVariableUserAgent(*this));
-    addVariable ("QUERY_STRING", 12, new ESIVariableQuery(uri));
-}
-
-void
-ESIVarState::removeVariable (String const &name)
-{
-    Variable *candidate = static_cast <Variable *>(variables.find (name.rawBuf(), name.size()));
-
-    if (candidate) {
-        /* XXX: remove me */
-        /* Note - this involves:
-         * extend libTrie to have a remove() call.
-         * delete from the vector.
-         * delete the object.
-         */
-    }
-}
-
-void
-ESIVarState::addVariable(char const *name, size_t len, Variable *aVariable)
-{
-    String temp;
-    temp.assign(name, len);
-    removeVariable (temp);
-    variables.add(name, len, aVariable);
-    variablesForCleanup.push_back(aVariable);
-}
-
-ESIVariableUserAgent::~ESIVariableUserAgent()
-{
-    safe_free (browserversion);
-}
-
-ESIVariableUserAgent::ESIVariableUserAgent(ESIVarState &state)
-{
-    /* An example:
-     *    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705) */
-    /* Grr this Node is painful - RFC 2616 specifies that 'by convention' the tokens are in order of importance
-     * in identifying the product. According to the RFC the above should be interpreted as:
-     * Product - Mozilla version 4.0
-     * in comments - compatible; .... 3705
-     *
-     * Using the RFC a more appropriate header would be
-     *    User-Agent: MSIE/6.0 Mozilla/4.0 Windows-NT/5.1 .NET-CLR/1.0.3705
-     *    or something similar.
-     *
-     * Because we can't parse under those rules and get real-world useful answers, we follow the following
-     * algorithm:
-     * if the string Windows appears in the header, the OS is WIN.
-     * If the string Mac appears in the header, the OS is MAC.
-     * If the string nix, or BSD appears in the header, the OS is UNIX.
-     * If the string MSIE appears in the header, the BROWSER is MSIE, and the version is the string from
-     * MSIE<sp> to the first ;, or end of string.
-     * If the String MSIE does not appear in the header, and MOZILLA does, we use the version from the
-     * /version field.
-     * if MOZILLA doesn't appear, the browser is set to OTHER.
-     * In future, this may be better implemented as a regexp.
-     */
-
-    if (state.header().has(Http::HdrType::USER_AGENT)) {
-        char const *s = state.header().getStr(Http::HdrType::USER_AGENT);
-        UserOs = identifyOs(s);
-        char const *t, *t1;
-
-        /* Now the browser and version */
-
-        if ((t = strstr (s, "MSIE"))) {
-            browser = ESI_BROWSER_MSIE;
-            t = strchr(t, ' ');
-
-            if (!t)
-                browserversion = xstrdup("");
-            else {
-                t1 = strchr(t, ';');
-
-                if (!t1)
-                    browserversion = xstrdup(t + 1);
-                else
-                    browserversion = xstrndup(t + 1, t1-t);
-            }
-        } else if (strstr (s, "Mozilla")) {
-            browser = ESI_BROWSER_MOZILLA;
-            browserversion = getProductVersion(s);
-        } else {
-            browser = ESI_BROWSER_OTHER;
-            browserversion = getProductVersion(s);
-        }
-    } else {
-        UserOs = ESI_OS_OTHER;
-        browser = ESI_BROWSER_OTHER;
-        browserversion = xstrdup("");
-    }
-}
-
-ESIVariableUserAgent::esiUserOs_t
-ESIVariableUserAgent::identifyOs(char const *s) const
-{
-    if (!s)
-        return ESI_OS_OTHER;
-
-    if (strstr (s, "Windows"))
-        return ESI_OS_WIN;
-    else if (strstr (s, "Mac"))
-        return ESI_OS_MAC;
-    else if (strstr (s, "nix") || strstr (s, "BSD"))
-        return ESI_OS_UNIX;
-    else
-        return ESI_OS_OTHER;
-}
-
-void
-ESIVariableCookie::eval (ESIVarState &state, char const *subref, char const *found_default) const
-{
-    const char *s = nullptr;
-    state.cookieUsed();
-
-    if (state.header().has(Http::HdrType::COOKIE)) {
-        if (!subref)
-            s = state.header().getStr (Http::HdrType::COOKIE);
-        else {
-            const auto subCookie = state.header().getListMember(Http::HdrType::COOKIE, subref, ';');
-
-            if (subCookie.length())
-                ESISegment::ListAppend(state.getOutput(), subCookie.rawContent(), subCookie.length());
-            else if (found_default)
-                ESISegment::ListAppend (state.getOutput(), found_default, strlen (found_default));
-        }
-    } else
-        s = found_default;
-
-    if (s)
-        ESISegment::ListAppend (state.getOutput(), s, strlen (s));
-}
-
-void
-ESIVariableHost::eval (ESIVarState &state, char const *subref, char const *found_default) const
-{
-    const char *s = nullptr;
-    state.hostUsed();
-
-    if (!subref && state.header().has(Http::HdrType::HOST)) {
-        s = state.header().getStr (Http::HdrType::HOST);
-    } else
-        s = found_default;
-
-    ESISegment::ListAppend (state.getOutput(), s, strlen (s));
-}
-
-void
-ESIVariableLanguage::eval (ESIVarState &state, char const *subref, char const *found_default) const
-{
-    char const *s = nullptr;
-    state.languageUsed();
-
-    if (state.header().has(Http::HdrType::ACCEPT_LANGUAGE)) {
-        if (!subref) {
-            String S (state.header().getList (Http::HdrType::ACCEPT_LANGUAGE));
-            ESISegment::ListAppend (state.getOutput(), S.rawBuf(), S.size());
-        } else {
-            if (state.header().hasListMember (Http::HdrType::ACCEPT_LANGUAGE, subref, ',')) {
-                s = "true";
-            } else {
-                s = "false";
-            }
-
-            ESISegment::ListAppend (state.getOutput(), s, strlen (s));
-        }
-    } else {
-        s = found_default;
-        ESISegment::ListAppend (state.getOutput(), s, strlen (s));
-    }
-}
-
-void
-ESIVariableQuery::eval (ESIVarState &state, char const *subref, char const *found_default) const
-{
-    char const *s = nullptr;
-
-    if (!subref)
-        s = queryString();
-    else {
-        unsigned int i = 0;
-
-        while (i < queryElements() && !s) {
-            if (!strcmp (subref, queryVector()[i].var))
-                s = queryVector()[i].val;
-
-            ++i;
-        }
-
-        if (!s)
-            s = found_default;
-    }
-
-    ESISegment::ListAppend (state.getOutput(), s, strlen (s));
-}
-
-void
-ESIVariableReferer::eval (ESIVarState &state, char const *subref, char const *found_default) const
-{
-    const char *s = nullptr;
-    state.refererUsed();
-
-    if (!subref && state.header().has(Http::HdrType::REFERER))
-        s = state.header().getStr (Http::HdrType::REFERER);
-    else
-        s = found_default;
-
-    ESISegment::ListAppend (state.getOutput(), s, strlen (s));
-}
-
-void
-ESIVariableUserAgent::eval (ESIVarState &state, char const *subref, char const *found_default) const
-{
-    char const *s = nullptr;
-    state.useragentUsed();
-
-    if (state.header().has(Http::HdrType::USER_AGENT)) {
-        if (!subref)
-            s = state.header().getStr (Http::HdrType::USER_AGENT);
-        else {
-            if (!strcmp (subref, "os")) {
-                s = esiUserOs[UserOs];
-            } else if (!strcmp (subref, "browser")) {
-                s = esiBrowsers[browser];
-            } else if (!strcmp (subref, "version")) {
-                s = browserVersion();
-            } else
-                s = "";
-        }
-    } else
-        s = found_default;
-
-    ESISegment::ListAppend (state.getOutput(), s, strlen (s));
-}
-
-/* thoughts on long term:
- * get $
- * get () handler
- * hand off to handler.
- * one handler for variables.
- * one handler for each function.
- */
-
-class ESIVariableProcessor;
-
-class ESIFunction
-{
-
-public:
-    static ESIFunction *GetFunction (char const *symbol, ESIVariableProcessor &);
-    ESIFunction(ESIVariableProcessor &);
-    void doIt();
-
-private:
-    ESIVariableProcessor &processor;
-
-};
-
-ESIFunction::ESIFunction(ESIVariableProcessor &aProcessor) : processor(aProcessor)
-{}
-
-ESIFunction *
-ESIFunction::GetFunction(char const *symbol, ESIVariableProcessor &aProcessor)
-{
-    if (*symbol == '(')
-        return new ESIFunction(aProcessor);
-
-    return nullptr;
-}
-
-class ESIVariableProcessor
-{
-
-public:
-    ESIVariableProcessor(char *, ESISegment::Pointer &, Trie &, ESIVarState *);
-    ~ESIVariableProcessor();
-    void doIt();
-
-private:
-    bool validChar (char c);
-    void eval (ESIVarState::Variable *var, char const *subref, char const *foundDefault );
-    void doFunction();
-    void identifyFunction();
-    char *string;
-    ESISegment::Pointer &output;
-    Trie &variables;
-    ESIVarState *varState;
-    int state;
-    size_t len;
-    size_t pos;
-    size_t var_pos;
-    size_t done_pos;
-    char * found_subref;
-    char *found_default;
-    ESIVarState::Variable *vartype;
-    ESIFunction *currentFunction;
-};
-
-void
-ESIVariableProcessor::eval (ESIVarState::Variable *var, char const *subref, char const *foundDefault )
-{
-    assert (var);
-
-    if (!foundDefault)
-        foundDefault = "";
-
-    var->eval (*varState, subref, foundDefault);
-}
-
-bool
-ESIVariableProcessor::validChar (char c)
-{
-    if (('A' <= c && c <= 'Z') ||
-            ('a' <= c && c <= 'z') ||
-            '_' == c || '-' == c)
-        return true;
-
-    return false;
-}
-
-ESIVarState::Variable *
-ESIVarState::GetVar(char const *symbol, int len)
-{
-    assert (symbol);
-
-    void *result = variables.find (symbol, len);
-
-    if (result)
-        return static_cast<Variable *>(result);
-
-    return defaultVariable;
-}
-
-void
-ESIVarState::doIt ()
-{
-    char *string = input->listToChar();
-    ESISegmentFreeList (input);
-    ESIVariableProcessor theProcessor(string, output, variables, this);
-    theProcessor.doIt();
-    safe_free(string);
-}
-
-#define LOOKFORSTART 0
-ESIVariableProcessor::ESIVariableProcessor(char *aString, ESISegment::Pointer &aSegment, Trie &aTrie, ESIVarState *aState) :
-    string(aString), output (aSegment), variables(aTrie), varState (aState),
-    state(LOOKFORSTART), pos(0), var_pos(0), done_pos(0), found_subref (nullptr),
-    found_default (nullptr), currentFunction(nullptr)
-{
-    len = strlen (string);
-    vartype = varState->GetVar("",0);
-}
-
-void
-ESIFunction::doIt()
-{}
-
-/* because we are only used to process:
- * - include URL's
- * - non-esi elements
- * - choose clauses
- * buffering is ok - we won't delay the start of async activity, or
- * of output data preparation
- */
-/* Should make these an enum or something...
- */
-void
-ESIVariableProcessor::doFunction()
-{
-    if (!currentFunction)
-        return;
-
-    /* stay in here whilst operating */
-    while (pos < len && state)
-        switch (state) {
-
-        case 2: /* looking for variable name */
-
-            if (!validChar(string[pos])) {
-                /* not a variable name char */
-
-                if (pos - var_pos) {
-                    vartype = varState->GetVar (string + var_pos, pos - var_pos);
-                }
-
-                state = 3;
-            } else {
-                ++pos;
-            }
-
-            break;
-
-        case 3: /* looking for variable subref, end bracket or default indicator */
-
-            if (string[pos] == ')') {
-                /* end of string */
-                eval(vartype, found_subref, found_default);
-                done_pos = ++pos;
-                safe_free(found_subref);
-                safe_free(found_default);
-                state = LOOKFORSTART;
-            } else if (!found_subref && !found_default && string[pos] == '{') {
-                debugs(86, 6, "ESIVarStateDoIt: Subref of some sort");
-                /* subreference of some sort */
-                /* look for the entry name */
-                var_pos = ++pos;
-                state = 4;
-            } else if (!found_default && string[pos] == '|') {
-                debugs(86, 6, "esiVarStateDoIt: Default present");
-                /* extract default value */
-                state = 5;
-                var_pos = ++pos;
-            } else {
-                /* unexpected char, not a variable after all */
-                debugs(86, 6, "esiVarStateDoIt: unexpected char after varname");
-                state = LOOKFORSTART;
-                pos = done_pos + 2;
-            }
-
-            break;
-
-        case 4: /* looking for variable subref */
-
-            if (string[pos] == '}') {
-                /* end of subref */
-                found_subref = xstrndup (&string[var_pos], pos - var_pos + 1);
-                debugs(86, 6, "esiVarStateDoIt: found end of variable subref '" << found_subref << "'");
-                state = 3;
-                ++pos;
-            } else if (!validChar (string[pos])) {
-                debugs(86, 6, "esiVarStateDoIt: found invalid char in variable subref");
-                /* not a valid subref */
-                safe_free(found_subref);
-                state = LOOKFORSTART;
-                pos = done_pos + 2;
-            } else {
-                ++pos;
-            }
-
-            break;
-
-        case 5: /* looking for a default value */
-
-            if (string[pos] == '\'') {
-                /* begins with a quote */
-                debugs(86, 6, "esiVarStateDoIt: found quoted default");
-                state = 6;
-                var_pos = ++pos;
-            } else {
-                /* doesn't */
-                debugs(86, 6, "esiVarStateDoIt: found unquoted default");
-                state = 7;
-                ++pos;
-            }
-
-            break;
-
-        case 6: /* looking for a quote terminate default value */
-
-            if (string[pos] == '\'') {
-                /* end of default */
-                found_default = xstrndup (&string[var_pos], pos - var_pos + 1);
-                debugs(86, 6, "esiVarStateDoIt: found end of quoted default '" << found_default << "'");
-                state = 3;
-            }
-
-            ++pos;
-            break;
-
-        case 7: /* looking for } terminate default value */
-
-            if (string[pos] == ')') {
-                /* end of default - end of variable*/
-                found_default = xstrndup (&string[var_pos], pos - var_pos + 1);
-                debugs(86, 6, "esiVarStateDoIt: found end of variable (w/ unquoted default) '" << found_default << "'");
-                eval(vartype,found_subref, found_default);
-                done_pos = ++pos;
-                safe_free(found_default);
-                safe_free(found_subref);
-                state = LOOKFORSTART;
-            }
-
-            ++pos;
-            break;
-
-        default:
-            fatal("esiVarStateDoIt: unexpected state\n");
-        }
-}
-
-void
-ESIVariableProcessor::identifyFunction()
-{
-    delete currentFunction;
-    currentFunction = ESIFunction::GetFunction (&string[pos], *this);
-
-    if (!currentFunction) {
-        state = LOOKFORSTART;
-    } else {
-        state = 2; /* process a function */
-        /* advance past function name */
-        var_pos = ++pos;
-    }
-}
-
-void
-ESIVariableProcessor::doIt()
-{
-    assert (output == nullptr);
-
-    while (pos < len) {
-        /* skipping pre-variables */
-
-        if (string[pos] != '$') {
-            ++pos;
-        } else {
-            if (pos - done_pos)
-                /* extract known plain text */
-                ESISegment::ListAppend (output, string + done_pos, pos - done_pos);
-
-            done_pos = pos;
-
-            ++pos;
-
-            identifyFunction();
-
-            doFunction();
-        }
-    }
-
-    /* pos-done_pos chars are ready to copy */
-    if (pos-done_pos)
-        ESISegment::ListAppend (output, string+done_pos, pos - done_pos);
-
-    safe_free (found_default);
-
-    safe_free (found_subref);
-}
-
-ESIVariableProcessor::~ESIVariableProcessor()
-{
-    delete currentFunction;
-}
-
-/* XXX: this should be comma delimited, no? */
-void
-ESIVarState::buildVary (HttpReply *rep)
-{
-    char tempstr[1024];
-    tempstr[0]='\0';
-
-    if (flags.language)
-        strcat (tempstr, "Accept-Language ");
-
-    if (flags.cookie)
-        strcat (tempstr, "Cookie ");
-
-    if (flags.host)
-        strcat (tempstr, "Host ");
-
-    if (flags.referer)
-        strcat (tempstr, "Referer ");
-
-    if (flags.useragent)
-        strcat (tempstr, "User-Agent ");
-
-    if (!tempstr[0])
-        return;
-
-    String strVary (rep->header.getList (Http::HdrType::VARY));
-
-    if (!strVary.size() || strVary[0] != '*') {
-        rep->header.putStr (Http::HdrType::VARY, tempstr);
-    }
-}
-
diff --git a/src/esi/VarState.h b/src/esi/VarState.h
deleted file mode 100644 (file)
index 18a8e54..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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.
- */
-
-#ifndef SQUID_SRC_ESI_VARSTATE_H
-#define SQUID_SRC_ESI_VARSTATE_H
-
-#include "esi/Segment.h"
-#include "HttpHeader.h"
-#include "libTrie/Trie.h"
-
-#include <vector>
-
-class HttpReply;
-
-/* esi variable replacement logic */
-
-typedef enum {
-    ESI_BROWSER_MSIE,
-    ESI_BROWSER_MOZILLA,
-    ESI_BROWSER_OTHER
-} esiBrowser_t;
-
-extern char const * esiBrowsers[];
-
-/* Recursive uses are not supported by design */
-
-struct _query_elem {char *var, *val;};
-
-class ESIVarState
-{
-    CBDATA_CLASS(ESIVarState);
-
-public:
-    ESIVarState(HttpHeader const *hdr, char const *uri);
-    ~ESIVarState();
-
-    ESISegment::Pointer extractList();
-    char *extractChar();
-    void feedData (const char *buf, size_t len);
-    void buildVary (HttpReply *rep);
-
-    class Variable;
-    void addVariable (char const *, size_t, Variable *);
-    void removeVariable (String const &);
-
-    /* For Variables */
-    void cookieUsed();
-    void hostUsed();
-    void languageUsed();
-    void refererUsed();
-    void useragentUsed();
-    ESISegment::Pointer &getOutput();
-    HttpHeader &header();
-
-private:
-    ESISegment::Pointer input;
-    ESISegment::Pointer output;
-    HttpHeader hdr;
-
-    struct {
-        unsigned int language:1;
-        unsigned int cookie:1;
-        unsigned int host:1;
-        unsigned int referer:1;
-        unsigned int useragent:1;
-    } flags;
-
-public:
-
-    class Variable
-    {
-
-    public:
-        Variable () {}
-
-        virtual ~Variable() {}
-
-        /* prevent synthetics */
-        Variable (Variable const &) {}
-
-        Variable &operator= (Variable const &);
-        virtual void eval (ESIVarState &state, char const *, char const *) const;
-    };
-
-    Variable* GetVar(char const *s, int len);
-
-private:
-    void doIt ();
-    void setupUserAgent();
-    Trie variables;
-    std::vector<Variable*> variablesForCleanup;
-    Variable *defaultVariable;
-};
-
-class ESIVariableCookie : public ESIVarState::Variable
-{
-
-public:
-    void eval (ESIVarState &state, char const *, char const *) const override;
-};
-
-class ESIVariableHost : public ESIVarState::Variable
-{
-
-public:
-    void eval (ESIVarState &state, char const *, char const *) const override;
-};
-
-class ESIVariableLanguage : public ESIVarState::Variable
-{
-
-public:
-    void eval (ESIVarState &state, char const *, char const *) const override;
-};
-
-class ESIVariableQuery : public ESIVarState::Variable
-{
-
-public:
-    ESIVariableQuery(char const *uri);
-    ~ESIVariableQuery() override;
-    void eval (ESIVarState &state, char const *, char const *) const override;
-    char const *queryString() const;
-
-    struct _query_elem const *queryVector() const;
-    size_t const &queryElements() const;
-
-    struct _query_elem *query;
-    size_t query_sz;
-    size_t query_elements;
-    char *query_string;
-};
-
-class ESIVariableReferer : public ESIVarState::Variable
-{
-
-public:
-    void eval (ESIVarState &state, char const *, char const *) const override;
-};
-
-class ESIVariableUserAgent : public ESIVarState::Variable
-{
-
-public:
-    ~ESIVariableUserAgent() override;
-    ESIVariableUserAgent (ESIVarState &state);
-    void eval (ESIVarState &state, char const *, char const *) const override;
-
-private:
-    static char const * esiUserOs[];
-    enum esiUserOs_t {
-        ESI_OS_WIN,
-        ESI_OS_MAC,
-        ESI_OS_UNIX,
-        ESI_OS_OTHER
-    };
-    esiUserOs_t identifyOs(char const *) const;
-    char const *browserVersion() const {return browserversion;}
-
-    char *getProductVersion (char const *s);
-    esiUserOs_t UserOs;
-    esiBrowser_t browser;
-    char *browserversion;
-};
-
-#endif /* SQUID_SRC_ESI_VARSTATE_H */
-
index e8f987a33a614d525477ee14ecd204e3b2bd9e51..55b56e3474e4e501fb316a8667810c0b3ae7a404 100644 (file)
@@ -1950,11 +1950,7 @@ HttpStateData::httpBuildRequestHeader(HttpRequest * request,
     if (request->flags.accelerated) {
         /* Append Surrogate-Capabilities */
         String strSurrogate(hdr_in->getList(Http::HdrType::SURROGATE_CAPABILITY));
-#if USE_SQUID_ESI
-        snprintf(bbuf, BBUF_SZ, "%s=\"Surrogate/1.0 ESI/1.0\"", Config.Accel.surrogate_id);
-#else
         snprintf(bbuf, BBUF_SZ, "%s=\"Surrogate/1.0\"", Config.Accel.surrogate_id);
-#endif
         strListAdd(&strSurrogate, bbuf, ',');
         hdr_out->putStr(Http::HdrType::SURROGATE_CAPABILITY, strSurrogate.termedBuf());
     }
index 31ca17961a2febfd046a170e74a5acd17e85d03f..6f729bfd58dd550a0ccd968dd85a3bac0297b85e 100644 (file)
@@ -109,8 +109,8 @@ enum HdrType {
     X_SQUID_ERROR,                  /**< Squid custom header on generated error responses */
     HDR_X_ACCELERATOR_VARY,             /**< obsolete Squid custom header. */
     X_NEXT_SERVICES,                /**< Squid custom ICAP header */
-    SURROGATE_CAPABILITY,           /**< Edge Side Includes (ESI) header */
-    SURROGATE_CONTROL,              /**< Edge Side Includes (ESI) header */
+    SURROGATE_CAPABILITY,           /**< W3C Edge Architecture Specification */
+    SURROGATE_CONTROL,              /**< W3C Edge Architecture Specification */
     FRONT_END_HTTPS,                /**< MS Exchange custom header we may have to add */
     FTP_COMMAND,                    /**< Internal header for FTP command */
     FTP_ARGUMENTS,                  /**< Internal header for FTP command arguments */
index 782bacb5984ba6c325435e58f3e55228aa738e77..f673d50ff642800e951d694865ee55accd8105ec 100644 (file)
@@ -1472,14 +1472,6 @@ RegisterModules()
     CallRunnerRegistrator(sslBumpCfgRr);
 #endif
 
-#if USE_SQUID_ESI && HAVE_LIBEXPAT
-    CallRunnerRegistratorIn(Esi, ExpatRr);
-#endif
-
-#if USE_SQUID_ESI && HAVE_LIBXML2
-    CallRunnerRegistratorIn(Esi, Libxml2Rr);
-#endif
-
 #if HAVE_FS_ROCK
     CallRunnerRegistratorIn(Rock, SwapDirRr);
 #endif
index 4f63413fbc8c27ab48c30040a1126915e0d3b301..6b68bd26bc2199f5e1d9a2fab81954336b82c4a2 100644 (file)
@@ -76,9 +76,6 @@ void *StoreEntry::operator new(size_t)
     return new StoreEntry();
 }
 void StoreEntry::operator delete(void *) STUB
-//#if USE_SQUID_ESI
-//ESIElement::Pointer StoreEntry::cachedESITree STUB_RETVAL(nullptr)
-//#endif
 void StoreEntry::buffer() STUB
 void StoreEntry::flush() STUB
 int StoreEntry::unlock(const char *) STUB_RETVAL(0)
diff --git a/test-suite/ESIExpressions.cc b/test-suite/ESIExpressions.cc
deleted file mode 100644 (file)
index 65fc3ff..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 1996-2023 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 86    ESI Expressions */
-
-#include "squid.h"
-#include "esi/Expression.h"
-
-int
-main ()
-{
-    char const *expressions[] = {
-        "!(1==1)", "!(1!=1)", "1!=1", "!1==1", "1==1",
-        "1 <=1","2<=1", "1 < 1", "1 < 2", "-1 < 1","!-1<1",
-        "1>2","2>1","2>=2", "2>3", "1==1&1==1","1==1&1==0",
-        "!('a'<='c')",
-        "(1==1)|('abc'=='def')",
-        "(4!=5)&(4==5)",
-        "(1==1)|(2==3)&(3==4)", /* should be true because of precedence */
-        "(1 & 4)",
-        "(\"abc\" | \"edf\")", "1==1==1",
-        "!('')",
-        /* End of array */""
-    };
-
-    int results[] = {0, 1, 0, 0, 1,
-                     1, 0, 0, 1, 1,
-                     0, 0, 1, 1, 0,
-                     1, 0, 0, 1, 0,
-                     1, 0, 0, 0, 0,
-                     1, 0
-                    };
-
-    int i = 0;
-
-    while (strlen (expressions[i])) {
-        int result = ESIExpression::Evaluate (expressions[i]);
-
-        if (result != results[i])
-            return 1;
-
-        ++i;
-    }
-
-    return 0;
-}
-
index 3ca55d18c3d18f0ae07c07030343fd1cb147a4ae..5803f21b4e1c89cb99daa8c09421e1e07f4b83a8 100644 (file)
@@ -27,27 +27,16 @@ EXTRA_DIST = \
        test-squid-conf.sh \
        testHeader.cc.in
 
-ESI_ALL_TESTS = \
-       ESIExpressions
-
-if ENABLE_ESI
-  ESI_TESTS = $(ESI_ALL_TESTS)
-else
-  ESI_TESTS =
-endif
-
 ## Sort by dependencies - test lowest layers first
 TESTS += \
        syntheticoperators \
        VirtualDeleteOperator \
        splay\
        mem_node_test\
-       mem_hdr_test\
-       $(ESI_TESTS)
+       mem_hdr_test
 
 ## Sort by alpha - any build failures are significant.
 check_PROGRAMS += \
-               $(ESI_TESTS) \
                mem_node_test\
                mem_hdr_test \
                splay \
@@ -87,15 +76,6 @@ stub_libmem.cc: $(top_srcdir)/src/tests/stub_libmem.cc STUB.h
 STUB.h: $(top_srcdir)/src/tests/STUB.h
        cp $(top_srcdir)/src/tests/STUB.h $@
 
-ESIExpressions_SOURCES = \
-       $(DEBUG_SOURCE) \
-       ESIExpressions.cc \
-       stub_libmem.cc
-ESIExpressions_LDADD = $(top_builddir)/src/esi/Expression.o \
-       $(top_builddir)/src/debug/libdebug.la \
-       $(top_builddir)/src/comm/libminimal.la \
-               $(LDADD)
-
 mem_node_test_SOURCES = \
        $(DEBUG_SOURCE) \
        mem_node_test.cc
index 22ddf38feca47e903c1ec5e02b256b82f6bdc0c0..b413aec1793ad878f4ebb388be192eb266915a03 100644 (file)
@@ -43,7 +43,6 @@ DISTCHECK_CONFIGURE_FLAGS=" \
        --disable-removal-policies \
        --disable-icmp \
        --disable-delay-pools \
-       --disable-esi \
        --disable-icap-client \
        --disable-ecap \
        --disable-useragent-log \
@@ -92,7 +91,6 @@ DISTCHECK_CONFIGURE_FLAGS=" \
        --without-aio \
        --without-cap \
        --without-dl \
-       --without-expat \
        --without-gnugss \
        --without-heimdal-krb5 \
        --without-large-files \
@@ -108,7 +106,6 @@ DISTCHECK_CONFIGURE_FLAGS=" \
        --without-psapi \
        --without-systemd \
        --without-tdb \
-       --without-xml2 \
        "
 
 # Fix the distclean testing.
index a9c8aa477013f91f152ab5235d327d13228d687b..56e75bdf686730b3835330936a1714454726c06b 100644 (file)
@@ -99,7 +99,6 @@ DISTCHECK_CONFIGURE_FLAGS=" \
        --enable-auto-locale \
        --enable-translation \
        --enable-zph-qos \
-       --enable-esi \
        --with-aio \
        --with-build-environment=default \
        --with-dl \
index b79d2cdf4e8baffbeea99fa607715c966b8ea8ce..b5ffd8a0fc24f23a27da3504797dbac53badb9b8 100644 (file)
@@ -101,7 +101,6 @@ DISTCHECK_CONFIGURE_FLAGS=" \
        --enable-auto-locale \
        --disable-translation \
        --enable-zph-qos \
-       --enable-esi \
        --with-aio \
        --with-build-environment=default \
        --with-dl \
index bfbd356462dab39e0f4d38618aaa06234e3e4cf3..28d20a87732f7f1973ed8b75113af5d3f835a42f 100644 (file)
@@ -25,7 +25,6 @@ DISTCHECK_CONFIGURE_FLAGS=" \
        --enable-snmp \
        --enable-htcp \
        --enable-carp \
-       --enable-esi \
        --enable-useragent-log \
        --enable-referer-log \
        --disable-wccp \