2 ashd - A Sane HTTP Daemon
3 Copyright (C) 2008 Fredrik Tolf <fredrik@dolda2000.com>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
44 static int dispmtime = 0;
45 static int dispsize = 0;
47 static void checkcache(struct stat *sb)
51 if((hdr = getenv("REQ_IF_MODIFIED_SINCE")) != NULL) {
52 if(parsehttpdate(hdr) < sb->st_mtime)
54 printf("HTTP/1.1 304 Not Modified\n");
55 printf("Date: %s\n", fmthttpdate(time(NULL)));
56 printf("Content-Length: 0\n");
62 static int dcmp(const void *ap, const void *bp)
64 const struct dentry *a = ap, *b = bp;
66 if(S_ISDIR(a->sb.st_mode) && !S_ISDIR(b->sb.st_mode))
68 if(!S_ISDIR(a->sb.st_mode) && S_ISDIR(b->sb.st_mode))
70 return(strcoll(a->name, b->name));
73 static void head(char *name, struct charbuf *dst)
77 bprintf(dst, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
78 bprintf(dst, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n");
79 bprintf(dst, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n");
80 bprintf(dst, "<head>\n");
81 title = htmlquote(name);
82 bprintf(dst, "<title>Index of %s</title>\n", title);
83 bprintf(dst, "</head>\n");
84 bprintf(dst, "<body>\n");
85 bprintf(dst, "<h1>Index of %s</h1>\n", title);
89 static void foot(struct charbuf *dst)
91 bprintf(dst, "</body>\n");
92 bprintf(dst, "</html>\n");
95 static void mkindex(char *name, DIR *dir, struct charbuf *dst)
107 while((dent = readdir(dir)) != NULL) {
108 if(*dent->d_name == '.')
110 memset(&f, 0, sizeof(f));
111 f.name = sstrdup(dent->d_name);
112 fn = sprintf3("%s/%s", name, dent->d_name);
117 if(!access(fn, W_OK))
119 if(!access(fn, X_OK))
121 else if(S_ISDIR(f.sb.st_mode))
125 qsort(dirbuf.b, dirbuf.d, sizeof(struct dentry), dcmp);
126 bprintf(dst, "<table class=\"dirindex\">\n");
127 for(i = 0; i < dirbuf.d; i++) {
128 bprintf(dst, "<tr class=\"dentry");
129 if(S_ISDIR(dirbuf.b[i].sb.st_mode))
130 bprintf(dst, " dir");
132 bprintf(dst, " writable");
134 bprintf(dst, " exec");
136 fn = htmlquote(dirbuf.b[i].name);
137 bprintf(dst, "<td class=\"filename\"><a href=\"%s\">%s</a></td>", fn, fn);
139 if(dispsize && !S_ISDIR(dirbuf.b[i].sb.st_mode))
140 bprintf(dst, "<td class=\"filesize\">%ji</td>", (intmax_t)dirbuf.b[i].sb.st_size);
142 bprintf(dst, "<td class=\"filemtime\">%s</td>", fmthttpdate(dirbuf.b[i].sb.st_mtime));
143 bprintf(dst, "</tr>\n");
144 free(dirbuf.b[i].name);
146 bprintf(dst, "</table>\n");
149 static void usage(void)
151 flog(LOG_ERR, "usage: htls [-hms] METHOD URL REST");
154 int main(int argc, char **argv)
162 setlocale(LC_ALL, "");
163 while((c = getopt(argc, argv, "hms")) >= 0) {
179 if(argc - optind < 3) {
183 if((dname = getenv("REQ_X_ASH_FILE")) == NULL) {
184 flog(LOG_ERR, "htls: needs to be called with the X-Ash-File header");
187 if(*argv[optind + 2]) {
188 simpleerror(1, 404, "Not Found", "The requested URL has no corresponding resource.");
192 if(stat(dname, &sb) || ((dir = opendir(dname)) == NULL)) {
193 flog(LOG_ERR, "htls: could not open directory `%s': %s", dname, strerror(errno));
194 simpleerror(1, 500, "Server Error", "Could not produce directory index.");
200 head(argv[optind + 1], &buf);
201 mkindex(dname, dir, &buf);
205 printf("HTTP/1.1 200 OK\n");
206 printf("Content-Type: text/html; charset=UTF-8\n");
207 printf("Last-Modified: %s\n", fmthttpdate(sb.st_mtime));
208 printf("Content-Length: %zi\n", buf.d);
210 fwrite(buf.b, 1, buf.d, stdout);