]> git.ipfire.org Git - thirdparty/squid.git/blame - src/esi/VarState.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / esi / VarState.cc
CommitLineData
924f73bc 1
2/*
262a0e14 3 * $Id$
924f73bc 4 *
5 * DEBUG: section 86 ESI processing
6 * AUTHOR: Robert Collins
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
26ac0430 24 *
924f73bc 25 * This program is distributed in the hope that it will be useful,
26 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
26ac0430 29 *
924f73bc 30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
35 */
36
582c2af2 37#include "squid.h"
f99c2cfe 38#include "esi/VarState.h"
924f73bc 39#include "HttpReply.h"
582c2af2 40#include "protos.h"
924f73bc 41
42CBDATA_TYPE (ESIVarState);
43FREE ESIVarStateFree;
44
26ac0430
AJ
45char const *ESIVariableUserAgent::esiUserOs[]= {
46 "WIN",
47 "MAC",
48 "UNIX",
49 "OTHER"
50};
924f73bc 51
26ac0430
AJ
52char const * esiBrowsers[]= {"MSIE",
53 "MOZILLA",
54 "OTHER"
55 };
924f73bc 56
924f73bc 57void
58ESIVarState::Variable::eval (ESIVarState &state, char const *subref, char const *found_default) const
59{
60 /* No-op. We swallow it */
61
62 if (found_default)
63 ESISegment::ListAppend (state.getOutput(), found_default, strlen (found_default));
64}
65
66void
67ESIVarState::hostUsed()
68{
69 flags.host = 1;
70}
71
72void
73ESIVarState::cookieUsed()
74{
75 flags.cookie = 1;
76}
77
78void
79ESIVarState::languageUsed()
80{
81 flags.language = 1;
82}
83
84void
85ESIVarState::refererUsed()
86{
87 flags.referer = 1;
88}
89
90void
91ESIVarState::useragentUsed()
92{
93 flags.useragent = 1;
94}
95
96HttpHeader &
97ESIVarState::header()
98{
99 return hdr;
100}
101
102ESISegment::Pointer &
103ESIVarState::getOutput()
104{
105 return output;
106}
107
108char const *
109ESIVariableQuery::queryString() const
110{
111 return query_string;
112}
113
114struct _query_elem const *
e1381638
AJ
115ESIVariableQuery::queryVector() const {
116 return query;
117}
924f73bc 118
119size_t const &
120ESIVariableQuery::queryElements() const
121{
122 return query_elements;
123}
124
125void
126ESIVarState::feedData (const char *buf, size_t len)
127{
128 /* TODO: if needed - tune to skip segment iteration */
137a13ea 129 debugs (86,6, "esiVarState::feedData: accepting " << len << " bytes");
924f73bc 130 ESISegment::ListAppend (input, buf, len);
131}
132
133ESISegment::Pointer
134ESIVarState::extractList()
135{
136 doIt();
137 ESISegment::Pointer rv = output;
138 output = NULL;
bf8fe701 139 debugs(86, 6, "ESIVarStateExtractList: Extracted list");
924f73bc 140 return rv;
141}
142
143char *
144ESIVarState::extractChar ()
145{
146 if (!input.getRaw())
147 fatal ("Attempt to extract variable state with no data fed in \n");
148
149 doIt();
150
151 char *rv = output->listToChar();
152
153 ESISegmentFreeList (output);
154
bf8fe701 155 debugs(86, 6, "ESIVarStateExtractList: Extracted char");
924f73bc 156
157 return rv;
158}
159
160/* ESIVarState */
161void
162esiVarStateFree (void *data)
163{
164 ESIVarState *thisNode = (ESIVarState*)data;
165 thisNode->freeResources();
166}
167
168ESIVarState::~ESIVarState()
169{
170 freeResources();
171
172 while (variablesForCleanup.size())
173 delete variablesForCleanup.pop_back();
174
175 delete defaultVariable;
176}
177
178void
179ESIVarState::freeResources()
180{
181 input = NULL;
182 ESISegmentFreeList (output);
519e0948 183 hdr.clean();
924f73bc 184}
185
186void *
187ESIVarState::operator new(size_t byteCount)
188{
189 assert (byteCount == sizeof (ESIVarState));
190 void *rv;
191 CBDATA_INIT_TYPE_FREECB(ESIVarState, esiVarStateFree);
192 rv = (void *)cbdataAlloc (ESIVarState);
193 return rv;
194}
195
196void
197ESIVarState::operator delete (void *address)
198{
199 cbdataFree (address);
200}
201
924f73bc 202char *
203ESIVariableUserAgent::getProductVersion (char const *s)
204{
205 char const *t;
206 int len;
207 t = index (s,'/');
208
209 if (!t || !*(++t))
210 return xstrdup ("");
211
212 len = strcspn (t, " \r\n()<>@,;:\\\"/[]?={}");
213
214 return xstrndup (t, len + 1);
215}
216
217ESIVariableQuery::ESIVariableQuery(char const *uri) : query (NULL), query_sz (0), query_elements (0), query_string (NULL)
218{
219 /* Count off the query elements */
220 char const *query_start = strchr (uri, '?');
221
222 if (query_start && query_start[1] != '\0' ) {
223 unsigned int n;
224 query_string = xstrdup (query_start + 1);
225 query_elements = 1;
226 char const *query_pos = query_start + 1;
227
228 while ((query_pos = strchr (query_pos, '&'))) {
229 ++query_elements;
230 ++query_pos;
231 }
232
233 query = (_query_elem *)memReallocBuf(query, query_elements * sizeof (struct _query_elem),
234 &query_sz);
235 query_pos = query_start + 1;
236 n = 0;
237
238 while (query_pos) {
411c6ea3 239 char const *next = strchr (query_pos, '&');
240 char const *div = strchr (query_pos, '=');
924f73bc 241
242 if (next)
243 ++next;
244
245 assert (n < query_elements);
246
247 if (!div)
248 div = next;
249
250 if (!(div - query_pos + 1))
251 /* zero length between & and = or & and & */
252 continue;
253
254 query[n].var = xstrndup (query_pos, div - query_pos + 1) ;
255
256 if (div == next) {
257 query[n].val = xstrdup ("");
258 } else {
259 query[n].val = xstrndup (div + 1, next - div - 1);
260 }
261
262 query_pos = next;
263 ++n;
264 }
265 } else {
266 query_string = xstrdup ("");
267 }
268
269 if (query) {
270 unsigned int n = 0;
bf8fe701 271 debugs(86, 6, "esiVarStateNew: Parsed Query string: '" << uri << "'");
924f73bc 272
273 while (n < query_elements) {
bf8fe701 274 debugs(86, 6, "esiVarStateNew: Parsed Query element " << n + 1 << " '" << query[n].var << "'='" << query[n].val << "'");
924f73bc 275 ++n;
276 }
277 }
278}
279
280ESIVariableQuery::~ESIVariableQuery()
281{
282 if (query) {
283 unsigned int i;
284
285 for (i = 0; i < query_elements; ++i) {
286 safe_free(query[i].var);
287 safe_free(query[i].val);
288 }
289
290 memFreeBuf (query_sz, query);
291 }
292
293 safe_free (query_string);
294}
295
296ESIVarState::ESIVarState (HttpHeader const *aHeader, char const *uri)
818c6c9e 297 : output (NULL), hdr(hoReply)
924f73bc 298{
299 /* TODO: only grab the needed headers */
300 /* Note that as we pass these through to included requests, we
301 * cannot trim them */
4dd8a5fd 302 hdr.append(aHeader);
924f73bc 303
304 /* populate our variables trie with the available variables.
305 * Additional ones can be added during the parsing.
306 * If there is a lazy evaluation approach to this, consider it!
307 */
308 defaultVariable = new Variable;
309 addVariable ("HTTP_ACCEPT_LANGUAGE", 20, new ESIVariableLanguage);
310 addVariable ("HTTP_COOKIE", 11, new ESIVariableCookie);
311 addVariable ("HTTP_HOST", 9, new ESIVariableHost);
312 addVariable ("HTTP_REFERER", 12, new ESIVariableReferer);
313 addVariable ("HTTP_USER_AGENT", 15, new ESIVariableUserAgent(*this));
314 addVariable ("QUERY_STRING", 12, new ESIVariableQuery(uri));
315}
316
317void
30abd221 318ESIVarState::removeVariable (String const &name)
924f73bc 319{
9c175897 320 Variable *candidate = static_cast <Variable *>(variables.find (name.rawBuf(), name.size()));
924f73bc 321
322 if (candidate) {
323 /* XXX: remove me */
324 /* Note - this involves:
325 * extend libTrie to have a remove() call.
326 * delete from the vector.
327 * delete the object.
328 */
329 }
330}
331
332void
333ESIVarState::addVariable(char const *name, size_t len, Variable *aVariable)
334{
30abd221 335 String temp;
924f73bc 336 temp.limitInit (name, len);
337 removeVariable (temp);
338 variables.add(name, len, aVariable);
339 variablesForCleanup.push_back(aVariable);
340}
341
342ESIVariableUserAgent::~ESIVariableUserAgent()
343{
344 safe_free (browserversion);
345}
346
347ESIVariableUserAgent::ESIVariableUserAgent(ESIVarState &state)
348{
349 /* An example:
350 * User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705) */
351 /* Grr this Node is painful - RFC 2616 specifies that 'by convention' the tokens are in order of importance
352 * in identifying the product. According to the RFC the above should be interpreted as:
353 * Product - Mozilla version 4.0
26ac0430 354 * in comments - compatible; .... 3705
924f73bc 355 *
356 * Useing the RFC a more appropriate header would be
357 * User-Agent: MSIE/6.0 Mozilla/4.0 Windows-NT/5.1 .NET-CLR/1.0.3705
358 * or something similar.
359 *
26ac0430 360 * Because we can't parse under those rules and get real-world useful answers, we follow the following
924f73bc 361 * algorithm:
362 * if the string Windows appears in the header, the OS is WIN.
363 * If the string Mac appears in the header, the OS is MAC.
364 * If the string nix, or BSD appears in the header, the OS is UNIX.
26ac0430 365 * If the string MSIE appears in the header, the BROWSER is MSIE, and the version is the string from
924f73bc 366 * MSIE<sp> to the first ;, or end of string.
26ac0430 367 * If the String MSIE does not appear in the header, and MOZILLA does, we use the version from the
924f73bc 368 * /version field.
369 * if MOZILLA doesn't appear, the browser is set to OTHER.
370 * In future, this may be better implemented as a regexp.
371 */
372
4dd8a5fd 373 if (state.header().has(HDR_USER_AGENT)) {
374 char const *s = state.header().getStr(HDR_USER_AGENT);
924f73bc 375 UserOs = identifyOs(s);
376 char const *t, *t1;
377
378 /* Now the browser and version */
379
380 if ((t = strstr (s, "MSIE"))) {
381 browser = ESI_BROWSER_MSIE;
382 t = index (t, ' ');
383
384 if (!t)
385 browserversion = xstrdup ("");
386 else {
387 t1 = index (t, ';');
388
389 if (!t1)
390 browserversion = xstrdup (t + 1);
391 else
392 browserversion = xstrndup (t + 1, t1-t);
393 }
394 } else if (strstr (s, "Mozilla")) {
395 browser = ESI_BROWSER_MOZILLA;
396 browserversion = getProductVersion(s);
397 } else {
398 browser = ESI_BROWSER_OTHER;
399 browserversion = getProductVersion(s);
400 }
401 } else {
402 UserOs = ESI_OS_OTHER;
403 browser = ESI_BROWSER_OTHER;
404 browserversion = xstrdup ("");
405 }
406}
407
408ESIVariableUserAgent::esiUserOs_t
409ESIVariableUserAgent::identifyOs(char const *s) const
410{
411 if (!s)
412 return ESI_OS_OTHER;
413
414 if (strstr (s, "Windows"))
415 return ESI_OS_WIN;
416 else if (strstr (s, "Mac"))
417 return ESI_OS_MAC;
418 else if (strstr (s, "nix") || strstr (s, "BSD"))
419 return ESI_OS_UNIX;
420 else
421 return ESI_OS_OTHER;
422}
423
424void
425ESIVariableCookie::eval (ESIVarState &state, char const *subref, char const *found_default) const
426{
427 const char *s = NULL;
428 state.cookieUsed();
429
4dd8a5fd 430 if (state.header().has(HDR_COOKIE)) {
924f73bc 431 if (!subref)
4dd8a5fd 432 s = state.header().getStr (HDR_COOKIE);
924f73bc 433 else {
30abd221 434 String S = state.header().getListMember (HDR_COOKIE, subref, ';');
924f73bc 435
436 if (S.size())
9c175897 437 ESISegment::ListAppend (state.getOutput(), S.rawBuf(), S.size());
924f73bc 438 else if (found_default)
439 ESISegment::ListAppend (state.getOutput(), found_default, strlen (found_default));
440 }
441 } else
442 s = found_default;
443
444 if (s)
445 ESISegment::ListAppend (state.getOutput(), s, strlen (s));
446}
447
448void
449ESIVariableHost::eval (ESIVarState &state, char const *subref, char const *found_default) const
450{
451 const char *s = NULL;
452 state.hostUsed();
453
4dd8a5fd 454 if (!subref && state.header().has(HDR_HOST)) {
455 s = state.header().getStr (HDR_HOST);
924f73bc 456 } else
457 s = found_default;
458
459 ESISegment::ListAppend (state.getOutput(), s, strlen (s));
460}
461
462void
463ESIVariableLanguage::eval (ESIVarState &state, char const *subref, char const *found_default) const
464{
465 char const *s = NULL;
466 state.languageUsed();
467
4dd8a5fd 468 if (state.header().has(HDR_ACCEPT_LANGUAGE)) {
924f73bc 469 if (!subref) {
30abd221 470 String S (state.header().getList (HDR_ACCEPT_LANGUAGE));
9c175897 471 ESISegment::ListAppend (state.getOutput(), S.rawBuf(), S.size());
924f73bc 472 } else {
4dd8a5fd 473 if (state.header().hasListMember (HDR_ACCEPT_LANGUAGE, subref, ',')) {
924f73bc 474 s = "true";
475 } else {
476 s = "false";
477 }
478
479 ESISegment::ListAppend (state.getOutput(), s, strlen (s));
480 }
481 } else {
482 s = found_default;
483 ESISegment::ListAppend (state.getOutput(), s, strlen (s));
484 }
485}
486
487void
488ESIVariableQuery::eval (ESIVarState &state, char const *subref, char const *found_default) const
489{
490 char const *s = NULL;
491
492 if (!subref)
493 s = queryString();
494 else {
495 unsigned int i = 0;
496
497 while (i < queryElements() && !s) {
498 if (!strcmp (subref, queryVector()[i].var))
499 s = queryVector()[i].val;
500
501 ++i;
502 }
503
504 if (!s)
505 s = found_default;
506 }
507
508 ESISegment::ListAppend (state.getOutput(), s, strlen (s));
509}
510
511void
512ESIVariableReferer::eval (ESIVarState &state, char const *subref, char const *found_default) const
513{
514 const char *s = NULL;
515 state.refererUsed();
516
4dd8a5fd 517 if (!subref && state.header().has(HDR_REFERER))
518 s = state.header().getStr (HDR_REFERER);
924f73bc 519 else
520 s = found_default;
521
522 ESISegment::ListAppend (state.getOutput(), s, strlen (s));
523}
524
525void
526ESIVariableUserAgent::eval (ESIVarState &state, char const *subref, char const *found_default) const
527{
528 char const *s = NULL;
529 state.useragentUsed();
530
4dd8a5fd 531 if (state.header().has(HDR_USER_AGENT)) {
924f73bc 532 if (!subref)
4dd8a5fd 533 s = state.header().getStr (HDR_USER_AGENT);
924f73bc 534 else {
535 if (!strcmp (subref, "os")) {
536 s = esiUserOs[UserOs];
537 } else if (!strcmp (subref, "browser")) {
538 s = esiBrowsers[browser];
539 } else if (!strcmp (subref, "version")) {
540 s = browserVersion();
541 } else
542 s = "";
543 }
544 } else
545 s = found_default;
546
547 ESISegment::ListAppend (state.getOutput(), s, strlen (s));
548}
549
550/* thoughts on long term:
551 * get $
552 * get () handler
553 * hand off to handler.
554 * one handler for variables.
555 * one handler for each function.
556 */
557
558class ESIVariableProcessor;
559
560class ESIFunction
561{
562
563public:
564 static ESIFunction *GetFunction (char const *symbol, ESIVariableProcessor &);
565 ESIFunction(ESIVariableProcessor &);
566 void doIt();
567
568private:
569 ESIVariableProcessor &processor;
570
571};
572
573ESIFunction::ESIFunction(ESIVariableProcessor &aProcessor) : processor(aProcessor)
574{}
575
576ESIFunction *
577ESIFunction::GetFunction(char const *symbol, ESIVariableProcessor &aProcessor)
578{
579 if (*symbol == '(')
580 return new ESIFunction(aProcessor);
581
582 return NULL;
583}
584
585class ESIVariableProcessor
586{
587
588public:
589 ESIVariableProcessor(char *, ESISegment::Pointer &, Trie &, ESIVarState *);
590 ~ESIVariableProcessor();
591 void doIt();
592
593private:
594 bool validChar (char c);
b0365bd9 595 void eval (ESIVarState::Variable *var, char const *subref, char const *foundDefault );
924f73bc 596 void doFunction();
597 void identifyFunction();
598 char *string;
599 ESISegment::Pointer &output;
600 Trie &variables;
601 ESIVarState *varState;
602 int state;
603 size_t len;
604 size_t pos;
605 size_t var_pos;
606 size_t done_pos;
607 char * found_subref;
608 char *found_default;
609 ESIVarState::Variable *vartype;
610 ESIFunction *currentFunction;
611};
612
613void
b0365bd9 614ESIVariableProcessor::eval (ESIVarState::Variable *var, char const *subref, char const *foundDefault )
924f73bc 615{
616 assert (var);
617
b0365bd9
FC
618 if (!foundDefault)
619 foundDefault = "";
924f73bc 620
b0365bd9 621 var->eval (*varState, subref, foundDefault);
924f73bc 622}
623
624bool
625ESIVariableProcessor::validChar (char c)
626{
627 if (('A' <= c && c <= 'Z') ||
628 ('a' <= c && c <= 'z') ||
629 '_' == c || '-' == c)
630 return true;
631
632 return false;
633}
634
635ESIVarState::Variable *
636ESIVarState::GetVar(char const *symbol, int len)
637{
638 assert (symbol);
639
640 void *result = variables.find (symbol, len);
641
642 if (result)
643 return static_cast<Variable *>(result);
644
645 return defaultVariable;
646}
647
648void
649ESIVarState::doIt ()
650{
651 char *string = input->listToChar();
652 ESISegmentFreeList (input);
653 ESIVariableProcessor theProcessor(string, output, variables, this);
654 theProcessor.doIt();
655 safe_free(string);
656}
657
658#define LOOKFORSTART 0
659ESIVariableProcessor::ESIVariableProcessor(char *aString, ESISegment::Pointer &aSegment, Trie &aTrie, ESIVarState *aState) :
660 string(aString), output (aSegment), variables(aTrie), varState (aState),
661 state(LOOKFORSTART), pos(0), var_pos(0), done_pos(0), found_subref (NULL),
662 found_default (NULL), currentFunction(NULL)
663{
664 len = strlen (string);
665 vartype = varState->GetVar("",0);
666}
667
668void
669ESIFunction::doIt()
670{}
671
672/* because we are only used to process:
673 * - include URL's
674 * - non-esi elements
675 * - choose clauses
676 * buffering is ok - we won't delay the start of async activity, or
677 * of output data preparation
678 */
679/* Should make these an enum or something...
680 */
681void
682ESIVariableProcessor::doFunction()
683{
684 if (!currentFunction)
685 return;
686
687 /* stay in here whilst operating */
688 while (pos < len && state)
689 switch (state) {
690
691 case 2: /* looking for variable name */
692
693 if (!validChar(string[pos])) {
694 /* not a variable name char */
695
696 if (pos - var_pos) {
697 vartype = varState->GetVar (string + var_pos, pos - var_pos);
698 }
699
700 state = 3;
701 } else {
702 ++pos;
703 }
704
705 break;
706
707 case 3: /* looking for variable subref, end bracket or default indicator */
708
709 if (string[pos] == ')') {
710 /* end of string */
711 eval(vartype, found_subref, found_default);
712 done_pos = ++pos;
713 safe_free(found_subref);
714 safe_free(found_default);
715 state = LOOKFORSTART;
716 } else if (!found_subref && !found_default && string[pos] == '{') {
bf8fe701 717 debugs(86, 6, "ESIVarStateDoIt: Subref of some sort");
924f73bc 718 /* subreference of some sort */
719 /* look for the entry name */
720 var_pos = ++pos;
721 state = 4;
722 } else if (!found_default && string[pos] == '|') {
bf8fe701 723 debugs(86, 6, "esiVarStateDoIt: Default present");
924f73bc 724 /* extract default value */
725 state = 5;
726 var_pos = ++pos;
727 } else {
728 /* unexpected char, not a variable after all */
bf8fe701 729 debugs(86, 6, "esiVarStateDoIt: unexpected char after varname");
924f73bc 730 state = LOOKFORSTART;
731 pos = done_pos + 2;
732 }
733
734 break;
735
736 case 4: /* looking for variable subref */
737
738 if (string[pos] == '}') {
739 /* end of subref */
740 found_subref = xstrndup (&string[var_pos], pos - var_pos + 1);
bf8fe701 741 debugs(86, 6, "esiVarStateDoIt: found end of variable subref '" << found_subref << "'");
924f73bc 742 state = 3;
743 ++pos;
744 } else if (!validChar (string[pos])) {
bf8fe701 745 debugs(86, 6, "esiVarStateDoIt: found invalid char in variable subref");
924f73bc 746 /* not a valid subref */
747 safe_free(found_subref);
748 state = LOOKFORSTART;
749 pos = done_pos + 2;
750 } else {
751 ++pos;
752 }
753
754 break;
755
756 case 5: /* looking for a default value */
757
758 if (string[pos] == '\'') {
759 /* begins with a quote */
bf8fe701 760 debugs(86, 6, "esiVarStateDoIt: found quoted default");
924f73bc 761 state = 6;
762 var_pos = ++pos;
763 } else {
764 /* doesn't */
bf8fe701 765 debugs(86, 6, "esiVarStateDoIt: found unquoted default");
924f73bc 766 state = 7;
767 ++pos;
768 }
769
770 break;
771
772 case 6: /* looking for a quote terminate default value */
773
774 if (string[pos] == '\'') {
775 /* end of default */
776 found_default = xstrndup (&string[var_pos], pos - var_pos + 1);
bf8fe701 777 debugs(86, 6, "esiVarStateDoIt: found end of quoted default '" << found_default << "'");
924f73bc 778 state = 3;
779 }
780
781 ++pos;
782 break;
783
784 case 7: /* looking for } terminate default value */
785
786 if (string[pos] == ')') {
787 /* end of default - end of variable*/
788 found_default = xstrndup (&string[var_pos], pos - var_pos + 1);
bf8fe701 789 debugs(86, 6, "esiVarStateDoIt: found end of variable (w/ unquoted default) '" << found_default << "'");
924f73bc 790 eval(vartype,found_subref, found_default);
791 done_pos = ++pos;
792 safe_free(found_default);
793 safe_free(found_subref);
794 state = LOOKFORSTART;
795 }
796
797 ++pos;
798 break;
799
800 default:
801 fatal("esiVarStateDoIt: unexpected state\n");
802 }
803}
804
805void
806ESIVariableProcessor::identifyFunction()
807{
808 delete currentFunction;
809 currentFunction = ESIFunction::GetFunction (&string[pos], *this);
810
811 if (!currentFunction) {
812 state = LOOKFORSTART;
813 } else {
814 state = 2; /* process a function */
815 /* advance past function name */
816 var_pos = ++pos;
817 }
818}
819
820void
821ESIVariableProcessor::doIt()
822{
823 assert (output == NULL);
824
825 while (pos < len) {
826 /* skipping pre-variables */
827
828 if (string[pos] != '$') {
829 ++pos;
830 } else {
831 if (pos - done_pos)
832 /* extract known plain text */
833 ESISegment::ListAppend (output, string + done_pos, pos - done_pos);
834
835 done_pos = pos;
836
837 ++pos;
838
839 identifyFunction();
840
841 doFunction();
842 }
843 }
844
845 /* pos-done_pos chars are ready to copy */
846 if (pos-done_pos)
847 ESISegment::ListAppend (output, string+done_pos, pos - done_pos);
848
849 safe_free (found_default);
850
851 safe_free (found_subref);
852}
853
854ESIVariableProcessor::~ESIVariableProcessor()
855{
856 delete currentFunction;
857}
858
924f73bc 859/* XXX FIXME: this should be comma delimited, no? */
860void
861ESIVarState::buildVary (HttpReply *rep)
862{
863 char tempstr[1024];
864 tempstr[0]='\0';
865
866 if (flags.language)
867 strcat (tempstr, "Accept-Language ");
868
869 if (flags.cookie)
870 strcat (tempstr, "Cookie ");
871
872 if (flags.host)
873 strcat (tempstr, "Host ");
874
875 if (flags.referer)
876 strcat (tempstr, "Referer ");
877
878 if (flags.useragent)
879 strcat (tempstr, "User-Agent ");
880
881 if (!tempstr[0])
882 return;
883
30abd221 884 String strVary (rep->header.getList (HDR_VARY));
924f73bc 885
9c175897 886 if (!strVary.size() || strVary[0] != '*') {
4dd8a5fd 887 rep->header.putStr (HDR_VARY, tempstr);
924f73bc 888 }
889}
30abd221 890