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