Initial commit.
[statserve.git] / statserve.c
CommitLineData
34d725a5
FT
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
14static struct source *sources = NULL;
15
16static 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
25static 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
52out:
53 if(out != NULL)
54 fclose(out);
55 else
56 close(fd);
57 freehthead(req);
58}
59
60static void usage(FILE *out)
61{
62 fprintf(out, "usage: statserve [-h] SOURCE...\n");
63}
64
65static 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
87int 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}