summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/htmlerror.c242
-rw-r--r--src/htmlerror.h20
2 files changed, 262 insertions, 0 deletions
diff --git a/src/htmlerror.c b/src/htmlerror.c
new file mode 100644
index 0000000..aee92f5
--- /dev/null
+++ b/src/htmlerror.c
@@ -0,0 +1,242 @@
+/* $Id: htmlerror.c,v 1.1 2003-03-13 21:25:06 rjkaes Exp $
+ *
+ * This file contains source code for the handling and display of
+ * HTML error pages with variable substitution.
+ */
+#include "tinyproxy.h"
+
+#include "common.h"
+#include "buffer.h"
+#include "conns.h"
+#include "heap.h"
+#include "htmlerror.h"
+#include "network.h"
+#include "utils.h"
+
+/* Add an error number -> filename mapping to the errorpages list. */
+int add_new_errorpage(char *filepath, unsigned int errornum) {
+ static int errorpage_count = 1;
+
+ /* First, add space for another pointer to the errorpages array. */
+ config.errorpages = saferealloc(config.errorpages, sizeof(struct error_pages_s *) * (errorpage_count + 1));
+ if(!config.errorpages)
+ return(-1);
+
+ /* Allocate space for an actual structure */
+ config.errorpages[errorpage_count - 1] = safemalloc(sizeof(struct error_pages_s));
+ if(!config.errorpages[errorpage_count - 1])
+ return(-1);
+
+ /* Set values for errorpage structure. */
+ config.errorpages[errorpage_count - 1]->errorpage_path = safestrdup(filepath);
+ if(!config.errorpages[errorpage_count - 1]->errorpage_path)
+ return(-1);
+
+ config.errorpages[errorpage_count - 1]->errorpage_errnum = errornum;
+
+ /* Set NULL to denote end of array */
+ config.errorpages[errorpage_count] = NULL;
+
+ errorpage_count++;
+ return(0);
+}
+
+/* Get the file appropriate for a given error. */
+char *get_html_file(int errornum) {
+ int i;
+
+ if(!config.errorpages) return(config.errorpage_undef);
+
+ for(i = 0; config.errorpages[i]; i++) {
+ if(config.errorpages[i]->errorpage_errnum == errornum)
+ return(config.errorpages[i]->errorpage_path);
+ }
+
+ return(config.errorpage_undef);
+}
+
+/* Look up the value for a variable. */
+char *lookup_variable(struct conn_s *connptr, char *varname) {
+ int i;
+
+ for(i = 0; i<connptr->error_variable_count; i++) {
+ if(!strcasecmp(connptr->error_variables[i]->error_key, varname))
+ return(connptr->error_variables[i]->error_val);
+ }
+
+ return(NULL);
+}
+
+#define HTML_BUFSIZE 4096
+
+/* Send an already-opened file to the client with
+ * variable substitution. */
+int send_html_file(FILE *infile, struct conn_s *connptr) {
+ char inbuf[HTML_BUFSIZE], *varstart = NULL, *p;
+ char *varval;
+ int in_variable = 0, writeret;
+
+ while(fgets(inbuf, HTML_BUFSIZE, infile) != NULL) {
+ for(p = inbuf; *p; p++) {
+ switch(*p) {
+ case '}':
+ if(in_variable) {
+ *p = '\0';
+ if(!(varval = lookup_variable(connptr, varstart)))
+ varval = "(unknown)";
+ writeret = write_message(connptr->client_fd, "%s",
+ varval);
+ if(writeret) return(writeret);
+ in_variable = 0;
+ break;
+ }
+ /* If we are not in a variable, then
+ * we fallthrough. the code for { will
+ * not do anything if in_variable is set to
+ * 0. it will end up in the default
+ * handler which will send the }.
+ */
+ 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++;
+ }
+ default:
+ if(!in_variable) {
+ writeret = write_message(connptr->client_fd, "%c",
+ *p);
+ if(writeret) return(writeret);
+ }
+
+ }
+ }
+ in_variable = 0;
+ }
+ return(0);
+}
+
+int send_http_headers(struct conn_s *connptr, int code, char *message) {
+ char *headers = \
+ "HTTP/1.0 %d %s\r\n" \
+ "Server: %s/%s\r\n" \
+ "Content-Type: text/html\r\n" \
+ "Connection: close\r\n" \
+ "\r\n";
+
+ return(write_message(connptr->client_fd, headers,
+ code, message,
+ PACKAGE, VERSION));
+}
+
+/*
+ * Display an error to the client.
+ */
+int
+send_http_error_message(struct conn_s *connptr)
+{
+ char *error_file;
+ FILE *infile;
+ int ret;
+ char *fallback_error = \
+ "<html><head><title>%s</title></head>" \
+ "<body><blockquote><i>%s %s</i><br>" \
+ "The page you requested was unavailable. The error code is listed " \
+ "below. In addition, the HTML file which has been configured as the " \
+ "page to be displayed when an error of this type was unavailable, " \
+ "with the error code %d (%s). Please contact your administrator." \
+ "<center>%s</center>" \
+ "</body></html>" \
+ "\r\n";
+
+ send_http_headers(connptr, connptr->error_number, connptr->error_string);
+
+ error_file = get_html_file(connptr->error_number);
+ if(!(infile = fopen(error_file, "r")))
+ return(write_message(connptr->client_fd, fallback_error,
+ connptr->error_string,
+ PACKAGE, VERSION,
+ errno, strerror(errno),
+ connptr->error_string));
+
+ ret = send_html_file(infile, connptr);
+ fclose(infile);
+ return(ret);
+}
+
+/*
+ * Add a key -> value mapping for HTML file substitution.
+ */
+int
+add_error_variable(struct conn_s *connptr, char *key, char *val)
+{
+ connptr->error_variable_count++;
+
+ /* Add space for a new pointer to the error_variables structure. */
+ connptr->error_variables = saferealloc(connptr->error_variables, sizeof(struct error_variable_s *) * connptr->error_variable_count);
+ if(!connptr->error_variables)
+ return(-1);
+
+ /* Allocate a new variable mapping structure. */
+ connptr->error_variables[connptr->error_variable_count - 1] = safemalloc(sizeof(struct error_variable_s));
+ if(!connptr->error_variables[connptr->error_variable_count - 1])
+ return(-1);
+
+ /* Set values for variable mapping. */
+ connptr->error_variables[connptr->error_variable_count - 1]->error_key = safestrdup(key);
+ connptr->error_variables[connptr->error_variable_count - 1]->error_val = safestrdup(val);
+ if((!connptr->error_variables[connptr->error_variable_count - 1]->error_key)
+ || (!connptr->error_variables[connptr->error_variable_count - 1]->error_val))
+ return(-1);
+
+ return(0);
+}
+
+#define ADD_VAR_RET(x, y) if(y) { if(add_error_variable(connptr, x, y) == -1) return(-1); }
+
+/* Set some standard variables used by all HTML pages */
+int add_standard_vars(struct conn_s *connptr) {
+ char timebuf[30];
+ time_t global_time = time(NULL);
+
+ strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT",
+ gmtime(&global_time));
+
+ ADD_VAR_RET("request", connptr->request_line);
+ ADD_VAR_RET("cause", connptr->error_string);
+ ADD_VAR_RET("clientip", connptr->client_ip_addr);
+ ADD_VAR_RET("clienthost", connptr->client_string_addr);
+ ADD_VAR_RET("version", VERSION);
+ ADD_VAR_RET("package", PACKAGE);
+ ADD_VAR_RET("date", timebuf);
+ return(0);
+}
+
+/*
+ * Add the error information to the conn structure.
+ */
+int
+indicate_http_error(struct conn_s* connptr, int number, char *message, ...)
+{
+ va_list ap;
+ char *key, *val;
+
+ va_start(ap, message);
+
+ while((key = va_arg(ap, char *))) {
+ val = va_arg(ap, char *);
+ if(add_error_variable(connptr, key, val) == -1)
+ return(-1);
+ }
+
+ connptr->error_number = number;
+ connptr->error_string = safestrdup(message);
+
+ return(add_standard_vars(connptr));
+}
+
diff --git a/src/htmlerror.h b/src/htmlerror.h
new file mode 100644
index 0000000..705faaa
--- /dev/null
+++ b/src/htmlerror.h
@@ -0,0 +1,20 @@
+/* $Id: htmlerror.h,v 1.1 2003-03-13 21:25:04 rjkaes Exp $
+ *
+ * Contains header declarations for the HTML error functions in htmlerror.c
+ */
+
+#ifndef TINYPROXY_HTMLERROR_H
+#define TINYPROXY_HTMLERROR_H
+
+/* Forward declaration */
+struct conn_s;
+
+extern int add_new_errorpage(char *filepath, unsigned int errornum);
+extern int send_http_error_message(struct conn_s *connptr);
+extern int indicate_http_error(struct conn_s *connptr, int number, char *message, ...);
+extern int add_error_variable(struct conn_s *connptr, char *key, char *val);
+extern int send_html_file(FILE *infile, struct conn_s *connptr);
+extern int send_http_headers(struct conn_s *connptr, int code, char *message);
+extern int add_standard_vars(struct conn_s *connptr);
+
+#endif /* !TINYPROXY_HTMLERROR_H */