1
0
mirror of https://github.com/squid-cache/squid.git synced 2025-04-18 22:04:07 +03:00

Remove Edge Side Include (ESI) protocol (#1905)

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.
This commit is contained in:
Amos Jeffries 2024-09-21 20:27:11 +00:00 committed by Squid Anubis
parent fdc5bf76a3
commit 5eb89ef3d8
63 changed files with 28 additions and 7708 deletions

View File

@ -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>

View 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

View 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.
*/

View 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

View 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.

View 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

View File

@ -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

View File

@ -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);
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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 \

View 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;

View 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 \

View File

@ -26,10 +26,6 @@
#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; }

View 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},

View 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

View 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

View 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
-----------------------------------------------------------------------------

View 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"

View 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;

View 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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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);
}

View File

@ -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 */

View File

@ -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 << "\"");
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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 */

View 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());
}

View 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 */

View 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

View 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)

View File

@ -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;
}

View 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

View 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.

View 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 \

View 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 \

View File

@ -25,7 +25,6 @@ DISTCHECK_CONFIGURE_FLAGS=" \
--enable-snmp \
--enable-htcp \
--enable-carp \
--enable-esi \
--enable-useragent-log \
--enable-referer-log \
--disable-wccp \