]> git.ipfire.org Git - thirdparty/squid.git/blame - src/esi/Sequence.cc
Removed CVS $ markers
[thirdparty/squid.git] / src / esi / Sequence.cc
CommitLineData
43ae1d95 1/*
43ae1d95 2 * DEBUG: section 86 ESI processing
3 * AUTHOR: Robert Collins
4 *
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
7 *
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
26ac0430 21 *
43ae1d95 22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26ac0430 26 *
43ae1d95 27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
30 *
31 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
32 */
33
582c2af2
FC
34#include "squid.h"
35#include "Debug.h"
36#include "fatal.h"
454e8283 37
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.
40 */
41#if (USE_SQUID_ESI == 1)
42
f99c2cfe
AR
43#include "esi/Sequence.h"
44#include "esi/Literal.h"
45#include "esi/Attempt.h"
46#include "esi/Except.h"
43ae1d95 47
48class esiExcept;
49
43ae1d95 50esiSequence::~esiSequence ()
51{
bf8fe701 52 debugs(86, 5, "esiSequence::~esiSequence " << this);
43ae1d95 53}
54
43ae1d95 55esiSequence::esiSequence(esiTreeParentPtr aParent, bool incrementalFlag) : elements(), parent (aParent), mayFail_(true), failed (false), provideIncrementalData (incrementalFlag), processing (false), processingResult (ESI_PROCESS_COMPLETE), nextElementToProcess_ (0)
56{}
57
58size_t
59esiSequence::nextElementToProcess() const
60{
61 return nextElementToProcess_;
62}
63
64void
65esiSequence::nextElementToProcess(size_t const &aSizeT)
66{
67 nextElementToProcess_ = aSizeT;
68}
69
70bool
71esiSequence::finishedProcessing() const
72{
73 return nextElementToProcess() >= elements.size();
74}
75
76bool
77esiSequence::mayFail () const
78{
79 if (failed)
80 return true;
81
82 return mayFail_;
83}
84
85void
86esiSequence::wontFail()
87{
88 assert (!failed);
89 mayFail_ = false;
90}
91
92void
93esiSequence::render(ESISegment::Pointer output)
94{
95 /* append all processed elements, and trim processed
26ac0430 96 * and rendered elements
43ae1d95 97 */
98 assert (output->next == NULL);
137a13ea 99 debugs (86,5, "esiSequenceRender: rendering " << processedcount << " elements");
43ae1d95 100
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();
106 }
107
108 elements.pop_front (processedcount);
109 processedcount = 0;
110 assert (output->next == NULL);
111}
112
113void
114esiSequence::finish()
115{
bf8fe701 116 debugs(86, 5, "esiSequence::finish: " << this << " is finished");
43ae1d95 117 elements.setNULL(0, elements.size());
118 parent = NULL;
119}
120
43ae1d95 121void
122esiSequence::provideData (ESISegment::Pointer data, ESIElement *source)
123{
124 ESIElement::Pointer lockthis = this;
125
126 if (processing)
bf8fe701 127 debugs(86, 5, "esiSequence::provideData: " << this << " data provided during processing");
26ac0430 128 debugs(86, 5, "esiSequence::provideData " << this << " " << data.getRaw() << " " << source);
43ae1d95 129
43ae1d95 130 /* when data is provided, the element *must* be completed */
131 /* XXX: when the callback model is complete,
26ac0430 132 * we can introduce 'finished'. And then this rule can be
43ae1d95 133 * relaxed
134 */
135 /* find the index */
136 int index = elementIndex (source);
137
138 assert (index >= 0);
139
140 /* remove the current node */
141 elements.setNULL(index, index+1);
142
143 /* create a literal */
144 esiLiteral *temp = new esiLiteral (data);
145
146 /* insert the literal */
147 elements[index] = temp;
148
149 /* XXX: TODO push any pushable data upwards */
150 /* fail() not done */
151 if (processing)
152 return;
153
154 assert (process (flags.dovars) != ESI_PROCESS_FAILED);
155}
156
157bool
158esiSequence::addElement (ESIElement::Pointer element)
159{
160 /* add an element to the output list */
161 /* Some elements require specific parents */
162
163 if (dynamic_cast<esiAttempt*>(element.getRaw()) ||
164 dynamic_cast<esiExcept*>(element.getRaw())) {
fa84c01d 165 debugs(86, DBG_CRITICAL, "esiSequenceAdd: misparented Attempt or Except element (section 3.4)");
43ae1d95 166 return false;
167 }
168
169 /* Tie literals together for efficiency */
170 if (elements.size() && dynamic_cast<esiLiteral*>(element.getRaw()) &&
171 dynamic_cast<esiLiteral*>(elements[elements.size() - 1].getRaw())) {
bf8fe701 172 debugs(86, 5, "esiSequenceAdd: tying Literals " <<
173 elements[elements.size() - 1].getRaw() << " and " <<
174 element.getRaw() << " together");
175
43ae1d95 176 ESISegment::ListTransfer (((esiLiteral *)element.getRaw())->buffer,
177 ((esiLiteral *)elements[elements.size() - 1].getRaw())->buffer);
178 return true;
179 }
180
181 elements.push_back(element);
137a13ea 182 debugs (86,3, "esiSequenceAdd: Added a new element, elements = " << elements.size());
43ae1d95 183 return true;
184}
185
186int
187esiSequence::elementIndex(ESIElement::Pointer anElement) const
188{
189 for (size_t i = 0; i < elements.size(); ++i)
190 if (elements[i] == anElement)
191 return i;
192
193 return -1;
194}
195
196void
197esiSequence::processStep(int dovars)
198{
199 size_t elementToProcess = nextElementToProcess();
200 nextElementToProcess(elementToProcess + 1);
201 esiProcessResult_t tempResult = processOne(dovars, elementToProcess);
202
203 if (processingResult < tempResult) {
bf8fe701 204 debugs(86, 5, "esiSequence::process: processingResult was " << processingResult << ", increasing to " << tempResult);
43ae1d95 205 processingResult = tempResult;
206 }
207}
208
209esiProcessResult_t
210esiSequence::processOne(int dovars, size_t index)
211{
137a13ea 212 debugs (86,5, "esiSequence::process " << this << " about to process element[" << index << "] " << elements[index].getRaw());
43ae1d95 213
214 switch (elements[index]->process(dovars)) {
215
216 case ESI_PROCESS_COMPLETE:
bf8fe701 217 debugs(86, 5, "esiSequenceProcess: " << this << " element " << elements[index].getRaw() << " Processed OK");
43ae1d95 218
219 if (index == processedcount)
220 /* another completely ready */
221 ++processedcount;
222
223 return ESI_PROCESS_COMPLETE;
224
225 case ESI_PROCESS_PENDING_WONTFAIL:
bf8fe701 226 debugs(86, 5, "esiSequenceProcess: element Processed PENDING OK");
43ae1d95 227
228 return ESI_PROCESS_PENDING_WONTFAIL;
229
230 case ESI_PROCESS_PENDING_MAYFAIL:
bf8fe701 231 debugs(86, 5, "eseSequenceProcess: element Processed PENDING UNKNOWN");
43ae1d95 232
233 return ESI_PROCESS_PENDING_MAYFAIL;
234
235 case ESI_PROCESS_FAILED:
bf8fe701 236 debugs(86, 5, "esiSequenceProcess: element Processed FAILED");
43ae1d95 237
238 return ESI_PROCESS_FAILED;
239
240 default:
241 fatal ("unexpected code in esiSequence::processOne\n");
242
243 return ESI_PROCESS_FAILED;
244 }
245}
246
247esiProcessResult_t
248esiSequence::process (int inheritedVarsFlag)
249{
bf8fe701 250 debugs(86, 5, "esiSequence::process: " << this << " processing");
43ae1d95 251
252 if (processing) {
bf8fe701 253 debugs(86, 5, "esiSequence::process: " << this <<
254 " reentry attempt during processing");
43ae1d95 255 }
256
257 /* process as much of the list as we can, stopping only on
258 * faliures
259 */
260 if (!processing || processedcount == 0)
261 processingResult = ESI_PROCESS_COMPLETE;
262
263 int dovars = inheritedVarsFlag;
264
265 if (flags.dovars)
266 dovars = 1;
267
bf8fe701 268 debugs(86, 5, "esiSequence::process: Processing " << this << " with" <<
269 (dovars ? "" : "out") << " variable processing");
43ae1d95 270
271 processing = true;
272
273 nextElementToProcess(processedcount);
274
275 while (!finishedProcessing()) {
276 processStep(dovars);
277
278 if (!processing)
279 return processingResult;
280
281 if (processingResult == ESI_PROCESS_FAILED) {
282 elements.setNULL (0, elements.size());
283 failed = true;
284 parent = NULL;
285 processing = false;
286 return processingResult;
287 }
288 }
289
290 assert (processingResult != ESI_PROCESS_COMPLETE || processedcount == elements.size());
291
292 if (processingResult == ESI_PROCESS_COMPLETE || processingResult == ESI_PROCESS_PENDING_WONTFAIL)
293 wontFail();
294
295 if (processedcount == elements.size() || provideIncrementalData) {
296 ESISegment::Pointer temp(new ESISegment);
297 render (temp);
298
299 if (temp->next.getRaw() || temp->len)
300 parent->provideData(temp, this);
301 else
302 ESISegmentFreeList (temp);
303 }
304
305 /* Depends on full parsing before processing */
306 if (processedcount == elements.size())
307 parent = NULL;
308
bf8fe701 309 debugs(86, 5, "esiSequence::process: " << this << " completed");
43ae1d95 310
311 processing = false;
312
313 return processingResult;
314}
315
316void
924f73bc 317esiSequence::fail (ESIElement *source, char const *anError)
43ae1d95 318{
319 failed = true;
320
321 if (processing) {
bf8fe701 322 debugs(86, 5, "esiSequence::fail: " << this << " failure callback during processing");
43ae1d95 323 return;
324 }
325
bf8fe701 326 debugs(86, 5, "esiSequence::fail: " << this << " has failed.");
924f73bc 327 parent->fail (this, anError);
43ae1d95 328 elements.setNULL(0, elements.size());
329 parent = NULL;
330}
331
332esiSequence::esiSequence(esiSequence const &old)
333 : processedcount (0), mayFail_(old.mayFail_), failed (old.failed), provideIncrementalData (old.provideIncrementalData), processing (false), nextElementToProcess_ (0)
334{
335 flags.dovars = old.flags.dovars;
336 parent = NULL;
337}
338
339void
340esiSequence::makeCachableElements(esiSequence const &old)
341{
342 for (size_t counter = 0; counter < old.elements.size(); ++counter) {
343 ESIElement::Pointer newElement = old.elements[counter]->makeCacheable();
344
345 if (newElement.getRaw())
346 assert (addElement(newElement));
347 }
348}
349
350void
924f73bc 351esiSequence::makeUsableElements(esiSequence const &old, ESIVarState &newVarState)
43ae1d95 352{
353 for (size_t counter = 0; counter < old.elements.size(); ++counter) {
354 ESIElement::Pointer newElement = old.elements[counter]->makeUsable (this, newVarState);
355
356 if (newElement.getRaw())
357 assert (addElement(newElement));
358 }
359}
360
361ESIElement::Pointer
362esiSequence::makeCacheable() const
363{
bf8fe701 364 debugs(86, 5, "esiSequence::makeCacheable: Making cachable sequence from " << this);
43ae1d95 365 assert (processedcount == 0);
366 assert (!failed);
367
368 if (elements.size() == 0) {
bf8fe701 369 debugs(86, 5, "esiSequence::makeCacheable: No elements in sequence " << this << ", returning NULL");
43ae1d95 370 return NULL;
371 }
372
373 esiSequence * resultS = new esiSequence (*this);
374 ESIElement::Pointer result = resultS;
375 resultS->makeCachableElements(*this);
bf8fe701 376 debugs(86, 5, "esiSequence::makeCacheable: " << this << " created " << result.getRaw());
43ae1d95 377 return result;
378}
379
380ESIElement::Pointer
924f73bc 381esiSequence::makeUsable(esiTreeParentPtr newParent, ESIVarState &newVarState) const
43ae1d95 382{
bf8fe701 383 debugs(86, 5, "esiSequence::makeUsable: Creating usable Sequence");
43ae1d95 384 assert (processedcount == 0);
385 assert (!failed);
386
387 if (elements.size() == 0) {
bf8fe701 388 debugs(86, 5, "esiSequence::makeUsable: No elements in sequence " << this << ", returning NULL");
43ae1d95 389 return NULL;
390 }
391
392 esiSequence * resultS = new esiSequence (*this);
393 ESIElement::Pointer result = resultS;
394 resultS->parent = newParent;
395 resultS->makeUsableElements(*this, newVarState);
396 return result;
397}
398
454e8283 399#endif /* USE_SQUID_ESI == 1 */