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