%c", LF); diff --git a/cgi-src/util.c b/cgi-src/util.c index 3f37f39..0901a66 100644 --- a/cgi-src/util.c +++ b/cgi-src/util.c @@ -120,3 +120,28 @@ void send_fd(FILE *f, FILE *fd) fputc(c,fd); } } + +int ind(char *s, char c) { + register int x; + + for(x=0;s[x];x++) + if(s[x] == c) return x; + + return -1; +} + +void escape_shell_cmd(char *cmd) { + register int x,y,l; + + l=strlen(cmd); + for(x=0;cmd[x];x++) { + if(ind("&;`'\"|*?~<>^()[]{}$\\",cmd[x]) != -1){ + for(y=l+1;y>x;y--) + cmd[y] = cmd[y-1]; + l++; /* length has been increased */ + cmd[x] = '\\'; + x++; /* skip the character */ + } + } +} + diff --git a/conf/httpd.conf-dist b/conf/httpd.conf-dist index e25f76a..0ad9036 100644 --- a/conf/httpd.conf-dist +++ b/conf/httpd.conf-dist @@ -52,8 +52,12 @@ TransferLog logs/access_log PidFile logs/httpd.pid # ServerName allows you to set a host name which is sent back to clients for -#your server if it's different than the one the program would get (i.e. use -#"www" instead of the host's real name). +# your server if it's different than the one the program would get (i.e. use +# "www" instead of the host's real name). +# +# Note: You cannot just invent host names and hope they work. The name you +# define here must be a valid DNS name for your host. If you don't understand +# this, ask your network administrator. #ServerName new.host.name diff --git a/conf/srm.conf-dist b/conf/srm.conf-dist index 6940570..779b578 100644 --- a/conf/srm.conf-dist +++ b/conf/srm.conf-dist @@ -1,6 +1,9 @@ # With this document, you define the name space that users see of your http # server. +# See the tutorials at http://hoohoo.ncsa.uiuc.edu/docs/tutorials/ for +# more information. + # Rob (robm@ncsa.uiuc.edu) @@ -27,13 +30,15 @@ FancyIndexing on # AddIcon tells the server which icon to show for different files or filename # extensions -AddIcon /icons/text.xbm .html .txt -AddIcon /icons/image.xbm .gif .jpg .xbm .tiff -AddIcon /icons/sound.xbm .au -AddIcon /icons/movie.xbm .mpg +AddIconByType (TXT,/icons/text.xbm) text/* +AddIconByType (IMG,/icons/image.xbm) image/* +AddIconByType (SND,/icons/sound.xbm) audio/* +AddIcon /icons/movie.xbm .mpg .qt AddIcon /icons/binary.xbm .bin + AddIcon /icons/back.xbm .. -AddIcon /icons/menu.xbm **DIRECTORY** +AddIcon /icons/menu.xbm ^^DIRECTORY^^ +AddIcon /icons/blank.xbm ^^BLANKICON^^ # DefaultIcon is which icon to show for files which do not have an icon # explicitly set. @@ -49,13 +54,17 @@ DefaultIcon /icons/unknown.xbm # # The server will first look for name.html, include it if found, and it will # then look for name and include it as plaintext if found. +# +# HeaderName is the name of a file which should be prepended to +# directory indexes. ReadmeName README +HeaderName HEADER # IndexIgnore is a set of filenames which directory indexing should ignore # Format: IndexIgnore name1 name2... -IndexIgnore /.htaccess ~ # +IndexIgnore */.??* *~ *# */HEADER* */README* # AccessFileName: The name of the file to look for in each directory # for access control information. @@ -71,6 +80,12 @@ DefaultType text/plain # make certain files to be certain types. # Format: AddType type/subtype ext1 +# AddEncoding allows you to have certain browsers (Mosaic/X 2.1+) uncompress +# information on the fly. Note: Not all browsers support this. + +#AddEncoding x-compress Z +#AddEncoding x-gzip gz + # Redirect allows you to tell clients about documents which used to exist in # your server's namespace, but do not anymore. This allows you to tell the # clients where to look for the relocated document. @@ -86,3 +101,9 @@ Alias /icons/ /usr/local/etc/httpd/icons/ # Format: ScriptAlias fakename realname ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin/ + +# If you want to use server side includes, or CGI outside +# ScriptAliased directories, uncomment the following lines. + +#AddType text/x-server-parsed-html .shtml +#AddType application/x-httpd-cgi .cgi diff --git a/icons/blank.xbm b/icons/blank.xbm new file mode 100644 index 0000000..eb10641 --- /dev/null +++ b/icons/blank.xbm @@ -0,0 +1,9 @@ +#define blank_width 20 +#define blank_height 23 +static char blank_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/src/Makefile b/src/Makefile index 50de6a6..2f0b5bd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,13 +4,13 @@ #CC= cc # For Suns or other non-ANSI platforms. Please make sure your gcc is # 2.0 or later, as 1.40 seems to create bad code for the Sun 4. -CC= gcc +CC= gcc # For optimization -#CFLAGS= -O2 +CFLAGS= -O2 # For debugging information -#CFLAGS= -g -DPEM_AUTH -CFLAGS= -g +#CFLAGS= -g -DPEM_AUTH +#CFLAGS= -g # Place here any extra libraries you may need to link to. You # shouldn't have to. @@ -34,7 +34,7 @@ AUX_CFLAGS= -DSUNOS4 # For HP-UX #AUX_CFLAGS= -DHPUX # For AIX -#AUX_CFLAGS= -DAIX +#AUX_CFLAGS= -DAIX -U__STR__ # For Ultrix #AUX_CFLAGS= -DULTRIX # For DEC OSF/1 @@ -47,6 +47,14 @@ AUX_CFLAGS= -DSUNOS4 #AUX_CFLAGS= -DLINUX # For A/UX #AUX_CFLAGS= -DAUX +# For SCO ODT +# libcrypt_i available from sosco.sco.com, files /SLS/lng225b.Z and +# /SLS/lng225b.ltr.Z +#AUX_CFLAGS= -DSCO +#EXTRA_LIBS= -lPW -lsocket -lmalloc -lcrypt_i +# For SVR4 +#AUX_CFLAGS= -DSVR4 +#EXTRA_LIBS= -lsocket -lnsl -lc # Place here any flags you may need upon linking, such as a flag to # prevent dynamic linking (if desired) @@ -56,7 +64,8 @@ LFLAGS= OBJS=http_config.o httpd.o http_request.o util.o http_dir.o \ http_alias.o http_log.o http_mime.o http_access.o http_auth.o \ -http_get.o http_put.o http_script.o rfc931.o +http_get.o http_post.o http_script.o http_include.o rfc931.o \ +http_put.o http_delete.o .c.o: $(CC) -c $(CFLAGS) $(AUX_CFLAGS) $< diff --git a/src/Makefile~ b/src/Makefile~ deleted file mode 100644 index 099a509..0000000 --- a/src/Makefile~ +++ /dev/null @@ -1,100 +0,0 @@ -# Makefile for NCSA's httpd. - -# For normal machines with ANSI compilers -#CC= cc -# For Suns or other non-ANSI platforms. Please make sure your gcc is -# 2.0 or later, as 1.40 seems to create bad code for the Sun 4. -CC= gcc - -# For optimization -#CFLAGS= -O2 -# For debugging information -CFLAGS= -g -DPEM_AUTH -#CFLAGS= -g - -# Place here any extra libraries you may need to link to. You -# shouldn't have to. -EXTRA_LIBS= - -# AUX_CFLAGS are system-specific control flags. -# NOTE: IF YOU DO NOT CHOOSE ONE OF THESE, EDIT httpd.h AND CHOOSE -# SETTINGS FOR THE SYSTEM FLAGS. IF YOU DON'T, BAD THINGS WILL HAPPEN. - -# For SunOS 4 -AUX_CFLAGS= -DSUNOS4 -# For Solaris 2. NOTE: Lots of problems have been identified with compiling -# httpd under Solaris. Use with caution. If you see aberrant behavior with -# httpd under Solaris 2, please mail us. -#AUX_CFLAGS= -DSOLARIS2 -#EXTRA_LIBS= -lsocket -lnsl -# For SGI IRIX. Use the EXTRA_LIBS line if you're using NIS and want -# user-supported directories -#AUX_CFLAGS= -DIRIX -#EXTRA_LIBS= -lsun -# For HP-UX -#AUX_CFLAGS= -DHPUX -# For AIX -#AUX_CFLAGS= -DAIX -# For Ultrix -#AUX_CFLAGS= -DULTRIX -# For DEC OSF/1 -#AUX_CFLAGS= -DOSF1 -# For NeXT -#AUX_CFLAGS= -DNEXT -# For Sequent -#AUX_CFLAGS= -DSEQUENT -# For Linux -m486 ONLY IF YOU HAVE 486 BINARY SUPPORT IN KERNEL -#AUX_CFLAGS= -DLINUX -# For A/UX -#AUX_CFLAGS= -DAUX - -# Place here any flags you may need upon linking, such as a flag to -# prevent dynamic linking (if desired) -LFLAGS= - -# You shouldn't have to edit anything else. - -OBJS=http_config.o httpd.o http_request.o util.o http_dir.o \ -http_alias.o http_log.o http_mime.o http_access.o http_auth.o \ -http_get.o http_put.o http_script.o rfc931.o - -.c.o: - $(CC) -c $(CFLAGS) $(AUX_CFLAGS) $< - -all: httpd - -ibm: - make tar AUX_CFLAGS=-DAIX CC=gcc CFLAGS=-O2 - -sun: - make tar AUX_CFLAGS=-DSUNOS4 CC=gcc CFLAGS=-O2 - -hp: - make tar AUX_CFLAGS=-DHPUX CC=gcc CFLAGS=-O2 - -sgi: - make tar AUX_CFLAGS=-DIRIX EXTRA_LIBS=-lsun CC=cc CFLAGS=-O2 - -decmips: - make tar AUX_CFLAGS=-DULTRIX CC=cc CFLAGS=-O2 - -decaxp: - make tar AUX_CFLAGS=-DOSF1 CC=cc CFLAGS=-O2 - -httpd: $(OBJS) - $(CC) $(LFLAGS) -o httpd $(OBJS) $(EXTRA_LIBS) - -purify: $(OBJS) - purify -logfile=/X11/robm/httpd/logs/pure_log \ - -program-name=/X11/robm/httpd/src/httpd \ - $(CC) $(LFLAGS) -o httpd $(OBJS) $(EXTRA_LIBS) - -tar: $(OBJS) - $(CC) $(LFLAGS) -o ../httpd $(OBJS) $(EXTRA_LIBS) - rm -f $(OBJS) - - -$(OBJS): Makefile httpd.h - -clean: - rm -f ../httpd httpd $(OBJS) *pure* diff --git a/src/http_access.c b/src/http_access.c index 2f1e28d..df9f1e9 100644 --- a/src/http_access.c +++ b/src/http_access.c @@ -73,16 +73,17 @@ void check_dir_access(int x, int m, int *w, int *n) { *w=1; if(find_deny(x,m)) *w=0; - if(sec[x].num_auth[m]) - *n=x; - } else { + } else if(sec[x].order[m] == DENY_THEN_ALLOW) { if(find_deny(x,m)) *w=0; if(find_allow(x,m)) *w=1; - if(sec[x].num_auth[m]) - *n=x; } + else + *w = find_allow(x,m) && (!find_deny(x,m)); + + if(sec[x].num_auth[m]) + *n=x; } void evaluate_access(char *p, struct stat *finfo, int m, int *allow, @@ -91,11 +92,14 @@ void evaluate_access(char *p, struct stat *finfo, int m, int *allow, int will_allow, need_auth, num_dirs; char opts[MAX_STRING_LEN], override[MAX_STRING_LEN]; char path[MAX_STRING_LEN], d[MAX_STRING_LEN]; + char errstr[MAX_STRING_LEN]; register int x,y,z,n; if(S_ISDIR(finfo->st_mode)) strcpy_dir(path,p); else strcpy(path,p); + no2slash(path); + num_dirs = count_dirs(path); will_allow=1;need_auth=-1; auth_type=NULL;auth_name=NULL;auth_pwfile=NULL;auth_grpfile=NULL; @@ -106,55 +110,101 @@ void evaluate_access(char *p, struct stat *finfo, int m, int *allow, } for(x=0;x",fd); + bytes_sent += 6; + } + else { + fputs("",fd); + bytes_sent += 5; } } + int dsortf(struct ent **s1,struct ent **s2) { return(strcmp((*s1)->name,(*s2)->name)); @@ -256,26 +513,33 @@ void index_directory(char *name, FILE *fd) struct ent *head,*p,*q; struct ent **ar; char unmunged_name[MAX_STRING_LEN]; + char *tmp; - strcpy(unmunged_name,name); + strcpy_dir(unmunged_name,name); unmunge_name(unmunged_name); if(!(d=opendir(name))) die(FORBIDDEN,unmunged_name,fd); strcpy(content_type,"text/html"); + status = 200; if(!assbackwards) send_http_header(fd); if(header_only) return; -/* Spew HTML preamble */ - fprintf(fd,"st_mode))) && (!(opts[n] & OPT_SYM_LINKS))) { - struct stat fi; + if((!(S_ISDIR(finfo->st_mode))) && + ((!(opts[n] & OPT_SYM_LINKS)) || (opts[x] & OPT_SYM_OWNER))) { + struct stat fi,lfi; lstat(path,&fi); if(!(S_ISREG(fi.st_mode))) { - char errstr[MAX_STRING_LEN]; - sprintf(errstr,"httpd: will not follow link %s",path); - log_error(errstr); - *allow=0; - *allow_options = OPT_NONE; - return; + if(opts[n] & OPT_SYM_OWNER) { + char realpath[512]; + int bsz; + + if((bsz = readlink(path,realpath,256)) == -1) + goto gong; + realpath[bsz] = '\0'; + if(realpath[0] != '/') { + char t[256]; + strcpy(t,"../"); + strcpy(&t[3],realpath); + make_full_path(path,t,realpath); + getparents(realpath); + } + lstat(realpath,&lfi); + if(fi.st_uid != lfi.st_uid) + goto gong; + } + else { + gong: + sprintf(errstr,"httpd: will not follow link %s",path); + log_error(errstr); + *allow=0; + *allow_options = OPT_NONE; + return; + } } } *allow = will_allow; @@ -179,6 +229,14 @@ void kill_security() { for(y=0;y '); - n=parse_access_dir(f,n,OR_ALL,w,NULL,stderr); + n=parse_access_dir(f,n,OR_ALL,w,NULL,errors); } fclose(f); } -int get_pw(char *user, char *pw) { +int get_pw(char *user, char *pw, FILE *errors) { FILE *f; char errstr[MAX_STRING_LEN]; char l[MAX_STRING_LEN]; @@ -788,7 +886,7 @@ int get_pw(char *user, char *pw) { if(!(f=fopen(auth_pwfile,"r"))) { sprintf(errstr,"Could not open user file %s",auth_pwfile); - die(SERVER_ERROR,errstr,stdout); /* AAAAAAAAGH stdout */ + die(SERVER_ERROR,errstr,errors); } while(!(cfg_getline(l,MAX_STRING_LEN,f))) { if((l[0] == '#') || (!l[0])) continue; @@ -868,12 +966,12 @@ void kill_group() { } } -void read_config() +void read_config(FILE *errors) { reset_aliases(); - process_server_config(); - init_mime(); + process_server_config(errors); + init_mime(errors); init_indexing(); - process_resource_config(); - process_access_config(); + process_resource_config(errors); + process_access_config(errors); } diff --git a/src/http_delete.c b/src/http_delete.c new file mode 100644 index 0000000..6b48fcd --- /dev/null +++ b/src/http_delete.c @@ -0,0 +1,57 @@ +/* + * http_delete.c: Handles DELETE + * + * Rob McCool + * + */ + +#include "httpd.h" + + +void handle_delete(char *name, char *args, int in, FILE *out) { + struct stat finfo; + char ct_bak[MAX_STRING_LEN]; + + if(stat(name,&finfo) == -1) { + if(find_script("DELETE",name,args,in,out)) + return; + if(errno==ENOENT) { + log_reason("file does not exist",name); + unmunge_name(name); + die(NOT_FOUND,name,out); + } + else { + log_reason("file permissions deny server access",name); + unmunge_name(name); + die(FORBIDDEN,name,out); + } + } + probe_content_type(name); + if(!strcmp(content_type,CGI_MAGIC_TYPE)) { + strcpy(content_type,ct_bak); + send_cgi("DELETE",name,"",args,&finfo,in,out); + return; + } + /* Not a script, do group ann thang */ + die(NOT_IMPLEMENTED,"DELETE to non-script",out); +} + + +void delete_node(char *name, char *args, int in, FILE *out) { + struct stat finfo; + int s; + + s=translate_name(name,out); + + switch(s) { + case STD_DOCUMENT: + handle_delete(name,args,in,out); + return; + case REDIRECT_URL: + die(REDIRECT,name,out); + case SCRIPT_CGI: + exec_cgi_script("DELETE",name,args,in,out); + default: + die(NOT_IMPLEMENTED,"NCSA script exeuction of delete",out); + } +} diff --git a/src/http_dir.c b/src/http_dir.c index df93f53..cb48376 100644 --- a/src/http_dir.c +++ b/src/http_dir.c @@ -13,31 +13,46 @@ struct ent { char *name; char *icon; + char *alt; char *desc; size_t size; + time_t lm; struct ent *next; }; + struct item { - char *msg; - char *fn; + int type; + char *apply_to; + char *apply_path; + char *data; struct item *next; }; -static struct item *icon_list, *desc_list, *ign_list; + +static struct item *icon_list, *alt_list, *desc_list, *ign_list; +static struct item *hdr_list, *rdme_list, *opts_list; + +static int dir_opts; void init_indexing() { icon_list = NULL; + alt_list = NULL; desc_list = NULL; ign_list = NULL; + + hdr_list = NULL; + rdme_list = NULL; + opts_list = NULL; } void kill_item_list(struct item *p) { struct item *q; while(p) { - if(p->msg) free(p->msg); - if(p->fn) free(p->fn); + if(p->apply_to) free(p->apply_to); + if(p->apply_path) free(p->apply_path); + if(p->data) free(p->data); q = p; p = p->next; free(q); @@ -46,202 +61,444 @@ void kill_item_list(struct item *p) { void kill_indexing() { kill_item_list(icon_list); + kill_item_list(alt_list); kill_item_list(desc_list); kill_item_list(ign_list); + + kill_item_list(hdr_list); + kill_item_list(rdme_list); + kill_item_list(opts_list); } -void add_icon(char *icon, char *ext, FILE *out) { +struct item *new_item(int type, char *to, char *path, char *data, FILE *out) +{ struct item *p; if(!(p = (struct item *)malloc(sizeof(struct item)))) - die(NO_MEMORY,"add_icon",out); - if(!(p->msg = strdup(icon))) - die(NO_MEMORY,"add_icon",out); - if(!(p->fn = strdup(ext))) - die(NO_MEMORY,"add_icon",out); + die(NO_MEMORY,"new_item",out); + + p->type = type; + if(data) { + if(!(p->data = strdup(data))) + die(NO_MEMORY,"new_item",out); + } else + p->data = NULL; + + if(to) { + if(!(p->apply_to = (char *)malloc(strlen(to) + 2))) + die(NO_MEMORY,"new_item",out); + if((type == BY_PATH) && (!is_matchexp(to))) { + p->apply_to[0] = '*'; + strcpy(&p->apply_to[1],to); + } else + strcpy(p->apply_to,to); + } else + p->apply_to = NULL; + + if(!(p->apply_path = (char *)malloc(strlen(path) + 2))) + die(NO_MEMORY,"new_item",out); + sprintf(p->apply_path,"%s*",path); + + return p; +} + +void add_alt(int type, char *alt, char *to, char *path, FILE *out) { + struct item *p; + + if(type == BY_PATH) { + if(!strcmp(to,"**DIRECTORY**")) + strcpy(to,"^^DIRECTORY^^"); + } + p = new_item(type,to,path,alt,out); + p->next = alt_list; + alt_list = p; +} + +void add_icon(int type, char *icon, char *to, char *path, FILE *out) { + struct item *p; + char iconbak[MAX_STRING_LEN]; + + strcpy(iconbak,icon); + if(icon[0] == '(') { + char alt[MAX_STRING_LEN]; + getword(alt,iconbak,','); + add_alt(type,&alt[1],to,path,out); + iconbak[strlen(iconbak) - 1] = '\0'; + } + if(type == BY_PATH) { + if(!strcmp(to,"**DIRECTORY**")) + strcpy(to,"^^DIRECTORY^^"); + } + p = new_item(type,to,path,iconbak,out); p->next = icon_list; icon_list = p; } -char *find_icon(char *path) { - struct item *p = icon_list; - int pl, el; - - pl = strlen(path); - while(p) { - el = strlen(p->fn); - if(el <= pl) - if(!strcmp(&path[pl - el],p->fn)) - return p->msg; - p = p->next; - } - return NULL; -} - -void add_desc(char *desc, char *ext, FILE *out) { +void add_desc(int type, char *desc, char *to, char *path, FILE *out) { struct item *p; - if(!(p = (struct item *)malloc(sizeof(struct item)))) - die(NO_MEMORY,"add_desc",out); - if(!(p->msg = strdup(desc))) - die(NO_MEMORY,"add_desc",out); - if(!(p->fn = strdup(ext))) - die(NO_MEMORY,"add_desc",out); + p = new_item(type,to,path,desc,out); p->next = desc_list; desc_list = p; } -char *find_desc(char *path) { - struct item *p = desc_list; - int pl, el; +void add_ignore(char *ext, char *path, FILE *out) { + struct item *p; + + p = new_item(0,ext,path,NULL,out); + p->next = ign_list; + ign_list = p; +} + +void add_header(char *name, char *path, FILE *out) { + struct item *p; + + p = new_item(0,NULL,path,name,out); + p->next = hdr_list; + hdr_list = p; +} + +void add_readme(char *name, char *path, FILE *out) { + struct item *p; + + p = new_item(0,NULL,path,name,out); + p->next = rdme_list; + rdme_list = p; +} + + +void add_opts_int(int opts, char *path, FILE *out) { + struct item *p; + + p = new_item(0,NULL,path,NULL,out); + p->type = opts; + p->next = opts_list; + opts_list = p; +} + +void add_opts(char *optstr, char *path, FILE *out) { + char w[MAX_STRING_LEN]; + int opts = 0; + + while(optstr[0]) { + cfg_getword(w,optstr); + if(!strcasecmp(w,"FancyIndexing")) + opts |= FANCY_INDEXING; + else if(!strcasecmp(w,"IconsAreLinks")) + opts |= ICONS_ARE_LINKS; + else if(!strcasecmp(w,"ScanHTMLTitles")) + opts |= SCAN_HTML_TITLES; + else if(!strcasecmp(w,"None")) + opts = 0; + } + add_opts_int(opts,path,out); +} + + +char *find_item(struct item *list, char *path, int path_only) { + struct item *p = list; + char *t; - pl = strlen(path); while(p) { - el = strlen(p->fn); - if(el <= pl) - if(!strcmp(&path[pl - el],p->fn)) - return p->msg; + /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */ + if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) { + if(!(p->apply_to)) + return p->data; + else if(p->type == BY_PATH) { + if(!strcmp_match(path,p->apply_to)) + return p->data; + } else if(!path_only) { + char pathbak[MAX_STRING_LEN]; + + strcpy(pathbak,path); + content_encoding[0] = '\0'; + set_content_type(pathbak); + if(!content_encoding[0]) { + if(p->type == BY_TYPE) { + if(!strcmp_match(content_type,p->apply_to)) + return p->data; + } + } else { + if(p->type == BY_ENCODING) { + if(!strcmp_match(content_encoding,p->apply_to)) + return p->data; + } + } + } + } p = p->next; } return NULL; } -void add_ignore(char *ext,FILE *out) { - struct item *p; +#define find_icon(p,t) find_item(icon_list,p,t) +#define find_alt(p) find_item(alt_list,p,0) +#define find_desc(p) find_item(desc_list,p,0) +#define find_header(p) find_item(hdr_list,p,0) +#define find_readme(p) find_item(rdme_list,p,0) - if(!(p = (struct item *)malloc(sizeof(struct item)))) - die(NO_MEMORY,"add_ignore",out); - p->msg = NULL; - if(!(p->fn = strdup(ext))) - die(NO_MEMORY,"add_ignore",out); - p->next = ign_list; - ign_list = p; -} int ignore_entry(char *path) { - struct item *p; - int pl,el; + struct item *p = ign_list; - pl = strlen(path); - p = ign_list; while(p) { - el = strlen(p->fn); - if(el <= pl) - if(!strcmp(&path[pl - el],p->fn)) + if(!strcmp_match(path,p->apply_path)) + if(!strcmp_match(path,p->apply_to)) return 1; p = p->next; } return 0; } -void insert_readme(char *name, FILE *fd) { +int find_opts(char *path) { + struct item *p = opts_list; + + while(p) { + if(!strcmp_match(path,p->apply_path)) + return p->type; + p = p->next; + } + return 0; +} + +int insert_readme(char *name, char *readme_fname, int rule, FILE *fd) { char fn[MAX_STRING_LEN]; FILE *r; struct stat finfo; int plaintext=0; - if(!readme_fname[0]) - return; make_full_path(name,readme_fname,fn); strcat(fn,".html"); if(stat(fn,&finfo) == -1) { fn[strlen(fn)-5] = '\0'; if(stat(fn,&finfo) == -1) - return; + return 0; plaintext=1; - fprintf(fd," %c",LF); + if(rule) bytes_sent += fprintf(fd,"%c",LF); + return 1; +} + + +char *find_title(char *filename) { + char titlebuf[MAX_STRING_LEN], *find = "
%c",LF); + bytes_sent += fprintf(fd,"%c",LF); } - else fprintf(fd,"%c",LF); + bytes_sent += fprintf(fd,"
"); + else if(rule) bytes_sent += fprintf(fd,"
%c",LF); if(!(r = fopen(fn,"r"))) - return; - send_fd(r,fd,""); + return 0; + send_fd(r,fd,NULL); fclose(r); if(plaintext) - fprintf(fd,""; + char filebak[MAX_STRING_LEN]; + FILE *thefile; + int x,n,p; + + content_encoding[0] = '\0'; + strcpy(filebak,filename); + set_content_type(filebak); + if((!strcmp(content_type,"text/html")) && (!content_encoding[0])) { + if(!(thefile = fopen(filename,"r"))) + return NULL; + n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile); + titlebuf[n] = '\0'; + for(x=0,p=0;titlebuf[x];x++) { + if(titlebuf[x] == find[p]) { + if(!find[++p]) { + if((p = ind(&titlebuf[++x],'<')) != -1) + titlebuf[x+p] = '\0'; + return strdup(&titlebuf[x]); + } + } else p=0; + } + return NULL; + } + content_encoding[0] = '\0'; + return NULL; } struct ent *make_dir_entry(char *path, char *name, FILE *out) { struct ent *p; struct stat finfo; - char t[MAX_STRING_LEN]; + char t[MAX_STRING_LEN], t2[MAX_STRING_LEN]; if((name[0] == '.') && (!name[1])) return(NULL); make_full_path(path,name,t); + if(ignore_entry(t)) return(NULL); if(!(p=(struct ent *)malloc(sizeof(struct ent)))) die(NO_MEMORY,"make_dir_entry",out); - if(!(p->name=strdup(name))) + if(!(p->name=(char *)malloc(strlen(name) + 2))) die(NO_MEMORY,"make_dir_entry",out); - if(fancy_indexing) { - p->icon = find_icon(t); - if((!fancy_indexing) || stat(t,&finfo) == -1) { + if(dir_opts & FANCY_INDEXING) { + p->alt = find_alt(t); + if((!(dir_opts & FANCY_INDEXING)) || stat(t,&finfo) == -1) { + strcpy(p->name,name); p->size = -1; + p->icon = NULL; + p->desc = NULL; + p->lm = -1; } else { + p->lm = finfo.st_mtime; if(S_ISDIR(finfo.st_mode)) { - if(!p->icon) - p->icon = find_icon("**DIRECTORY**"); + if(!(p->icon = find_icon(t,1))) + p->icon = find_icon("^^DIRECTORY^^",1); + p->alt = "DIR"; p->size = -1; + strcpy_dir(p->name,name); } - else + else { + p->icon = find_icon(t,0); p->size = finfo.st_size; + strcpy(p->name,name); + } } - p->desc = find_desc(t); + if(p->desc = find_desc(t)) + p->desc = strdup(p->desc); + if((!p->desc) && (dir_opts & SCAN_HTML_TITLES)) + p->desc = find_title(t); } else { p->icon = NULL; + p->alt = NULL; p->desc = NULL; p->size = -1; + p->lm = -1; + strcpy(p->name,name); } return(p); } + +void send_size(size_t size, FILE *fd) { + char schar; + + if(size == -1) { + fputs(" -",fd); + bytes_sent += 5; + } + else { + if(!size) { + fputs(" 0K",fd); + bytes_sent += 5; + } + else if(size < 1024) { + fputs(" 1K",fd); + bytes_sent += 5; + } + else if(size < 1048576) + bytes_sent += fprintf(fd,"%4dK",size / 1024); + else + bytes_sent += fprintf(fd,"%4dM",size / 1048576); + } +} + + void output_directories(struct ent **ar,int n,char *name,FILE *fd) { - int x; - char blorf[MAX_STRING_LEN]; + int x,pad; + char anchor[HUGE_STRING_LEN],t[MAX_STRING_LEN],t2[MAX_STRING_LEN]; + char *tp; if(name[0] == '\0') { name[0] = '/'; name[1] = '\0'; } /* aaaaargh Solaris sucks. */ fflush(fd); + + if(dir_opts & FANCY_INDEXING) { + fputs(" ",fd); + bytes_sent += 5; + if(tp = find_icon("^^BLANKICON^^",1)) + bytes_sent += fprintf(fd,"",tp); + bytes_sent += fprintf(fd, +"Name Last modified Size Description%c
%c",LF,LF); + } + else { + fputs("",fd); + bytes_sent += 4; + } + for(x=0;x
%c",(fancy_indexing ? "DD" : "LI"),LF); - if(fancy_indexing && ((ar[x]->icon) || default_icon[0])) { - fprintf(fd," ", - ar[x]->icon ? ar[x]->icon : default_icon); - } - if(strcmp(ar[x]->name,"..")) { - make_full_path(name,ar[x]->name,blorf); - escape_url(blorf); - fprintf(fd,"%s",ar[x]->name, - blorf,ar[x]->name); + if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) { + make_full_path(name,"..",t); + getparents(t); + if(t[0] == '\0') { + t[0] = '/'; t[1] = '\0'; + } + sprintf(anchor,"",t); + strcpy(t2,"Parent Directory"); } else { - make_full_path(name,"..",blorf); - getparents(blorf); - if(blorf[0] == '\0') { - blorf[0] = '/'; blorf[1] = '\0'; + strcpy(t,ar[x]->name); + strcpy(t2,t); + if(strlen(t2) > 21) { + t2[21] = '>'; + t2[22] = '\0'; } - escape_url(blorf); - fprintf(fd,"%s",blorf,"Parent Directory"); + strcat(t2,""); + escape_url(t); + sprintf(anchor,"",t,t); } - if(fancy_indexing) { - if(ar[x]->desc) - fprintf(fd," : %s",ar[x]->desc,LF); - if(ar[x]->size != -1) - fprintf(fd," (%d bytes)",ar[x]->size); + escape_url(t); + + if(dir_opts & FANCY_INDEXING) { + if(dir_opts & ICONS_ARE_LINKS) + bytes_sent += fprintf(fd,"%s",anchor); + if((ar[x]->icon) || default_icon[0]) { + bytes_sent += fprintf(fd,"
", + ar[x]->icon ? ar[x]->icon : default_icon, + ar[x]->alt ? ar[x]->alt : " "); + } + if(dir_opts & ICONS_ARE_LINKS) { + fputs("",fd); + bytes_sent += 4; + } + bytes_sent += fprintf(fd," %s",anchor); + bytes_sent += fprintf(fd,"%-27.27s",t2); + if(ar[x]->lm != -1) { + struct tm *ts = localtime(&ar[x]->lm); + strftime(t,MAX_STRING_LEN,"%d-%h-%y %H:%M ",ts); + fputs(t,fd); + bytes_sent += strlen(t); + } + else { + fputs(" ",fd); + bytes_sent += 17; + } + send_size(ar[x]->size,fd); + fputs(" ",fd); + bytes_sent += 2; + if(ar[x]->desc) { + if(strlen(ar[x]->desc) > 23) { + ar[x]->desc[23] = '>'; + ar[x]->desc[24] = '\0'; + } + bytes_sent += fprintf(fd,"%s",ar[x]->desc); + } } + else + bytes_sent += fprintf(fd,"
- %s %s",anchor,t2); fputc(LF,fd); + ++bytes_sent; + } + if(dir_opts & FANCY_INDEXING) { + fputs("
') {
+ strcpy(tag,"done");
+ return tag;
+ }
+ }
+ }
+ /* this parser is very rigid, needs quotes around value and no spaces */
+ while(1) {
+ if(++n == MAX_STRING_LEN) {
+ t[MAX_STRING_LEN - 1] = '\0';
+ return NULL;
+ }
+ if((*t = c) == '\\') {
+ GET_CHAR(in,c,NULL);
+ *t = c;
+ } else if(*t == '=') {
+ *t++ = '\0';
+ tag_val = t;
+ GET_CHAR(in,c,NULL);
+ if(c == '\"') {
+ while(1) {
+ GET_CHAR(in,c,NULL);
+ if(++n == MAX_STRING_LEN) {
+ t[MAX_STRING_LEN - 1] = '\0';
+ return NULL;
+ }
+ if((*t = c) == '\\') {
+ GET_CHAR(in,c,NULL);
+ *t = c;
+ } else if(*t == '\"') {
+ *t = '\0';
+ return tag_val;
+ }
+ ++t;
+ }
+ } else
+ return NULL;
+ }
+ ++t;
+ GET_CHAR(in,c,NULL);
+ }
+}
+
+int get_directive(FILE *in,char *d) {
+ char c;
+
+ /* skip initial whitespace */
+ while(1) {
+ GET_CHAR(in,c,1);
+ if(!isspace(c))
+ break;
+ }
+ /* now get directive */
+ while(1) {
+ *d++ = c;
+ GET_CHAR(in,c,1);
+ if(isspace(c))
+ break;
+ }
+ *d = '\0';
+ return 0;
+}
+
+/* --------------------------- Action handlers ---------------------------- */
+
+int send_included_file(char *file, FILE *out, char *fn) {
+ FILE *f;
+ struct stat finfo;
+ int allow;char op,i;
+
+ if(stat(file,&finfo) == -1)
+ return -1;
+ evaluate_access(file,&finfo,M_GET,&allow,&op,out);
+ if(!allow)
+ return -1;
+ set_content_type(file);
+ if((op & OPT_INCLUDES) && (!strcmp(content_type,INCLUDES_MAGIC_TYPE))) {
+ send_parsed_file(file,out,"","",op & OPT_INCNOEXEC);
+ chdir_file(fn); /* grumble */
+ }
+ else if(!strcmp(content_type,CGI_MAGIC_TYPE))
+ return -1;
+ else {
+ if(!(f=fopen(file,"r")))
+ return -1;
+ send_fd(f,out,NULL);
+ fclose(f);
+ }
+ return 0;
+}
+
+int handle_include(FILE *in, FILE *out, char *fn, char *error) {
+ char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN];
+ char *tag_val;
+
+ while(1) {
+ if(!(tag_val = get_tag(in,tag)))
+ return 1;
+ if(!strcmp(tag,"file")) {
+ char dir[MAX_STRING_LEN],to_send[MAX_STRING_LEN];
+
+ getparents(tag_val); /* get rid of any nasties */
+ getwd(dir);
+ make_full_path(dir,tag_val,to_send);
+ if(send_included_file(to_send,out,fn)) {
+ sprintf(errstr,"unable to include %s in parsed file %s",
+ tag_val, fn);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ }
+ }
+ else if(!strcmp(tag,"virtual")) {
+ if(translate_name(tag_val,out) != STD_DOCUMENT) {
+ bytes_sent += fprintf(out,"%s",error);
+ log_error_noclose(errstr);
+ }
+ else if(send_included_file(tag_val,out,fn)) {
+ sprintf(errstr,"unable to include %s in parsed file %s",
+ tag_val, fn);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ }
+ }
+ else if(!strcmp(tag,"done"))
+ return 0;
+ else {
+ sprintf(errstr,"unknown parameter %s to tag echo in %s",tag,fn);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ }
+ }
+}
+
+int handle_echo(FILE *in, FILE *out, char *file, char *error, char **env) {
+ char tag[MAX_STRING_LEN];
+ char *tag_val;
+
+ while(1) {
+ if(!(tag_val = get_tag(in,tag)))
+ return 1;
+ if(!strcmp(tag,"var")) {
+ int x,i;
+
+ for(x=0;env[x] != NULL; x++) {
+ i = ind(env[x],'=');
+ if(!strncmp(env[x],tag_val,i)) {
+ bytes_sent += fprintf(out,"%s",&env[x][i+1]);
+ break;
+ }
+ }
+ if(!env[x]) bytes_sent += fprintf(out,"(none)");
+ } else if(!strcmp(tag,"done"))
+ return 0;
+ else {
+ char errstr[MAX_STRING_LEN];
+ sprintf(errstr,"unknown parameter %s to tag echo in %s",tag,file);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ }
+ }
+}
+
+int include_cgi(char *s, char *pargs, char *args, char **env, FILE *out)
+{
+ char *argp,op,d[HUGE_STRING_LEN];
+ int allow,check_cgiopt;
+ struct stat finfo;
+
+ getparents(s);
+ if(s[0] == '/') {
+ strcpy(d,s);
+ if(translate_name(d,out) != SCRIPT_CGI)
+ return -1;
+ check_cgiopt=0;
+ } else {
+ char dir[MAX_STRING_LEN];
+ getwd(dir);
+ make_full_path(dir,s,d);
+ check_cgiopt=1;
+ }
+ /* No hardwired path info or query allowed */
+ if(stat(d,&finfo) == -1)
+ return -1;
+
+ evaluate_access(d,&finfo,M_GET,&allow,&op,out);
+ if((!allow) || (check_cgiopt && (!(op & OPT_EXECCGI))))
+ return -1;
+
+ if(cgi_stub("GET",d,pargs,args,env,&finfo,-1,out) == REDIRECT_URL)
+ bytes_sent += fprintf(out,"%s",location,location);
+ return 0;
+}
+
+static int ipid;
+void kill_include_child() {
+ char errstr[MAX_STRING_LEN];
+ sprintf(errstr,"killing command process %d",ipid);
+ log_error_noclose(errstr);
+ kill(ipid,SIGKILL);
+ waitpid(ipid,NULL,0);
+}
+
+int include_cmd(char *s, char *pargs, char *args, char **env, FILE *out) {
+ int p[2],x;
+ FILE *f;
+
+ if(pipe(p) == -1)
+ die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
+ if((ipid = fork()) == -1)
+ die(SERVER_ERROR,"httpd: could not fork new process",out);
+ if(!ipid) {
+ char *argv0;
+
+ if(pargs[0] || args[0]) {
+ if(!(env = new_env(env,4,&x)))
+ return -1;
+ if(pargs[0]) {
+ char p2[HUGE_STRING_LEN];
+
+ escape_shell_cmd(pargs);
+ env[x++] = make_env_str("PATH_INFO",pargs,out);
+ strcpy(p2,pargs);
+ translate_name(p2,out);
+ env[x++] = make_env_str("PATH_TRANSLATED",p2,out);
+ }
+ if(args[0]) {
+ env[x++] = make_env_str("QUERY_STRING",args,out);
+ unescape_url(args);
+ escape_shell_cmd(args);
+ env[x++] = make_env_str("QUERY_STRING_UNESCAPED",args,out);
+ }
+ env[x] = NULL;
+ }
+
+ close(p[0]);
+ if(p[1] != STDOUT_FILENO) {
+ dup2(p[1],STDOUT_FILENO);
+ close(p[1]);
+ }
+ error_log2stderr();
+ if(!(argv0 = strrchr(SHELL_PATH,'/')))
+ argv0=SHELL_PATH;
+ if(execle(SHELL_PATH,argv0,"-c",s,(char *)0,env) == -1) {
+ fprintf(stderr,"httpd: exec of %s failed, errno is %d\n",
+ SHELL_PATH,errno);
+ exit(1);
+ }
+ }
+ close(p[1]);
+ if(!(f=fdopen(p[0],"r"))) {
+ waitpid(ipid,NULL,0);
+ return -1;
+ }
+ send_fd(f,out,kill_include_child);
+ fclose(f);
+ waitpid(ipid,NULL,0);
+ return 0;
+}
+
+
+int handle_exec(FILE *in, FILE *out, char *file, char *path_args, char *args,
+ char *error, char **env)
+{
+ char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN];
+ char *tag_val;
+
+ while(1) {
+ if(!(tag_val = get_tag(in,tag)))
+ return 1;
+ if(!strcmp(tag,"cmd")) {
+ if(include_cmd(tag_val,path_args,args,env,out) == -1) {
+ sprintf(errstr,"invalid command exec %s in %s",tag_val,file);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ }
+ /* just in case some stooge changed directories */
+ chdir_file(file);
+ }
+ else if(!strcmp(tag,"cgi")) {
+ if(include_cgi(tag_val,path_args,args,env,out) == -1) {
+ sprintf(errstr,"invalid CGI ref %s in %s",tag_val,file);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ }
+ /* grumble groan */
+ chdir_file(file);
+ }
+ else if(!strcmp(tag,"done"))
+ return 0;
+ else {
+ char errstr[MAX_STRING_LEN];
+ sprintf(errstr,"unknown parameter %s to tag echo in %s",tag,file);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ }
+ }
+
+}
+
+int handle_config(FILE *in, FILE *out, char *file, char *error, char *tf,
+ int *sizefmt, char **env) {
+ char tag[MAX_STRING_LEN];
+ char *tag_val;
+
+ while(1) {
+ if(!(tag_val = get_tag(in,tag)))
+ return 1;
+ if(!strcmp(tag,"errmsg"))
+ strcpy(error,tag_val);
+ else if(!strcmp(tag,"timefmt")) {
+ strcpy(tf,tag_val);
+ /* Replace DATE* and LAST_MODIFIED (they should be first) */
+ free(env[0]);
+ env[0] = make_env_str("DATE_LOCAL",ht_time(date,tf,0),out);
+ free(env[1]);
+ env[1] = make_env_str("DATE_GMT",ht_time(date,tf,1),out);
+ if(!strncmp(env[2],"LAST_MODIFIED",13)) {
+ free(env[2]);
+ env[2] = make_env_str("LAST_MODIFIED",ht_time(lm,tf,1),out);
+ }
+ }
+ else if(!strcmp(tag,"sizefmt")) {
+ if(!strcmp(tag_val,"bytes"))
+ *sizefmt = SIZEFMT_BYTES;
+ else if(!strcmp(tag_val,"abbrev"))
+ *sizefmt = SIZEFMT_KMG;
+ }
+ else if(!strcmp(tag,"done"))
+ return 0;
+ else {
+ char errstr[MAX_STRING_LEN];
+ sprintf(errstr,"unknown parameter %s to tag config in %s",
+ tag,file);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ }
+ }
+}
+
+
+
+int find_file(FILE *out, char *file, char *directive, char *tag,
+ char *tag_val, struct stat *finfo, char *error)
+{
+ char errstr[MAX_STRING_LEN], dir[MAX_STRING_LEN], to_send[MAX_STRING_LEN];
+
+ if(!strcmp(tag,"file")) {
+ getparents(tag_val); /* get rid of any nasties */
+ getwd(dir);
+ make_full_path(dir,tag_val,to_send);
+ if(stat(to_send,finfo) == -1) {
+ sprintf(errstr,
+ "unable to get information about %s in parsed file %s",
+ to_send,file);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ return -1;
+ }
+ return 0;
+ }
+ else if(!strcmp(tag,"virtual")) {
+ if(translate_name(tag_val,out) != STD_DOCUMENT) {
+ bytes_sent += fprintf(out,"%s",error);
+ log_error_noclose(errstr);
+ }
+ else if(stat(tag_val,finfo) == -1) {
+ sprintf(errstr,
+ "unable to get information about %s in parsed file %s",
+ to_send,file);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ return -1;
+ }
+ return 0;
+ }
+ else {
+ sprintf(errstr,"unknown parameter %s to tag %s in %s",
+ tag,directive,file);
+ log_error_noclose(errstr);
+ bytes_sent += fprintf(out,"%s",error);
+ return -1;
+ }
+}
+
+
+int handle_fsize(FILE *in, FILE *out, char *file, char *error, int sizefmt,
+ char **env)
+{
+ char tag[MAX_STRING_LEN];
+ char *tag_val;
+ struct stat finfo;
+
+ while(1) {
+ if(!(tag_val = get_tag(in,tag)))
+ return 1;
+ else if(!strcmp(tag,"done"))
+ return 0;
+ else if(!find_file(out,file,"fsize",tag,tag_val,&finfo,error)) {
+ if(sizefmt == SIZEFMT_KMG) {
+ send_size(finfo.st_size,out);
+ bytes_sent += 5;
+ }
+ else {
+ int l,x;
+ sprintf(tag,"%ld",finfo.st_size);
+ l = strlen(tag); /* grrr */
+ for(x=0;x %c",
err_string,LF);
break;
+ case USE_LOCAL_COPY:
+ status = USE_LOCAL_COPY;
+ begin_http_header(fd,"304 Not modified");
+ fputc(LF,fd);
+ header_only = 1;
+ break;
case AUTH_REQUIRED:
+ status = 401;
if(!assbackwards) {
begin_http_header(fd,"401 Unauthorized");
+ fprintf(fd,"Content-type: text/html%c",LF);
fprintf(fd,"WWW-Authenticate: %s%c%c",err_string,LF,LF);
}
if(header_only) break;
@@ -117,6 +185,7 @@ void die(int type, char *err_string, FILE *fd) {
fprintf(fd,"authentication failed.%c",LF);
break;
case BAD_REQUEST:
+ status = 400;
error_head(fd,"400 Bad Request");
if(header_only) break;
fprintf(fd,"Your client sent a query that this server could not%c",LF);
@@ -124,6 +193,7 @@ void die(int type, char *err_string, FILE *fd) {
fprintf(fd,"Reason: %s %c",err_string,LF);
break;
case FORBIDDEN:
+ status = 403;
error_head(fd,"403 Forbidden");
if(header_only) break;
fprintf(fd,"Your client does not have permission to get URL %s ",
@@ -131,12 +201,14 @@ void die(int type, char *err_string, FILE *fd) {
fprintf(fd,"from this server. %c",LF);
break;
case NOT_FOUND:
+ status = 404;
error_head(fd,"404 Not Found");
if(header_only) break;
fprintf(fd,"The requested URL %s was not found on this server. %c",
err_string,LF);
break;
case SERVER_ERROR:
+ status = 500;
error_head(fd,"500 Server Error");
log_error(err_string);
if(header_only)
@@ -150,16 +222,8 @@ void die(int type, char *err_string, FILE *fd) {
fprintf(fd,"anything you might have done that may have caused%c",LF);
fprintf(fd,"the error. %c",LF);
break;
- case INCLUDE_ERROR:
-/* error_head(fd,"500 Server Error"); */
- log_error(err_string);
- if(header_only) break;
- fprintf(fd,"[we're sorry, the following error has occurred: %s]%c",
- err_string,LF);
- fflush(fd);
- htexit(1,fd);
- break;
case NOT_IMPLEMENTED:
+ status = 501;
error_head(fd,"501 Not Implemented");
if(header_only) break;
fprintf(fd,"We are sorry to be unable to perform the method %s",
@@ -171,9 +235,18 @@ void die(int type, char *err_string, FILE *fd) {
SERVER_VERSION,LF);
fprintf(fd,"to %c",SERVER_SUPPORT,LF);
break;
+ case NO_MEMORY:
+ log_error("httpd: memory exhausted");
+ status = 500;
+ error_head(fd,"500 Server Error");
+ if(header_only) break;
+ fprintf(fd,"The server has temporarily run out of resources for%c",LF);
+ fprintf(fd,"your request. Please try again at a later time. %c",LF);
+ break;
}
if(!header_only)
fprintf(fd,"