summaryrefslogtreecommitdiffhomepage
path: root/src/html-error.c
diff options
context:
space:
mode:
authorrofl0r <rofl0r@users.noreply.github.com>2020-09-07 04:32:13 +0100
committerrofl0r <rofl0r@users.noreply.github.com>2020-09-07 04:32:13 +0100
commita8848d4bd898a15e02a8f4210917166bca9f50b1 (patch)
tree77f3b6399fe928f456264bccdf31e5d9c2f6bb59 /src/html-error.c
parent17ae1b512c386970d0f5b84b385b89749a89b1e5 (diff)
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
Diffstat (limited to 'src/html-error.c')
-rw-r--r--src/html-error.c93
1 files changed, 33 insertions, 60 deletions
diff --git a/src/html-error.c b/src/html-error.c
index f04943e..c94dbd7 100644
--- a/src/html-error.c
+++ b/src/html-error.c
@@ -83,76 +83,49 @@ static char *get_html_file (unsigned int errornum)
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.
*/
int
send_html_file (FILE *infile, struct conn_s *connptr)
{
- char *inbuf;
- char *varstart = NULL;
- char *p;
- const char *varval;
- int in_variable = 0;
- int r = 0;
-
- inbuf = (char *) safemalloc (4096);
-
- 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;
- }
+ regex_t re;
+ char *inbuf = safemalloc (4096);
+ (void) regcomp(&re, "{[a-z]\\{1,32\\}}", 0);
- if (r)
- break;
-
- in_variable = 0;
+ while (fgets (inbuf, 4096, infile)) {
+ varsubst_sendline(connptr, &re, inbuf);
}
+ regfree (&re);
safefree (inbuf);
-
- return r;
+ return 1;
}
int send_http_headers (struct conn_s *connptr, int code, const char *message)