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