html-error: substitute template variables via a regex
previously, in order to detect and insert {variables} into error/stats templates, tinyproxy iterated char-by-char over the input file, and would try to parse anything inside {} pairs and treat it like a variable name. this breaks CSS, and additionally it's dog slow as tinyproxy wrote every single character to the client via a write syscall. now we process line-by-line, and inspect all matches of the regex \{[a-z]{1,32}\}. if the contents of the regex are a known variable name, substitution is taking place. if not, the contents are passed as-is to the client. also the chunks before and after matches are written in a single syscall. closes #108
This commit is contained in:
parent
17ae1b512c
commit
a8848d4bd8
@ -83,76 +83,49 @@ static char *get_html_file (unsigned int errornum)
|
|||||||
return (val);
|
return (val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void varsubst_sendline(struct conn_s *connptr, regex_t *re, char *p) {
|
||||||
|
int fd = connptr->client_fd;
|
||||||
|
while(*p) {
|
||||||
|
regmatch_t match;
|
||||||
|
char varname[32+1], *varval;
|
||||||
|
size_t l;
|
||||||
|
int st = regexec(re, p, 1, &match, 0);
|
||||||
|
if(st == 0) {
|
||||||
|
if(match.rm_so > 0) safe_write(fd, p, match.rm_so);
|
||||||
|
l = match.rm_eo - match.rm_so;
|
||||||
|
assert(l>2 && l-2 < sizeof(varname));
|
||||||
|
p += match.rm_so;
|
||||||
|
memcpy(varname, p+1, l-2);
|
||||||
|
varname[l-2] = 0;
|
||||||
|
varval = lookup_variable(connptr->error_variables, varname);
|
||||||
|
if(varval) write_message(fd, "%s", varval);
|
||||||
|
else if(varval && !*varval) write_message(fd, "(unknown)");
|
||||||
|
else safe_write(fd, p, l);
|
||||||
|
p += l;
|
||||||
|
} else {
|
||||||
|
write_message(fd, "%s", p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send an already-opened file to the client with variable substitution.
|
* Send an already-opened file to the client with variable substitution.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
send_html_file (FILE *infile, struct conn_s *connptr)
|
send_html_file (FILE *infile, struct conn_s *connptr)
|
||||||
{
|
{
|
||||||
char *inbuf;
|
regex_t re;
|
||||||
char *varstart = NULL;
|
char *inbuf = safemalloc (4096);
|
||||||
char *p;
|
(void) regcomp(&re, "{[a-z]\\{1,32\\}}", 0);
|
||||||
const char *varval;
|
|
||||||
int in_variable = 0;
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
inbuf = (char *) safemalloc (4096);
|
while (fgets (inbuf, 4096, infile)) {
|
||||||
|
varsubst_sendline(connptr, &re, inbuf);
|
||||||
while (fgets (inbuf, 4096, infile) != NULL) {
|
|
||||||
for (p = inbuf; *p; p++) {
|
|
||||||
switch (*p) {
|
|
||||||
case '}':
|
|
||||||
if (in_variable) {
|
|
||||||
*p = '\0';
|
|
||||||
varval = (const char *)
|
|
||||||
lookup_variable (connptr->error_variables,
|
|
||||||
varstart);
|
|
||||||
if (!varval || !varval[0])
|
|
||||||
varval = "(unknown)";
|
|
||||||
r = write_message (connptr->client_fd,
|
|
||||||
"%s", varval);
|
|
||||||
in_variable = 0;
|
|
||||||
} else {
|
|
||||||
r = write_message (connptr->client_fd,
|
|
||||||
"%c", *p);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '{':
|
|
||||||
/* a {{ will print a single {. If we are NOT
|
|
||||||
* already in a { variable, then proceed with
|
|
||||||
* setup. If we ARE already in a { variable,
|
|
||||||
* this code will fallthrough to the code that
|
|
||||||
* just dumps a character to the client fd.
|
|
||||||
*/
|
|
||||||
if (!in_variable) {
|
|
||||||
varstart = p + 1;
|
|
||||||
in_variable++;
|
|
||||||
} else
|
|
||||||
in_variable = 0;
|
|
||||||
|
|
||||||
/* FALL THROUGH */
|
|
||||||
default:
|
|
||||||
if (!in_variable) {
|
|
||||||
r = write_message (connptr->client_fd,
|
|
||||||
"%c", *p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r)
|
|
||||||
break;
|
|
||||||
|
|
||||||
in_variable = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regfree (&re);
|
||||||
safefree (inbuf);
|
safefree (inbuf);
|
||||||
|
return 1;
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int send_http_headers (struct conn_s *connptr, int code, const char *message)
|
int send_http_headers (struct conn_s *connptr, int code, const char *message)
|
||||||
|
Loading…
Reference in New Issue
Block a user