# Steve Young's code to implement file based HTML error messages,
rather than the hard coded string.
This commit is contained in:
		
							parent
							
								
									d28d9fb195
								
							
						
					
					
						commit
						a830af5097
					
				
							
								
								
									
										242
									
								
								src/htmlerror.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								src/htmlerror.c
									
									
									
									
									
										Normal file
									
								
							@ -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));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/htmlerror.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/htmlerror.h
									
									
									
									
									
										Normal file
									
								
							@ -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 */
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user