From 121d8be9d4bdeea6a083d9bf791677e9150e6324 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Sun, 29 Aug 2010 23:37:23 +0200 Subject: [PATCH] Added a htls program for directory listings. --- lib/resp.h | 1 + src/.gitignore | 1 + src/Makefile.am | 2 +- src/htls.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 src/htls.c diff --git a/lib/resp.h b/lib/resp.h index 00f1872..4578b03 100644 --- a/lib/resp.h +++ b/lib/resp.h @@ -3,6 +3,7 @@ #include +char *htmlquote(char *text); void simpleerror(int fd, int code, char *msg, char *fmt, ...); void stdredir(struct hthead *req, int fd, int code, char *dst); char *fmthttpdate(time_t time); diff --git a/src/.gitignore b/src/.gitignore index 4179187..98d71b8 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -5,3 +5,4 @@ /callcgi /patplex /userplex +/htls diff --git a/src/Makefile.am b/src/Makefile.am index fd9c71d..32e50fb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -bin_PROGRAMS = htparser dirplex sendfile callcgi patplex userplex +bin_PROGRAMS = htparser dirplex sendfile callcgi patplex userplex htls noinst_PROGRAMS = debugsink htparser_SOURCES = htparser.c htparser.h plaintcp.c diff --git a/src/htls.c b/src/htls.c new file mode 100644 index 0000000..e16004d --- /dev/null +++ b/src/htls.c @@ -0,0 +1,213 @@ +/* + ashd - A Sane HTTP Daemon + Copyright (C) 2008 Fredrik Tolf + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include + +struct dentry { + char *name; + struct stat sb; + int w, x; +}; + +static int dispmtime = 0; +static int dispsize = 0; + +static void checkcache(struct stat *sb) +{ + char *hdr; + + if((hdr = getenv("REQ_IF_MODIFIED_SINCE")) != NULL) { + if(parsehttpdate(hdr) < sb->st_mtime) + return; + printf("HTTP/1.1 304 Not Modified\n"); + printf("Date: %s\n", fmthttpdate(time(NULL))); + printf("Content-Length: 0\n"); + printf("\n"); + exit(0); + } +} + +static int dcmp(const void *ap, const void *bp) +{ + const struct dentry *a = ap, *b = bp; + + if(S_ISDIR(a->sb.st_mode) && !S_ISDIR(b->sb.st_mode)) + return(-1); + if(!S_ISDIR(a->sb.st_mode) && S_ISDIR(b->sb.st_mode)) + return(1); + return(strcoll(a->name, b->name)); +} + +static void head(char *name, struct charbuf *dst) +{ + char *title; + + bprintf(dst, "\n"); + bprintf(dst, "\n"); + bprintf(dst, "\n"); + bprintf(dst, "\n"); + title = htmlquote(name); + bprintf(dst, "Index of %s\n", title); + bprintf(dst, "\n"); + bprintf(dst, "\n"); + bprintf(dst, "

Index of %s

\n", title); + free(title); +} + +static void foot(struct charbuf *dst) +{ + bprintf(dst, "\n"); + bprintf(dst, "\n"); +} + +static void mkindex(char *name, DIR *dir, struct charbuf *dst) +{ + struct { + struct dentry *b; + size_t s, d; + } dirbuf; + struct dentry f; + struct dirent *dent; + char *fn; + int i; + + bufinit(dirbuf); + while((dent = readdir(dir)) != NULL) { + if(*dent->d_name == '.') + continue; + memset(&f, 0, sizeof(f)); + f.name = sstrdup(dent->d_name); + fn = sprintf3("%s/%s", name, dent->d_name); + if(access(fn, R_OK)) + continue; + if(stat(fn, &f.sb)) + continue; + if(!access(fn, W_OK)) + f.w = 1; + if(!access(fn, X_OK)) + f.x = 1; + else if(S_ISDIR(f.sb.st_mode)) + continue; + bufadd(dirbuf, f); + } + qsort(dirbuf.b, dirbuf.d, sizeof(struct dentry), dcmp); + bprintf(dst, "\n"); + for(i = 0; i < dirbuf.d; i++) { + bprintf(dst, ""); + fn = htmlquote(dirbuf.b[i].name); + bprintf(dst, "", fn, fn); + free(fn); + if(dispsize && !S_ISDIR(dirbuf.b[i].sb.st_mode)) + bprintf(dst, "", (intmax_t)dirbuf.b[i].sb.st_size); + if(dispmtime) + bprintf(dst, "", fmthttpdate(dirbuf.b[i].sb.st_mtime)); + bprintf(dst, "\n"); + free(dirbuf.b[i].name); + } + bprintf(dst, "
%s%ji%s
\n"); +} + +static void usage(void) +{ + flog(LOG_ERR, "usage: htls [-hms] METHOD URL REST"); +} + +int main(int argc, char **argv) +{ + int c; + char *dname; + DIR *dir; + struct charbuf buf; + struct stat sb; + + setlocale(LC_ALL, ""); + while((c = getopt(argc, argv, "hms")) >= 0) { + switch(c) { + case 'h': + usage(); + exit(0); + case 'm': + dispmtime = 1; + break; + case 's': + dispsize = 1; + break; + default: + usage(); + exit(1); + } + } + if(argc - optind < 3) { + usage(); + exit(1); + } + if((dname = getenv("REQ_X_ASH_FILE")) == NULL) { + flog(LOG_ERR, "htls: needs to be called with the X-Ash-File header"); + exit(1); + } + if(*argv[optind + 2]) { + simpleerror(1, 404, "Not Found", "The requested URL has no corresponding resource."); + exit(0); + } + + if(stat(dname, &sb) || ((dir = opendir(dname)) == NULL)) { + flog(LOG_ERR, "htls: could not open directory `%s': %s", dname, strerror(errno)); + simpleerror(1, 500, "Server Error", "Could not produce directory index."); + exit(1); + } + checkcache(&sb); + + bufinit(buf); + head(argv[optind + 1], &buf); + mkindex(dname, dir, &buf); + foot(&buf); + closedir(dir); + + printf("HTTP/1.1 200 OK\n"); + printf("Content-Type: text/html; charset=UTF-8\n"); + printf("Last-Modified: %s\n", fmthttpdate(sb.st_mtime)); + printf("Content-Length: %zi\n", buf.d); + printf("\n"); + fwrite(buf.b, 1, buf.d, stdout); + buffree(buf); + return(0); +} -- 2.11.0