This is http_dir.c in view mode; [Download] [Up]
/************************************************************************ * NCSA HTTPd Server * Software Development Group * National Center for Supercomputing Applications * University of Illinois at Urbana-Champaign * 605 E. Springfield, Champaign, IL 61820 * httpd@ncsa.uiuc.edu * * Copyright (C) 1995, Board of Trustees of the University of Illinois * ************************************************************************ * * http_dir.c: Handles the on-the-fly html index generation * * 03-23-93 Rob McCool * Wrote base code up to release 1.3 * * 03-12-95 blong * Added patch by Roy T. Fielding <fielding@avron.ICS.UCI.EDU> * to fix missing trailing slash for parent directory */ #include "config.h" #include "portability.h" #include <stdio.h> #ifndef NO_STDLIB_H # include <stdlib.h> #endif /* NO_STDLIB_H */ #ifndef NO_MALLOC_H # ifdef NEED_SYS_MALLOC_H # include <sys/malloc.h> # else # include <malloc.h> # endif /* NEED_SYS_MALLOC_H */ #endif /* NO_MALLOC_H */ #include <string.h> #include <time.h> #include <sys/stat.h> #include <sys/types.h> #include <ctype.h> #include <dirent.h> #include "constants.h" #include "http_dir.h" #include "http_mime.h" #include "http_log.h" #include "http_config.h" #include "http_request.h" #include "http_send.h" #include "http_alias.h" #include "util.h" #include "fdwrap.h" 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->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); } } 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); } struct item *new_item(per_request *reqInfo,int type, char *to, char *path, char *data) { struct item *p; if(!(p = (struct item *)malloc(sizeof(struct item)))) die(reqInfo,SC_NO_MEMORY,"new_item"); p->type = type; if(data) { if(!(p->data = strdup(data))) die(reqInfo,SC_NO_MEMORY,"new_item"); } else p->data = NULL; if(to) { if(!(p->apply_to = (char *)malloc(strlen(to) + 2))) die(reqInfo,SC_NO_MEMORY,"new_item"); 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(reqInfo,SC_NO_MEMORY,"new_item"); sprintf(p->apply_path,"%s*",path); return p; } void add_alt(per_request *reqInfo, int type, char *alt, char *to, char *path) { struct item *p; if(type == BY_PATH) { if(!strcmp(to,"**DIRECTORY**")) strcpy(to,"^^DIRECTORY^^"); } p = new_item(reqInfo,type,to,path,alt); p->next = alt_list; alt_list = p; } void add_icon(per_request *reqInfo, int type, char *icon, char *to, char *path) { struct item *p; char iconbak[MAX_STRING_LEN]; strcpy(iconbak,icon); if(icon[0] == '(') { char alt[MAX_STRING_LEN]; getword(alt,iconbak,','); add_alt(reqInfo,type,&alt[1],to,path); iconbak[strlen(iconbak) - 1] = '\0'; } if(type == BY_PATH) { if(!strcmp(to,"**DIRECTORY**")) strcpy(to,"^^DIRECTORY^^"); } p = new_item(reqInfo,type,to,path,iconbak); p->next = icon_list; icon_list = p; } void add_desc(per_request *reqInfo, int type, char *desc, char *to, char *path) { struct item *p; p = new_item(reqInfo,type,to,path,desc); p->next = desc_list; desc_list = p; } void add_ignore(per_request *reqInfo,char *ext, char *path) { struct item *p; p = new_item(reqInfo,0,ext,path,NULL); p->next = ign_list; ign_list = p; } void add_header(per_request *reqInfo, char *name, char *path) { struct item *p; p = new_item(reqInfo,0,NULL,path,name); p->next = hdr_list; hdr_list = p; } void add_readme(per_request *reqInfo,char *name, char *path) { struct item *p; p = new_item(reqInfo,0,NULL,path,name); p->next = rdme_list; rdme_list = p; } void add_opts_int(per_request *reqInfo, int opts, char *path) { struct item *p; p = new_item(reqInfo,0,NULL,path,NULL); p->type = opts; p->next = opts_list; opts_list = p; } void add_opts(per_request *reqInfo, char *optstr, char *path) { 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,"SuppressLastModified")) opts |= SUPPRESS_LAST_MOD; else if(!strcasecmp(w,"SuppressSize")) opts |= SUPPRESS_SIZE; else if(!strcasecmp(w,"SuppressDescription")) opts |= SUPPRESS_DESC; else if(!strcasecmp(w,"None")) opts = 0; } add_opts_int(reqInfo,opts,path); } char *find_item(per_request *reqInfo, struct item *list, char *path, int path_only) { struct item *p = list; while(p) { /* 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(reqInfo,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; } #define find_icon(r,p,t) find_item(r,icon_list,p,t) #define find_alt(r,p,t) find_item(r,alt_list,p,t) #define find_desc(r,p) find_item(r,desc_list,p,0) #define find_header(r,p) find_item(r,hdr_list,p,0) #define find_readme(r,p) find_item(r,rdme_list,p,0) int ignore_entry(char *path) { struct item *p = ign_list; while(p) { if(!strcmp_match(path,p->apply_path)) if(!strcmp_match(path,p->apply_to)) return 1; p = p->next; } return 0; } 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(per_request *reqInfo, char *name, char *readme_fname, int rule) { char fn[MAX_STRING_LEN]; FILE *r; struct stat finfo; int plaintext=0; 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 0; plaintext=1; if(rule) reqInfo->bytes_sent += fprintf(reqInfo->out,"<HR>%c",LF); reqInfo->bytes_sent += fprintf(reqInfo->out,"<PRE>%c",LF); } else if(rule) reqInfo->bytes_sent += fprintf(reqInfo->out,"<HR>%c",LF); if(!(r = FOpen(fn,"r"))) return 0; send_fp(reqInfo,r,NULL); FClose(r); if(plaintext) reqInfo->bytes_sent += fprintf(reqInfo->out,"</PRE>%c",LF); return 1; } char *find_title(per_request *reqInfo, char *filename) { char titlebuf[MAX_STRING_LEN], *find = "<TITLE>"; char filebak[MAX_STRING_LEN]; FILE *thefile; int x,y,n,p; content_encoding[0] = '\0'; strcpy(filebak,filename); set_content_type(reqInfo,filebak); if(((!strcmp(content_type,"text/html")) || (strcmp(content_type, INCLUDES_MAGIC_TYPE) == 0)) && (!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(toupper(titlebuf[x]) == find[p]) { if(!find[++p]) { if((p = ind(&titlebuf[++x],'<')) != -1) titlebuf[x+p] = '\0'; /* Scan for line breaks for Tanmoy's secretary */ for(y=x;titlebuf[y];y++) if((titlebuf[y] == CR) || (titlebuf[y] == LF)) titlebuf[y] = ' '; FClose(thefile); return strdup(&titlebuf[x]); } } else p=0; } FClose(thefile); return NULL; } content_encoding[0] = '\0'; return NULL; } void escape_html(char *fn) { register int x,y; char copy[MAX_STRING_LEN]; strcpy(copy,fn); for(x=0,y=0;copy[y];x++,y++) { if(copy[y] == '<') { strcpy(&fn[x],"<"); x+=3; } else if(copy[y] == '>') { strcpy(&fn[x],">"); x+=3; } else if(copy[y] == '&') { strcpy(&fn[x],"&"); x+=4; } else fn[x] = copy[y]; } fn[x] = '\0'; } struct ent *make_dir_entry(per_request *reqInfo, char *path, char *name) { struct ent *p; struct stat finfo; char t[MAX_STRING_LEN]; char *tmp; 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(reqInfo,SC_NO_MEMORY,"make_dir_entry"); if(!(p->name=(char *)malloc(strlen(name) + 2))) die(reqInfo,SC_NO_MEMORY,"make_dir_entry"); if(dir_opts & FANCY_INDEXING) { if((!(dir_opts & FANCY_INDEXING)) || stat(t,&finfo) == -1) { strcpy(p->name,name); p->size = -1; p->icon = NULL; p->alt = NULL; p->desc = NULL; p->lm = -1; } else { p->lm = finfo.st_mtime; p->size = -1; p->icon = NULL; p->alt = NULL; p->desc = NULL; if(S_ISDIR(finfo.st_mode)) { if(!(p->icon = find_icon(reqInfo,t,1))) if (p->icon != NULL) free(p->icon); p->icon = find_icon(reqInfo,"^^DIRECTORY^^",1); if(!(tmp = find_alt(reqInfo,t,1))){ p->alt = (char *) malloc(sizeof(char)*4); strcpy(p->alt,"DIR"); } else { p->alt = strdup(tmp); } p->size = -1; strncpy_dir(p->name,name, MAX_STRING_LEN); } else { p->icon = find_icon(reqInfo,t,0); tmp = find_alt(reqInfo,t,0); if (tmp != NULL) p->alt = strdup(tmp); p->size = finfo.st_size; strcpy(p->name,name); } } if((p->desc = find_desc(reqInfo,t))) p->desc = strdup(p->desc); if((!p->desc) && (dir_opts & SCAN_HTML_TITLES)) p->desc = find_title(reqInfo,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(per_request *reqInfo, size_t size) { if(size == -1) { fputs(" -",reqInfo->out); reqInfo->bytes_sent += 5; } else { if(!size) { fputs(" 0K",reqInfo->out); reqInfo->bytes_sent += 5; } else if(size < 1024) { fputs(" 1K",reqInfo->out); reqInfo->bytes_sent += 5; } else if(size < 1048576) reqInfo->bytes_sent += fprintf(reqInfo->out,"%4dK",size / 1024); else reqInfo->bytes_sent += fprintf(reqInfo->out,"%4dM",size / 1048576); } } void terminate_description(char *desc) { int maxsize = 23; register int x; if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17; if(dir_opts & SUPPRESS_SIZE) maxsize += 7; for(x=0;desc[x] && maxsize;x++) { if(desc[x] == '<') { while(desc[x] != '>') { if(!desc[x]) { maxsize = 0; break; } ++x; } } else --maxsize; } if(!maxsize) { desc[x] = '>'; desc[x+1] = '\0'; } } void output_directories(per_request *reqInfo, struct ent **ar,int n,char *name) { int x; char anchor[2 * MAX_STRING_LEN + 64],t[MAX_STRING_LEN],t2[MAX_STRING_LEN]; char *tp; if(name[0] == '\0') { name[0] = '/'; name[1] = '\0'; } /* aaaaargh Solaris sucks. */ fflush(reqInfo->out); if(dir_opts & FANCY_INDEXING) { fputs("<PRE>",reqInfo->out); (reqInfo->bytes_sent) += 5; if((tp = find_icon(reqInfo,"^^BLANKICON^^",1))) reqInfo->bytes_sent += (fprintf(reqInfo->out, "<IMG SRC=\"%s\" ALT=\" \"> ",tp)); reqInfo->bytes_sent += fprintf(reqInfo->out,"Name "); if(!(dir_opts & SUPPRESS_LAST_MOD)) reqInfo->bytes_sent += fprintf(reqInfo->out,"Last modified "); if(!(dir_opts & SUPPRESS_SIZE)) reqInfo->bytes_sent += fprintf(reqInfo->out,"Size "); if(!(dir_opts & SUPPRESS_DESC)) reqInfo->bytes_sent += fprintf(reqInfo->out,"Description"); reqInfo->bytes_sent += fprintf(reqInfo->out,"%c<HR>%c",LF,LF); } else { fputs("<UL>",reqInfo->out); reqInfo->bytes_sent += 4; } for(x=0;x<n;x++) { if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) { /* Fixes trailing slash for fancy indexing. Thanks Roy ? */ make_full_path(name,"../",t); getparents(t); if(t[0] == '\0') { t[0] = '/'; t[1] = '\0'; } escape_uri(t); sprintf(anchor,"<A HREF=\"%s\">",t); strcpy(t2,"Parent Directory</A>"); } else { lim_strcpy(t,ar[x]->name, MAX_STRING_LEN); strcpy(t2,t); if(strlen(t2) > 21) { t2[21] = '>'; t2[22] = '\0'; } /* screws up formatting, but some need it. should fix. */ /* escape_html(t2); */ strcat(t2,"</A>"); escape_uri(t); sprintf(anchor,"<A NAME=\"%s\" HREF=\"%s\">",t,t); } escape_url(t); if(dir_opts & FANCY_INDEXING) { if(dir_opts & ICONS_ARE_LINKS) reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",anchor); if((ar[x]->icon) || reqInfo->hostInfo->default_icon[0] || local_default_icon[0]) { reqInfo->bytes_sent += fprintf(reqInfo->out, "<IMG SRC=\"%s\" ALT=\"[%s]\">", ar[x]->icon ? ar[x]->icon : local_default_icon[0] ? local_default_icon : reqInfo->hostInfo->default_icon, ar[x]->alt ? ar[x]->alt : " "); } if(dir_opts & ICONS_ARE_LINKS) { fputs("</A>",reqInfo->out); reqInfo->bytes_sent += 4; } reqInfo->bytes_sent += fprintf(reqInfo->out," %s",anchor); reqInfo->bytes_sent += fprintf(reqInfo->out,"%-27.27s",t2); if(!(dir_opts & SUPPRESS_LAST_MOD)) { if(ar[x]->lm != -1) { struct tm *ts = localtime(&ar[x]->lm); strftime(t,MAX_STRING_LEN,"%d-%b-%y %H:%M ",ts); fputs(t,reqInfo->out); reqInfo->bytes_sent += strlen(t); } else { fputs(" ",reqInfo->out); reqInfo->bytes_sent += 17; } } if(!(dir_opts & SUPPRESS_SIZE)) { send_size(reqInfo,ar[x]->size); fputs(" ",reqInfo->out); reqInfo->bytes_sent += 2; } if(!(dir_opts & SUPPRESS_DESC)) { if(ar[x]->desc) { terminate_description(ar[x]->desc); reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",ar[x]->desc); } } } else reqInfo->bytes_sent += fprintf(reqInfo->out,"<LI> %s %s",anchor,t2); fputc(LF,reqInfo->out); ++(reqInfo->bytes_sent); } if(dir_opts & FANCY_INDEXING) { fputs("</PRE>",reqInfo->out); reqInfo->bytes_sent += 6; } else { fputs("</UL>",reqInfo->out); reqInfo->bytes_sent += 5; } } int dsortf(struct ent **s1,struct ent **s2) { return(strcmp((*s1)->name,(*s2)->name)); } void index_directory(per_request *reqInfo) { DIR *d; struct DIR_TYPE *dstruct; int num_ent=0,x; struct ent *head,*p,*q; struct ent **ar; char *tmp; if(!(d=Opendir(reqInfo->filename))) die(reqInfo,SC_FORBIDDEN,reqInfo->url); strcpy(content_type,"text/html"); if(!no_headers) send_http_header(reqInfo); if(header_only) { Closedir(d); return; } reqInfo->bytes_sent = 0; dir_opts = find_opts(reqInfo->filename); /* Spew HTML preamble */ reqInfo->bytes_sent += fprintf(reqInfo->out, "<HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>", reqInfo->url); fputc(LF,reqInfo->out); ++(reqInfo->bytes_sent); if((!(tmp = find_header(reqInfo, reqInfo->filename))) || (!(insert_readme(reqInfo,reqInfo->filename,tmp,0)))) reqInfo->bytes_sent += fprintf(reqInfo->out, "<H1>Index of %s</H1>%c",reqInfo->url,LF); /* * Since we don't know how many dir. entries there are, put them into a * linked list and then arrayificate them so qsort can use them. */ head=NULL; while((dstruct=readdir(d))) { if((p = make_dir_entry(reqInfo,reqInfo->filename,dstruct->d_name))) { p->next = head; head = p; num_ent++; } } if(!(ar=(struct ent **) malloc(num_ent*sizeof(struct ent *)))) { Closedir(d); die(reqInfo,SC_NO_MEMORY,"index_directory"); } p=head; x=0; while(p) { ar[x++]=p; p = p->next; } qsort((void *)ar,num_ent,sizeof(struct ent *), #ifdef ULTRIX_BRAIN_DEATH (int (*))dsortf); #else (int (*)(const void *,const void *))dsortf); #endif /* ULTRIX_BRAIN_DEATH */ output_directories(reqInfo,ar,num_ent,reqInfo->url); free(ar); q = head; while(q) { p=q->next; free(q->name); if(q->desc) free(q->desc); if(q->alt) free(q->alt); free(q); q=p; } Closedir(d); if(dir_opts & FANCY_INDEXING) if((tmp = find_readme(reqInfo,reqInfo->filename))) insert_readme(reqInfo,reqInfo->filename,tmp,1); else { fputs("</UL>",reqInfo->out); reqInfo->bytes_sent += 5; } fputs("</BODY>", reqInfo->out); fflush(reqInfo->out); reqInfo->bytes_sent += 7; fflush(reqInfo->out); log_transaction(reqInfo); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.