Initial commit.
[statserve.git] / statserve.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <ashd/req.h>
7 #include <ashd/resp.h>
8 #include <ashd/log.h>
9 #include <ashd/mt.h>
10 #include <ashd/mtio.h>
11
12 #include "statserve.h"
13
14 static struct source *sources = NULL;
15
16 static struct source *parsesource(char *arg)
17 {
18     if(arg[strlen(arg) - 1] == '/') {
19         return(mkfssrc(arg));
20     } else {
21         return(mkdbsrc(arg, NULL));
22     }
23 }
24
25 static void serve(struct muth *muth, va_list args)
26 {
27     vavar(struct hthead *, req);
28     vavar(int, fd);
29     FILE *out;
30     struct source *src;
31     struct fileinfo f;
32     
33     out = NULL;
34     for(src = sources; src != NULL; src = src->next) {
35         f = src->serve(src, req->rest);
36         if(f.data != NULL)
37             break;
38     }
39     if(src == NULL) {
40         simpleerror(fd, 404, "Resource not found", "The resource %s was not found", htmlquote(req->rest));
41         goto out;
42     }
43     out = mtstdopen(fd, 1, 60, "r+");
44     fprintf(out, "HTTP/1.1 200 OK\n");
45     fprintf(out, "Content-Type: %s\n", f.ctype);
46     fprintf(out, "Content-Length: %zi\n", f.sz);
47     fprintf(out, "Last-Modified: %s\n", fmthttpdate(f.mtime));
48     fprintf(out, "\n");
49     fwrite(f.data, 1, f.sz, out);
50     free(f.data);
51     
52 out:
53     if(out != NULL)
54         fclose(out);
55     else
56         close(fd);
57     freehthead(req);
58 }
59
60 static void usage(FILE *out)
61 {
62     fprintf(out, "usage: statserve [-h] SOURCE...\n");
63 }
64
65 static void listenloop(struct muth *muth, va_list args)
66 {
67     vavar(int, lfd);
68     int fd;
69     struct hthead *req;
70     struct source *src;
71     
72     while(1) {
73         block(0, EV_READ, 0);
74         if((fd = recvreq(lfd, &req)) < 0) {
75             if(errno != 0)
76                 flog(LOG_ERR, "recvreq: %s", strerror(errno));
77             break;
78         }
79         mustart(serve, req, fd);
80         for(src = sources; src != NULL; src = src->next) {
81             if(src->idle)
82                 src->idle(src);
83         }
84     }
85 }
86
87 int main(int argc, char **argv)
88 {
89     int c;
90     struct source *last, *src;
91     
92     while((c = getopt(argc, argv, "+h")) >= 0) {
93         switch(c) {
94         case 'h':
95             usage(stdout);
96             return(0);
97         default:
98             usage(stderr);
99             return(1);
100         }
101     }
102     last = NULL;
103     while(optind < argc) {
104         src = parsesource(argv[optind++]);
105         if(!sources)
106             sources = src;
107         if(last)
108             last->next = src;
109         last = src;
110     }
111     if(!sources) {
112         usage(stderr);
113         return(1);
114     }
115     mustart(listenloop, 0);
116     ioloop();
117     return(0);
118 }