]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Summary: Merge of robertc@squid-cache.org--squid/squid--esi--3.0
authorrobertc <>
Mon, 14 Jul 2003 20:15:53 +0000 (20:15 +0000)
committerrobertc <>
Mon, 14 Jul 2003 20:15:53 +0000 (20:15 +0000)
Keywords:

Patches applied:

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-149
     Fixup test-suite makefile pre-merge.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-148
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-262

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-147
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-261

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-146
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-260

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-145
     More merge fixups.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-144
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-259

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-143
     Adjust for recent merges.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-142
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-258

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-141
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-257

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-140
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-256

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-139
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-255

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-138
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-254

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-137
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-253

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-136
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-252

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-135
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-251

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-134
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-250

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-133
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-249

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-132
     Merge of projects@swelltech.com--private/squid--mem-to-disk--3.0--patch-1

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-131
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-247

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-130
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-246

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-129
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-245

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-128
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-244

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-127
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-243

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-126
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-242

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-125
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-241

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-124
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-240

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-123
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-239

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-122
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-238

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-121
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-237

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-120
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-236

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-119
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-235

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-118
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-234

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-117
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-233

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-116
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-232

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-115
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-231

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-114
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-230

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-113
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-229

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-112
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-228

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-111
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-227

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-110
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-226

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-109
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-225

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-108
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-224

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-107
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-223

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-106
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-222

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-105
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-221

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-104
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-220

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-103
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-219

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-102
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-218

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-101
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-217

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-100
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-216

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-99
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-215

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-98
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-214

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-97
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-213

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-96
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-212

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-95
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-211

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-94
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-210

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-93
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-209

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-92
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-208

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-91
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-207

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-90
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-206

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-89
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-205

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-88
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-204

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-87
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-203

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-86
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-202

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-85
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-201

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-84
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-200

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-83
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-199

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-82
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-198

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-81
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-197

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-80
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-196

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-79
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-195

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-78
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-194

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-77
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-193

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-76
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-192

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-75
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-191

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-74
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-190

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-73
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-189

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-72
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-188

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-71
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-187

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-70
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-186

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-69
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-185

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-68
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-184

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-67
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-183

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-66
     Towards esi Functions.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-65
     Refactoring towards ESI Functions.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-64
     Propogate message headers to ESI includes.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-63
     Extract HttpHeader class to HttpHeader.h

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-62
     Extract ESIInclude to separate files.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-61
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-182

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-60
     Merge of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-181

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-59
     Merge from HEAD

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-58
     Prevent a race condition in esi includes.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-57
     Merge from HEAD.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-56
     Merge from HEAD.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-55
     BUGFIX: Memory leak in ESI requests.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-54
     BUGFIX: libTrie was returning random values when adding a node.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-53
     Give libTrie stricter g++ flags.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-52
     Parse '' correctly in esi expressions.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-51
     Fixup build.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-50
     Merge from HEAD.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-49
     Merge from HEAD.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-48
     ESI logging tweaks.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-47
     Bugfix: redirection of internal requests would segv.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-46
     Merge from HEAD

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-45
     Merge from HEAD.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-44
     Implement variable evaluation in esi:assign short form.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-43
     Implement ESI long form variable assignment.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-42
     Inital addition of ESIAssign.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-41
     Finish inserting all variables for ESI into a trie.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-40
     Variable logic extraction.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-39
     Separate out various variable logic.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-38
     Allow character transforms for tries.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-37
     ESI Variable refactoring to ease support of dynamic variables.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-36
     Allow low expiry dates on objects when using ESI.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-35
     Bugfix TrieNode constructor.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-34
     Eliminate esiVarState::esiVar_t.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-33
     Introduce esiVarState::Variable class.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-32
     Merge from HEAD.

  * robertc@squid-cache.org--squid/squid--esi--3.0--patch-31
     Merge CVS changes to ESI.

65 files changed:
lib/libTrie/configure.in
lib/libTrie/include/Makefile.am
lib/libTrie/include/Trie.cci
lib/libTrie/include/Trie.h
lib/libTrie/include/TrieCharTransform.h [new file with mode: 0644]
lib/libTrie/include/TrieNode.cci
lib/libTrie/include/TrieNode.h
lib/libTrie/src/Makefile.am
lib/libTrie/src/Trie.cc
lib/libTrie/src/TrieNode.cc
lib/libTrie/test/Makefile.am
lib/libTrie/test/trie.cc
src/ACLChecklist.h
src/ACLReplyMIMEType.h
src/ESI.cc
src/ESIAssign.cc [new file with mode: 0644]
src/ESIAssign.h [new file with mode: 0644]
src/ESIContext.cc
src/ESIContext.h
src/ESICustomParser.cc
src/ESICustomParser.h
src/ESIElement.h
src/ESIExpression.cc
src/ESIExpression.h [new file with mode: 0644]
src/ESIInclude.cc [new file with mode: 0644]
src/ESIInclude.h [new file with mode: 0644]
src/ESILiteral.h
src/ESISegment.h
src/ESISequence.cc
src/ESISequence.h
src/ESIVar.h [new file with mode: 0644]
src/ESIVarState.cc [new file with mode: 0644]
src/ESIVarState.h [new file with mode: 0644]
src/HttpHdrRange.cc
src/HttpHeader.cc
src/HttpHeader.h
src/HttpReply.h
src/HttpRequest.h
src/Makefile.am
src/asn.cc
src/auth/basic/auth_basic.cc
src/auth/digest/auth_digest.cc
src/auth/ntlm/auth_ntlm.cc
src/authenticate.cc
src/authenticate.h
src/client_side_reply.cc
src/client_side_request.h
src/forward.cc
src/htcp.cc
src/htcp.h
src/http.cc
src/http.h
src/mem.cc
src/neighbors.cc
src/peer_select.cc
src/protos.h
src/redirect.cc
src/refresh.cc
src/store_client.cc
src/store_log.cc
src/structs.h
src/typedefs.h
src/whois.cc
test-suite/ESIExpressions.cc [new file with mode: 0644]
test-suite/Makefile.am

index 367923ccf1250d94c4142b2f7648fe96351cff48..80ce90bd25b66af782737fd5c3d7afe96139305a 100644 (file)
@@ -4,48 +4,59 @@ AC_CONFIG_SRCDIR([src/Trie.cc])
 AM_CONFIG_HEADER([config.h])
 
 SquidInline="yes"
-AC_ARG_ENABLE(inline,
-[  --disable-inline        Don't compile trivial methods as inline. Squid
-                            is coded with much of the code able to be inlined.<                             Inlining is good for production builds, but not
-                            good for development. During development, use
-                            --disable-inline to reduce compilation times and
-                            allow incremental builds to be quick. For
-                            production builds, or load tests, use
-                            --enable-inline to have squid make all trivial
-                            methods inlinable by the compiler.],
-[ if test "$enableval" = "no" ; then
-     SquidInline="no"
-   fi
-])
-
-if test "$SquidInline" = "yes" ; then
-    AC_DEFINE(_SQUID_INLINE_, inline, [Keyword used by squid for inlining methods])
-    AC_DEFINE(_USE_INLINE_,, [Include inline methods into header file])
-else
-    AC_DEFINE(_SQUID_INLINE_,, [Keyword used by squid for inlining methods])
-fi
+            AC_ARG_ENABLE(inline,
+                          [  --disable-inline        Don't compile trivial methods as inline. Squid
+                             is coded with much of the code able to be inlined.<                             Inlining is good for production builds, but not
+                             good for development. During development, use
+                             --disable-inline to reduce compilation times and
+                             allow incremental builds to be quick. For
+                             production builds, or load tests, use
+                             --enable-inline to have squid make all trivial
+                             methods inlinable by the compiler.],
+                             [ if test "$enableval" = "no" ; then
+                             SquidInline="no"
+                             fi
+                             ])
+
+                             if test "$SquidInline" = "yes" ; then
+                             AC_DEFINE(_SQUID_INLINE_, inline, [Keyword used by squid for inlining methods])
+                             AC_DEFINE(_USE_INLINE_,, [Include inline methods into header file])
+                             else
+                             AC_DEFINE(_SQUID_INLINE_,, [Keyword used by squid for inlining methods])
+                             fi
 
 # Checks for programs.
-AC_PROG_CXX
-AC_PROG_CC
-AC_PROG_MAKE_SET
+                             AC_PROG_CXX
+                             AC_PROG_CC
+                             AC_PROG_MAKE_SET
 # for old automakes - like squid-cache.orgs!
-AM_INIT_AUTOMAKE(libTrie, 0.1)
-AM_MAINTAINER_MODE
-AC_PROG_RANLIB
+                             AM_INIT_AUTOMAKE(libTrie, 0.1)
+                             AM_MAINTAINER_MODE
+                             AC_PROG_RANLIB
+
+                             dnl set useful flags
+                             if test "$GCC" = "yes"; then
+                             TRIE_CFLAGS="-Werror -Wall -Wpointer-arith -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wcomments"
+                             TRIE_CXXFLAGS="-Werror -Wall -Wpointer-arith -Wwrite-strings -Wmissing-prototypes -Wcomments"
+                             else
+                             TRIE_CFLAGS=
+                             TRIE_CXXFLAGS=
+                             fi
+                             AC_SUBST(TRIE_CFLAGS)
+                             AC_SUBST(TRIE_CXXFLAGS)
 
 # Checks for libraries.
 
 # Checks for header files.
 
 # Checks for typedefs, structures, and compiler characteristics.
-AC_C_CONST
-AC_TYPE_SIZE_T
+                             AC_C_CONST
+                             AC_TYPE_SIZE_T
 
 # Checks for library functions.
 
-AC_CONFIG_FILES([Makefile
-               include/Makefile
-                 src/Makefile
-                test/Makefile])
-AC_OUTPUT
+                             AC_CONFIG_FILES([Makefile
+                             include/Makefile
+                             src/Makefile
+                             test/Makefile])
+                             AC_OUTPUT
index a52bae3667df63bb89125a44718fd6db7daf209a..395e2db3be9d369f570b44e8d075457099972c28 100644 (file)
@@ -1 +1 @@
-noinst_HEADERS = Trie.h TrieNode.h
+noinst_HEADERS = Trie.h TrieNode.h TrieCharTransform.h
index fe3e461e1d68dffd4c97938f4235c4783337ed6c..ae77d501b855a31419e3b01de8ab5c657d595f79 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 Robert Collins <rbtcollins@hotmail.com>
+ * Copyright (c) 2002,2003 Robert Collins <rbtcollins@hotmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,7 +25,8 @@ void *
 Trie::find (char const *aString, size_t theLength)
 {
     if (head)
-       return head->find (aString, theLength);
+        return head->find (aString, theLength, transform, false);
+
     return NULL;
 }
 
@@ -33,7 +34,9 @@ void *
 Trie::findPrefix (char const *aString, size_t theLength)
 {
     if (head)
-       return head->find (aString, theLength, true);
+        return head->find (aString, theLength, transform, true);
+
     return NULL;
 }
+
 #endif
index 838bfb7b19e9b76cd48ffe13cee3191cf57d6252..856595689ca39276cfa38211c94d762696e8ac90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 Robert Collins <rbtcollins@hotmail.com>
+ * Copyright (c) 2002,2003 Robert Collins <rbtcollins@hotmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -36,6 +36,7 @@
 /* C bindings */
 #ifndef   __cplusplus
 
+/* TODO: provide parameterisation for C bindings */
 void *TrieCreate ();
 void TrieDestroy (void *);
 void *TrieFind (void *, char const *, size_t);
@@ -44,6 +45,8 @@ int TrieAdd (void *, char const *, size_t, void *);
 /* C++ bindings */
 #else
 
+class TrieCharTransform;
+
 class TrieNode;
 
 /* TODO: parameterize this to be more generic -
@@ -54,7 +57,7 @@ class Trie
 {
 
 public:
-    Trie();
+    Trie(TrieCharTransform *aTransform = 0);
     ~Trie();
     Trie (Trie const &);
     Trie &operator= (Trie const &);
@@ -79,6 +82,9 @@ public:
 
 private:
     TrieNode *head;
+
+    /* transfor each 8 bits in the element */
+    TrieCharTransform *transform;
 };
 
 #endif /* __cplusplus */
diff --git a/lib/libTrie/include/TrieCharTransform.h b/lib/libTrie/include/TrieCharTransform.h
new file mode 100644 (file)
index 0000000..523a392
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2003 Robert Collins <rbtcollins@hotmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef   LIBTRIE_TRIECHARTRANSFORM_H
+#define   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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* C bindings */
+#ifndef   __cplusplus
+
+/* C++ bindings */
+#else
+#include <sys/types.h>
+#include <utility>
+#include <ctype.h>
+
+/* TODO: parameterize this to be more generic -
+* i.e. M-ary internal node sizes etc
+*/
+
+class TrieCharTransform
+{
+
+public:
+    virtual ~TrieCharTransform() {}
+
+    virtual char const operator () (char const) = 0;
+};
+
+class TrieCaseless : public TrieCharTransform
+{
+    virtual char const operator () (char const aChar) {return tolower(aChar);}
+};
+
+#endif /* __cplusplus */
+
+#endif /* LIBTRIE_TRIECHARTRANSFORM_H */
index b51b7790e0df87144f5aa7840990472bed19c6fb..3d33fe62524f17715a22946cff8fc33124b00ac1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 Robert Collins <rbtcollins@hotmail.com>
+ * Copyright (c) 2002,2003 Robert Collins <rbtcollins@hotmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
 
 #ifdef __cplusplus
 #include "TrieNode.h"
+#include "TrieCharTransform.h"
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 
 /* recursive. TODO? make iterative */
 void *
-TrieNode::find (char const *aString, size_t theLength, bool prefix) const
+TrieNode::find (char const *aString, size_t theLength, TrieCharTransform *transform, bool const prefix) const
 {
     if (theLength) {
-       int index = -1;
-       if (internal[*aString])
-           index = *aString;
-       else if (internal[tolower(*aString)])
-           index = tolower(*aString);
-       if (index > -1) {
-           void *result;
-           result = internal[index]->find(aString + 1, theLength - 1, prefix);
-           if (result)
-               return result;
-       }
-       if (prefix)
-           return _privateData;
-       return NULL;
+        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 NULL;
     } else {
-       /* terminal node */
-       return _privateData;
+        /* terminal node */
+        return _privateData;
     }
 }
+
 #endif
index 950f8ce3f0b77754747b677c43eb472325bb51a5..e9aaec8a3cb55a3e0e59bc66c750ce3a673f2f63 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 Robert Collins <rbtcollins@hotmail.com>
+ * Copyright (c) 2002,2003 Robert Collins <rbtcollins@hotmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -43,6 +43,8 @@
 * i.e. M-ary internal node sizes etc
 */
 
+class TrieCharTransform;
+
 class TrieNode
 {
 
@@ -56,7 +58,7 @@ public:
     * If found, return the private data.
     * If not found, return NULL.
     */
-    _SQUID_INLINE_ void *find (char const *, size_t, bool prefix = false) const;
+    _SQUID_INLINE_ void *find (char const *, size_t, TrieCharTransform *, bool const prefix) const;
 
     /* Add a string.
     * returns false if the string is already
@@ -64,7 +66,7 @@ public:
     */
 
     bool add
-        (char const *, size_t, void *);
+        (char const *, size_t, void *, TrieCharTransform *);
 
 private:
     /* 256-way Trie */
index 95d3fa5455d2a6379e04201e9340de9561e38d8d..0fed01f36f5819ee4074f7f929965d6d74d29474 100644 (file)
@@ -1,6 +1,9 @@
 
 INCLUDES = -I$(top_srcdir)/include
 
+AM_CFLAGS = @TRIE_CFLAGS@
+AM_CXXFLAGS = @TRIE_CXXFLAGS@
+
 noinst_LIBRARIES = libTrie.a
 
 libTrie_a_SOURCES = Trie.cc \
index 3226e9be5657a07d0453ef134f463db1facbfdcb..150fb1716eb7cecfa42e8c7316c83301b2877632 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 Robert Collins <rbtcollins@hotmail.com>
+ * Copyright (c) 2002,2003 Robert Collins <rbtcollins@hotmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,8 +22,9 @@
 #include <unistd.h>
 #endif
 #include "TrieNode.h"
+#include "TrieCharTransform.h"
 
-Trie::Trie () : head (0)
+Trie::Trie (TrieCharTransform *aTransform) : head (0) , transform (aTransform)
 {}
 
 extern "C" void *TrieCreate ()
@@ -34,6 +35,7 @@ extern "C" void *TrieCreate ()
 Trie::~Trie ()
 {
     delete head;
+    delete transform;
 }
 
 extern "C" void TrieDestroy (void *aTrie)
@@ -59,13 +61,13 @@ Trie::add
             return false;
 
         return head->add
-               (aString, theLength, privatedata);
+               (aString, theLength, privatedata, transform);
     }
 
     head = new TrieNode;
 
     return head->add
-           (aString, theLength, privatedata);
+           (aString, theLength, privatedata, transform);
 }
 
 extern "C" int TrieAdd (void *aTrie, char const *aString, size_t theLength, void *privatedata)
index a7f4786428b94bed460e17ad3d92660723dd8f4b..b5ea5084293ce007223657eb258dd1e56fbaba27 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 Robert Collins <rbtcollins@hotmail.com>
+ * Copyright (c) 2002,2003 Robert Collins <rbtcollins@hotmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 
 #include "TrieNode.h"
+#include "TrieCharTransform.h"
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#include <ctype.h>
 
-TrieNode::TrieNode ()
+TrieNode::TrieNode () : _privateData (NULL)
 {
     for (int i = 0; i < 256; ++i)
         internal[i] = NULL;
@@ -39,24 +39,18 @@ TrieNode::~TrieNode ()
 bool
 
 TrieNode::add
-    (char const *aString, size_t theLength, void *privatedata)
+    (char const *aString, size_t theLength, void *privatedata, TrieCharTransform *transform)
 {
     /* We trust that privatedata and existant keys have already been checked */
 
     if (theLength) {
-        int index;
+        int index = transform ? (*transform) (*aString): *aString;
 
-        if (internal[*aString])
-            index = *aString;
-        else if (internal[tolower(*aString)])
-            index = tolower (*aString);
-        else {
-            index = *aString;
+        if (!internal[index])
             internal[index] = new TrieNode;
-        }
 
-        internal[index]->add
-        (aString + 1, theLength - 1, privatedata);
+        return internal[index]->add
+               (aString + 1, theLength - 1, privatedata, transform);
     } else {
         /* terminal node */
 
@@ -72,4 +66,3 @@ TrieNode::add
 #ifndef _USE_INLINE_
 #include "TrieNode.cci"
 #endif
-
index dabb1ab44f025c7733b34793379ed90f9f740b7f..abb8cad137fc12da0ee1d1d10e51b0a219e4bb0f 100644 (file)
@@ -1,5 +1,8 @@
 INCLUDES = -I$(top_srcdir)/include
 
+AM_CFLAGS = @TRIE_CFLAGS@
+AM_CXXFLAGS = @TRIE_CXXFLAGS@
+
 TESTS = trie trie-c
 
 check_PROGRAMS = trie trie-c
@@ -9,4 +12,3 @@ trie_LDADD = $(top_builddir)/src/libTrie.a
 
 trie_c_SOURCES = trie-c.c
 trie_c_LDADD = $(top_builddir)/src/libTrie.a -lstdc++
-
index b05d3c695c9214e24cfa7db7d12b745a4045ec3d..d3ace8871bf2ec42d55e79c8fdcec42938dd3450 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 Robert Collins <rbtcollins@hotmail.com>
+ * Copyright (c) 2002,2003 Robert Collins <rbtcollins@hotmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 
 #include "Trie.h"
+#include "TrieCharTransform.h"
 #include <iostream>
 
-int main (int argc, char **argv)
+bool
+CaseSensitiveCheck()
 {
     Trie aTrie;
 
@@ -39,10 +41,93 @@ int main (int argc, char **argv)
         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;
+}
+
+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 argc, char **argv)
+{
+    if (CaseSensitiveCheck()) {
+        std::cerr << "Case sensitive check failure." << std::endl;
+        return 1;
+    }
+
+    if (CaseInsensitiveCheck()) {
+        std::cerr << "Case in-sensitive check failure." << std::endl;
+        return 1;
+    }
+
     return 0;
 }
index 3aa9862561936aaf3cc084d02addfcb3599af4e3..a3edcaba9ced7b49667d510e7bf9235df15a4af6 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ACLChecklist.h,v 1.13 2003/07/11 01:40:34 robertc Exp $
+ * $Id: ACLChecklist.h,v 1.14 2003/07/14 14:15:55 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -39,6 +39,8 @@
 
 class ExternalACLEntry;
 
+class ConnStateData;
+
 class ACLChecklist
 {
 
index f328689518424c23477a48834eacf1991e20c9dc..0e03f41d3c0af641bd1a0c9826350e0f0e962b15 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ACLReplyMIMEType.h,v 1.2 2003/07/11 01:40:34 robertc Exp $
+ * $Id: ACLReplyMIMEType.h,v 1.3 2003/07/14 14:15:55 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -40,6 +40,7 @@
 #include "ACLReplyHeaderStrategy.h"
 #include "ACLStrategised.h"
 #include "ACLChecklist.h"
+/* FIXME: TODO: this is broken - should be HttpReply checks!! */
 #include "HttpRequest.h"
 
 class ACLReplyMIMEType
index d02a28aed973475a831b36a5e3bc18123ae340d0..8a6006c4c0276e0602e40c951e81c3bee9d6ffad 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ESI.cc,v 1.3 2003/03/15 04:17:38 robertc Exp $
+ * $Id: ESI.cc,v 1.4 2003/07/14 14:15:55 robertc Exp $
  *
  * DEBUG: section 86    ESI processing
  * AUTHOR: Robert Collins
 #include "ESIAttempt.h"
 #include "ESIExcept.h"
 #include "client_side.h"
+#include "ESIVarState.h"
+#include "ESIAssign.h"
+#include "ESIExpression.h"
+#include "HttpRequest.h"
 
 /* quick reference on behaviour here.
  * The ESI specification 1.0 requires the ESI processor to be able to 
@@ -57,8 +61,6 @@
 
 class ESIStreamContext;
 
-typedef class ESIStreamContext esiStreamContext;
-
 /* TODO: split this out into separate files ? */
 /* Parsing: quick and dirty. ESI files are not valid XML, so a generic
  * XML parser is not much use. Also we need a push parser not a pull 
@@ -86,107 +88,6 @@ bool operator == (ESIElement const *lhs, ESIElement::Pointer const &rhs)
     return lhs == rhs.getRaw();
 }
 
-
-/* esi variable replacement logic */
-
-typedef enum {
-    ESI_BROWSER_MSIE,
-    ESI_BROWSER_MOZILLA,
-    ESI_BROWSER_OTHER
-} esiBrowser_t;
-
-static char const * esiBrowsers[]=
-    {"MSIE",
-     "MOZILLA",
-     "OTHER"
-    };
-
-/* Recursive uses are not supported by design */
-
-struct _query_elem{char *var, *val;};
-
-struct esiVarState
-{
-    ESISegment::Pointer extractList();
-    char *extractChar();
-    void feedData (const char *buf, size_t len);
-    void buildVary (HttpReply *rep);
-
-    void *operator new (size_t byteCount);
-    void operator delete (void *address);
-    void deleteSelf() const;
-    void freeResources();
-    esiVarState (HttpHeader const *hdr, char const *uri);
-
-private:
-    char *getProductVersion (char const *s);
-    ESISegment::Pointer input;
-    ESISegment::Pointer output;
-    HttpHeader hdr;
-
-    struct _query_elem *query;
-    size_t query_sz;
-    size_t query_elements;
-    char *query_string;
-
-    struct
-    {
-
-int language:
-        1;
-
-int cookie:
-        1;
-
-int host:
-        1;
-
-int referer:
-        1;
-
-int useragent:
-        1;
-    }
-
-    flags;
-    esiBrowser_t browser;
-    char *browserversion;
-    enum esiVar_t {
-        ESI_VAR_LANGUAGE,
-        ESI_VAR_COOKIE,
-        ESI_VAR_HOST,
-        ESI_VAR_REFERER,
-        ESI_VAR_USERAGENT,
-        ESI_QUERY_STRING,
-        ESI_VAR_OTHER
-    };
-    void doIt ();
-    void eval (esiVar_t type, char const *, char const *);
-    enum esiUserOs_t{
-        ESI_OS_WIN,
-        ESI_OS_MAC,
-        ESI_OS_UNIX,
-        ESI_OS_OTHER
-    } UserOs;
-    static char const * esiUserOs[];
-    static esiVar_t GetVar(char *s, int len);
-    bool validChar (char c);
-};
-
-CBDATA_TYPE (esiVarState);
-FREE esiVarStateFree;
-
-char const *esiVarState::esiUserOs[]=
-    {
-        "WIN",
-        "MAC",
-        "UNIX",
-        "OTHER"
-    };
-
-
-extern int esiExpressionEval (char const *);
-
 typedef ESIContext::esiKick_t esiKick_t;
 
 
@@ -202,7 +103,7 @@ struct esiComment : public ESIElement
     ~esiComment();
     esiComment();
     Pointer makeCacheable() const;
-    Pointer makeUsable(esiTreeParentPtr, esiVarState &) const;
+    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const;
 
     void render(ESISegment::Pointer);
     void finish();
@@ -213,89 +114,13 @@ private:
 
 MemPool * esiComment::pool = NULL;
 
-class esiInclude;
-typedef RefCount<esiInclude> esiIncludePtr;
-
-class ESIStreamContext : public RefCountable
-{
-
-public:
-    typedef RefCount<ESIStreamContext> Pointer;
-    void *operator new(size_t);
-    void operator delete(void *);
-    void deleteSelf() const;
-    ESIStreamContext();
-    ~ESIStreamContext();
-    void freeResources();
-    int finished;
-    esiIncludePtr include;
-    ESISegment::Pointer localbuffer;
-    ESISegment::Pointer buffer;
-
-private:
-    CBDATA_CLASS(ESIStreamContext);
-};
-
-CBDATA_CLASS_INIT (ESIStreamContext);
 
 #include "ESILiteral.h"
 MemPool *esiLiteral::pool = NULL;
 
 #include "ESISequence.h"
 
-/* esiInclude */
-
-class esiInclude : public ESIElement
-{
-
-public:
-    void *operator new (size_t byteCount);
-    void operator delete (void *address);
-    void deleteSelf() const;
-
-    esiInclude(esiTreeParentPtr, int attributes, const char **attr, ESIContext *);
-    ~esiInclude();
-    void render(ESISegment::Pointer);
-    esiProcessResult_t process (int dovars);
-    Pointer makeCacheable() const;
-    Pointer makeUsable(esiTreeParentPtr, esiVarState &) const;
-    void subRequestDone (ESIStreamContext::Pointer, bool);
-
-    struct
-    {
-
-int onerrorcontinue:
-        1; /* on error return zero data */
-
-int failed:
-        1; /* Failed to process completely */
-
-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 fail(ESIStreamContext::Pointer);
-    void finish();
-
-private:
-    static MemPool *Pool;
-    static void Start (ESIStreamContext::Pointer, char const *, esiVarState *);
-    esiTreeParentPtr parent;
-    void start();
-    bool started;
-    bool sent;
-    esiInclude(esiInclude const &);
-    bool dataNeeded() const;
-};
-
-MemPool *esiInclude::Pool = NULL;
+#include "ESIInclude.h"
 
 /* esiRemove */
 
@@ -311,7 +136,7 @@ public:
     void render(ESISegment::Pointer);
     bool addElement (ESIElement::Pointer);
     Pointer makeCacheable() const;
-    Pointer makeUsable(esiTreeParentPtr, esiVarState &) const;
+    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const;
     void finish();
 };
 
@@ -333,11 +158,11 @@ struct esiTry : public ESIElement
 
     void render(ESISegment::Pointer);
     bool addElement (ESIElement::Pointer);
-    void fail(ESIElement *);
+    void fail(ESIElement *, char const * = NULL);
     esiProcessResult_t process (int dovars);
     void provideData (ESISegment::Pointer data, ESIElement * source);
     Pointer makeCacheable() const;
-    Pointer makeUsable(esiTreeParentPtr, esiVarState &) const;
+    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const;
 
     ESIElement::Pointer attempt;
     ESIElement::Pointer except;
@@ -372,18 +197,7 @@ private:
 
 MemPool *esiTry::Pool = NULL;
 
-/* esiVar */
-
-struct esiVar:public esiSequence
-{
-    //    void *operator new (size_t byteCount);
-    //    void operator delete (void *address);
-    void deleteSelf() const;
-    esiVar(esiTreeParentPtr aParent) : esiSequence (aParent)
-    {
-        flags.dovars = 1;
-    }
-};
+#include "ESIVar.h"
 
 /* esiChoose */
 
@@ -398,14 +212,14 @@ struct esiChoose : public ESIElement
 
     void render(ESISegment::Pointer);
     bool addElement (ESIElement::Pointer);
-    void fail(ESIElement *);
+    void fail(ESIElement *, char const * = NULL);
     esiProcessResult_t process (int dovars);
 
     void provideData (ESISegment::Pointer data, ESIElement *source);
     void makeCachableElements(esiChoose const &old);
-    void makeUsableElements(esiChoose const &old, esiVarState &);
+    void makeUsableElements(esiChoose const &old, ESIVarState &);
     Pointer makeCacheable() const;
-    Pointer makeUsable(esiTreeParentPtr, esiVarState &) const;
+    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const;
     void NULLUnChosen();
 
     ElementList elements;
@@ -430,10 +244,10 @@ struct esiWhen : public esiSequence
     void *operator new (size_t byteCount);
     void operator delete (void *address);
     void deleteSelf() const;
-    esiWhen(esiTreeParentPtr aParent, int attributes, const char **attr, esiVarState *);
+    esiWhen(esiTreeParentPtr aParent, int attributes, const char **attr, ESIVarState *);
     ~esiWhen();
     Pointer makeCacheable() const;
-    Pointer makeUsable(esiTreeParentPtr, esiVarState &) const;
+    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const;
 
     bool testsTrue() const { return testValue;}
 
@@ -444,7 +258,7 @@ private:
     esiWhen (esiWhen const &);
     bool testValue;
     char const *unevaluatedExpression;
-    esiVarState *varState;
+    ESIVarState *varState;
     void evaluate();
 };
 
@@ -487,16 +301,7 @@ ESIStreamContext::ESIStreamContext() : finished(false), include (NULL), localbuf
 /* Local functions */
 /* ESIContext */
 static ESIContext *ESIContextNew(HttpReply *, clientStreamNode *, clientHttpRequest *);
-/* esiStreamContext */
-static esiStreamContext *esiStreamContextNew (esiIncludePtr);
-
-/* other */
-static CSCB esiBufferRecipient;
-static CSD esiBufferDetach;
 
-/* ESI TO CONSIDER:
- * 1. retry failed upstream requests
- */
 
 void *
 ESIContext::operator new(size_t byteCount)
@@ -564,9 +369,10 @@ ESIContext::provideData (ESISegment::Pointer theData, ESIElement * source)
 }
 
 void
-ESIContext::fail (ESIElement * source)
+ESIContext::fail (ESIElement * source, char const *anError)
 {
     setError();
+    setErrorMessage (anError);
     fail ();
     send ();
 }
@@ -613,7 +419,7 @@ ESIContext::kick ()
             break;
 
         case ESI_PROCESS_FAILED:
-            debug (86,0)("esiKick: esiProcess %p FAILED\n", this);
+            debug (86,2)("esiKick: esiProcess %p FAILED\n", this);
             /* this can not happen - processing can't fail until we have data,
              * and when we come here we have sent data to the client
              */
@@ -1128,7 +934,7 @@ ESIContextNew (HttpReply *rep, clientStreamNode *thisNode, clientHttpRequest *ht
         rv->thisNode = thisNode;
         rv->http = http;
         rv->flags.clientwantsdata = 1;
-        rv->varState = new esiVarState (&http->request->header, http->uri);
+        rv->varState = new ESIVarState (&http->request->header, http->uri);
         debug (86,5)("ESIContextNew: Client wants data (always created during reply cycle\n");
     }
 
@@ -1164,6 +970,9 @@ ESIElement::IdentifyElement (const char *el)
     if (!strncmp (el + offset, "attempt", 7))
         return ESI_ELEMENT_ATTEMPT;
 
+    if (!strncmp (el + offset, "assign", 6))
+        return ESI_ELEMENT_ASSIGN;
+
     if (!strncmp (el + offset, "remove", 6))
         return ESI_ELEMENT_REMOVE;
 
@@ -1270,7 +1079,7 @@ ESIContext::start(const char *el, const char **attr, size_t attrCount)
 
     case ESIElement::ESI_ELEMENT_INCLUDE:
         /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new esiInclude (parserState.top().getRaw(), specifiedattcount, attr, this);
+        element = new ESIInclude (parserState.top().getRaw(), specifiedattcount, attr, this);
         break;
 
     case ESIElement::ESI_ELEMENT_REMOVE:
@@ -1295,7 +1104,7 @@ ESIContext::start(const char *el, const char **attr, size_t attrCount)
 
     case ESIElement::ESI_ELEMENT_VARS:
         /* Put on the stack to allow skipping of 'invalid' markup */
-        element = new esiVar (parserState.top().getRaw());
+        element = new ESIVar (parserState.top().getRaw());
         break;
 
     case ESIElement::ESI_ELEMENT_CHOOSE:
@@ -1312,6 +1121,11 @@ ESIContext::start(const char *el, const char **attr, size_t attrCount)
         /* Put on the stack to allow skipping of 'invalid' markup */
         element = new esiOtherwise (parserState.top().getRaw());
         break;
+
+    case ESIElement::ESI_ELEMENT_ASSIGN:
+        /* Put on the stack to allow skipping of 'invalid' markup */
+        element = new ESIAssign (parserState.top().getRaw(), specifiedattcount, attr, this);
+        break;
     }
 
     addStackElement(element);
@@ -1364,6 +1178,8 @@ ESIContext::end(const char *el)
     case ESIElement::ESI_ELEMENT_WHEN:
 
     case ESIElement::ESI_ELEMENT_OTHERWISE:
+
+    case ESIElement::ESI_ELEMENT_ASSIGN:
         /* pop of the stack */
         parserState.stack[--parserState.stackdepth] = NULL;
         break;
@@ -1403,8 +1219,7 @@ ESIContext::parserComment (const char *s)
                      tempParser->errorString());
             debug (86,0)("%s",tempstr);
 
-            if (!errormessage)
-                errormessage = xstrdup (tempstr);
+            setErrorMessage(tempstr);
         }
 
         debug (86,5)("ESIContext::parserComment: ESI <!-- block parsed\n");
@@ -1466,8 +1281,7 @@ ESIContext::parseOneBuffer()
                   parserState.theParser->errorString());
         debug (86,0)("%s", tempstr);
 
-        if (!errormessage)
-            errormessage = xstrdup (tempstr);
+        setErrorMessage(tempstr);
 
         assert (flags.error);
 
@@ -1584,8 +1398,7 @@ ESIContext::process ()
             debug (86,0)("esiProcess: tree Processed FAILED\n");
             setError();
 
-            if (!errormessage)
-                errormessage = xstrdup("esiProcess: ESI template Processing failed.");
+            setErrorMessage("esiProcess: ESI template Processing failed.");
 
             PROF_stop(esiProcessing);
 
@@ -1650,7 +1463,7 @@ ESIContext::freeResources ()
     ESISegmentFreeList (buffered);
     ESISegmentFreeList (outbound);
     ESISegmentFreeList (outboundtail);
-    cbdataFree (varState);
+    varState->deleteSelf();
     /* don't touch incoming, it's a pointer into buffered anyway */
 }
 
@@ -1673,7 +1486,7 @@ ESIContext::fail ()
     flags.error = 1;
     /* create an error object */
     ErrorState * err = clientBuildError(errorpage, errorstatus, NULL,
-                                        http->conn ? &http->conn->peer.sin_addr : &no_addr, http->request);
+                                        http->getConn().getRaw() != NULL ? &http->getConn()->peer.sin_addr : &no_addr, http->request);
     err->err_msg = errormessage;
     errormessage = NULL;
     rep = errorBuildReply (err);
@@ -1699,217 +1512,6 @@ ESIContext::fail ()
      */
 }
 
-/* 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,
- * and clean them up when finished.
- * Pre-condition: 
- *   The request is an internal ESI subrequest.
- *   data context is not NULL
- *   There are no more entries in the stream chain.
- */
-void
-esiBufferRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply *rep, StoreIOBuffer recievedData)
-{
-    /* Test preconditions */
-    assert (node != NULL);
-    /* 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 == NULL);
-    assert (http->conn == NULL);
-
-    esiStreamContext::Pointer esiStream = dynamic_cast<esiStreamContext *>(node->data.getRaw());
-    assert (esiStream.getRaw() != NULL);
-    /* If segments become more flexible, ignore thisNode */
-    assert (recievedData.length <= sizeof(esiStream->localbuffer->buf));
-    assert (!esiStream->finished);
-
-    debug (86,5) ("esiBufferRecipient rep %p body %p len %d\n", rep, recievedData.data, recievedData.length);
-    assert (node->readBuffer.offset == recievedData.offset || recievedData.length == 0);
-
-    /* trivial case */
-
-    if (http->out.offset != 0) {
-        assert(rep == NULL);
-    } else {
-        if (rep) {
-            if (rep->sline.status != HTTP_OK) {
-                httpReplyDestroy(rep);
-                rep = NULL;
-                esiStream->include->fail (esiStream);
-                esiStream->finished = 1;
-                httpRequestFree (http);
-                return;
-            }
-
-#if HEADERS_LOG
-            /* should be done in the store rather than every recipient?  */
-            headersLog(0, 0, http->request->method, rep);
-
-#endif
-
-            httpReplyDestroy(rep);
-
-            rep = NULL;
-        }
-    }
-
-    if (recievedData.data && recievedData.length) {
-        http->out.offset += recievedData.length;
-
-        if (recievedData.data >= esiStream->localbuffer->buf &&
-                recievedData.data < &esiStream->localbuffer->buf[sizeof(esiStream->localbuffer->buf)]) {
-            /* original static buffer */
-
-            if (recievedData.data != esiStream->localbuffer->buf) {
-                /* But not the start of it */
-                xmemmove (esiStream->localbuffer->buf, recievedData.data, recievedData.length);
-            }
-
-            esiStream->localbuffer->len = recievedData.length;
-        } else {
-            assert (esiStream->buffer.getRaw() != NULL);
-            esiStream->buffer->len = recievedData.length;
-        }
-    }
-
-    /* EOF / Read error /  aborted entry */
-    if (rep == NULL && recievedData.data == NULL && recievedData.length == 0) {
-        /* TODO: get stream status to test the entry for aborts */
-        debug (86,5)("Finished reading upstream data in subrequest\n");
-        esiStream->include->subRequestDone (esiStream, true);
-        esiStream->finished = 1;
-        httpRequestFree (http);
-        return;
-    }
-
-
-    /* after the write to the user occurs, (ie here, or in a callback)
-     * we call */
-    if (clientHttpRequestStatus(-1, http)) {
-        /* TODO: Does thisNode if block leak htto ? */
-        /* XXX when reviewing ESI this is the first place to look */
-        node->data = NULL;
-        esiStream->finished = 1;
-        esiStream->include->fail (esiStream);
-        return;
-    };
-
-    switch (clientStreamStatus (node, http)) {
-
-    case STREAM_UNPLANNED_COMPLETE: /* fallthru ok */
-
-    case STREAM_COMPLETE: /* ok */
-        debug (86,3)("ESI subrequest finished OK\n");
-        esiStream->include->subRequestDone (esiStream, true);
-        esiStream->finished = 1;
-        httpRequestFree (http);
-        return;
-
-    case STREAM_FAILED:
-        debug (86,1)("ESI subrequest failed transfer\n");
-        esiStream->include->fail (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);
-            debug (86,5)("esiBufferRecipient: Requested more data for ESI subrequest\n");
-        }
-
-        break;
-
-    default:
-        fatal ("Hit unreachable code in esiBufferRecipient\n");
-    }
-
-}
-
-/* esiStream functions */
-ESIStreamContext::~ESIStreamContext()
-{
-    assert (this);
-    freeResources();
-}
-
-void
-ESIStreamContext::freeResources()
-{
-    debug (86,5)("Freeing stream context resources.\n");
-    buffer = NULL;
-    localbuffer = NULL;
-    include = NULL;
-}
-
-void *
-ESIStreamContext::operator new(size_t byteCount)
-{
-    assert (byteCount == sizeof (ESIStreamContext));
-    CBDATA_INIT_TYPE(ESIStreamContext);
-    ESIStreamContext *result = cbdataAlloc(ESIStreamContext);
-    /* Mark result as being owned - we want the refcounter to do the
-     * delete call
-     */
-    cbdataReference(result);
-    return result;
-}
-
-void
-ESIStreamContext::operator delete (void *address)
-{
-    ESIStreamContext *t = static_cast<ESIStreamContext *>(address);
-    cbdataFree(t);
-    /* And allow the memory to be freed */
-    cbdataReferenceDone (address);
-}
-
-void
-ESIStreamContext::deleteSelf() const
-{
-    delete this;
-}
-
-esiStreamContext *
-esiStreamContextNew (esiIncludePtr include)
-{
-    esiStreamContext *rv = new ESIStreamContext;
-    rv->include = include;
-    return rv;
-}
-
 /* Implementation of ESIElements */
 
 /* esiComment */
@@ -1963,7 +1565,7 @@ esiComment::makeCacheable() const
 }
 
 ESIElement::Pointer
-esiComment::makeUsable(esiTreeParentPtr, esiVarState &) const
+esiComment::makeUsable(esiTreeParentPtr, ESIVarState &) const
 {
     fatal ("esiComment::Usable: unreachable code!\n");
     return NULL;
@@ -2085,7 +1687,7 @@ esiLiteral::makeCacheable() const
 }
 
 ESIElement::Pointer
-esiLiteral::makeUsable(esiTreeParentPtr , esiVarState &newVarState) const
+esiLiteral::makeUsable(esiTreeParentPtr , ESIVarState &newVarState) const
 {
     debug (86,5)("esiLiteral::makeUsable: Creating usable literal\n");
     esiLiteral * result = new esiLiteral (*this);
@@ -2093,419 +1695,101 @@ esiLiteral::makeUsable(esiTreeParentPtr , esiVarState &newVarState) const
     return result;
 }
 
-/* esiInclude */
-esiInclude::~esiInclude()
-{
-    debug (86,5)("esiInclude::Free %p\n", this);
-    ESISegmentFreeList (srccontent);
-    ESISegmentFreeList (altcontent);
-    cbdataReferenceDone (varState);
-    safe_free (srcurl);
-    safe_free (alturl);
-}
-
+/* esiRemove */
 void
-esiInclude::finish()
+esiRemoveFree (void *data)
 {
-    parent = NULL;
+    esiRemove *thisNode = (esiRemove *)data;
+    debug (86,5)("esiRemoveFree %p\n", thisNode);
 }
 
 void *
-esiInclude::operator new(size_t byteCount)
+esiRemove::operator new(size_t byteCount)
 {
-    assert (byteCount == sizeof (esiInclude));
-
-    if (!Pool)
-        Pool = memPoolCreate ("esiInclude", sizeof (esiInclude));
-
-    return memPoolAlloc(Pool);
+    assert (byteCount == sizeof (esiRemove));
+    void *rv;
+    CBDATA_INIT_TYPE_FREECB(esiRemove, esiRemoveFree);
+    rv = (void *)cbdataAlloc (esiRemove);
+    return rv;
 }
 
 void
-esiInclude::operator delete (void *address)
+esiRemove::operator delete (void *address)
 {
-    memPoolFree (Pool, address);
+    cbdataFree (address);
 }
 
 void
-esiInclude::deleteSelf() const
+esiRemove::deleteSelf() const
 {
     delete this;
 }
 
-ESIElement::Pointer
-esiInclude::makeCacheable() const
+ESIElement *
+esiRemoveNew ()
 {
-    return new esiInclude (*this);
+    return new esiRemove;
 }
 
-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);
+esiRemove::esiRemove()
+{}
 
-    if (resultI->alturl)
-        resultI->alt = esiStreamContextNew (resultI);
+void
+esiRemove::finish()
+{}
 
-    return result;
+void
+esiRemove::render(ESISegment::Pointer output)
+{
+    /* Removes do nothing dude */
+    debug (86, 5)("esiRemoveRender: Rendering remove %p\n", this);
 }
 
-esiInclude::esiInclude(esiInclude const &old) : parent (NULL), started (false), sent (false)
+/* Accept non-ESI children */
+bool
+esiRemove::addElement (ESIElement::Pointer element)
 {
-    varState = NULL;
-    flags.onerrorcontinue = old.flags.onerrorcontinue;
-
-    if (old.srcurl)
-        srcurl = xstrdup (old.srcurl);
+    if (!dynamic_cast<esiLiteral*>(element.getRaw())) {
+        debug (86,5)("esiRemoveAdd: Failed for %p\n",this);
+        return false;
+    }
 
-    if (old.alturl)
-        alturl = xstrdup (old.alturl);
+    return true;
 }
 
-void
-esiInclude::Start (ESIStreamContext::Pointer stream, char const *url, esiVarState *vars)
+ESIElement::Pointer
+esiRemove::makeCacheable() const
 {
-    HttpHeader tempheaders;
-
-    if (!stream.getRaw())
-        return;
-
-    httpHeaderInit (&tempheaders, hoRequest);
+    debug (86,5)("esiRemove::makeCacheable: Returning NULL\n");
+    return NULL;
+}
 
-    /* Ensure variable state is clean */
-    vars->feedData(url, strlen (url));
+ESIElement::Pointer
+esiRemove::makeUsable(esiTreeParentPtr, ESIVarState &) const
+{
+    fatal ("esiRemove::Usable: unreachable code!\n");
+    return NULL;
+}
 
-    /* tempUrl is eaten by the request */
-    char const *tempUrl = vars->extractChar ();
+/* esiTry */
+esiTry::~esiTry()
+{
+    debug (86,5)("esiTry::~esiTry %p\n", this);
+}
 
-    debug (86,5)("esiIncludeStart: Starting subrequest with url '%s'\n", tempUrl);
+void *
+esiTry::operator new(size_t byteCount)
+{
+    assert (byteCount == sizeof (esiTry));
 
-    if (clientBeginRequest(METHOD_GET, tempUrl, esiBufferRecipient, esiBufferDetach, stream.getRaw(), &tempheaders, stream->localbuffer->buf, HTTP_REQBUF_SZ)) {
-        debug (86,0) ("starting new ESI subrequest failed\n");
-    }
+    if (!Pool)
+        Pool = memPoolCreate ("esiTry", sizeof(esiTry));
 
-    httpHeaderClean (&tempheaders);
+    return memPoolAlloc (Pool);
 }
 
-esiInclude::esiInclude (esiTreeParentPtr aParent, int attrcount, char const **attr, ESIContext *aContext) : parent (aParent), started (false), sent (false)
-{
-    int i;
-    assert (aContext);
-
-    for (i = 0; i < attrcount && attr[i]; i += 2) {
-        if (!strcmp(attr[i],"src")) {
-            /* Start a request for thisNode url */
-            debug (86,5)("esiIncludeNew: Requesting source '%s'\n",attr[i+1]);
-            /* TODO: don't assert on thisNode, ignore the duplicate */
-            assert (src.getRaw() == NULL);
-            src = esiStreamContextNew (this);
-            assert (src.getRaw() != NULL);
-            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
-             */
-            debug (86,5)("esiIncludeNew: Requesting alternate '%s'\n",attr[i+1]);
-            assert (alt.getRaw() == NULL); /* TODO: FIXME */
-            alt = esiStreamContextNew (this);
-            assert (alt.getRaw() != NULL);
-            alturl = xstrdup (attr[i+1]);
-        } else if (!strcmp(attr[i],"onerror")) {
-            if (!strcmp(attr[i+1], "continue")) {
-                flags.onerrorcontinue = 1;
-            } else {
-                /* ignore mistyped attributes */
-                debug (86, 1)("invalid value for onerror='%s'\n", 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 = NULL;
-
-        debug (86,1)("esiIncludeNew: esi:include with no src attributes\n");
-
-        flags.failed = 1;
-    }
-}
-
-void
-esiInclude::render(ESISegment::Pointer output)
-{
-    if (sent)
-        return;
-
-    ESISegment::Pointer myout;
-
-    debug (86, 5)("esiIncludeRender: Rendering include %p\n", this);
-
-    assert (flags.finished || (flags.failed && flags.onerrorcontinue));
-
-    if (flags.failed && flags.onerrorcontinue) {
-        return;
-    }
-
-    /* Render the content */
-    if (srccontent.getRaw()) {
-        myout = srccontent;
-        srccontent = NULL;
-    } else if (altcontent.getRaw()) {
-        myout = altcontent;
-        altcontent = NULL;
-    } else
-        fatal ("esiIncludeRender called with no content, and no failure!\n");
-
-    assert (output->next == NULL);
-
-    output->next = myout;
-
-    sent = true;
-}
-
-esiProcessResult_t
-esiInclude::process (int dovars)
-{
-    start();
-    debug (86, 5)("esiIncludeRender: Processing include %p\n", 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::fail (ESIStreamContext::Pointer stream)
-{
-    subRequestDone (stream, false);
-}
-
-bool
-esiInclude::dataNeeded() const
-{
-    return !(flags.finished || flags.failed);
-}
-
-void
-esiInclude::subRequestDone (ESIStreamContext::Pointer stream, bool success)
-{
-    assert (this);
-
-    if (!dataNeeded())
-        return;
-
-    if (stream == src) {
-        debug (86,3)("esiInclude::subRequestDone: %s\n", srcurl);
-
-        if (success) {
-            /* copy the lead segment */
-            debug (86,3)("esiIncludeSubRequestDone: Src OK - include PASSED.\n");
-            assert (!srccontent.getRaw());
-            ESISegment::ListTransfer (stream->localbuffer, srccontent);
-            /* we're done! */
-            flags.finished = 1;
-        } else {
-            /* Fail if there is no alt being retrieved */
-            debug (86,3)("esiIncludeSubRequestDone: Src FAILED\n");
-
-            if (!(alt.getRaw() || altcontent.getRaw())) {
-                debug (86,3)("esiIncludeSubRequestDone: Include FAILED - No ALT\n");
-                flags.failed = 1;
-            } else if (altcontent.getRaw()) {
-                debug (86,3)("esiIncludeSubRequestDone: Include PASSED - ALT already Complete\n");
-                /* ALT was already retrieved, we are done */
-                flags.finished = 1;
-            }
-        }
-
-        src = NULL;
-    } else if (stream == alt) {
-        debug (86,3)("esiInclude::subRequestDone: %s\n", alturl);
-
-        if (success) {
-            debug (86,3)("esiIncludeSubRequestDone: ALT OK.\n");
-            /* 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 */
-                debug (86,3)("esiIncludeSubRequestDone: Include PASSED - SRC already failed.\n");
-                flags.finished = 1;
-            }
-        } else {
-            if (!(src.getRaw() || srccontent.getRaw())) {
-                debug (86,3)("esiIncludeSubRequestDone: ALT FAILED, Include FAILED - SRC already failed\n");
-                /* src already failed */
-                flags.failed = 1;
-            }
-        }
-
-        alt = NULL;
-    } else {
-        fatal ("esiIncludeSubRequestDone: non-owned stream found!\n");
-    }
-
-    if (flags.finished || flags.failed) {
-        /* Kick ESI Processor */
-        debug (86,5)("esiInclude %p SubRequest %p completed, kicking processor , status %s\n", this, stream.getRaw(), flags.finished ? "OK" : "FAILED");
-        assert (parent.getRaw());
-
-        if (!flags.failed) {
-            sent = true;
-            parent->provideData (srccontent.getRaw() ? srccontent:altcontent,this);
-
-            if (srccontent.getRaw())
-                srccontent = NULL;
-            else
-                altcontent = NULL;
-        } 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);
-    }
-}
-
-/* esiRemove */
-void
-esiRemoveFree (void *data)
-{
-    esiRemove *thisNode = (esiRemove *)data;
-    debug (86,5)("esiRemoveFree %p\n", thisNode);
-}
-
-void *
-esiRemove::operator new(size_t byteCount)
-{
-    assert (byteCount == sizeof (esiRemove));
-    void *rv;
-    CBDATA_INIT_TYPE_FREECB(esiRemove, esiRemoveFree);
-    rv = (void *)cbdataAlloc (esiRemove);
-    return rv;
-}
-
-void
-esiRemove::operator delete (void *address)
-{
-    cbdataFree (address);
-}
-
-void
-esiRemove::deleteSelf() const
-{
-    delete this;
-}
-
-ESIElement *
-esiRemoveNew ()
-{
-    return new esiRemove;
-}
-
-esiRemove::esiRemove()
-{}
-
-void
-esiRemove::finish()
-{}
-
-void
-esiRemove::render(ESISegment::Pointer output)
-{
-    /* Removes do nothing dude */
-    debug (86, 5)("esiRemoveRender: Rendering remove %p\n", this);
-}
-
-/* Accept non-ESI children */
-bool
-esiRemove::addElement (ESIElement::Pointer element)
-{
-    if (!dynamic_cast<esiLiteral*>(element.getRaw())) {
-        debug (86,5)("esiRemoveAdd: Failed for %p\n",this);
-        return false;
-    }
-
-    return true;
-}
-
-ESIElement::Pointer
-esiRemove::makeCacheable() const
-{
-    debug (86,5)("esiRemove::makeCacheable: Returning NULL\n");
-    return NULL;
-}
-
-ESIElement::Pointer
-esiRemove::makeUsable(esiTreeParentPtr, esiVarState &) const
-{
-    fatal ("esiRemove::Usable: unreachable code!\n");
-    return NULL;
-}
-
-/* esiTry */
-esiTry::~esiTry()
-{
-    debug (86,5)("esiTry::~esiTry %p\n", this);
-}
-
-void *
-esiTry::operator new(size_t byteCount)
-{
-    assert (byteCount == sizeof (esiTry));
-
-    if (!Pool)
-        Pool = memPoolCreate ("esiTry", sizeof(esiTry));
-
-    return memPoolAlloc (Pool);
-}
-
-void
-esiTry::operator delete (void *address)
+void
+esiTry::operator delete (void *address)
 {
     memPoolFree (Pool, address);
 }
@@ -2671,7 +1955,7 @@ esiTry::notifyParent()
             parent->provideData (exceptbuffer, this);
             exceptbuffer = NULL;
         } else if (flags.exceptfailed || except.getRaw() == NULL) {
-            parent->fail (this);
+            parent->fail (this, "esi:try - except claused failed, or no except clause found");
         }
     }
 
@@ -2679,11 +1963,11 @@ esiTry::notifyParent()
 }
 
 void
-esiTry::fail(ESIElement *source)
+esiTry::fail(ESIElement *source, char const *anError)
 {
     assert (source);
     assert (source == attempt || source == except);
-    debug (86,5) ("esiTry::fail: this=%p, source=%p\n", this, source);
+    debug (86,5) ("esiTry::fail: this=%p, source=%p, message=%s\n", this, source, anError);
 
     if (source == except) {
         flags.exceptfailed = 1;
@@ -2737,7 +2021,7 @@ esiTry::makeCacheable() const
 }
 
 ESIElement::Pointer
-esiTry::makeUsable(esiTreeParentPtr newParent, esiVarState &newVarState) const
+esiTry::makeUsable(esiTreeParentPtr newParent, ESIVarState &newVarState) const
 {
     debug (86,5)("esiTry::makeUsable: making usable Try from %p\n",this);
     esiTry *resultT = new esiTry (*this);
@@ -2817,7 +2101,7 @@ esiExcept::deleteSelf() const
     delete this;
 }
 
-/* esiVar */
+/* ESIVar */
 #if 0
 void *
 esiVar::operator new(size_t byteCount)
@@ -2838,673 +2122,11 @@ esiVar::operator delete (void *address)
 #endif
 
 void
-esiVar::deleteSelf() const
+ESIVar::deleteSelf() const
 {
     delete this;
 }
 
-/* esiVarState */
-void
-esiVarStateFree (void *data)
-{
-    esiVarState *thisNode = (esiVarState*)data;
-    thisNode->freeResources();
-}
-
-void
-esiVarState::freeResources()
-{
-    input = NULL;
-    ESISegmentFreeList (output);
-    httpHeaderClean (&hdr);
-
-    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);
-    safe_free (browserversion);
-}
-
-void *
-esiVarState::operator new(size_t byteCount)
-{
-    assert (byteCount == sizeof (esiVarState));
-    void *rv;
-    CBDATA_INIT_TYPE_FREECB(esiVarState, esiVarStateFree);
-    rv = (void *)cbdataAlloc (esiVarState);
-    return rv;
-}
-
-void
-esiVarState::operator delete (void *address)
-{
-    cbdataFree (address);
-}
-
-void
-esiVarState::deleteSelf() const
-{
-    delete this;
-}
-
-char *
-esiVarState::getProductVersion (char const *s)
-{
-    char const *t;
-    int len;
-    t = index (s,'/');
-
-    if (!t || !*(++t))
-        return xstrdup ("");
-
-    len = strcspn (t, " \r\n()<>@,;:\\\"/[]?={}");
-
-    return xstrndup (t, len);
-}
-
-esiVarState::esiVarState (HttpHeader const *aHeader, char const *uri)
-        : output (NULL)
-{
-    /* Fill out variable values */
-    /* 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 = (_query_elem *)memReallocBuf(query, query_elements * sizeof (struct _query_elem),
-                                             &query_sz);
-        query_pos = query_start + 1;
-        n = 0;
-
-        while (query_pos) {
-            char *next = strchr (query_pos, '&');
-            char *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;
-        debug (86,6)("esiVarStateNew: Parsed Query string: '%s'\n",uri);
-
-        while (n < query_elements) {
-            debug (86,6)("esiVarStateNew: Parsed Query element %d '%s'='%s'\n",n + 1, query[n].var, query[n].val);
-            ++n;
-        }
-    }
-
-    /* Now setup the UserAgent values */
-    /* An example:
-     *    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705) */
-    /* Grr thisNode 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 
-     *
-     * Useing 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, thisNode may be better implemented as a regexp.
-     */
-    /* TODO: only grab the needed headers */
-    httpHeaderInit (&hdr, hoReply);
-
-    httpHeaderAppend (&hdr, aHeader);
-
-    if (httpHeaderHas(&hdr, HDR_USER_AGENT)) {
-        char const *s = httpHeaderGetStr (&hdr, HDR_USER_AGENT);
-        char const *t, *t1;
-
-        if (strstr (s, "Windows"))
-            UserOs = ESI_OS_WIN;
-        else if (strstr (s, "Mac"))
-            UserOs = ESI_OS_MAC;
-        else if (strstr (s, "nix") || strstr (s, "BSD"))
-            UserOs = ESI_OS_UNIX;
-        else
-            UserOs = ESI_OS_OTHER;
-
-        /* Now the browser and version */
-        if ((t = strstr (s, "MSIE"))) {
-            browser = ESI_BROWSER_MSIE;
-            t = index (t, ' ');
-
-            if (!t)
-                browserversion = xstrdup ("");
-            else {
-                t1 = index (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 ("");
-    }
-}
-
-void
-esiVarState::feedData (const char *buf, size_t len)
-{
-    /* TODO: if needed - tune to skip segment iteration */
-    debug (86,6)("esiVarState::feedData: accepting %d bytes\n", len);
-    ESISegment::ListAppend (input, buf, len);
-}
-
-ESISegment::Pointer
-esiVarState::extractList()
-{
-    doIt();
-    ESISegment::Pointer rv = output;
-    output = NULL;
-    debug (86,6)("esiVarStateExtractList: Extracted list\n");
-    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);
-
-    debug (86,6)("esiVarStateExtractList: Extracted char\n");
-
-    return rv;
-}
-
-int
-httpHeaderHasListMember(const HttpHeader * hdr, http_hdr_type id, const char *member, const char separator);
-
-int
-httpHeaderHasListMember(const HttpHeader * hdr, http_hdr_type id, const char *member, const char separator)
-{
-    int result = 0;
-    const char *pos = NULL;
-    const char *item;
-    int ilen;
-    int mlen = strlen(member);
-
-    assert(hdr);
-    assert(id >= 0);
-
-    String header (httpHeaderGetStrOrList(hdr, id));
-
-    while (strListGetItem(&header, separator, &item, &ilen, &pos)) {
-        if (strncmp(item, member, mlen) == 0
-                && (item[mlen] == '=' || item[mlen] == separator || item[mlen] == ';' || item[mlen] == '\0')) {
-            result = 1;
-            break;
-        }
-    }
-
-    return result;
-}
-
-void
-esiVarState::eval (esiVar_t type, char const *subref, char const *found_default )
-{
-    const char *s = NULL;
-
-    if (!found_default)
-        found_default = "";
-
-    switch (type) {
-
-    case ESI_VAR_HOST:
-        flags.host = 1;
-
-        if (!subref && httpHeaderHas(&hdr,HDR_HOST)) {
-            s = httpHeaderGetStr (&hdr, HDR_HOST);
-        } else
-            s = found_default;
-
-        ESISegment::ListAppend (output, s, strlen (s));
-
-        break;
-
-    case ESI_VAR_COOKIE:
-        flags.cookie = 1;
-
-        if (httpHeaderHas(&hdr, HDR_COOKIE)) {
-            if (!subref)
-                s = httpHeaderGetStr (&hdr, HDR_COOKIE);
-            else {
-                String S = httpHeaderGetListMember (&hdr, HDR_COOKIE, subref, ';');
-
-                if (S.size())
-                    ESISegment::ListAppend (output, S.buf(), S.size());
-                else if (found_default)
-                    ESISegment::ListAppend (output, found_default, strlen (found_default));
-            }
-        } else
-            s = found_default;
-
-        if (s)
-            ESISegment::ListAppend (output, s, strlen (s));
-
-        break;
-
-    case ESI_VAR_REFERER:
-        flags.referer = 1;
-
-        if (!subref && httpHeaderHas(&hdr, HDR_REFERER))
-            s = httpHeaderGetStr (&hdr, HDR_REFERER);
-        else
-            s = found_default;
-
-        ESISegment::ListAppend (output, s, strlen (s));
-
-        break;
-
-    case ESI_QUERY_STRING:
-        if (!subref)
-            s = query_string;
-        else {
-            unsigned int i = 0;
-
-            while (i < query_elements && !s) {
-                if (!strcmp (subref, query[i].var))
-                    s = query[i].val;
-
-                ++i;
-            }
-
-            if (!s)
-                s = found_default;
-        }
-
-        ESISegment::ListAppend (output, s, strlen (s));
-        break;
-
-    case ESI_VAR_USERAGENT:
-        flags.useragent = 1;
-
-        if (httpHeaderHas(&hdr, HDR_USER_AGENT)) {
-            if (!subref)
-                s = httpHeaderGetStr (&hdr, HDR_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 (output, s, strlen (s));
-
-        break;
-
-    case ESI_VAR_LANGUAGE:
-        flags.language = 1;
-
-        if (httpHeaderHas(&hdr, HDR_ACCEPT_LANGUAGE)) {
-            if (!subref) {
-                String S (httpHeaderGetList (&hdr, HDR_ACCEPT_LANGUAGE));
-                ESISegment::ListAppend (output, S.buf(), S.size());
-            } else {
-                if (httpHeaderHasListMember (&hdr, HDR_ACCEPT_LANGUAGE, subref, ',')) {
-                    s = "true";
-                } else {
-                    s = "false";
-                }
-
-                ESISegment::ListAppend (output, s, strlen (s));
-            }
-        } else {
-            s = found_default;
-            ESISegment::ListAppend (output, s, strlen (s));
-        }
-
-        break;
-
-    case ESI_VAR_OTHER:
-        /* No-op. We swallow it */
-
-        if (found_default) {
-            ESISegment::ListAppend (output, found_default, strlen (found_default));
-        }
-
-        break;
-    }
-}
-
-bool
-esiVarState::validChar (char c)
-{
-    if (('A' <= c && c <= 'Z') ||
-            ('a' <= c && c <= 'z') ||
-            '_' == c || '-' == c)
-        return true;
-
-    return false;
-}
-
-esiVarState::esiVar_t
-esiVarState::GetVar(char *s, int len)
-{
-    assert (s);
-
-    if (len == 9) {
-        if (!strncmp (s, "HTTP_HOST", 9))
-            return ESI_VAR_HOST;
-        else
-            return ESI_VAR_OTHER;
-    }
-
-    if (len == 11) {
-        if (!strncmp (s, "HTTP_COOKIE", 11))
-            return ESI_VAR_COOKIE;
-        else
-            return ESI_VAR_OTHER;
-    }
-
-    if (len == 12) {
-        if (!strncmp (s, "HTTP_REFERER", 12))
-            return ESI_VAR_REFERER;
-        else if (!strncmp (s, "QUERY_STRING", 12))
-            return ESI_QUERY_STRING;
-        else
-            return ESI_VAR_OTHER;
-    }
-
-    if (len == 15) {
-        if (!strncmp (s, "HTTP_USER_AGENT", 15))
-            return ESI_VAR_USERAGENT;
-        else
-            return ESI_VAR_OTHER;
-    }
-
-    if (len == 20) {
-        if (!strncmp (s, "HTTP_ACCEPT_LANGUAGE", 20))
-            return ESI_VAR_LANGUAGE;
-        else
-            return ESI_VAR_OTHER;
-    }
-
-    return ESI_VAR_OTHER;
-}
-
-/* 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
- */
-void
-esiVarState::doIt ()
-{
-    assert (output == NULL);
-    int state = 0;
-    char *string = input->listToChar();
-    size_t len = strlen (string);
-    size_t pos = 0;
-    size_t var_pos = 0;
-    size_t done_pos = 0;
-    char * found_subref = NULL;
-    char *found_default = NULL;
-    esiVar_t vartype = ESI_VAR_OTHER;
-    ESISegmentFreeList (input);
-
-    while (pos < len) {
-        switch (state) {
-
-        case 0: /* skipping pre-variables */
-
-            if (string[pos] != '$') {
-                ++pos;
-            } else {
-                if (pos - done_pos)
-                    /* extract known good text */
-                    ESISegment::ListAppend (output, string + done_pos, pos - done_pos);
-
-                done_pos = pos;
-
-                state = 1;
-
-                ++pos;
-            }
-
-            break;
-
-        case 1:/* looking for ( */
-
-            if (string[pos] != '(') {
-                state = 0;
-            } else {
-                state = 2; /* extract a variable name */
-                var_pos = ++pos;
-            }
-
-            break;
-
-        case 2: /* looking for variable name */
-
-            if (!validChar(string[pos])) {
-                /* not a variable name char */
-
-                if (pos - var_pos)
-                    vartype = 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 = 0;
-            } else if (!found_subref && !found_default && string[pos] == '{') {
-                debug (86,6)("esiVarStateDoIt: Subref of some sort\n");
-                /* subreference of some sort */
-                /* look for the entry name */
-                var_pos = ++pos;
-                state = 4;
-            } else if (!found_default && string[pos] == '|') {
-                debug (86,6)("esiVarStateDoIt: Default present\n");
-                /* extract default value */
-                state = 5;
-                var_pos = ++pos;
-            } else {
-                /* unexpected char, not a variable after all */
-                debug (86,6)("esiVarStateDoIt: unexpected char after varname\n");
-                state = 0;
-                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);
-                debug (86,6)("esiVarStateDoIt: found end of variable subref '%s'\n", found_subref);
-                state = 3;
-                ++pos;
-            } else if (!validChar (string[pos])) {
-                debug (86,6)("esiVarStateDoIt: found invalid char in variable subref\n");
-                /* not a valid subref */
-                safe_free(found_subref);
-                state = 0;
-                pos = done_pos + 2;
-            } else {
-                ++pos;
-            }
-
-            break;
-
-        case 5: /* looking for a default value */
-
-            if (string[pos] == '\'') {
-                /* begins with a quote */
-                debug (86,6)("esiVarStateDoIt: found quoted default\n");
-                state = 6;
-                var_pos = ++pos;
-            } else {
-                /* doesn't */
-                debug (86,6)("esiVarStateDoIt: found unquoted default\n");
-                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);
-                debug (86,6)("esiVarStateDoIt: found end of quoted default '%s'\n", 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);
-                debug (86,6)("esiVarStateDoIt: found end of variable (w/ unquoted default) '%s'\n",found_default);
-                eval(vartype,found_subref, found_default);
-                done_pos = ++pos;
-                safe_free(found_default);
-                safe_free(found_subref);
-                state = 0;
-            }
-
-            ++pos;
-            break;
-
-        default:
-            fatal("esiVarStateDoIt: unexpected state\n");
-        }
-    }
-
-    /* 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);
-}
-
-/* XXX FIXME: 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 (httpHeaderGetList (&rep->header, HDR_VARY));
-
-    if (!strVary.size() || strVary.buf()[0] != '*') {
-        httpHeaderPutStr (&rep->header, HDR_VARY, tempstr);
-    }
-}
-
 /* esiChoose */
 esiChoose::~esiChoose()
 {
@@ -3698,7 +2320,7 @@ esiChoose::checkValidSource (ESIElement::Pointer source) const
 }
 
 void
-esiChoose::fail(ESIElement * source)
+esiChoose::fail(ESIElement * source, char const *anError)
 {
     checkValidSource (source);
     elements.setNULL (0, elements.size());
@@ -3708,7 +2330,7 @@ esiChoose::fail(ESIElement * source)
 
     otherwise = NULL;
 
-    parent->fail(this);
+    parent->fail(this, anError);
 
     parent = NULL;
 }
@@ -3743,7 +2365,7 @@ esiChoose::makeCachableElements(esiChoose const &old)
 }
 
 void
-esiChoose::makeUsableElements(esiChoose const &old, esiVarState &newVarState)
+esiChoose::makeUsableElements(esiChoose const &old, ESIVarState &newVarState)
 {
     for (size_t counter = 0; counter < old.elements.size(); ++counter) {
         ESIElement::Pointer newElement = old.elements[counter]->makeUsable (this, newVarState);
@@ -3767,7 +2389,7 @@ esiChoose::makeCacheable() const
 }
 
 ESIElement::Pointer
-esiChoose::makeUsable(esiTreeParentPtr newParent, esiVarState &newVarState) const
+esiChoose::makeUsable(esiTreeParentPtr newParent, ESIVarState &newVarState) const
 {
     esiChoose *resultC = new esiChoose (*this);
     ESIElement::Pointer result = resultC;
@@ -3858,7 +2480,7 @@ esiWhen::deleteSelf() const
     delete this;
 }
 
-esiWhen::esiWhen (esiTreeParentPtr aParent, int attrcount, const char **attr,esiVarState *aVar) : esiSequence (aParent)
+esiWhen::esiWhen (esiTreeParentPtr aParent, int attrcount, const char **attr,ESIVarState *aVar) : esiSequence (aParent)
 {
     varState = NULL;
     char const *expression = NULL;
@@ -3866,7 +2488,7 @@ esiWhen::esiWhen (esiTreeParentPtr aParent, int attrcount, const char **attr,esi
     for (int loopCounter = 0; loopCounter < attrcount && attr[loopCounter]; loopCounter += 2) {
         if (!strcmp(attr[loopCounter],"test")) {
             /* evaluate test */
-            debug (86,5)("esiIncludeNew: Evaluating '%s'\n",attr[loopCounter+1]);
+            debug (86,5)("esiWhen::esiWhen: Evaluating '%s'\n",attr[loopCounter+1]);
             /* TODO: warn the user instead of asserting */
             assert (expression == NULL);
             expression = attr[loopCounter+1];
@@ -3909,7 +2531,7 @@ esiWhen::evaluate()
 
     char const *expression = varState->extractChar ();
 
-    setTestResult(esiExpressionEval (expression));
+    setTestResult(ESIExpression::Evaluate (expression));
 
     safe_free (expression);
 }
@@ -3931,7 +2553,7 @@ esiWhen::makeCacheable() const
 }
 
 ESIElement::Pointer
-esiWhen::makeUsable(esiTreeParentPtr newParent, esiVarState &newVarState) const
+esiWhen::makeUsable(esiTreeParentPtr newParent, ESIVarState &newVarState) const
 {
     esiWhen *resultW = new esiWhen (*this);
     ESIElement::Pointer result = resultW;
diff --git a/src/ESIAssign.cc b/src/ESIAssign.cc
new file mode 100644 (file)
index 0000000..46a13e8
--- /dev/null
@@ -0,0 +1,217 @@
+
+/*
+ * $Id: ESIAssign.cc,v 1.1 2003/07/14 14:15:55 robertc Exp $
+ *
+ * DEBUG: section 86    ESI processing
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ ;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "ESIAssign.h"
+#include "ESIContext.h"
+#include "ESISequence.h"
+
+MemPool *ESIAssign::Pool = NULL;
+
+void *
+ESIAssign::operator new (size_t byteCount)
+{
+    assert (byteCount == sizeof (ESIAssign));
+
+    if (!Pool)
+        Pool = memPoolCreate ("ESIAssign", sizeof (ESIAssign));
+
+    return memPoolAlloc(Pool);
+}
+
+void
+ESIAssign::operator delete (void *address)
+{
+    memPoolFree (Pool, address);
+}
+
+void
+ESIAssign::deleteSelf() const
+{
+    delete this;
+}
+
+ESIAssign::~ESIAssign()
+{
+    if (value)
+        delete value;
+}
+
+ESIAssign::ESIAssign (ESIAssign const &old) : parent (NULL), varState (NULL), name (old.name), value (old.value ? new ESIVariableExpression (*old.value): NULL), variable (NULL), unevaluatedVariable(old.unevaluatedVariable)
+{}
+
+ESIAssign::ESIAssign (esiTreeParentPtr aParent, int attrcount, char const **attr, ESIContext *aContext) : parent (aParent), varState (NULL), name(), value (NULL), variable (NULL), 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 ...  */
+            debug (86,5)("ESIAssign::ESIAssign: Variable name '%s'\n",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:  */
+            debug (86,5)("ESIAssign::ESIAssign: Unevaluated variable '%s'\n",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 = NULL;
+
+    if (unevaluatedVariable.size()) {
+        varState->feedData(unevaluatedVariable.buf(), 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 dovars)
+{
+    assert (varState);
+
+    if (!value)
+        evaluateVariable();
+
+    if (!value)
+        return ESI_PROCESS_COMPLETE;
+
+    varState->addVariable (name.buf(), name.size(), value);
+
+    value = NULL;
+
+    debug (86,5) ("ESIAssign: Processed %p\n",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()
+{
+    if (varState)
+        cbdataReferenceDone (varState);
+
+    if (parent.getRaw())
+        parent = NULL;
+}
+
+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 *subref, char const *defaultOnEmpty) const
+{
+    /* XXX: Implement evaluation of the expression */
+    ESISegment::ListAppend (state.getOutput(), expression.buf(), expression.size());
+}
diff --git a/src/ESIAssign.h b/src/ESIAssign.h
new file mode 100644 (file)
index 0000000..31b3a54
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * $Id: ESIAssign.h,v 1.1 2003/07/14 14:15:55 robertc Exp $
+ *
+ * DEBUG: section 86    ESI processing
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ */
+
+#ifndef SQUID_ESIASSIGN_H
+#define SQUID_ESIASSIGN_H
+
+#include "squid.h"
+#include "ESIElement.h"
+#include "SquidString.h"
+#include "ESIVarState.h"
+
+/* ESIVariableExpression */
+/* This is a variable that is itself and expression */
+
+class ESIVariableExpression : public ESIVarState::Variable
+{
+
+public:
+    ~ESIVariableExpression();
+    ESIVariableExpression (String const &value);
+    virtual void eval (ESIVarState &state, char const *, char const *) const;
+
+private:
+    String expression;
+};
+
+/* ESIAssign */
+
+class ESIContext;
+
+class ESIAssign : public ESIElement
+{
+
+public:
+    void *operator new (size_t byteCount);
+    void operator delete (void *address);
+    void deleteSelf() const;
+    ESIAssign (esiTreeParentPtr, int, const char **, ESIContext *);
+    ESIAssign (ESIAssign const &);
+    ESIAssign &operator=(ESIAssign const &);
+    ~ESIAssign();
+    esiProcessResult_t process (int dovars);
+    void render(ESISegment::Pointer);
+    bool addElement(ESIElement::Pointer);
+    void provideData (ESISegment::Pointer data, ESIElement * source);
+    Pointer makeCacheable() const;
+    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const;
+    void finish();
+
+private:
+    static MemPool *Pool;
+    void evaluateVariable();
+    esiTreeParentPtr parent;
+    ESIVarState *varState;
+    String name;
+    ESIVariableExpression * value;
+    ESIElement::Pointer variable;
+    String unevaluatedVariable;
+};
+
+#endif /* SQUID_ESIASSIGN_H */
index 46919f652c97c4945eee8feaafa6f2cc74e46d0a..b26f99d9b0a0a88c8759b3c60763b39051188612 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ESIContext.cc,v 1.1 2003/03/10 04:56:35 robertc Exp $
+ * $Id: ESIContext.cc,v 1.2 2003/07/14 14:15:56 robertc Exp $
  *
  * DEBUG: section 86    ESI processing
  * AUTHOR: Robert Collins
@@ -42,20 +42,20 @@ void
 ESIContext::updateCachedAST()
 {
     assert (http);
-    assert (http->entry);
+    assert (http->storeEntry());
 
     if (hasCachedAST()) {
-        debug (86,5)("ESIContext::updateCachedAST: not updating AST cache for entry %p from ESI Context %p as there is already a cached AST.\n", http->entry, this);
+        debug (86,5)("ESIContext::updateCachedAST: not updating AST cache for entry %p from ESI Context %p as there is already a cached AST.\n", http->storeEntry(), this);
         return;
     }
 
     ESIElement::Pointer treeToCache = tree->makeCacheable();
-    debug (86,5)("ESIContext::updateCachedAST: Updating AST cache for entry %p with current value %p to new value %p\n", http->entry, http->entry->cachedESITree.getRaw(), treeToCache.getRaw());
+    debug (86,5)("ESIContext::updateCachedAST: Updating AST cache for entry %p with current value %p to new value %p\n", http->storeEntry(), http->storeEntry()->cachedESITree.getRaw(), treeToCache.getRaw());
 
-    if (http->entry->cachedESITree.getRaw())
-        http->entry->cachedESITree->finish();
+    if (http->storeEntry()->cachedESITree.getRaw())
+        http->storeEntry()->cachedESITree->finish();
 
-    http->entry->cachedESITree = treeToCache;
+    http->storeEntry()->cachedESITree = treeToCache;
 
     treeToCache = NULL;
 }
@@ -64,13 +64,13 @@ bool
 ESIContext::hasCachedAST() const
 {
     assert (http);
-    assert (http->entry);
+    assert (http->storeEntry());
 
-    if (http->entry->cachedESITree.getRaw()) {
-        debug (86,5)("ESIContext::hasCachedAST: %p - Cached AST present in store entry %p.\n", this, http->entry);
+    if (http->storeEntry()->cachedESITree.getRaw()) {
+        debug (86,5)("ESIContext::hasCachedAST: %p - Cached AST present in store entry %p.\n", this, http->storeEntry());
         return true;
     } else {
-        debug (86,5)("ESIContext::hasCachedAST: %p - Cached AST not present in store entry %p.\n", this, http->entry);
+        debug (86,5)("ESIContext::hasCachedAST: %p - Cached AST not present in store entry %p.\n", this, http->storeEntry());
         return false;
     }
 }
@@ -87,7 +87,14 @@ ESIContext::getCachedAST()
 
     parserState.popAll();
 
-    tree = http->entry->cachedESITree->makeUsable (this, *varState);
+    tree = http->storeEntry()->cachedESITree->makeUsable (this, *varState);
 
     cachedASTInUse = true;
 }
+
+void
+ESIContext::setErrorMessage(char const *anError)
+{
+    if (!errormessage)
+        errormessage = xstrdup (anError);
+}
index 5965c05ed39241fc6bc72b78db69d8bcf8f1c1cf..1d687deb264f5a7c9f8103d1a2cf9488595331b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ESIContext.h,v 1.2 2003/03/15 04:17:38 robertc Exp $
+ * $Id: ESIContext.h,v 1.3 2003/07/14 14:15:56 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -37,7 +37,7 @@
 #include "ESIElement.h"
 #include "clientStream.h"
 
-class esiVarState;
+class ESIVarState;
 
 class ClientHttpRequest;
 
@@ -66,11 +66,12 @@ public:
 
     /* when esi processing completes */
     void provideData(ESISegment::Pointer, ESIElement *source);
-    void fail (ESIElement *source);
+    void fail (ESIElement *source, char const*anError = NULL);
     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);
@@ -158,7 +159,7 @@ int detached:
     }
 
     parserState; /* todo factor this off somewhere else; */
-    esiVarState *varState;
+    ESIVarState *varState;
     ESIElement::Pointer tree;
 
     esiKick_t kick ();
index d0de92500ddaee0865bd3d4e26b15ee445777636..6300c45230714187be56f7170efa344359a86d50 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ESICustomParser.cc,v 1.1 2003/03/10 04:56:35 robertc Exp $
+ * $Id: ESICustomParser.cc,v 1.2 2003/07/14 14:15:56 robertc Exp $
  *
  * DEBUG: section 86    ESI processing
  * AUTHOR: Robert Collins
 #include "squid.h"
 #include "ESICustomParser.h"
 #include "Trie.h"
+#include "TrieCharTransform.h"
 #include "Array.h"
 
 Trie *ESICustomParser::SearchTrie=NULL;
-bool ESICustomParser::TrieInited;
 
 Trie *
 ESICustomParser::GetTrie()
@@ -47,7 +47,7 @@ ESICustomParser::GetTrie()
     if (SearchTrie)
         return SearchTrie;
 
-    SearchTrie = new Trie;
+    SearchTrie = new Trie(new TrieCaseless);
 
     assert (SearchTrie->add
             ("<esi:",5,(void *)ESITAG));
@@ -76,16 +76,16 @@ ESICustomParser::~ESICustomParser()
 }
 
 char const *
-ESICustomParser::findTag(char const *a, size_t b)
+ESICustomParser::findTag(char const *buffer, size_t bufferLength)
 {
     size_t myOffset (0);
     void *resulttype (NULL);
 
-    while (myOffset < b &&
-            (resulttype =GetTrie()->findPrefix (a + myOffset, b + myOffset)) == NULL)
+    while (myOffset < bufferLength &&
+            (resulttype =GetTrie()->findPrefix (buffer + myOffset, bufferLength - myOffset)) == NULL)
         ++myOffset;
 
-    if (myOffset == b)
+    if (myOffset == bufferLength)
         return NULL;
 
     debug (86,9)("ESICustomParser::findTag: found %p\n", resulttype);
@@ -93,7 +93,7 @@ ESICustomParser::findTag(char const *a, size_t b)
     /* Yuck! */
     lastTag = static_cast<ESITAG_t>((int)resulttype);
 
-    return a + myOffset;
+    return buffer + myOffset;
 }
 
 bool
index bae97be5762249d239fc82ed811c3034d0e7956e..32899c7475505127ee4119d6cdb82372ee3a5ef7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ESICustomParser.h,v 1.2 2003/06/09 05:12:04 robertc Exp $
+ * $Id: ESICustomParser.h,v 1.3 2003/07/14 14:15:56 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -51,7 +51,6 @@ public:
 
 private:
     static Trie *SearchTrie;
-    static bool TrieInited;
     static Trie *GetTrie();
     enum ESITAG_t {
         ESITAG=1,
index 3878ca2d8db4fc86b6773dd87784d8840896ac58..0e53d7dd58fe463e835aa280c0911f5acbd375b4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ESIElement.h,v 1.1 2003/03/10 04:56:35 robertc Exp $
+ * $Id: ESIElement.h,v 1.2 2003/07/14 14:15:56 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -53,7 +53,7 @@ struct esiTreeParent : public RefCountable
         assert (0);
     }
 
-    virtual void fail(ESIElement * source) {}
+    virtual void fail(ESIElement * source, char const *reason = NULL) {}
 
     virtual ~esiTreeParent(){}}
 
@@ -61,7 +61,7 @@ struct esiTreeParent : public RefCountable
 
 typedef RefCount<esiTreeParent> esiTreeParentPtr;
 
-class esiVarState;
+class ESIVarState;
 
 struct ESIElement : public esiTreeParent
 {
@@ -79,7 +79,8 @@ struct ESIElement : public esiTreeParent
         ESI_ELEMENT_VARS,
         ESI_ELEMENT_CHOOSE,
         ESI_ELEMENT_WHEN,
-        ESI_ELEMENT_OTHERWISE
+        ESI_ELEMENT_OTHERWISE,
+        ESI_ELEMENT_ASSIGN
     };
     static ESIElementType_t IdentifyElement (const char *);
     virtual bool addElement(ESIElement::Pointer)
@@ -105,7 +106,7 @@ struct ESIElement : public esiTreeParent
     }
 
     virtual Pointer makeCacheable() const = 0;
-    virtual Pointer makeUsable(esiTreeParentPtr, esiVarState &) const = 0;
+    virtual Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const = 0;
 
     /* The top level no longer needs this element */
     virtual void finish() = 0;
index f372b7e6780f54158ae605a20430269d7534c51f..288473cb80db20a479d32b7390406771d2868f44 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ESIExpression.cc,v 1.2 2003/06/09 05:22:33 robertc Exp $
+ * $Id: ESIExpression.cc,v 1.3 2003/07/14 14:15:56 robertc Exp $
  *
  * DEBUG: section 86    ESI processing
  * AUTHOR: Robert Collins
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "ESIExpression.h"
 
 /* stack precedence rules:
  * before pushing an operator onto the stack, the 
@@ -145,13 +146,6 @@ static stackmember getsymbol (const char *s, char const **endptr);
 static void printliteral (stackmember s);
 static void printmember (stackmember s);
 
-
-
-
-extern int
-    esiExpressionEval (char const *s);
-
-
 /* -2 = failed to compate
  * -1 = a less than b
  * 0 = a equal b
@@ -784,11 +778,21 @@ getsymbol (const char *s, char const **endptr)
             *endptr = origs;
         } else {
             *endptr = t + 1;
-            rv.value.string = xstrndup (s + 1, t - s - 1);
+            /* Special case for zero length strings */
+
+            if (t - s - 1)
+                rv.value.string = xstrndup (s + 1, t - s - 1);
+            else
+                rv.value.string = static_cast<char *>(xcalloc (1,1));
+
             rv.eval = evalliteral;
+
             rv.valuestored = ESI_LITERAL_STRING;
+
             rv.valuetype = ESI_EXPR_LITERAL;
+
             rv.precedence = 1;
+
             debug (86,6) ("found  string '%s'\n", rv.value.string);
         }
     } else if ('(' == *s) {
@@ -1010,7 +1014,7 @@ addmember (stackmember * stack, int *stackdepth, stackmember * candidate)
 }
 
 int
-esiExpressionEval (char const *s)
+ESIExpression::Evaluate (char const *s)
 {
     stackmember stack[20];
     int stackdepth = 0;
@@ -1066,32 +1070,3 @@ esiExpressionEval (char const *s)
 
     return stack[0].value.integral ? 1 : 0;
 }
-
-#if TESTING
-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",
-                                };
-
-    int i = 0;
-
-    while (strlen (expressions[i])) {
-        printf("Expr '%s' = '%s'\n", expressions[i],
-               expreval (expressions[i]) ? "true" : "false");
-        ++i;
-    }
-
-    return 0;
-}
-
-#endif
diff --git a/src/ESIExpression.h b/src/ESIExpression.h
new file mode 100644 (file)
index 0000000..90141d5
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * $Id: ESIExpression.h,v 1.1 2003/07/14 14:15:55 robertc Exp $
+ *
+ * DEBUG: section 86    ESI processing
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ */
+
+#ifndef SQUID_ESIEXPRESSION_H
+#define SQUID_ESIEXPRESSION_H
+
+#include "squid.h"
+
+class ESIExpression
+{
+
+public:
+    static int Evaluate (char const *);
+};
+
+#endif /* SQUID_ESIEXPRESSION_H */
diff --git a/src/ESIInclude.cc b/src/ESIInclude.cc
new file mode 100644 (file)
index 0000000..28da073
--- /dev/null
@@ -0,0 +1,599 @@
+
+/*
+ * $Id: ESIInclude.cc,v 1.1 2003/07/14 14:15:55 robertc Exp $
+ *
+ * DEBUG: section 86    ESI processing
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ ;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ */
+
+#include "squid.h"
+#include "ESIInclude.h"
+#include "ESIVarState.h"
+#include "client_side_request.h"
+#include "HttpReply.h"
+
+CBDATA_CLASS_INIT (ESIStreamContext);
+
+MemPool *ESIInclude::Pool = NULL;
+
+/* 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,
+ * and clean them up when finished.
+ * Pre-condition: 
+ *   The request is an internal ESI subrequest.
+ *   data context is not NULL
+ *   There are no more entries in the stream chain.
+ */
+void
+esiBufferRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply *rep, StoreIOBuffer recievedData)
+{
+    /* Test preconditions */
+    assert (node != NULL);
+    /* 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 == NULL);
+    assert (http->getConn().getRaw() == NULL);
+
+    ESIStreamContext::Pointer esiStream = dynamic_cast<ESIStreamContext *>(node->data.getRaw());
+    assert (esiStream.getRaw() != NULL);
+    /* If segments become more flexible, ignore thisNode */
+    assert (recievedData.length <= sizeof(esiStream->localbuffer->buf));
+    assert (!esiStream->finished);
+
+    debug (86,5) ("esiBufferRecipient rep %p body %p len %d\n", rep, recievedData.data, recievedData.length);
+    assert (node->readBuffer.offset == recievedData.offset || recievedData.length == 0);
+
+    /* trivial case */
+
+    if (http->out.offset != 0) {
+        assert(rep == NULL);
+    } else {
+        if (rep) {
+            if (rep->sline.status != HTTP_OK) {
+                httpReplyDestroy(rep);
+                rep = NULL;
+                esiStream->include->fail (esiStream);
+                esiStream->finished = 1;
+                httpRequestFree (http);
+                return;
+            }
+
+#if HEADERS_LOG
+            /* should be done in the store rather than every recipient?  */
+            headersLog(0, 0, http->request->method, rep);
+
+#endif
+
+            httpReplyDestroy(rep);
+
+            rep = NULL;
+        }
+    }
+
+    if (recievedData.data && recievedData.length) {
+        http->out.offset += recievedData.length;
+
+        if (recievedData.data >= esiStream->localbuffer->buf &&
+                recievedData.data < &esiStream->localbuffer->buf[sizeof(esiStream->localbuffer->buf)]) {
+            /* original static buffer */
+
+            if (recievedData.data != esiStream->localbuffer->buf) {
+                /* But not the start of it */
+                xmemmove (esiStream->localbuffer->buf, recievedData.data, recievedData.length);
+            }
+
+            esiStream->localbuffer->len = recievedData.length;
+        } else {
+            assert (esiStream->buffer.getRaw() != NULL);
+            esiStream->buffer->len = recievedData.length;
+        }
+    }
+
+    /* EOF / Read error /  aborted entry */
+    if (rep == NULL && recievedData.data == NULL && recievedData.length == 0) {
+        /* TODO: get stream status to test the entry for aborts */
+        debug (86,5)("Finished reading upstream data in subrequest\n");
+        esiStream->include->subRequestDone (esiStream, true);
+        esiStream->finished = 1;
+        httpRequestFree (http);
+        return;
+    }
+
+
+    /* after the write to the user occurs, (ie here, or in a callback)
+     * we call */
+    if (clientHttpRequestStatus(-1, http)) {
+        /* TODO: Does thisNode if block leak htto ? */
+        /* XXX when reviewing ESI this is the first place to look */
+        node->data = NULL;
+        esiStream->finished = 1;
+        esiStream->include->fail (esiStream);
+        return;
+    };
+
+    switch (clientStreamStatus (node, http)) {
+
+    case STREAM_UNPLANNED_COMPLETE: /* fallthru ok */
+
+    case STREAM_COMPLETE: /* ok */
+        debug (86,3)("ESI subrequest finished OK\n");
+        esiStream->include->subRequestDone (esiStream, true);
+        esiStream->finished = 1;
+        httpRequestFree (http);
+        return;
+
+    case STREAM_FAILED:
+        debug (86,1)("ESI subrequest failed transfer\n");
+        esiStream->include->fail (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);
+            debug (86,5)("esiBufferRecipient: Requested more data for ESI subrequest\n");
+        }
+
+        break;
+
+    default:
+        fatal ("Hit unreachable code in esiBufferRecipient\n");
+    }
+
+}
+
+/* esiStream functions */
+ESIStreamContext::~ESIStreamContext()
+{
+    assert (this);
+    freeResources();
+}
+
+void
+ESIStreamContext::freeResources()
+{
+    debug (86,5)("Freeing stream context resources.\n");
+    buffer = NULL;
+    localbuffer = NULL;
+    include = NULL;
+}
+
+void *
+ESIStreamContext::operator new(size_t byteCount)
+{
+    assert (byteCount == sizeof (ESIStreamContext));
+    CBDATA_INIT_TYPE(ESIStreamContext);
+    ESIStreamContext *result = cbdataAlloc(ESIStreamContext);
+    /* Mark result as being owned - we want the refcounter to do the
+     * delete call
+     */
+    cbdataReference(result);
+    return result;
+}
+
+void
+ESIStreamContext::operator delete (void *address)
+{
+    ESIStreamContext *t = static_cast<ESIStreamContext *>(address);
+    cbdataFree(t);
+    /* And allow the memory to be freed */
+    cbdataReferenceDone (address);
+}
+
+void
+ESIStreamContext::deleteSelf() const
+{
+    delete this;
+}
+
+ESIStreamContext *
+ESIStreamContextNew (ESIIncludePtr include)
+{
+    ESIStreamContext *rv = new ESIStreamContext;
+    rv->include = include;
+    return rv;
+}
+
+
+
+/* ESIInclude */
+ESIInclude::~ESIInclude()
+{
+    debug (86,5)("ESIInclude::Free %p\n", this);
+    ESISegmentFreeList (srccontent);
+    ESISegmentFreeList (altcontent);
+    cbdataReferenceDone (varState);
+    safe_free (srcurl);
+    safe_free (alturl);
+}
+
+void
+ESIInclude::finish()
+{
+    parent = NULL;
+}
+
+void *
+ESIInclude::operator new(size_t byteCount)
+{
+    assert (byteCount == sizeof (ESIInclude));
+
+    if (!Pool)
+        Pool = memPoolCreate ("ESIInclude", sizeof (ESIInclude));
+
+    return memPoolAlloc(Pool);
+}
+
+void
+ESIInclude::operator delete (void *address)
+{
+    memPoolFree (Pool, address);
+}
+
+void
+ESIInclude::deleteSelf() const
+{
+    delete this;
+}
+
+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) : parent (NULL), started (false), sent (false)
+{
+    varState = NULL;
+    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)
+{
+    httpHeaderInit (&tempheaders, hoRequest);
+
+    tempheaders.update (&vars->header(), NULL);
+    tempheaders.removeConnectionHeaderEntries();
+}
+
+
+void
+ESIInclude::Start (ESIStreamContext::Pointer stream, char const *url, ESIVarState *vars)
+{
+    HttpHeader tempheaders;
+
+    if (!stream.getRaw())
+        return;
+
+    prepareRequestHeaders(tempheaders, vars);
+
+    /* Ensure variable state is clean */
+    vars->feedData(url, strlen (url));
+
+    /* tempUrl is eaten by the request */
+    char const *tempUrl = vars->extractChar ();
+
+    debug (86,5)("ESIIncludeStart: Starting subrequest with url '%s'\n", tempUrl);
+
+    if (clientBeginRequest(METHOD_GET, tempUrl, esiBufferRecipient, esiBufferDetach, stream.getRaw(), &tempheaders, stream->localbuffer->buf, HTTP_REQBUF_SZ)) {
+        debug (86,0) ("starting new ESI subrequest failed\n");
+    }
+
+    httpHeaderClean (&tempheaders);
+}
+
+ESIInclude::ESIInclude (esiTreeParentPtr aParent, int attrcount, char const **attr, ESIContext *aContext) : parent (aParent), started (false), sent (false)
+{
+    int i;
+    assert (aContext);
+
+    for (i = 0; i < attrcount && attr[i]; i += 2) {
+        if (!strcmp(attr[i],"src")) {
+            /* Start a request for thisNode url */
+            debug (86,5)("ESIIncludeNew: Requesting source '%s'\n",attr[i+1]);
+            /* TODO: don't assert on thisNode, ignore the duplicate */
+            assert (src.getRaw() == NULL);
+            src = ESIStreamContextNew (this);
+            assert (src.getRaw() != NULL);
+            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
+             */
+            debug (86,5)("ESIIncludeNew: Requesting alternate '%s'\n",attr[i+1]);
+            assert (alt.getRaw() == NULL); /* TODO: FIXME */
+            alt = ESIStreamContextNew (this);
+            assert (alt.getRaw() != NULL);
+            alturl = xstrdup (attr[i+1]);
+        } else if (!strcmp(attr[i],"onerror")) {
+            if (!strcmp(attr[i+1], "continue")) {
+                flags.onerrorcontinue = 1;
+            } else {
+                /* ignore mistyped attributes */
+                debug (86, 1)("invalid value for onerror='%s'\n", 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 = NULL;
+
+        debug (86,1)("ESIIncludeNew: esi:include with no src attributes\n");
+
+        flags.failed = 1;
+    }
+}
+
+void
+ESIInclude::render(ESISegment::Pointer output)
+{
+    if (sent)
+        return;
+
+    ESISegment::Pointer myout;
+
+    debug (86, 5)("ESIIncludeRender: Rendering include %p\n", this);
+
+    assert (flags.finished || (flags.failed && flags.onerrorcontinue));
+
+    if (flags.failed && flags.onerrorcontinue) {
+        return;
+    }
+
+    /* Render the content */
+    if (srccontent.getRaw()) {
+        myout = srccontent;
+        srccontent = NULL;
+    } else if (altcontent.getRaw()) {
+        myout = altcontent;
+        altcontent = NULL;
+    } else
+        fatal ("ESIIncludeRender called with no content, and no failure!\n");
+
+    assert (output->next == NULL);
+
+    output->next = myout;
+
+    sent = true;
+}
+
+esiProcessResult_t
+ESIInclude::process (int dovars)
+{
+    /* Prevent refcount race leading to free */
+    Pointer me (this);
+    start();
+    debug (86, 5)("ESIIncludeRender: Processing include %p\n", 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::fail (ESIStreamContext::Pointer stream)
+{
+    subRequestDone (stream, false);
+}
+
+bool
+ESIInclude::dataNeeded() const
+{
+    return !(flags.finished || flags.failed);
+}
+
+void
+ESIInclude::subRequestDone (ESIStreamContext::Pointer stream, bool success)
+{
+    assert (this);
+
+    if (!dataNeeded())
+        return;
+
+    if (stream == src) {
+        debug (86,3)("ESIInclude::subRequestDone: %s\n", srcurl);
+
+        if (success) {
+            /* copy the lead segment */
+            debug (86,3)("ESIIncludeSubRequestDone: Src OK - include PASSED.\n");
+            assert (!srccontent.getRaw());
+            ESISegment::ListTransfer (stream->localbuffer, srccontent);
+            /* we're done! */
+            flags.finished = 1;
+        } else {
+            /* Fail if there is no alt being retrieved */
+            debug (86,3)("ESIIncludeSubRequestDone: Src FAILED\n");
+
+            if (!(alt.getRaw() || altcontent.getRaw())) {
+                debug (86,3)("ESIIncludeSubRequestDone: Include FAILED - No ALT\n");
+                flags.failed = 1;
+            } else if (altcontent.getRaw()) {
+                debug (86,3)("ESIIncludeSubRequestDone: Include PASSED - ALT already Complete\n");
+                /* ALT was already retrieved, we are done */
+                flags.finished = 1;
+            }
+        }
+
+        src = NULL;
+    } else if (stream == alt) {
+        debug (86,3)("ESIInclude::subRequestDone: %s\n", alturl);
+
+        if (success) {
+            debug (86,3)("ESIIncludeSubRequestDone: ALT OK.\n");
+            /* 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 */
+                debug (86,3)("ESIIncludeSubRequestDone: Include PASSED - SRC already failed.\n");
+                flags.finished = 1;
+            }
+        } else {
+            if (!(src.getRaw() || srccontent.getRaw())) {
+                debug (86,3)("ESIIncludeSubRequestDone: ALT FAILED, Include FAILED - SRC already failed\n");
+                /* src already failed */
+                flags.failed = 1;
+            }
+        }
+
+        alt = NULL;
+    } else {
+        fatal ("ESIIncludeSubRequestDone: non-owned stream found!\n");
+    }
+
+    if (flags.finished || flags.failed) {
+        /* Kick ESI Processor */
+        debug (86,5)("ESIInclude %p SubRequest %p completed, kicking processor , status %s\n", this, stream.getRaw(), flags.finished ? "OK" : "FAILED");
+        assert (parent.getRaw());
+
+        if (!flags.failed) {
+            sent = true;
+            parent->provideData (srccontent.getRaw() ? srccontent:altcontent,this);
+
+            if (srccontent.getRaw())
+                srccontent = NULL;
+            else
+                altcontent = NULL;
+        } 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.");
+    }
+}
+
diff --git a/src/ESIInclude.h b/src/ESIInclude.h
new file mode 100644 (file)
index 0000000..3c1f145
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * $Id: ESIInclude.h,v 1.1 2003/07/14 14:15:55 robertc Exp $
+ *
+ * DEBUG: section 86    ESI processing
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ */
+
+#ifndef SQUID_ESIINCLUDE_H
+#define SQUID_ESIINCLUDE_H
+
+#include "squid.h"
+#include "ESISegment.h"
+#include "ESIElement.h"
+#include "ESIContext.h"
+
+class ESIInclude;
+typedef RefCount<ESIInclude> ESIIncludePtr;
+
+class ESIStreamContext : public RefCountable
+{
+
+public:
+    typedef RefCount<ESIStreamContext> Pointer;
+    void *operator new(size_t);
+    void operator delete(void *);
+    void deleteSelf() const;
+    ESIStreamContext();
+    ~ESIStreamContext();
+    void freeResources();
+    int finished;
+    ESIIncludePtr include;
+    ESISegment::Pointer localbuffer;
+    ESISegment::Pointer buffer;
+
+private:
+    CBDATA_CLASS(ESIStreamContext);
+};
+
+/* ESIInclude */
+
+class ESIInclude : public ESIElement
+{
+
+public:
+    void *operator new (size_t byteCount);
+    void operator delete (void *address);
+    void deleteSelf() const;
+
+    ESIInclude(esiTreeParentPtr, int attributes, const char **attr, ESIContext *);
+    ~ESIInclude();
+    void render(ESISegment::Pointer);
+    esiProcessResult_t process (int dovars);
+    Pointer makeCacheable() const;
+    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const;
+    void subRequestDone (ESIStreamContext::Pointer, bool);
+
+    struct
+    {
+
+int onerrorcontinue:
+        1; /* on error return zero data */
+
+int failed:
+        1; /* Failed to process completely */
+
+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 fail(ESIStreamContext::Pointer);
+    void finish();
+
+private:
+    static MemPool *Pool;
+    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_ESIINCLUDE_H */
index a209a13449c1068169e1ec0c7ca3d80bff31d6bd..7c4c0ac79d6ad27b05d669cd4f4369e00a50916c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ESILiteral.h,v 1.1 2003/03/10 04:56:35 robertc Exp $
+ * $Id: ESILiteral.h,v 1.2 2003/07/14 14:15:56 robertc Exp $
  *
  * DEBUG: section 86    ESI processing
  * AUTHOR: Robert Collins
@@ -55,7 +55,7 @@ struct esiLiteral : public ESIElement
     void render(ESISegment::Pointer);
     esiProcessResult_t process (int dovars);
     Pointer makeCacheable() const;
-    Pointer makeUsable(esiTreeParentPtr, esiVarState &) const;
+    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const;
     /* optimise copies away later */
     ESISegment::Pointer buffer;
 
@@ -67,7 +67,7 @@ int donevars:
     }
 
     flags;
-    esiVarState *varState;
+    ESIVarState *varState;
     void finish();
 
 private:
index 2825736067bf0fc253436ad7291bc06984c1c2f4..ff4a18bc384599c3ef7c65be3fdfb3347f5ee697 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ESISegment.h,v 1.1 2003/03/10 04:56:36 robertc Exp $
+ * $Id: ESISegment.h,v 1.2 2003/07/14 14:15:56 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -38,6 +38,7 @@
  */
 
 #include "RefCount.h"
+#include "SquidString.h"
 
 class ESISegment : public RefCountable
 {
index 3b06c47e30f6cfadd7c074488e99f0adbc00c527..63441338075890e6d7c5276200a575fa44e9d081 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ESISequence.cc,v 1.1 2003/03/10 04:56:36 robertc Exp $
+ * $Id: ESISequence.cc,v 1.2 2003/07/14 14:15:56 robertc Exp $
  *
  * DEBUG: section 86    ESI processing
  * AUTHOR: Robert Collins
@@ -333,7 +333,7 @@ esiSequence::process (int inheritedVarsFlag)
 }
 
 void
-esiSequence::fail (ESIElement *source)
+esiSequence::fail (ESIElement *source, char const *anError)
 {
     failed = true;
 
@@ -343,7 +343,7 @@ esiSequence::fail (ESIElement *source)
     }
 
     debug (86,5)("esiSequence::fail: %p has failed.\n", this);
-    parent->fail (this);
+    parent->fail (this, anError);
     elements.setNULL(0, elements.size());
     parent = NULL;
 }
@@ -367,7 +367,7 @@ esiSequence::makeCachableElements(esiSequence const &old)
 }
 
 void
-esiSequence::makeUsableElements(esiSequence const &old, esiVarState &newVarState)
+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);
@@ -397,7 +397,7 @@ esiSequence::makeCacheable() const
 }
 
 ESIElement::Pointer
-esiSequence::makeUsable(esiTreeParentPtr newParent, esiVarState &newVarState) const
+esiSequence::makeUsable(esiTreeParentPtr newParent, ESIVarState &newVarState) const
 {
     debug (86,5)("esiSequence::makeUsable: Creating usable Sequence\n");
     assert (processedcount == 0);
index 06d9ec95efc4b9bbe1a906216bca0613e4ca5c64..81bf9bd45e5e90a3e21d5282afdbadd5cf47e34e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ESISequence.h,v 1.1 2003/03/10 04:56:36 robertc Exp $
+ * $Id: ESISequence.h,v 1.2 2003/07/14 14:15:56 robertc Exp $
  *
  * DEBUG: section 86    ESI processing
  * AUTHOR: Robert Collins
@@ -59,11 +59,11 @@ public:
     void provideData (ESISegment::Pointer, ESIElement*);
     bool mayFail () const;
     void wontFail();
-    void fail(ESIElement *);
+    void fail(ESIElement *, char const *anError = NULL);
     void makeCachableElements(esiSequence const &old);
     Pointer makeCacheable() const;
-    void makeUsableElements(esiSequence const &old, esiVarState &);
-    Pointer makeUsable(esiTreeParentPtr, esiVarState &) const;
+    void makeUsableElements(esiSequence const &old, ESIVarState &);
+    Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const;
 
     ElementList elements; /* unprocessed or rendered nodes */
     size_t processedcount;
diff --git a/src/ESIVar.h b/src/ESIVar.h
new file mode 100644 (file)
index 0000000..d28a705
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * $Id: ESIVar.h,v 1.1 2003/07/14 14:15:55 robertc Exp $
+ *
+ * DEBUG: section 86    ESI processing
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ */
+
+#ifndef SQUID_ESIVAR_H
+#define SQUID_ESIVAR_H
+
+#include "squid.h"
+#include "ESIElement.h"
+#include "ESISequence.h"
+
+/* esiVar */
+
+class ESIVar:public esiSequence
+{
+
+public:
+    //    void *operator new (size_t byteCount);
+    //    void operator delete (void *address);
+    void deleteSelf() const;
+    ESIVar(esiTreeParentPtr aParent) : esiSequence (aParent)
+    {
+        flags.dovars = 1;
+    }
+};
+
+#endif /* SQUID_ESIVAR_H */
diff --git a/src/ESIVarState.cc b/src/ESIVarState.cc
new file mode 100644 (file)
index 0000000..8ee72aa
--- /dev/null
@@ -0,0 +1,902 @@
+
+/*
+ * $Id: ESIVarState.cc,v 1.1 2003/07/14 14:15:55 robertc Exp $
+ *
+ * DEBUG: section 86    ESI processing
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ ;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ */
+
+#include "squid.h"
+#include "ESIVarState.h"
+#include "HttpReply.h"
+
+CBDATA_TYPE (ESIVarState);
+FREE ESIVarStateFree;
+
+char const *ESIVariableUserAgent::esiUserOs[]=
+    {
+        "WIN",
+        "MAC",
+        "UNIX",
+        "OTHER"
+    };
+
+char const * esiBrowsers[]=
+    {"MSIE",
+     "MOZILLA",
+     "OTHER"
+    };
+
+
+void
+ESIVarState::Variable::eval (ESIVarState &state, char const *subref, 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 */
+    debug (86,6)("esiVarState::feedData: accepting %d bytes\n", len);
+    ESISegment::ListAppend (input, buf, len);
+}
+
+ESISegment::Pointer
+ESIVarState::extractList()
+{
+    doIt();
+    ESISegment::Pointer rv = output;
+    output = NULL;
+    debug (86,6)("ESIVarStateExtractList: Extracted list\n");
+    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);
+
+    debug (86,6)("ESIVarStateExtractList: Extracted char\n");
+
+    return rv;
+}
+
+/* ESIVarState */
+void
+esiVarStateFree (void *data)
+{
+    ESIVarState *thisNode = (ESIVarState*)data;
+    thisNode->freeResources();
+}
+
+ESIVarState::~ESIVarState()
+{
+    freeResources();
+
+    while (variablesForCleanup.size())
+        delete variablesForCleanup.pop_back();
+
+    delete defaultVariable;
+}
+
+void
+ESIVarState::freeResources()
+{
+    input = NULL;
+    ESISegmentFreeList (output);
+    httpHeaderClean (&hdr);
+}
+
+void *
+ESIVarState::operator new(size_t byteCount)
+{
+    assert (byteCount == sizeof (ESIVarState));
+    void *rv;
+    CBDATA_INIT_TYPE_FREECB(ESIVarState, esiVarStateFree);
+    rv = (void *)cbdataAlloc (ESIVarState);
+    return rv;
+}
+
+void
+ESIVarState::operator delete (void *address)
+{
+    cbdataFree (address);
+}
+
+void
+ESIVarState::deleteSelf() const
+{
+    delete this;
+}
+
+char *
+ESIVariableUserAgent::getProductVersion (char const *s)
+{
+    char const *t;
+    int len;
+    t = index (s,'/');
+
+    if (!t || !*(++t))
+        return xstrdup ("");
+
+    len = strcspn (t, " \r\n()<>@,;:\\\"/[]?={}");
+
+    return xstrndup (t, len + 1);
+}
+
+ESIVariableQuery::ESIVariableQuery(char const *uri) : query (NULL), query_sz (0), query_elements (0), query_string (NULL)
+{
+    /* 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 = (_query_elem *)memReallocBuf(query, query_elements * sizeof (struct _query_elem),
+                                             &query_sz);
+        query_pos = query_start + 1;
+        n = 0;
+
+        while (query_pos) {
+            char *next = strchr (query_pos, '&');
+            char *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;
+        debug (86,6)("esiVarStateNew: Parsed Query string: '%s'\n",uri);
+
+        while (n < query_elements) {
+            debug (86,6)("esiVarStateNew: Parsed Query element %d '%s'='%s'\n",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 (NULL)
+{
+    /* TODO: only grab the needed headers */
+    /* Note that as we pass these through to included requests, we
+     * cannot trim them */
+    httpHeaderInit (&hdr, hoReply);
+
+    httpHeaderAppend (&hdr, 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.buf(), 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.limitInit (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 
+     *
+     * Useing 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 (httpHeaderHas(&state.header(), HDR_USER_AGENT)) {
+        char const *s = httpHeaderGetStr (&state.header(), HDR_USER_AGENT);
+        UserOs = identifyOs(s);
+        char const *t, *t1;
+
+        /* Now the browser and version */
+
+        if ((t = strstr (s, "MSIE"))) {
+            browser = ESI_BROWSER_MSIE;
+            t = index (t, ' ');
+
+            if (!t)
+                browserversion = xstrdup ("");
+            else {
+                t1 = index (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 = NULL;
+    state.cookieUsed();
+
+    if (httpHeaderHas(&state.header(), HDR_COOKIE)) {
+        if (!subref)
+            s = httpHeaderGetStr (&state.header(), HDR_COOKIE);
+        else {
+            String S = httpHeaderGetListMember (&state.header(), HDR_COOKIE, subref, ';');
+
+            if (S.size())
+                ESISegment::ListAppend (state.getOutput(), S.buf(), S.size());
+            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 = NULL;
+    state.hostUsed();
+
+    if (!subref && httpHeaderHas(&state.header(),HDR_HOST)) {
+        s = httpHeaderGetStr (&state.header(), HDR_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 = NULL;
+    state.languageUsed();
+
+    if (httpHeaderHas(&state.header(), HDR_ACCEPT_LANGUAGE)) {
+        if (!subref) {
+            String S (httpHeaderGetList (&state.header(), HDR_ACCEPT_LANGUAGE));
+            ESISegment::ListAppend (state.getOutput(), S.buf(), S.size());
+        } else {
+            if (httpHeaderHasListMember (&state.header(), HDR_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 = NULL;
+
+    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 = NULL;
+    state.refererUsed();
+
+    if (!subref && httpHeaderHas(&state.header(), HDR_REFERER))
+        s = httpHeaderGetStr (&state.header(), HDR_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 = NULL;
+    state.useragentUsed();
+
+    if (httpHeaderHas(&state.header(), HDR_USER_AGENT)) {
+        if (!subref)
+            s = httpHeaderGetStr (&state.header(), HDR_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 NULL;
+}
+
+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 *found_default );
+    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 *found_default )
+{
+    assert (var);
+
+    if (!found_default)
+        found_default = "";
+
+    var->eval (*varState, subref, found_default);
+}
+
+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 (NULL),
+        found_default (NULL), currentFunction(NULL)
+{
+    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] == '{') {
+                debug (86,6)("ESIVarStateDoIt: Subref of some sort\n");
+                /* subreference of some sort */
+                /* look for the entry name */
+                var_pos = ++pos;
+                state = 4;
+            } else if (!found_default && string[pos] == '|') {
+                debug (86,6)("esiVarStateDoIt: Default present\n");
+                /* extract default value */
+                state = 5;
+                var_pos = ++pos;
+            } else {
+                /* unexpected char, not a variable after all */
+                debug (86,6)("esiVarStateDoIt: unexpected char after varname\n");
+                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);
+                debug (86,6)("esiVarStateDoIt: found end of variable subref '%s'\n", found_subref);
+                state = 3;
+                ++pos;
+            } else if (!validChar (string[pos])) {
+                debug (86,6)("esiVarStateDoIt: found invalid char in variable subref\n");
+                /* 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 */
+                debug (86,6)("esiVarStateDoIt: found quoted default\n");
+                state = 6;
+                var_pos = ++pos;
+            } else {
+                /* doesn't */
+                debug (86,6)("esiVarStateDoIt: found unquoted default\n");
+                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);
+                debug (86,6)("esiVarStateDoIt: found end of quoted default '%s'\n", 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);
+                debug (86,6)("esiVarStateDoIt: found end of variable (w/ unquoted default) '%s'\n",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 == NULL);
+
+    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 FIXME: 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 (httpHeaderGetList (&rep->header, HDR_VARY));
+
+    if (!strVary.size() || strVary.buf()[0] != '*') {
+        httpHeaderPutStr (&rep->header, HDR_VARY, tempstr);
+    }
+}
+
diff --git a/src/ESIVarState.h b/src/ESIVarState.h
new file mode 100644 (file)
index 0000000..36929ee
--- /dev/null
@@ -0,0 +1,211 @@
+
+/*
+ * $Id: ESIVarState.h,v 1.1 2003/07/14 14:15:55 robertc Exp $
+ *
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef SQUID_ESIVARSTATE_H
+#define SQUID_ESIVARSTATE_H
+
+#include "ESISegment.h"
+#include "Trie.h"
+#include "Array.h"
+#include "HttpHeader.h"
+
+/* 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
+{
+
+public:
+    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 &);
+
+    void *operator new (size_t byteCount);
+    void operator delete (void *address);
+    void deleteSelf() const;
+    void freeResources();
+    ESIVarState (HttpHeader const *hdr, char const *uri);
+    ~ESIVarState();
+
+    /* 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
+    {
+
+int language:
+        1;
+
+int cookie:
+        1;
+
+int host:
+        1;
+
+int referer:
+        1;
+
+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;
+    Vector<Variable*> variablesForCleanup;
+    Variable *defaultVariable;
+};
+
+class ESIVariableCookie : public ESIVarState::Variable
+{
+
+public:
+    virtual void eval (ESIVarState &state, char const *, char const *) const;
+};
+
+class ESIVariableHost : public ESIVarState::Variable
+{
+
+public:
+    virtual void eval (ESIVarState &state, char const *, char const *) const;
+};
+
+class ESIVariableLanguage : public ESIVarState::Variable
+{
+
+public:
+    virtual void eval (ESIVarState &state, char const *, char const *) const;
+};
+
+class ESIVariableQuery : public ESIVarState::Variable
+{
+
+public:
+    ESIVariableQuery(char const *uri);
+    ~ESIVariableQuery();
+    virtual void eval (ESIVarState &state, char const *, char const *) const;
+    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:
+    virtual void eval (ESIVarState &state, char const *, char const *) const;
+};
+
+class ESIVariableUserAgent : public ESIVarState::Variable
+{
+
+public:
+    ~ESIVariableUserAgent();
+    ESIVariableUserAgent (ESIVarState &state);
+    virtual void eval (ESIVarState &state, char const *, char const *) const;
+
+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_ESIVARSTATE_H */
index 3de32b2d00effdb4eb64c3319fff3c6cf1265530..aedc9e09c56f0ecf0be96085c04bfb11ec76d11d 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpHdrRange.cc,v 1.35 2003/06/19 13:12:01 robertc Exp $
+ * $Id: HttpHdrRange.cc,v 1.36 2003/07/14 14:15:56 robertc Exp $
  *
  * DEBUG: section 64    HTTP Range Header
  * AUTHOR: Alex Rousskov
@@ -37,6 +37,7 @@
 #include "Store.h"
 #include "HttpHeaderRange.h"
 #include "client_side_request.h"
+#include "HttpReply.h"
 
 /*
  *    Currently only byte ranges are supported
index d3b1b85cbce5dc66947308cbd685172ddd2a486a..75aa3a465bd080feca4c03c2b368ad7957c578fa 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpHeader.cc,v 1.91 2003/07/14 08:21:56 robertc Exp $
+ * $Id: HttpHeader.cc,v 1.92 2003/07/14 14:15:56 robertc Exp $
  *
  * DEBUG: section 55    HTTP Header
  * AUTHOR: Alex Rousskov
@@ -405,12 +405,19 @@ httpHeaderAppend(HttpHeader * dest, const HttpHeader * src)
 /* use fresh entries to replace old ones */
 void
 httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask)
+{
+    assert (old);
+    old->update (fresh, denied_mask);
+}
+
+void
+HttpHeader::update (HttpHeader const *fresh, HttpHeaderMask const *denied_mask)
 {
     const HttpHeaderEntry *e;
     HttpHeaderPos pos = HttpHeaderInitPos;
-    assert(old && fresh);
-    assert(old != fresh);
-    debug(55, 7) ("updating hdr: %p <- %p\n", old, fresh);
+    assert(this && fresh);
+    assert(this != fresh);
+    debug(55, 7) ("updating hdr: %p <- %p\n", this, fresh);
 
     while ((e = httpHeaderGetEntry(fresh, &pos))) {
         /* deny bad guys (ok to check for HDR_OTHER) here */
@@ -418,9 +425,9 @@ httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMas
         if (denied_mask && CBIT_TEST(*denied_mask, e->id))
             continue;
 
-        httpHeaderDelByName(old, e->name.buf());
+        httpHeaderDelByName(this, e->name.buf());
 
-        httpHeaderAddEntry(old, httpHeaderEntryClone(e));
+        httpHeaderAddEntry(this, httpHeaderEntryClone(e));
     }
 }
 
@@ -1470,3 +1477,55 @@ HttpHeaderEntry::operator delete (void *address)
 {
     memPoolFree (Pool, address);
 }
+
+int
+httpHeaderHasListMember(const HttpHeader * hdr, http_hdr_type id, const char *member, const char separator)
+{
+    int result = 0;
+    const char *pos = NULL;
+    const char *item;
+    int ilen;
+    int mlen = strlen(member);
+
+    assert(hdr);
+    assert(id >= 0);
+
+    String header (httpHeaderGetStrOrList(hdr, id));
+
+    while (strListGetItem(&header, separator, &item, &ilen, &pos)) {
+        if (strncmp(item, member, mlen) == 0
+                && (item[mlen] == '=' || item[mlen] == separator || item[mlen] == ';' || item[mlen] == '\0')) {
+            result = 1;
+            break;
+        }
+    }
+
+    return result;
+}
+
+void
+HttpHeader::removeConnectionHeaderEntries()
+{
+    if (httpHeaderHas(this, HDR_CONNECTION)) {
+        /* anything that matches Connection list member will be deleted */
+        String strConnection = httpHeaderGetList(this, HDR_CONNECTION);
+        const HttpHeaderEntry *e;
+        HttpHeaderPos pos = HttpHeaderInitPos;
+        /*
+         * think: on-average-best nesting of the two loops (hdrEntry
+         * and strListItem) @?@
+         */
+        /*
+         * maybe we should delete standard stuff ("keep-alive","close")
+         * from strConnection first?
+         */
+
+        while ((e = httpHeaderGetEntry(this, &pos))) {
+            if (strListIsMember(&strConnection, e->name.buf(), ','))
+                httpHeaderDelAt(this, pos);
+        }
+
+        httpHeaderDelById(this, HDR_CONNECTION);
+        strConnection.clean();
+    }
+}
index 57539ef6bb7d2226fe521d2dfe75699647a28e39..95d9d81f1869d6f891bb3c8d4350a45daee0fce0 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpHeader.h,v 1.4 2003/03/10 04:56:36 robertc Exp $
+ * $Id: HttpHeader.h,v 1.5 2003/07/14 14:15:56 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -50,5 +50,21 @@ extern int httpHeaderParseQuotedString (const char *start, String *val);
 extern void httpHeaderPutSc(HttpHeader *hdr, const HttpHdrSc *sc);
 extern HttpHdrSc *httpHeaderGetSc(const HttpHeader *hdr);
 SQUIDCEXTERN void httpHeaderAddContRange(HttpHeader *, HttpHdrRangeSpec, ssize_t);
+extern int httpHeaderHasListMember(const HttpHeader * hdr, http_hdr_type id, const char *member, const char separator);
+SQUIDCEXTERN void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask);
+
+class HttpHeader
+{
+
+public:
+    /* Interface functions */
+    void update (HttpHeader const *fresh, HttpHeaderMask const *denied_mask);
+    void removeConnectionHeaderEntries();
+    /* protected, do not use these, use interface functions instead */
+    Array entries;             /* parsed fields in raw format */
+    HttpHeaderMask mask;       /* bit set <=> entry present */
+    http_hdr_owner_type owner; /* request or reply */
+    int len;                   /* length when packed, not counting terminating '\0' */
+};
 
 #endif /* SQUID_HTTPHEADER_H */
index e43671484e51bcb9c88cc053346b6b436eb5210a..73365850e71825e8cb65f485bfa715b20a14d645 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpReply.h,v 1.3 2003/05/11 13:53:03 hno Exp $
+ * $Id: HttpReply.h,v 1.4 2003/07/14 14:15:56 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -35,6 +35,7 @@
 #define SQUID_HTTPREPLY_H
 
 #include "typedefs.h"
+#include "HttpHeader.h"
 
 /* Http Reply */
 extern void httpReplyInitModule(void);
@@ -75,4 +76,41 @@ extern void httpRedirectReply(HttpReply *, http_status, const char *);
 extern int httpReplyBodySize(method_t, HttpReply const *);
 extern int httpReplyValidatorsMatch (HttpReply const *, HttpReply const *);
 
+/* Sync changes here with HttpReply.cc */
+
+class HttpHdrContRange;
+
+class HttpReply
+{
+
+public:
+    void *operator new (size_t);
+    void operator delete (void *);
+    /* unsupported, writable, may disappear/change in the future */
+    int hdr_sz;                        /* sums _stored_ status-line, headers, and <CRLF> */
+
+    /* public, readable; never update these or their .hdr equivalents directly */
+    int content_length;
+    time_t date;
+    time_t last_modified;
+    time_t expires;
+    String content_type;
+    HttpHdrCc *cache_control;
+    HttpHdrSc *surrogate_control;
+    HttpHdrContRange *content_range;
+    short int keep_alive;
+
+    /* public, readable */
+    HttpMsgParseState pstate;  /* the current parsing state */
+
+    /* public, writable, but use httpReply* interfaces when possible */
+    HttpStatusLine sline;
+    HttpHeader header;
+    HttpBody body;             /* for small constant memory-resident text bodies only */
+
+private:
+    static MemPool *Pool;
+};
+
+
 #endif /* SQUID_HTTPREPLY_H */
index 3c7b24078177273441512c79714c75395ee9e83e..34e382fd17419355d154ac000bc4125f68e6004c 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpRequest.h,v 1.2 2003/07/11 01:40:35 robertc Exp $
+ * $Id: HttpRequest.h,v 1.3 2003/07/14 14:15:56 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
 #define SQUID_HTTPREQUEST_H
 
 #include "typedefs.h"
+#include "HttpHeader.h"
 #include "client_side.h"
 
+/*  Http Request */
+extern request_t *requestCreate(method_t, protocol_t, const char *urlpath);
+extern void requestDestroy(request_t *);
+extern request_t *requestLink(request_t *);
+extern void requestUnlink(request_t *);
+extern int httpRequestParseHeader(request_t * req, const char *parse_start);
+extern void httpRequestSwapOut(const request_t * req, StoreEntry * e);
+extern void httpRequestPack(const request_t * req, Packer * p);
+extern int httpRequestPrefixLen(const request_t * req);
+extern int httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConnection);
+extern int httpRequestHdrAllowedByName(http_hdr_type id);
+
+class HttpHdrRange;
+
 class request_t
 {
 
@@ -81,17 +96,5 @@ public:
     String extacl_log;         /* String to be used for access.log purposes */
 };
 
-/*  Http Request */
-extern request_t *requestCreate(method_t, protocol_t, const char *urlpath);
-extern void requestDestroy(request_t *);
-extern request_t *requestLink(request_t *);
-extern void requestUnlink(request_t *);
-extern int httpRequestParseHeader(request_t * req, const char *parse_start);
-extern void httpRequestSwapOut(const request_t * req, StoreEntry * e);
-extern void httpRequestPack(const request_t * req, Packer * p);
-extern int httpRequestPrefixLen(const request_t * req);
-extern int httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConnection);
-extern int httpRequestHdrAllowedByName(http_hdr_type id);
-
 
 #endif /* SQUID_HTTPREQUEST_H */
index 82ea21d4efdade330726f7673bca1a6b29b6cdc0..a4d9644719d321ca995c938d6e9f33d69829872f 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.am,v 1.81 2003/07/07 22:44:28 robertc Exp $
+#  $Id: Makefile.am,v 1.82 2003/07/14 14:15:56 robertc Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -55,6 +55,8 @@ ESI_ALL_SOURCE = \
        ElementList.h \
        ESI.cc \
        ESI.h \
+       ESIAssign.cc \
+       ESIAssign.h \
        ESIAttempt.h \
        ESIContext.cc \
        ESIContext.h \
@@ -65,13 +67,19 @@ ESI_ALL_SOURCE = \
        ESIExpatParser.cc \
        ESIExpatParser.h \
        ESIExpression.cc \
+       ESIExpression.h \
+       ESIInclude.cc \
+       ESIInclude.h \
        ESILiteral.h \
        ESIParser.cc \
        ESIParser.h \
        ESISegment.cc \
        ESISegment.h \
        ESISequence.cc \
-       ESISequence.h
+       ESISequence.h \
+       ESIVar.h \
+       ESIVarState.cc \
+       ESIVarState.h
 if USE_ESI
   ESI_SOURCE = $(ESI_ALL_SOURCE)
 else
@@ -85,7 +93,7 @@ XPROF_STATS_SOURCE =
 endif
 
 if ENABLE_HTCP
-HTCPSOURCE = htcp.cc
+HTCPSOURCE = htcp.cc htcp.h
 endif
 
 if MAKE_LEAKFINDER
index 0751f55ef70c594c41b341e040cbb7e6c1bb9bb5..4df85f6c811daf22d0e8824e8d367f93a82434a1 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: asn.cc,v 1.94 2003/07/14 08:21:56 robertc Exp $
+ * $Id: asn.cc,v 1.95 2003/07/14 14:15:58 robertc Exp $
  *
  * DEBUG: section 53    AS Number handling
  * AUTHOR: Duane Wessels, Kostas Anagnostakis
@@ -43,6 +43,7 @@
 #include "ACLSourceASN.h"
 #include "ACLDestinationASN.h"
 #include "ACLDestinationIP.h"
+#include "HttpReply.h"
 
 #define WHOIS_PORT 43
 #define        AS_REQBUF_SZ    4096
index 6bd70d43ae226865c36b2b9ffb8b92431fabec3e..88dc120206e2b4fbcde2ab1bcf3c19435d193e46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: auth_basic.cc,v 1.26 2003/07/11 01:40:39 robertc Exp $
+ * $Id: auth_basic.cc,v 1.27 2003/07/14 14:16:21 robertc Exp $
  *
  * DEBUG: section 29    Authenticator
  * AUTHOR: Duane Wessels
@@ -41,6 +41,7 @@
 #include "auth_basic.h"
 #include "authenticate.h"
 #include "Store.h"
+#include "HttpReply.h"
 
 static void
 authenticateStateFree(AuthenticateStateData * r)
index 250af3be4e832a29bf38c3fc2db771e139f86f1e..6b58848b9591c889ef4161064d46fbc8dd846047 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: auth_digest.cc,v 1.26 2003/07/14 08:22:01 robertc Exp $
+ * $Id: auth_digest.cc,v 1.27 2003/07/14 14:16:21 robertc Exp $
  *
  * DEBUG: section 29    Authenticator
  * AUTHOR: Robert Collins
@@ -44,6 +44,7 @@
 #include "authenticate.h"
 #include "Store.h"
 #include "HttpRequest.h"
+#include "HttpReply.h"
 
 extern AUTHSSETUP authSchemeSetup_digest;
 
index 27be1f31aeccefa0d42a031d3faa56364fc52d4a..ce18661ed4b028625cc1f2a180e518db63d4357d 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: auth_ntlm.cc,v 1.33 2003/07/14 08:21:58 robertc Exp $
+ * $Id: auth_ntlm.cc,v 1.34 2003/07/14 14:16:21 robertc Exp $
  *
  * DEBUG: section 29    NTLM Authenticator
  * AUTHOR: Robert Collins
@@ -43,6 +43,7 @@
 #include "authenticate.h"
 #include "Store.h"
 #include "client_side.h"
+#include "HttpReply.h"
 #include "HttpRequest.h"
 
 extern AUTHSSETUP authSchemeSetup_ntlm;
index db8d3f7aa8ce287177a58f7f739ef697d90da9ed..46f034bd6c1f3c9f7b6c6ce1cbb522eed562c716 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: authenticate.cc,v 1.59 2003/07/11 01:40:35 robertc Exp $
+ * $Id: authenticate.cc,v 1.60 2003/07/14 14:15:59 robertc Exp $
  *
  * DEBUG: section 29    Authenticator
  * AUTHOR:  Robert Collins
@@ -41,6 +41,7 @@
 #include "authenticate.h"
 #include "ACL.h"
 #include "client_side.h"
+#include "HttpReply.h"
 #include "HttpRequest.h"
 
 CBDATA_TYPE(auth_user_ip_t);
index 9a2f87ce86c6bdce3c4a97bb982e1548553bf31e..3ebfa60b5f139364d0f2d18e70a31ce16000822c 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: authenticate.h,v 1.10 2003/07/12 12:39:56 robertc Exp $
+ * $Id: authenticate.h,v 1.11 2003/07/14 14:15:59 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -110,6 +110,8 @@ private:
 
 /* Per scheme request data ABC */
 
+class ConnStateData;
+
 class AuthUserRequestState
 {
 
index 0dc77d07965b7d48f604717e45b300d095d2be4d..4e2bec765ba39679f61b2b048261c638fbe07ab3 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side_reply.cc,v 1.58 2003/07/11 01:40:36 robertc Exp $
+ * $Id: client_side_reply.cc,v 1.59 2003/07/14 14:15:59 robertc Exp $
  *
  * DEBUG: section 88    Client-side Reply Routines
  * AUTHOR: Robert Collins (Originally Duane Wessels in client_side.c)
@@ -1277,29 +1277,7 @@ void
 clientReplyContext::obeyConnectionHeader()
 {
     HttpHeader *hdr = &holdingReply->header;
-
-    if (httpHeaderHas(hdr, HDR_CONNECTION)) {
-        /* anything that matches Connection list member will be deleted */
-        String strConnection = httpHeaderGetList(hdr, HDR_CONNECTION);
-        const HttpHeaderEntry *e;
-        HttpHeaderPos pos = HttpHeaderInitPos;
-        /*
-         * think: on-average-best nesting of the two loops (hdrEntry
-         * and strListItem) @?@
-         */
-        /*
-         * maybe we should delete standard stuff ("keep-alive","close")
-         * from strConnection first?
-         */
-
-        while ((e = httpHeaderGetEntry(hdr, &pos))) {
-            if (strListIsMember(&strConnection, e->name.buf(), ','))
-                httpHeaderDelAt(hdr, pos);
-        }
-
-        httpHeaderDelById(hdr, HDR_CONNECTION);
-        strConnection.clean();
-    }
+    hdr->removeConnectionHeaderEntries();
 }
 
 /*
index a3aeb48bb3e53a2c2bd644a8bc6b8aff225ce040..fa6dccf6ff4a4c447b909bbfeb5d630ce5e9b74b 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side_request.h,v 1.14 2003/07/11 01:40:36 robertc Exp $
+ * $Id: client_side_request.h,v 1.15 2003/07/14 14:16:00 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -45,6 +45,8 @@ class MemObject;
 
 typedef class ClientHttpRequest clientHttpRequest;
 
+class ConnStateData;
+
 class ClientHttpRequest
 {
 
index 4ae056faf3eb2f69ab214b7af78729eb0c272cb3..42a9bb1284b25fa609361a89ed5d89999b79a369 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: forward.cc,v 1.106 2003/07/11 01:40:36 robertc Exp $
+ * $Id: forward.cc,v 1.107 2003/07/14 14:16:00 robertc Exp $
  *
  * DEBUG: section 17    Request Forwarding
  * AUTHOR: Duane Wessels
@@ -41,6 +41,7 @@
 #include "MemObject.h"
 #include "ACLChecklist.h"
 #include "ACL.h"
+#include "HttpReply.h"
 
 static PSC fwdStartComplete;
 static void fwdDispatch(FwdState *);
index 85fca8bbddcb56e7c7d4dc8c44a969df819c5f37..1886d8933e47c2ed585f27268090f215ce82f59b 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: htcp.cc,v 1.52 2003/02/23 00:08:04 robertc Exp $
+ * $Id: htcp.cc,v 1.53 2003/07/14 14:16:00 robertc Exp $
  *
  * DEBUG: section 31    Hypertext Caching Protocol
  * AUTHOR: Duane Wesssels
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "htcp.h"
 #include "Store.h"
 #include "StoreClient.h"
 #include "HttpRequest.h"
index 7975ae82036477b73c3a87e24282e88e1f9725f7..f0cf9ddcc122d3c87fd1a409d0f1cf90c61c2ca0 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: htcp.h,v 1.2 2003/01/23 00:37:22 robertc Exp $
+ * $Id: htcp.h,v 1.3 2003/07/14 14:16:00 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
 #ifndef SQUID_HTCP_H
 #define SQUID_HTCP_H
 
+#if USE_HTCP
+#include "HttpHeader.h"
+
+struct _htcpReplyData
+{
+    int hit;
+    HttpHeader hdr;
+    u_int32_t msg_id;
+    double version;
+
+    struct
+    {
+        /* cache-to-origin */
+        double rtt;
+        int samp;
+        int hops;
+    }
+
+    cto;
+};
+
+#endif
+
 #endif /* SQUID_HTCP_H */
index 96bc2e4cbb1b577ee392764b16859877899c9920..d7e6c3cd12f01a42db62e9b97e22c22c5786d115 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: http.cc,v 1.418 2003/07/11 01:40:36 robertc Exp $
+ * $Id: http.cc,v 1.419 2003/07/14 14:16:00 robertc Exp $
  *
  * DEBUG: section 11    Hypertext Transfer Protocol (HTTP)
  * AUTHOR: Harvest Derived
@@ -65,7 +65,6 @@ static PF httpTimeout;
 static void httpCacheNegatively(StoreEntry *);
 static void httpMakePrivate(StoreEntry *);
 static void httpMakePublic(StoreEntry *);
-static int httpCachableReply(HttpStateData *);
 static void httpMaybeRemovePublic(StoreEntry *, http_status);
 static void copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, String strConnection, request_t * request, request_t * orig_request,
         HttpHeader * hdr_out, int we_do_ranges, http_state_flags);
@@ -349,21 +348,21 @@ cacheControlAllowsCaching(HttpHdrCc *cc)
     return 1;
 }
 
-static int
-httpCachableReply(HttpStateData * httpState)
+int
+HttpStateData::cacheableReply()
 {
-    HttpReply const *rep = httpState->entry->getReply();
+    HttpReply const *rep = entry->getReply();
     HttpHeader const *hdr = &rep->header;
     const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0;
     const char *v;
 
-    if (httpState->surrogateNoStore)
+    if (surrogateNoStore)
         return 0;
 
     if (!cacheControlAllowsCaching(rep->cache_control))
         return 0;
 
-    if (!httpState->ignoreCacheControl) {
+    if (!ignoreCacheControl) {
         if (EBIT_TEST(cc_mask, CC_PRIVATE))
             return 0;
 
@@ -374,7 +373,7 @@ httpCachableReply(HttpStateData * httpState)
             return 0;
     }
 
-    if (httpState->request->flags.auth) {
+    if (request->flags.auth) {
         /*
          * Responses to requests with authorization may be cached
          * only if a Cache-Control: public reply header is present.
@@ -405,7 +404,7 @@ httpCachableReply(HttpStateData * httpState)
         if (!strncasecmp(v, "multipart/x-mixed-replace", 25))
             return 0;
 
-    switch (httpState->entry->getReply()->sline.status) {
+    switch (entry->getReply()->sline.status) {
         /* Responses that are cacheable */
 
     case HTTP_OK:
@@ -422,7 +421,7 @@ httpCachableReply(HttpStateData * httpState)
          * unless we know how to refresh it.
          */
 
-        if (!refreshIsCachable(httpState->entry))
+        if (!refreshIsCachable(entry))
             return 0;
 
         /* don't cache objects from peers w/o LMT, Date, or Expires */
@@ -431,7 +430,7 @@ httpCachableReply(HttpStateData * httpState)
             return 1;
         else if (rep->last_modified > -1)
             return 1;
-        else if (!httpState->_peer)
+        else if (!_peer)
             return 1;
 
         /* @?@ (here and 302): invalid expires header compiles to squid_curtime */
@@ -500,7 +499,7 @@ httpCachableReply(HttpStateData * httpState)
         return 0;
 
     default:                   /* Unknown status code */
-        debug (11,0)("httpCachableReply: unknown http status code in reply\n");
+        debug (11,0)("HttpStateData::cacheableReply: unknown http status code in reply\n");
 
         return 0;
 
@@ -677,7 +676,7 @@ HttpStateData::processReplyHeader(const char *buf, int size)
     if (neighbors_do_private_keys)
         httpMaybeRemovePublic(entry, entry->getReply()->sline.status);
 
-    switch (httpCachableReply(this)) {
+    switch (cacheableReply()) {
 
     case 1:
 
index 646752aa2322db40d289ea5c86511c0b90fd0b7f..93ec0bcc81ebc63803d4fe0847252ec7849bd158 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: http.h,v 1.7 2003/03/10 04:56:38 robertc Exp $
+ * $Id: http.h,v 1.8 2003/07/14 14:16:00 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -46,6 +46,7 @@ public:
     void processReplyData(const char *, size_t);
     IOCB readReply;
     void maybeReadData();
+    int cacheableReply();
 
     StoreEntry *entry;
     request_t *request;
index ede16c8d4f018893fd098ab771da4642ba908bfd..92426faa14ae54db1f1cede1672ccf038244be42 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: mem.cc,v 1.80 2003/07/11 01:40:36 robertc Exp $
+ * $Id: mem.cc,v 1.81 2003/07/14 14:16:00 robertc Exp $
  *
  * DEBUG: section 13    High Level Memory Pool Management
  * AUTHOR: Harvest Derived
@@ -37,6 +37,7 @@
 #include "Mem.h"
 #include "memMeter.h"
 #include "Store.h"
+#include "HttpRequest.h"
 
 /* module globals */
 
index 558cc7ff320b301806fd2f2b48fec923cecde40f..80b42def9d197f4dbb276ba0f85e75ca35fa5d88 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: neighbors.cc,v 1.319 2003/03/02 23:13:49 hno Exp $
+ * $Id: neighbors.cc,v 1.320 2003/07/14 14:16:00 robertc Exp $
  *
  * DEBUG: section 15    Neighbor Routines
  * AUTHOR: Harvest Derived
@@ -39,6 +39,7 @@
 #include "HttpRequest.h"
 #include "MemObject.h"
 #include "ACLChecklist.h"
+#include "htcp.h"
 
 /* count mcast group peers every 15 minutes */
 #define MCAST_COUNT_RATE 900
index 373038d2c01b0b56e4d4076ad0ef6dbaeffcbaeb..9fbdbd99ab9d1e6f5216af4258bf2c102c303d46 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: peer_select.cc,v 1.129 2003/02/21 22:50:10 robertc Exp $
+ * $Id: peer_select.cc,v 1.130 2003/07/14 14:16:00 robertc Exp $
  *
  * DEBUG: section 44    Peer Selection Algorithm
  * AUTHOR: Duane Wessels
@@ -38,6 +38,7 @@
 #include "ICP.h"
 #include "HttpRequest.h"
 #include "ACLChecklist.h"
+#include "htcp.h"
 
 const char *hier_strings[] =
     {
index ac208c74b45626a39ae041b8ccf1753e2edb7473..3af3c2262ca364c40a9e08d02c75f36de73f1c99 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: protos.h,v 1.481 2003/07/06 21:50:56 hno Exp $
+ * $Id: protos.h,v 1.482 2003/07/14 14:16:01 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -405,7 +405,6 @@ SQUIDCEXTERN void httpHeaderInit(HttpHeader * hdr, http_hdr_owner_type owner);
 SQUIDCEXTERN void httpHeaderClean(HttpHeader * hdr);
 /* append/update */
 SQUIDCEXTERN void httpHeaderAppend(HttpHeader * dest, const HttpHeader * src);
-SQUIDCEXTERN void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask);
 /* parse/pack */
 SQUIDCEXTERN int httpHeaderParse(HttpHeader * hdr, const char *header_start, const char *header_end);
 SQUIDCEXTERN void httpHeaderPackInto(const HttpHeader * hdr, Packer * p);
@@ -416,7 +415,11 @@ SQUIDCEXTERN void httpHeaderPutTime(HttpHeader * hdr, http_hdr_type type, time_t
 SQUIDCEXTERN void httpHeaderPutStr(HttpHeader * hdr, http_hdr_type type, const char *str);
 SQUIDCEXTERN void httpHeaderPutAuth(HttpHeader * hdr, const char *auth_scheme, const char *realm);
 SQUIDCEXTERN void httpHeaderPutCc(HttpHeader * hdr, const HttpHdrCc * cc);
+
+class HttpHdrContRange;
 SQUIDCEXTERN void httpHeaderPutContRange(HttpHeader * hdr, const HttpHdrContRange * cr);
+
+class HttpHdrRange;
 SQUIDCEXTERN void httpHeaderPutRange(HttpHeader * hdr, const HttpHdrRange * range);
 SQUIDCEXTERN void httpHeaderPutExt(HttpHeader * hdr, const char *name, const char *value);
 SQUIDCEXTERN int httpHeaderGetInt(const HttpHeader * hdr, http_hdr_type id);
@@ -635,22 +638,6 @@ SQUIDCEXTERN void urnStart(request_t *, StoreEntry *);
 SQUIDCEXTERN void redirectInit(void);
 SQUIDCEXTERN void redirectShutdown(void);
 
-SQUIDCEXTERN void refreshAddToList(const char *, int, time_t, int, time_t);
-SQUIDCEXTERN int refreshIsCachable(const StoreEntry *);
-SQUIDCEXTERN int refreshCheckHTTP(const StoreEntry *, request_t *);
-SQUIDCEXTERN int refreshCheckICP(const StoreEntry *, request_t *);
-SQUIDCEXTERN int refreshCheckHTCP(const StoreEntry *, request_t *);
-SQUIDCEXTERN int refreshCheckDigest(const StoreEntry *, time_t delta);
-SQUIDCEXTERN time_t getMaxAge(const char *url);
-SQUIDCEXTERN void refreshInit(void);
-
-SQUIDCEXTERN void serverConnectionsClose(void);
-SQUIDCEXTERN void shut_down(int);
-
-
-SQUIDCEXTERN void start_announce(void *unused);
-SQUIDCEXTERN void waisStart(FwdState *);
-
 extern void refreshAddToList(const char *, int, time_t, int, time_t);
 extern int refreshIsCachable(const StoreEntry *);
 extern int refreshCheckHTTP(const StoreEntry *, request_t *);
index e7d4b8f84af62b8309b365d0a83037a02b723db2..6400c8dd4b71e3b1aeda00acd4c6f60776ae0902 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: redirect.cc,v 1.100 2003/07/11 01:40:36 robertc Exp $
+ * $Id: redirect.cc,v 1.101 2003/07/14 14:16:02 robertc Exp $
  *
  * DEBUG: section 61    Redirector
  * AUTHOR: Duane Wessels
@@ -121,9 +121,13 @@ redirectStart(clientHttpRequest * http, RH * handler, void *data)
 
     if (Config.accessList.redirector) {
         ACLChecklist ch;
-        ch.src_addr = http->getConn()->peer.sin_addr;
-        ch.my_addr = http->getConn()->me.sin_addr;
-        ch.my_port = ntohs(http->getConn()->me.sin_port);
+
+        if (conn.getRaw() != NULL) {
+            ch.src_addr = conn->peer.sin_addr;
+            ch.my_addr = conn->me.sin_addr;
+            ch.my_port = ntohs(conn->me.sin_port);
+        }
+
         ch.request = requestLink(http->request);
 
         if (!aclCheckFast(Config.accessList.redirector, &ch)) {
@@ -142,11 +146,11 @@ redirectStart(clientHttpRequest * http, RH * handler, void *data)
 
     r = cbdataAlloc(redirectStateData);
     r->orig_url = xstrdup(http->uri);
-    r->client_addr = conn->log_addr;
+    r->client_addr = conn.getRaw() != NULL ? conn->log_addr : no_addr;
 
     if (http->request->auth_user_request)
         r->client_ident = authenticateUserRequestUsername(http->request->auth_user_request);
-    else if (conn->rfc931[0]) {
+    else if (conn.getRaw() != NULL && conn->rfc931[0]) {
         r->client_ident = conn->rfc931;
     } else {
         r->client_ident = dash_str;
index e7ae058fc9ce731e93e484c71f3ab60674eb335b..e32e779f68b8916fca50b142bb60d849d6f644b3 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: refresh.cc,v 1.61 2003/07/11 01:40:37 robertc Exp $
+ * $Id: refresh.cc,v 1.62 2003/07/14 14:16:02 robertc Exp $
  *
  * DEBUG: section 22    Refresh Calculation
  * AUTHOR: Harvest Derived
@@ -41,6 +41,7 @@
 #include "Store.h"
 #include "MemObject.h"
 #include "HttpRequest.h"
+#include "HttpReply.h"
 
 typedef enum {
     rcHTTP,
@@ -393,7 +394,11 @@ refreshIsCachable(const StoreEntry * entry)
      * 60 seconds delta, to avoid objects which expire almost
      * immediately, and which can't be refreshed.
      */
-    int reason = refreshCheck(entry, NULL, 60);
+    /* For ESI, we use a delta of 0, as ESI objects typically can be
+     * refreshed, but the expiry may be low to enforce regular
+     * checks
+     */
+    int reason = refreshCheck(entry, NULL, ESI ? 0 : 60);
     refreshCounts[rcStore].total++;
     refreshCounts[rcStore].status[reason]++;
 
index 0120e156962948748453f12e30377fc61a0dd525..9d76a0a36ba2c984a22f350f9531cd91e35eb7b7 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_client.cc,v 1.130 2003/07/11 04:02:01 robertc Exp $
+ * $Id: store_client.cc,v 1.131 2003/07/14 14:16:02 robertc Exp $
  *
  * DEBUG: section 90    Storage Manager Client-Side Interface
  * AUTHOR: Duane Wessels
@@ -116,6 +116,7 @@ storeClientIsThisAClient(store_client * sc, void *someClient)
 }
 
 #endif
+#include "HttpRequest.h"
 
 /* add client with fd to client list */
 store_client *
index f7d225fb81c5e8db225c376416a46299d02f1807..52ef763f012c206f57edf43ed409642c8035d91f 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_log.cc,v 1.27 2003/02/21 22:50:12 robertc Exp $
+ * $Id: store_log.cc,v 1.28 2003/07/14 14:16:02 robertc Exp $
  *
  * DEBUG: section 20    Storage Manager Logging Functions
  * AUTHOR: Duane Wessels
@@ -36,6 +36,7 @@
 #include "squid.h"
 #include "Store.h"
 #include "MemObject.h"
+#include "HttpReply.h"
 
 static const char *storeLogTags[] =
     {
index 61d17798e24092ff9b6bdcccf673fc4a137f6dda..8acf326ff3049829324c2230409f1745dca9087b 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: structs.h,v 1.471 2003/07/11 01:40:37 robertc Exp $
+ * $Id: structs.h,v 1.472 2003/07/14 14:16:02 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -925,15 +925,6 @@ private:
     static MemPool *Pool;
 };
 
-struct _HttpHeader
-{
-    /* protected, do not use these, use interface functions instead */
-    Array entries;             /* parsed fields in raw format */
-    HttpHeaderMask mask;       /* bit set <=> entry present */
-    http_hdr_owner_type owner; /* request or reply */
-    int len;                   /* length when packed, not counting terminating '\0' */
-};
-
 /* http surogate control header field */
 
 struct _HttpHdrScTarget
@@ -951,42 +942,6 @@ struct _HttpHdrSc
     dlink_list targets;
 };
 
-/* Sync changes here with HttpReply.c */
-
-class HttpHdrContRange;
-
-class HttpReply
-{
-
-public:
-    void *operator new (size_t);
-    void operator delete (void *);
-    /* unsupported, writable, may disappear/change in the future */
-    int hdr_sz;                        /* sums _stored_ status-line, headers, and <CRLF> */
-
-    /* public, readable; never update these or their .hdr equivalents directly */
-    int content_length;
-    time_t date;
-    time_t last_modified;
-    time_t expires;
-    String content_type;
-    HttpHdrCc *cache_control;
-    HttpHdrSc *surrogate_control;
-    HttpHdrContRange *content_range;
-    short int keep_alive;
-
-    /* public, readable */
-    HttpMsgParseState pstate;  /* the current parsing state */
-
-    /* public, writable, but use httpReply* interfaces when possible */
-    HttpStatusLine sline;
-    HttpHeader header;
-    HttpBody body;             /* for small constant memory-resident text bodies only */
-
-private:
-    static MemPool *Pool;
-};
-
 struct _http_state_flags
 {
 
@@ -1576,11 +1531,6 @@ struct _RemovalPurgeWalker
     void (*Done) (RemovalPurgeWalker * walker);
 };
 
-/* To hard to pull this into another file just yet.
- * SO, we stop globals.c seeing it 
- */
-#ifdef __cplusplus
-
 struct request_flags
 {
     request_flags():range(0),nocache(0),ims(0),auth(0),cachable(0),hierarchical(0),loopdetect(0),proxy_keepalive(0),proxying(0),refresh(0),redirected(0),need_validation(0),accelerated(0),transparent(0),internal(0),internalclient(0),body_sent(0),destinationIPLookedUp_(0)
@@ -1668,13 +1618,6 @@ struct _link_list
     struct _link_list *next;
 };
 
-class HttpHdrRange;
-
-class ConnStateData;
-
-class request_t;
-#endif
-
 struct _cachemgr_passwd
 {
     char *passwd;
@@ -2066,28 +2009,6 @@ unsigned int ftp_pasv_failed:
     flags;
 };
 
-#if USE_HTCP
-
-struct _htcpReplyData
-{
-    int hit;
-    HttpHeader hdr;
-    u_int32_t msg_id;
-    double version;
-
-    struct
-    {
-        /* cache-to-origin */
-        double rtt;
-        int samp;
-        int hops;
-    }
-
-    cto;
-};
-
-#endif
-
 
 struct _helper_request
 {
index 83442b44f1a8f379636699024f33fb056ae9f3ca..aadfaf4eb0a5edaf35a850c19cb0811b4b154c85 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: typedefs.h,v 1.164 2003/07/12 12:39:56 robertc Exp $
+ * $Id: typedefs.h,v 1.165 2003/07/14 14:16:02 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -119,7 +119,7 @@ typedef struct _HttpHeaderFieldAttrs HttpHeaderFieldAttrs;
 
 class HttpHeaderFieldInfo;
 
-typedef struct _HttpHeader HttpHeader;
+class HttpHeader;
 
 typedef struct _HttpHdrCc HttpHdrCc;
 
index b4647da730db0650a3810b60efaac894294765e7..c7dc27b63e57d315608d5982e579cd3a29183b9b 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: whois.cc,v 1.25 2003/07/11 01:40:37 robertc Exp $
+ * $Id: whois.cc,v 1.26 2003/07/14 14:16:02 robertc Exp $
  *
  * DEBUG: section 75    WHOIS protocol
  * AUTHOR: Duane Wessels, Kostas Anagnostakis
@@ -36,6 +36,7 @@
 #include "squid.h"
 #include "Store.h"
 #include "HttpReply.h"
+#include "HttpRequest.h"
 #include "comm.h"
 #include "HttpRequest.h"
 
diff --git a/test-suite/ESIExpressions.cc b/test-suite/ESIExpressions.cc
new file mode 100644 (file)
index 0000000..6d2e2bc
--- /dev/null
@@ -0,0 +1,81 @@
+
+/*
+ * $Id: ESIExpressions.cc,v 1.1 2003/07/14 14:16:12 robertc Exp $
+ *
+ * DEBUG: section 86           ESI Expressions
+ * AUTHOR:  Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "ESIExpression.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 VERBOSEDEBUG
+
+        printf("Expr '%s' = '%s' (expected %s)\n", expressions[i],
+               result ? "true" : "false",
+               results[i] ? "true" : "false");
+#endif
+
+        if (result != results[i])
+            return 1;
+
+        ++i;
+    }
+
+    return 0;
+}
index cd6f72a080c1bf8a29fdb8d3a0b1ecf2a7430e82..adb81d3a0da7705ab7100390ba038a1d3db9194e 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.am,v 1.13 2003/07/14 10:36:44 robertc Exp $
+#  $Id: Makefile.am,v 1.14 2003/07/14 14:16:12 robertc Exp $
 #
 
 AUTOMAKE_OPTIONS = subdir-objects
@@ -23,10 +23,12 @@ TESTS = debug \
        MemPoolTest\
        mem_node_test\
        mem_hdr_test\
-       http_range_test
+       http_range_test \
+       ESIExpressions
 
 ## Sort by alpha - any build failures are significant.
 check_PROGRAMS= debug \
+               ESIExpressions \
                http_range_test \
                MemPoolTest\
                mem_node_test\
@@ -38,33 +40,36 @@ check_PROGRAMS= debug \
                syntheticoperators
 
 LDADD = -L$(top_builddir)/lib -lmiscutil
-debug_SOURCES = debug.cc test_tools.cc
-debug_LDADD = $(top_builddir)/src/globals.o \
-               $(LDADD)
+DEBUG_SOURCE = test_tools.cc
+DEBUG_OBJECTS = $(top_builddir)/src/globals.o
+debug_SOURCES = debug.cc $(DEBUG_SOURCE)
+debug_LDADD = $(DEBUG_OBJECTS) $(LDADD)
+ESIExpressions_SOURCES = ESIExpressions.cc $(DEBUG_SOURCE)
+ESIExpressions_LDADD = $(top_builddir)/src/ESIExpression.o \
+               $(DEBUG_OBJECTS) $(LDADD)
 mem_node_test_SOURCES = mem_node_test.cc
 mem_node_test_LDADD = $(top_builddir)/src/mem_node.o $(LDADD)
-mem_hdr_test_SOURCES = mem_hdr_test.cc test_tools.cc
+mem_hdr_test_SOURCES = mem_hdr_test.cc $(DEBUG_SOURCE)
 mem_hdr_test_LDADD = $(top_builddir)/src/stmem.o \
-                    $(top_builddir)/src/globals.o \
+                    $(DEBUG_OBJECTS) \
                     $(top_builddir)/src/mem_node.o $(LDADD)
 MemPoolTest_SOURCES = MemPoolTest.cc
 refcount_SOURCES = refcount.cc
 
-http_range_test_SOURCES = http_range_test.cc test_tools.cc
+http_range_test_SOURCES = http_range_test.cc $(DEBUG_SOURCE)
 http_range_test_LDADD = $(top_builddir)/src/HttpHdrRange.o \
                $(top_builddir)/src/HttpHeaderTools.o \
                $(top_builddir)/src/MemBuf.o \
                $(top_builddir)/src/Packer.o \
                $(top_builddir)/src/String.o \
                $(top_builddir)/src/mem.o \
-               $(top_builddir)/src/globals.o \
-               $(LDADD)
+               $(DEBUG_OBJECTS) $(LDADD)
 
 splay_SOURCES = splay.cc
 
-StackTest_SOURCES = StackTest.cc test_tools.cc
+StackTest_SOURCES = StackTest.cc $(DEBUG_SOURCE)
 
-syntheticoperators_SOURCES = syntheticoperators.cc test_tools.cc
+syntheticoperators_SOURCES = syntheticoperators.cc $(DEBUG_SOURCE)
 
 rfc1738_SOURCES = rfc1738.cc