4 * DEBUG: section 86 ESI processing
5 * AUTHOR: Robert Collins
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
38 /* MS Visual Studio Projects are monolithic, so we need the following
39 * #if to exclude the ESI code from compile process when not needed.
41 #if (USE_SQUID_ESI == 1)
43 #include "esi/Sequence.h"
44 #include "esi/Literal.h"
45 #include "esi/Attempt.h"
46 #include "esi/Except.h"
50 esiSequence::~esiSequence ()
52 debugs(86, 5, "esiSequence::~esiSequence " << this);
55 esiSequence::esiSequence(esiTreeParentPtr aParent
, bool incrementalFlag
) : elements(), parent (aParent
), mayFail_(true), failed (false), provideIncrementalData (incrementalFlag
), processing (false), processingResult (ESI_PROCESS_COMPLETE
), nextElementToProcess_ (0)
59 esiSequence::nextElementToProcess() const
61 return nextElementToProcess_
;
65 esiSequence::nextElementToProcess(size_t const &aSizeT
)
67 nextElementToProcess_
= aSizeT
;
71 esiSequence::finishedProcessing() const
73 return nextElementToProcess() >= elements
.size();
77 esiSequence::mayFail () const
86 esiSequence::wontFail()
93 esiSequence::render(ESISegment::Pointer output
)
95 /* append all processed elements, and trim processed
96 * and rendered elements
98 assert (output
->next
== NULL
);
99 debugs (86,5, "esiSequenceRender: rendering " << processedcount
<< " elements");
101 for (size_t i
= 0; i
< processedcount
; ++i
) {
102 elements
[i
]->render(output
);
103 elements
.setNULL(i
,i
+1);
104 /* FIXME: pass a ESISegment ** ? */
105 output
= output
->tail();
108 elements
.pop_front (processedcount
);
110 assert (output
->next
== NULL
);
114 esiSequence::finish()
116 debugs(86, 5, "esiSequence::finish: " << this << " is finished");
117 elements
.setNULL(0, elements
.size());
123 esiSequence::provideData (ESISegment::Pointer data
, ESIElement
*source
)
125 ESIElement::Pointer lockthis
= this;
128 debugs(86, 5, "esiSequence::provideData: " << this << " data provided during processing");
129 debugs(86, 5, "esiSequence::provideData " << this << " " << data
.getRaw() << " " << source
);
132 /* when data is provided, the element *must* be completed */
133 /* XXX: when the callback model is complete,
134 * we can introduce 'finished'. And then this rule can be
138 int index
= elementIndex (source
);
142 /* remove the current node */
143 elements
.setNULL(index
, index
+1);
145 /* create a literal */
146 esiLiteral
*temp
= new esiLiteral (data
);
148 /* insert the literal */
149 elements
[index
] = temp
;
151 /* XXX: TODO push any pushable data upwards */
152 /* fail() not done */
156 assert (process (flags
.dovars
) != ESI_PROCESS_FAILED
);
160 esiSequence::addElement (ESIElement::Pointer element
)
162 /* add an element to the output list */
163 /* Some elements require specific parents */
165 if (dynamic_cast<esiAttempt
*>(element
.getRaw()) ||
166 dynamic_cast<esiExcept
*>(element
.getRaw())) {
167 debugs(86, 0, "esiSequenceAdd: misparented Attempt or Except element (section 3.4)");
171 /* Tie literals together for efficiency */
172 if (elements
.size() && dynamic_cast<esiLiteral
*>(element
.getRaw()) &&
173 dynamic_cast<esiLiteral
*>(elements
[elements
.size() - 1].getRaw())) {
174 debugs(86, 5, "esiSequenceAdd: tying Literals " <<
175 elements
[elements
.size() - 1].getRaw() << " and " <<
176 element
.getRaw() << " together");
178 ESISegment::ListTransfer (((esiLiteral
*)element
.getRaw())->buffer
,
179 ((esiLiteral
*)elements
[elements
.size() - 1].getRaw())->buffer
);
183 elements
.push_back(element
);
184 debugs (86,3, "esiSequenceAdd: Added a new element, elements = " << elements
.size());
189 esiSequence::elementIndex(ESIElement::Pointer anElement
) const
191 for (size_t i
= 0; i
< elements
.size(); ++i
)
192 if (elements
[i
] == anElement
)
199 esiSequence::processStep(int dovars
)
201 size_t elementToProcess
= nextElementToProcess();
202 nextElementToProcess(elementToProcess
+ 1);
203 esiProcessResult_t tempResult
= processOne(dovars
, elementToProcess
);
205 if (processingResult
< tempResult
) {
206 debugs(86, 5, "esiSequence::process: processingResult was " << processingResult
<< ", increasing to " << tempResult
);
207 processingResult
= tempResult
;
212 esiSequence::processOne(int dovars
, size_t index
)
214 debugs (86,5, "esiSequence::process " << this << " about to process element[" << index
<< "] " << elements
[index
].getRaw());
216 switch (elements
[index
]->process(dovars
)) {
218 case ESI_PROCESS_COMPLETE
:
219 debugs(86, 5, "esiSequenceProcess: " << this << " element " << elements
[index
].getRaw() << " Processed OK");
221 if (index
== processedcount
)
222 /* another completely ready */
225 return ESI_PROCESS_COMPLETE
;
227 case ESI_PROCESS_PENDING_WONTFAIL
:
228 debugs(86, 5, "esiSequenceProcess: element Processed PENDING OK");
230 return ESI_PROCESS_PENDING_WONTFAIL
;
232 case ESI_PROCESS_PENDING_MAYFAIL
:
233 debugs(86, 5, "eseSequenceProcess: element Processed PENDING UNKNOWN");
235 return ESI_PROCESS_PENDING_MAYFAIL
;
237 case ESI_PROCESS_FAILED
:
238 debugs(86, 5, "esiSequenceProcess: element Processed FAILED");
240 return ESI_PROCESS_FAILED
;
243 fatal ("unexpected code in esiSequence::processOne\n");
245 return ESI_PROCESS_FAILED
;
250 esiSequence::process (int inheritedVarsFlag
)
252 debugs(86, 5, "esiSequence::process: " << this << " processing");
255 debugs(86, 5, "esiSequence::process: " << this <<
256 " reentry attempt during processing");
259 /* process as much of the list as we can, stopping only on
262 if (!processing
|| processedcount
== 0)
263 processingResult
= ESI_PROCESS_COMPLETE
;
265 int dovars
= inheritedVarsFlag
;
270 debugs(86, 5, "esiSequence::process: Processing " << this << " with" <<
271 (dovars
? "" : "out") << " variable processing");
275 nextElementToProcess(processedcount
);
277 while (!finishedProcessing()) {
281 return processingResult
;
283 if (processingResult
== ESI_PROCESS_FAILED
) {
284 elements
.setNULL (0, elements
.size());
288 return processingResult
;
292 assert (processingResult
!= ESI_PROCESS_COMPLETE
|| processedcount
== elements
.size());
294 if (processingResult
== ESI_PROCESS_COMPLETE
|| processingResult
== ESI_PROCESS_PENDING_WONTFAIL
)
297 if (processedcount
== elements
.size() || provideIncrementalData
) {
298 ESISegment::Pointer
temp(new ESISegment
);
301 if (temp
->next
.getRaw() || temp
->len
)
302 parent
->provideData(temp
, this);
304 ESISegmentFreeList (temp
);
307 /* Depends on full parsing before processing */
308 if (processedcount
== elements
.size())
311 debugs(86, 5, "esiSequence::process: " << this << " completed");
315 return processingResult
;
319 esiSequence::fail (ESIElement
*source
, char const *anError
)
324 debugs(86, 5, "esiSequence::fail: " << this << " failure callback during processing");
328 debugs(86, 5, "esiSequence::fail: " << this << " has failed.");
329 parent
->fail (this, anError
);
330 elements
.setNULL(0, elements
.size());
334 esiSequence::esiSequence(esiSequence
const &old
)
335 : processedcount (0), mayFail_(old
.mayFail_
), failed (old
.failed
), provideIncrementalData (old
.provideIncrementalData
), processing (false), nextElementToProcess_ (0)
337 flags
.dovars
= old
.flags
.dovars
;
342 esiSequence::makeCachableElements(esiSequence
const &old
)
344 for (size_t counter
= 0; counter
< old
.elements
.size(); ++counter
) {
345 ESIElement::Pointer newElement
= old
.elements
[counter
]->makeCacheable();
347 if (newElement
.getRaw())
348 assert (addElement(newElement
));
353 esiSequence::makeUsableElements(esiSequence
const &old
, ESIVarState
&newVarState
)
355 for (size_t counter
= 0; counter
< old
.elements
.size(); ++counter
) {
356 ESIElement::Pointer newElement
= old
.elements
[counter
]->makeUsable (this, newVarState
);
358 if (newElement
.getRaw())
359 assert (addElement(newElement
));
364 esiSequence::makeCacheable() const
366 debugs(86, 5, "esiSequence::makeCacheable: Making cachable sequence from " << this);
367 assert (processedcount
== 0);
370 if (elements
.size() == 0) {
371 debugs(86, 5, "esiSequence::makeCacheable: No elements in sequence " << this << ", returning NULL");
375 esiSequence
* resultS
= new esiSequence (*this);
376 ESIElement::Pointer result
= resultS
;
377 resultS
->makeCachableElements(*this);
378 debugs(86, 5, "esiSequence::makeCacheable: " << this << " created " << result
.getRaw());
383 esiSequence::makeUsable(esiTreeParentPtr newParent
, ESIVarState
&newVarState
) const
385 debugs(86, 5, "esiSequence::makeUsable: Creating usable Sequence");
386 assert (processedcount
== 0);
389 if (elements
.size() == 0) {
390 debugs(86, 5, "esiSequence::makeUsable: No elements in sequence " << this << ", returning NULL");
394 esiSequence
* resultS
= new esiSequence (*this);
395 ESIElement::Pointer result
= resultS
;
396 resultS
->parent
= newParent
;
397 resultS
->makeUsableElements(*this, newVarState
);
401 #endif /* USE_SQUID_ESI == 1 */