2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 86 ESI processing */
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.
18 #if (USE_SQUID_ESI == 1)
20 #include "esi/Attempt.h"
21 #include "esi/Except.h"
22 #include "esi/Literal.h"
23 #include "esi/Sequence.h"
27 esiSequence::~esiSequence ()
29 debugs(86, 5, "esiSequence::~esiSequence " << this);
30 FinishAllElements(elements
); // finish if not already done
33 esiSequence::esiSequence(esiTreeParentPtr aParent
, bool incrementalFlag
) :
39 provideIncrementalData(incrementalFlag
),
41 processingResult(ESI_PROCESS_COMPLETE
),
42 nextElementToProcess_(0)
44 memset(&flags
, 0, sizeof(flags
));
48 esiSequence::nextElementToProcess() const
50 return nextElementToProcess_
;
54 esiSequence::nextElementToProcess(size_t const &aSizeT
)
56 nextElementToProcess_
= aSizeT
;
60 esiSequence::finishedProcessing() const
62 return nextElementToProcess() >= elements
.size();
66 esiSequence::mayFail () const
75 esiSequence::wontFail()
82 esiSequence::render(ESISegment::Pointer output
)
84 /* append all processed elements, and trim processed
85 * and rendered elements
87 assert (output
->next
== NULL
);
88 debugs (86,5, "esiSequenceRender: rendering " << processedcount
<< " elements");
90 for (size_t i
= 0; i
< processedcount
; ++i
) {
91 elements
[i
]->render(output
);
92 FinishAnElement(elements
[i
], i
);
93 // TODO: pass an "ESISegment **" ?
94 output
= output
->tail();
97 // prune completed elements
98 elements
.erase(elements
.begin(), elements
.begin() + processedcount
);
100 assert (output
->next
== NULL
);
104 esiSequence::finish()
106 debugs(86, 5, "esiSequence::finish: " << this << " is finished");
107 FinishAllElements(elements
);
112 esiSequence::provideData (ESISegment::Pointer data
, ESIElement
*source
)
114 ESIElement::Pointer lockthis
= this;
117 debugs(86, 5, "esiSequence::provideData: " << this << " data provided during processing");
118 debugs(86, 5, "esiSequence::provideData " << this << " " << data
.getRaw() << " " << source
);
120 /* when data is provided, the element *must* be completed */
121 /* XXX: when the callback model is complete,
122 * we can introduce 'finished'. And then this rule can be
126 int index
= elementIndex (source
);
130 /* remove the current node */
131 FinishAnElement(elements
[index
], index
);
133 /* create a literal */
134 esiLiteral
*temp
= new esiLiteral (data
);
136 /* insert the literal */
137 elements
[index
] = temp
;
139 /* XXX: TODO push any pushable data upwards */
140 /* fail() not done */
144 assert (process (flags
.dovars
) != ESI_PROCESS_FAILED
);
148 esiSequence::addElement (ESIElement::Pointer element
)
150 /* add an element to the output list */
151 /* Some elements require specific parents */
153 if (dynamic_cast<esiAttempt
*>(element
.getRaw()) ||
154 dynamic_cast<esiExcept
*>(element
.getRaw())) {
155 debugs(86, DBG_CRITICAL
, "esiSequenceAdd: misparented Attempt or Except element (section 3.4)");
159 /* Tie literals together for efficiency */
160 if (elements
.size() && dynamic_cast<esiLiteral
*>(element
.getRaw()) &&
161 dynamic_cast<esiLiteral
*>(elements
[elements
.size() - 1].getRaw())) {
162 debugs(86, 5, "esiSequenceAdd: tying Literals " <<
163 elements
[elements
.size() - 1].getRaw() << " and " <<
164 element
.getRaw() << " together");
166 ESISegment::ListTransfer (((esiLiteral
*)element
.getRaw())->buffer
,
167 ((esiLiteral
*)elements
[elements
.size() - 1].getRaw())->buffer
);
171 elements
.push_back(element
);
172 debugs (86,3, "esiSequenceAdd: Added a new element, elements = " << elements
.size());
177 esiSequence::elementIndex(ESIElement::Pointer anElement
) const
179 for (size_t i
= 0; i
< elements
.size(); ++i
)
180 if (elements
[i
] == anElement
)
187 esiSequence::processStep(int dovars
)
189 size_t elementToProcess
= nextElementToProcess();
190 nextElementToProcess(elementToProcess
+ 1);
191 esiProcessResult_t tempResult
= processOne(dovars
, elementToProcess
);
193 if (processingResult
< tempResult
) {
194 debugs(86, 5, "esiSequence::process: processingResult was " << processingResult
<< ", increasing to " << tempResult
);
195 processingResult
= tempResult
;
200 esiSequence::processOne(int dovars
, size_t index
)
202 debugs (86,5, "esiSequence::process " << this << " about to process element[" << index
<< "] " << elements
[index
].getRaw());
204 switch (elements
[index
]->process(dovars
)) {
206 case ESI_PROCESS_COMPLETE
:
207 debugs(86, 5, "esiSequenceProcess: " << this << " element " << elements
[index
].getRaw() << " Processed OK");
209 if (index
== processedcount
)
210 /* another completely ready */
213 return ESI_PROCESS_COMPLETE
;
215 case ESI_PROCESS_PENDING_WONTFAIL
:
216 debugs(86, 5, "esiSequenceProcess: element Processed PENDING OK");
218 return ESI_PROCESS_PENDING_WONTFAIL
;
220 case ESI_PROCESS_PENDING_MAYFAIL
:
221 debugs(86, 5, "eseSequenceProcess: element Processed PENDING UNKNOWN");
223 return ESI_PROCESS_PENDING_MAYFAIL
;
225 case ESI_PROCESS_FAILED
:
226 debugs(86, 5, "esiSequenceProcess: element Processed FAILED");
228 return ESI_PROCESS_FAILED
;
231 fatal ("unexpected code in esiSequence::processOne\n");
233 return ESI_PROCESS_FAILED
;
238 esiSequence::process (int inheritedVarsFlag
)
240 debugs(86, 5, "esiSequence::process: " << this << " processing");
243 debugs(86, 5, "esiSequence::process: " << this <<
244 " reentry attempt during processing");
247 /* process as much of the list as we can, stopping only on
250 if (!processing
|| processedcount
== 0)
251 processingResult
= ESI_PROCESS_COMPLETE
;
253 int dovars
= inheritedVarsFlag
;
258 debugs(86, 5, "esiSequence::process: Processing " << this << " with" <<
259 (dovars
? "" : "out") << " variable processing");
263 nextElementToProcess(processedcount
);
265 while (!finishedProcessing()) {
269 return processingResult
;
271 if (processingResult
== ESI_PROCESS_FAILED
) {
272 FinishAllElements(elements
);
276 return processingResult
;
280 assert (processingResult
!= ESI_PROCESS_COMPLETE
|| processedcount
== elements
.size());
282 if (processingResult
== ESI_PROCESS_COMPLETE
|| processingResult
== ESI_PROCESS_PENDING_WONTFAIL
)
285 if (processedcount
== elements
.size() || provideIncrementalData
) {
286 ESISegment::Pointer
temp(new ESISegment
);
289 if (temp
->next
.getRaw() || temp
->len
)
290 parent
->provideData(temp
, this);
292 ESISegmentFreeList (temp
);
295 /* Depends on full parsing before processing */
296 if (processedcount
== elements
.size())
299 debugs(86, 5, "esiSequence::process: " << this << " completed");
303 return processingResult
;
307 esiSequence::fail (ESIElement
*source
, char const *anError
)
312 debugs(86, 5, "esiSequence::fail: " << this << " failure callback during processing");
316 debugs(86, 5, "esiSequence::fail: " << this << " has failed.");
317 parent
->fail (this, anError
);
318 FinishAllElements(elements
);
322 esiSequence::esiSequence(esiSequence
const &old
) :
325 mayFail_(old
.mayFail_
),
327 provideIncrementalData(old
.provideIncrementalData
),
329 processingResult(ESI_PROCESS_COMPLETE
),
330 nextElementToProcess_(0)
332 flags
.dovars
= old
.flags
.dovars
;
336 esiSequence::makeCachableElements(esiSequence
const &old
)
338 for (size_t counter
= 0; counter
< old
.elements
.size(); ++counter
) {
339 ESIElement::Pointer newElement
= old
.elements
[counter
]->makeCacheable();
341 if (newElement
.getRaw())
342 assert (addElement(newElement
));
347 esiSequence::makeUsableElements(esiSequence
const &old
, ESIVarState
&newVarState
)
349 for (size_t counter
= 0; counter
< old
.elements
.size(); ++counter
) {
350 ESIElement::Pointer newElement
= old
.elements
[counter
]->makeUsable (this, newVarState
);
352 if (newElement
.getRaw())
353 assert (addElement(newElement
));
358 esiSequence::makeCacheable() const
360 debugs(86, 5, "esiSequence::makeCacheable: Making cachable sequence from " << this);
361 assert (processedcount
== 0);
364 if (elements
.size() == 0) {
365 debugs(86, 5, "esiSequence::makeCacheable: No elements in sequence " << this << ", returning NULL");
369 esiSequence
* resultS
= new esiSequence (*this);
370 ESIElement::Pointer result
= resultS
;
371 resultS
->makeCachableElements(*this);
372 debugs(86, 5, "esiSequence::makeCacheable: " << this << " created " << result
.getRaw());
377 esiSequence::makeUsable(esiTreeParentPtr newParent
, ESIVarState
&newVarState
) const
379 debugs(86, 5, "esiSequence::makeUsable: Creating usable Sequence");
380 assert (processedcount
== 0);
383 if (elements
.size() == 0) {
384 debugs(86, 5, "esiSequence::makeUsable: No elements in sequence " << this << ", returning NULL");
388 esiSequence
* resultS
= new esiSequence (*this);
389 ESIElement::Pointer result
= resultS
;
390 resultS
->parent
= newParent
;
391 resultS
->makeUsableElements(*this, newVarState
);
395 #endif /* USE_SQUID_ESI == 1 */