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