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