Sequence.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 86 ESI processing */
10
11#include "squid.h"
12#include "debug/Stream.h"
13#include "fatal.h"
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
20#include "esi/Attempt.h"
21#include "esi/Except.h"
22#include "esi/Literal.h"
23#include "esi/Sequence.h"
24
25class esiExcept;
26
28{
29 debugs(86, 5, "esiSequence::~esiSequence " << this);
30 FinishAllElements(elements); // finish if not already done
31}
32
33esiSequence::esiSequence(esiTreeParentPtr aParent, bool incrementalFlag) :
34 elements(),
36 parent(aParent),
37 mayFail_(true),
38 failed(false),
39 provideIncrementalData(incrementalFlag),
40 processing(false),
43{
44 memset(&flags, 0, sizeof(flags));
45}
46
47size_t
49{
51}
52
53void
55{
56 nextElementToProcess_ = aSizeT;
57}
58
59bool
61{
62 return nextElementToProcess() >= elements.size();
63}
64
65bool
67{
68 if (failed)
69 return true;
70
71 return mayFail_;
72}
73
74void
76{
77 assert (!failed);
78 mayFail_ = false;
79}
80
81void
83{
84 /* append all processed elements, and trim processed
85 * and rendered elements
86 */
87 assert (output->next == nullptr);
88 debugs (86,5, "esiSequenceRender: rendering " << processedcount << " elements");
89
90 for (size_t i = 0; i < processedcount; ++i) {
91 elements[i]->render(output);
93 // TODO: pass an "ESISegment **" ?
94 output = output->tail();
95 }
96
97 // prune completed elements
98 elements.erase(elements.begin(), elements.begin() + processedcount);
100 assert (output->next == nullptr);
101}
102
103void
105{
106 debugs(86, 5, "esiSequence::finish: " << this << " is finished");
108 parent = nullptr;
109}
110
111void
113{
114 ESIElement::Pointer lockthis = this;
115
116 if (processing)
117 debugs(86, 5, "esiSequence::provideData: " << this << " data provided during processing");
118 debugs(86, 5, "esiSequence::provideData " << this << " " << data.getRaw() << " " << source);
119
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
123 * relaxed
124 */
125 /* find the index */
126 int index = elementIndex (source);
127
128 assert (index >= 0);
129
130 /* remove the current node */
131 FinishAnElement(elements[index], index);
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
145}
146
147bool
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())) {
155 debugs(86, DBG_CRITICAL, "esiSequenceAdd: misparented Attempt or Except element (section 3.4)");
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())) {
162 debugs(86, 5, "esiSequenceAdd: tying Literals " <<
163 elements[elements.size() - 1].getRaw() << " and " <<
164 element.getRaw() << " together");
165
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);
172 debugs (86,3, "esiSequenceAdd: Added a new element, elements = " << elements.size());
173 return true;
174}
175
176int
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
188{
189 size_t elementToProcess = nextElementToProcess();
190 nextElementToProcess(elementToProcess + 1);
191 esiProcessResult_t tempResult = processOne(dovars, elementToProcess);
192
193 if (processingResult < tempResult) {
194 debugs(86, 5, "esiSequence::process: processingResult was " << processingResult << ", increasing to " << tempResult);
195 processingResult = tempResult;
196 }
197}
198
201{
202 debugs (86,5, "esiSequence::process " << this << " about to process element[" << index << "] " << elements[index].getRaw());
203
204 switch (elements[index]->process(dovars)) {
205
207 debugs(86, 5, "esiSequenceProcess: " << this << " element " << elements[index].getRaw() << " Processed OK");
208
209 if (index == processedcount)
210 /* another completely ready */
212
214
216 debugs(86, 5, "esiSequenceProcess: element Processed PENDING OK");
217
219
221 debugs(86, 5, "eseSequenceProcess: element Processed PENDING UNKNOWN");
222
224
226 debugs(86, 5, "esiSequenceProcess: element Processed FAILED");
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
238esiSequence::process (int inheritedVarsFlag)
239{
240 debugs(86, 5, "esiSequence::process: " << this << " processing");
241
242 if (processing) {
243 debugs(86, 5, "esiSequence::process: " << this <<
244 " reentry attempt during processing");
245 }
246
247 /* process as much of the list as we can, stopping only on
248 * failures
249 */
250 if (!processing || processedcount == 0)
252
253 int dovars = inheritedVarsFlag;
254
255 if (flags.dovars)
256 dovars = 1;
257
258 debugs(86, 5, "esiSequence::process: Processing " << this << " with" <<
259 (dovars ? "" : "out") << " variable processing");
260
261 processing = true;
262
264
265 while (!finishedProcessing()) {
267
268 if (!processing)
269 return processingResult;
270
273 failed = true;
274 parent = nullptr;
275 processing = false;
276 return processingResult;
277 }
278 }
279
281
283 wontFail();
284
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 = nullptr;
298
299 debugs(86, 5, "esiSequence::process: " << this << " completed");
300
301 processing = false;
302
303 return processingResult;
304}
305
306void
307esiSequence::fail(ESIElement * /* source */, char const *anError)
308{
309 failed = true;
310
311 if (processing) {
312 debugs(86, 5, "esiSequence::fail: " << this << " failure callback during processing");
313 return;
314 }
315
316 debugs(86, 5, "esiSequence::fail: " << this << " has failed.");
317 parent->fail (this, anError);
319 parent = nullptr;
320}
321
324 parent(nullptr),
325 mayFail_(old.mayFail_),
326 failed(old.failed),
328 processing(false),
331{
332 flags.dovars = old.flags.dovars;
333}
334
335void
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
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
359{
360 debugs(86, 5, "esiSequence::makeCacheable: Making cachable sequence from " << this);
361 assert (processedcount == 0);
362 assert (!failed);
363
364 if (elements.size() == 0) {
365 debugs(86, 5, "esiSequence::makeCacheable: No elements in sequence " << this << ", returning NULL");
366 return nullptr;
367 }
368
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());
373 return result;
374}
375
378{
379 debugs(86, 5, "esiSequence::makeUsable: Creating usable Sequence");
380 assert (processedcount == 0);
381 assert (!failed);
382
383 if (elements.size() == 0) {
384 debugs(86, 5, "esiSequence::makeUsable: No elements in sequence " << this << ", returning NULL");
385 return nullptr;
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
395#endif /* USE_SQUID_ESI == 1 */
396
esiProcessResult_t
Definition: Element.h:18
@ ESI_PROCESS_FAILED
Definition: Element.h:22
@ ESI_PROCESS_PENDING_WONTFAIL
Definition: Element.h:20
@ ESI_PROCESS_COMPLETE
Definition: Element.h:19
@ ESI_PROCESS_PENDING_MAYFAIL
Definition: Element.h:21
void FinishAnElement(ESIElement::Pointer &, int pos=-1)
Definition: Esi.cc:1973
void FinishAllElements(Esi::Elements &)
Definition: Esi.cc:1983
#define assert(EX)
Definition: assert.h:17
static void ListTransfer(Pointer &from, Pointer &to)
Definition: Segment.cc:53
size_t len
Definition: Segment.h:41
ESISegment const * tail() const
Definition: Segment.cc:153
Pointer next
Definition: Segment.h:42
C * getRaw() const
Definition: RefCount.h:89
unsigned int dovars
Definition: Sequence.h:43
bool failed
Definition: Sequence.h:54
~esiSequence() override
Definition: Sequence.cc:27
void processStep(int dovars)
Definition: Sequence.cc:187
bool finishedProcessing() const
Definition: Sequence.cc:60
struct esiSequence::@61 flags
Pointer makeCacheable() const override
Definition: Sequence.cc:358
esiProcessResult_t process(int dovars) override
Definition: Sequence.cc:238
Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const override
Definition: Sequence.cc:377
size_t processedcount
Definition: Sequence.h:40
bool mayFail() const override
Definition: Sequence.cc:66
size_t nextElementToProcess() const
Definition: Sequence.cc:48
bool mayFail_
Definition: Sequence.h:53
void makeUsableElements(esiSequence const &old, ESIVarState &)
Definition: Sequence.cc:347
bool const provideIncrementalData
Definition: Sequence.h:56
void render(ESISegment::Pointer) override
Definition: Sequence.cc:82
esiTreeParentPtr parent
Definition: Sequence.h:49
Esi::Elements elements
Definition: Sequence.h:39
size_t nextElementToProcess_
Definition: Sequence.h:59
esiSequence(esiTreeParentPtr, bool=false)
Definition: Sequence.cc:33
void fail(ESIElement *, char const *anError=nullptr) override
Definition: Sequence.cc:307
void finish() override
Definition: Sequence.cc:104
void wontFail()
Definition: Sequence.cc:75
esiProcessResult_t processOne(int, size_t)
Definition: Sequence.cc:200
bool addElement(ESIElement::Pointer) override
Definition: Sequence.cc:148
int elementIndex(ESIElement::Pointer anElement) const
Definition: Sequence.cc:177
void makeCachableElements(esiSequence const &old)
Definition: Sequence.cc:336
bool processing
Definition: Sequence.h:57
esiProcessResult_t processingResult
Definition: Sequence.h:58
void provideData(ESISegment::Pointer, ESIElement *) override
Definition: Sequence.cc:112
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DBG_CRITICAL
Definition: Stream.h:37
void ESISegmentFreeList(ESISegment::Pointer &head)
Definition: Segment.cc:19
void fatal(const char *message)
Definition: fatal.cc:28
virtual void fail(ESIElement *, char const *=nullptr)
Definition: Element.h:33
virtual void provideData(ESISegment::Pointer, ESIElement *)
Definition: Element.h:28

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors