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