/* * Copyright (c) 2003-2015 Hypertriton, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This input filter processes a text/html stream. It performs the following * substitutions: * * - percgi(3) variable values: "$foo" => (Value of foo) * "%24foo" => (Value of foo) * - Gettext translation: "$_(String)" => (Translation of String) * - Quoted instances of "&" => "&" */ #include "cgi.h" #include #include #define VARSUBST_TRANSLATE_MAX 256 /* Max string length for $_(foo) */ enum varsubst_mode { VARSUBST_NORMAL, VARSUBST_VAR, VARSUBST_ESCAPE, VARSUBST_TRANSLATE }; static __inline__ const char * FetchVar(const char *key) { char *s; s = VAR_Get(key); return (s != NULL) ? s : ""; } static __inline__ int VarnameChar(const char c) { return (isalnum(c) || c == '_'); } static size_t Filter(struct cgi_query *q, void **pBuf, size_t src_len) { char vName[VARSUBST_TRANSLATE_MAX], *pName; char *src = *(char **)pBuf, *p, *endp; int quot = 0; enum varsubst_mode mode; TEXT te; TEXT_Init(&te, src_len, q->cset); for (p = src; p < &src[src_len];) { #if 0 if (*p == '"' || *p == '\'') { quot = !quot; } if (quot && p < &src[src_len-5] && /* Quoted & => & */ strncmp(p, "&", 5) == 0) { TEXT_CatC(&te, '&'); p += 5; } #endif mode = VARSUBST_NORMAL; if (p[0] == '%' && p < &src[src_len-3] && /* %24foo */ p[1] == '2' && p[2] == '4') { if (p[3] == '%' && &p[3] < &src[src_len-3] && p[4] == '2' && p[5] == '4') { mode = VARSUBST_ESCAPE; } else { mode = VARSUBST_VAR; } p+=3; if (p[0] == '_' && p[1] == '(') { mode = VARSUBST_TRANSLATE; p+=2; for (pName = &vName[0]; p < &src[src_len-1] && *p != ')' && isprint(*p) && pName < &vName[sizeof(vName)-1]; p++) { *pName = *p; pName++; } p++; } else { for (pName = &vName[0]; p < &src[src_len-1] && VarnameChar(*p) && pName < &vName[sizeof(vName)-1]; p++, pName++) { *pName = *p; } } *pName = '\0'; } else if (p[0] == '$') { if (p[1] == '$') { mode = VARSUBST_ESCAPE; } else { mode = VARSUBST_VAR; } p++; if (p[0] == '_' && p[1] == '(') { mode = VARSUBST_TRANSLATE; p+=2; for (pName = &vName[0]; p < &src[src_len-1] && *p != ')' && isprint(*p) && pName < &vName[sizeof(vName)-1]; p++) { *pName = *p; pName++; } p++; } else { for (pName = &vName[0]; p < &src[src_len-1] && VarnameChar(*p) && pName < &vName[sizeof(vName)-1]; p++, pName++) { *pName = *p; } } *pName = '\0'; } switch (mode) { case VARSUBST_NORMAL: TEXT_CatC(&te, *(p++)); break; case VARSUBST_ESCAPE: TEXT_CatC(&te, '$'); TEXT_CatS(&te, vName); break; case VARSUBST_TRANSLATE: TEXT_CatS_UTF8(&te, gettext(vName)); break; case VARSUBST_VAR: if (vName[0] != '\0') { char *s = VAR_Get(vName); if (s != NULL) { TEXT_CatS_UTF8(&te, FetchVar(vName)); } else { CGI_Log(CGI_LOG_ERR, "Uninitialized variable: $%s", vName); } } break; } } *pBuf = Realloc(*pBuf, te.len); memcpy(*pBuf, te.buf, te.len); TEXT_Destroy(&te); return (te.len); } struct cgi_filter cgiVarSubstFilter = { CGI_INPUT_FILTER, "text/html", Filter };