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