/*
* 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
};