Sequence.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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.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 
25 class esiExcept;
26 
28 {
29  debugs(86, 5, "esiSequence::~esiSequence " << this);
30  FinishAllElements(elements); // finish if not already done
31 }
32 
33 esiSequence::esiSequence(esiTreeParentPtr aParent, bool incrementalFlag) :
34  elements(),
35  processedcount(0),
36  parent(aParent),
37  mayFail_(true),
38  failed(false),
39  provideIncrementalData(incrementalFlag),
43 {
44  memset(&flags, 0, sizeof(flags));
45 }
46 
47 size_t
49 {
50  return nextElementToProcess_;
51 }
52 
53 void
54 esiSequence::nextElementToProcess(size_t const &aSizeT)
55 {
56  nextElementToProcess_ = aSizeT;
57 }
58 
59 bool
61 {
62  return nextElementToProcess() >= elements.size();
63 }
64 
65 bool
67 {
68  if (failed)
69  return true;
70 
71  return mayFail_;
72 }
73 
74 void
76 {
77  assert (!failed);
78  mayFail_ = false;
79 }
80 
81 void
83 {
84  /* append all processed elements, and trim processed
85  * and rendered elements
86  */
87  assert (output->next == NULL);
88  debugs (86,5, "esiSequenceRender: rendering " << processedcount << " elements");
89 
90  for (size_t i = 0; i < processedcount; ++i) {
91  elements[i]->render(output);
93  /* FIXME: pass a ESISegment ** ? */
94  output = output->tail();
95  }
96 
97  // prune completed elements
98  elements.erase(elements.begin(), elements.begin() + processedcount);
99  processedcount = 0;
100  assert (output->next == NULL);
101 }
102 
103 void
105 {
106  debugs(86, 5, "esiSequence::finish: " << this << " is finished");
108  parent = NULL;
109 }
110 
111 void
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 
144  assert (process (flags.dovars) != ESI_PROCESS_FAILED);
145 }
146 
147 bool
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 
176 int
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 
186 void
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 
200 esiSequence::processOne(int dovars, size_t index)
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 */
211  ++processedcount;
212 
213  return ESI_PROCESS_COMPLETE;
214 
216  debugs(86, 5, "esiSequenceProcess: element Processed PENDING OK");
217 
219 
221  debugs(86, 5, "eseSequenceProcess: element Processed PENDING UNKNOWN");
222 
224 
225  case ESI_PROCESS_FAILED:
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 
238 esiSequence::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  * faliures
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()) {
266  processStep(dovars);
267 
268  if (!processing)
269  return processingResult;
270 
273  failed = true;
274  parent = NULL;
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 = NULL;
298 
299  debugs(86, 5, "esiSequence::process: " << this << " completed");
300 
301  processing = false;
302 
303  return processingResult;
304 }
305 
306 void
307 esiSequence::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 = NULL;
320 }
321 
323  processedcount(0),
324  parent(NULL),
325  mayFail_(old.mayFail_),
326  failed(old.failed),
328  processing(false),
331 {
332  flags.dovars = old.flags.dovars;
333 }
334 
335 void
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 
346 void
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 NULL;
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 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 
395 #endif /* USE_SQUID_ESI == 1 */
396 
Esi::Elements elements
Definition: Sequence.h:39
void FinishAllElements(Esi::Elements &)
Definition: Esi.cc:1981
size_t nextElementToProcess_
Definition: Sequence.h:59
#define assert(EX)
Definition: assert.h:17
void finish()
Definition: Sequence.cc:104
Pointer makeCacheable() const
Definition: Sequence.cc:358
void render(ESISegment::Pointer)
Definition: Sequence.cc:82
int i
Definition: membanger.c:49
bool processing
Definition: Sequence.h:57
esiProcessResult_t
Definition: Element.h:18
size_t len
Definition: Segment.h:41
#define DBG_CRITICAL
Definition: Debug.h:45
struct esiSequence::@66 flags
void FinishAnElement(ESIElement::Pointer &, int pos=-1)
Definition: Esi.cc:1971
Pointer next
Definition: Segment.h:42
esiSequence(esiTreeParentPtr, bool=false)
Definition: Sequence.cc:33
ESISegment const * tail() const
Definition: Segment.cc:153
virtual void fail(ESIElement *source, char const *reason=NULL)
Definition: Element.h:33
bool mayFail() const
Definition: Sequence.cc:66
bool mayFail_
Definition: Sequence.h:53
void makeUsableElements(esiSequence const &old, ESIVarState &)
Definition: Sequence.cc:347
void const char HLPCB void * data
Definition: stub_helper.cc:16
Pointer makeUsable(esiTreeParentPtr, ESIVarState &) const
Definition: Sequence.cc:377
esiProcessResult_t processOne(int, size_t)
Definition: Sequence.cc:200
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
#define true
Definition: GnuRegex.c:234
~esiSequence()
Definition: Sequence.cc:27
bool addElement(ESIElement::Pointer)
Definition: Sequence.cc:148
void fatal(const char *message)
Definition: fatal.cc:28
void provideData(ESISegment::Pointer, ESIElement *)
Definition: Sequence.cc:112
void wontFail()
Definition: Sequence.cc:75
void processStep(int dovars)
Definition: Sequence.cc:187
void ESISegmentFreeList(ESISegment::Pointer &head)
Definition: Segment.cc:19
int dovars
Definition: Sequence.h:43
int elementIndex(ESIElement::Pointer anElement) const
Definition: Sequence.cc:177
size_t nextElementToProcess() const
Definition: Sequence.cc:48
void makeCachableElements(esiSequence const &old)
Definition: Sequence.cc:336
void fail(ESIElement *, char const *anError=NULL)
Definition: Sequence.cc:307
esiProcessResult_t processingResult
Definition: Sequence.h:58
bool const provideIncrementalData
Definition: Sequence.h:56
esiProcessResult_t process(int dovars)
Definition: Sequence.cc:238
static void ListTransfer(Pointer &from, Pointer &to)
Definition: Segment.cc:53
C * getRaw() const
Definition: RefCount.h:74
virtual void provideData(ESISegment::Pointer data, ESIElement *source)
Definition: Element.h:28
size_t processedcount
Definition: Sequence.h:40
bool finishedProcessing() const
Definition: Sequence.cc:60
esiTreeParentPtr parent
Definition: Sequence.h:49
#define NULL
Definition: types.h:166
bool failed
Definition: Sequence.h:54
#define false
Definition: GnuRegex.c:233

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors