diff options
Diffstat (limited to 'src/html-error.c')
-rw-r--r-- | src/html-error.c | 170 |
1 files changed, 82 insertions, 88 deletions
diff --git a/src/html-error.c b/src/html-error.c index 625a586..fcb0b94 100644 --- a/src/html-error.c +++ b/src/html-error.c @@ -20,9 +20,9 @@ * HTML error pages with variable substitution. */ +#include "common.h" #include "main.h" -#include "common.h" #include "buffer.h" #include "conns.h" #include "heap.h" @@ -31,25 +31,33 @@ #include "utils.h" #include "conf.h" +#include <regex.h> + /* * Add an error number -> filename mapping to the errorpages list. */ #define ERRORNUM_BUFSIZE 8 /* this is more than required */ #define ERRPAGES_BUCKETCOUNT 16 -int add_new_errorpage (char *filepath, unsigned int errornum) +int add_new_errorpage (struct config_s *conf, char *filepath, + unsigned int errornum) { - char errornbuf[ERRORNUM_BUFSIZE]; + char errornbuf[ERRORNUM_BUFSIZE], *k; - config.errorpages = hashmap_create (ERRPAGES_BUCKETCOUNT); - if (!config.errorpages) + if (!conf->errorpages) + conf->errorpages = htab_create (ERRPAGES_BUCKETCOUNT); + if (!conf->errorpages) return (-1); snprintf (errornbuf, ERRORNUM_BUFSIZE, "%u", errornum); - if (hashmap_insert (config.errorpages, errornbuf, - filepath, strlen (filepath) + 1) < 0) + k = safestrdup(errornbuf); + if (!k) return -1; + + if (!htab_insert (conf->errorpages, k, HTV_P(filepath))) { + safefree(k); return (-1); + } return (0); } @@ -59,28 +67,51 @@ int add_new_errorpage (char *filepath, unsigned int errornum) */ static char *get_html_file (unsigned int errornum) { - hashmap_iter result_iter; char errornbuf[ERRORNUM_BUFSIZE]; - char *key; - char *val; + htab_value *hv; assert (errornum >= 100 && errornum < 1000); - if (!config.errorpages) - return (config.errorpage_undef); + if (!config->errorpages) + return (config->errorpage_undef); snprintf (errornbuf, ERRORNUM_BUFSIZE, "%u", errornum); - result_iter = hashmap_find (config.errorpages, errornbuf); - - if (hashmap_is_end (config.errorpages, result_iter)) - return (config.errorpage_undef); + hv = htab_find (config->errorpages, errornbuf); + if (!hv) return (config->errorpage_undef); + return hv->p; +} - if (hashmap_return_entry (config.errorpages, result_iter, - &key, (void **) &val) < 0) - return (config.errorpage_undef); +static char *lookup_variable (struct htab *map, const char *varname) { + htab_value *v; + v = htab_find(map, varname); + return v ? v->p : 0; +} - 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; + } + } } /* @@ -89,90 +120,42 @@ static char *get_html_file (unsigned int errornum) 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 = "(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; + regex_t re; + char *inbuf = safemalloc (4096); + (void) regcomp(&re, "{[a-z]\\{1,32\\}}", 0); - 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) { const char headers[] = - "HTTP/1.0 %d %s\r\n" + "HTTP/1.%u %d %s\r\n" "Server: %s/%s\r\n" "Content-Type: text/html\r\n" "%s" "Connection: close\r\n" "\r\n"; - const char auth_str[] = + const char p_auth_str[] = "Proxy-Authenticate: Basic realm=\"" PACKAGE_NAME "\"\r\n"; + const char w_auth_str[] = + "WWW-Authenticate: Basic realm=\"" + PACKAGE_NAME "\"\r\n"; + /* according to rfc7235, the 407 error must be accompanied by a Proxy-Authenticate header field. */ - const char *add = code == 407 ? auth_str : ""; + const char *add = code == 407 ? p_auth_str : (code == 401 ? w_auth_str : ""); return (write_message (connptr->client_fd, headers, + connptr->protocol.major != 1 ? 0 : connptr->protocol.minor, code, message, PACKAGE, VERSION, add)); } @@ -225,14 +208,25 @@ int send_http_error_message (struct conn_s *connptr) int add_error_variable (struct conn_s *connptr, const char *key, const char *val) { + char *k, *v; + if (!connptr->error_variables) if (! (connptr->error_variables = - hashmap_create (ERRVAR_BUCKETCOUNT))) + htab_create (ERRVAR_BUCKETCOUNT))) return (-1); - return hashmap_insert (connptr->error_variables, key, val, - strlen (val) + 1); + k = safestrdup(key); + v = safestrdup(val); + + if (!v || !k) goto oom; + + if(htab_insert (connptr->error_variables, k, HTV_P(v))) + return 1; +oom:; + safefree(k); + safefree(v); + return -1; } #define ADD_VAR_RET(x, y) \ @@ -251,6 +245,7 @@ int add_standard_vars (struct conn_s *connptr) char errnobuf[16]; char timebuf[30]; time_t global_time; + struct tm tm_buf; snprintf (errnobuf, sizeof errnobuf, "%d", connptr->error_number); ADD_VAR_RET ("errno", errnobuf); @@ -258,7 +253,6 @@ int add_standard_vars (struct conn_s *connptr) ADD_VAR_RET ("cause", connptr->error_string); ADD_VAR_RET ("request", connptr->request_line); ADD_VAR_RET ("clientip", connptr->client_ip_addr); - ADD_VAR_RET ("clienthost", connptr->client_string_addr); /* The following value parts are all non-NULL and will * trigger warnings in ADD_VAR_RET(), so we use @@ -267,7 +261,7 @@ int add_standard_vars (struct conn_s *connptr) global_time = time (NULL); strftime (timebuf, sizeof (timebuf), "%a, %d %b %Y %H:%M:%S GMT", - gmtime (&global_time)); + gmtime_r (&global_time, &tm_buf)); add_error_variable (connptr, "date", timebuf); add_error_variable (connptr, "website", |