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