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:
parent
fdc5bf76a3
commit
5eb89ef3d8
9
CREDITS
9
CREDITS
@ -1522,15 +1522,6 @@ src/auth/ntlm/smb_lm/:
|
||||
|
||||
==============================================================================
|
||||
|
||||
src/esi/Libxml2Parser.cc,
|
||||
src/esi/Libxml2Parser.h:
|
||||
|
||||
* The ESI Libxml2 parser is Copyright (c) 2004 by Joachim Bauch
|
||||
* http://www.joachim-bauch.de
|
||||
* mail@joachim-bauch.de
|
||||
|
||||
==============================================================================
|
||||
|
||||
src/external_acl.c:
|
||||
|
||||
Copyright (C) 2002 MARA Systems AB, Sweden <info@marasystems.com>
|
||||
|
35
configure.ac
35
configure.ac
@ -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
|
||||
|
@ -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.
|
||||
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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},
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
-----------------------------------------------------------------------------
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
2260
src/esi/Esi.cc
2260
src/esi/Esi.cc
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 << "\"");
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -25,7 +25,6 @@ DISTCHECK_CONFIGURE_FLAGS=" \
|
||||
--enable-snmp \
|
||||
--enable-htcp \
|
||||
--enable-carp \
|
||||
--enable-esi \
|
||||
--enable-useragent-log \
|
||||
--enable-referer-log \
|
||||
--disable-wccp \
|
||||
|
Loading…
x
Reference in New Issue
Block a user