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