Updated to current mtstdopen interface.
[statserve.git] / statserve.c
index ed49388..50719df 100644 (file)
@@ -3,6 +3,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
+#include <sys/socket.h>
 #include <ashd/req.h>
 #include <ashd/resp.h>
 #include <ashd/log.h>
@@ -22,6 +23,18 @@ static struct source *parsesource(char *arg)
     }
 }
 
+static int cached(struct hthead *req, struct fileinfo f)
+{
+    char *hdr;
+    time_t cdate;
+    
+    if((hdr = getheader(req, "If-Modified-Since")) != NULL) {
+       cdate = parsehttpdate(hdr);
+       return((cdate > 0) && !(cdate < f.mtime));
+    }
+    return(0);
+}
+
 static void serve(struct muth *muth, va_list args)
 {
     vavar(struct hthead *, req);
@@ -40,13 +53,19 @@ static void serve(struct muth *muth, va_list args)
        simpleerror(fd, 404, "Resource not found", "The resource %s was not found", htmlquote(req->rest));
        goto out;
     }
-    out = mtstdopen(fd, 1, 60, "r+");
-    fprintf(out, "HTTP/1.1 200 OK\n");
-    fprintf(out, "Content-Type: %s\n", f.ctype);
-    fprintf(out, "Content-Length: %zi\n", f.sz);
-    fprintf(out, "Last-Modified: %s\n", fmthttpdate(f.mtime));
-    fprintf(out, "\n");
-    fwrite(f.data, 1, f.sz, out);
+    out = mtstdopen(fd, 1, 60, "r+", NULL);
+    if(cached(req, f)) {
+       fprintf(out, "HTTP/1.1 304 Not Modified\n");
+       fprintf(out, "Content-Length: 0\n");
+       fprintf(out, "\n");
+    } else {
+       fprintf(out, "HTTP/1.1 200 OK\n");
+       fprintf(out, "Content-Type: %s\n", f.ctype);
+       fprintf(out, "Content-Length: %zi\n", f.sz);
+       fprintf(out, "Last-Modified: %s\n", fmthttpdate(f.mtime));
+       fprintf(out, "\n");
+       fwrite(f.data, 1, f.sz, out);
+    }
     free(f.data);
     
 out:
@@ -59,7 +78,7 @@ out:
 
 static void usage(FILE *out)
 {
-    fprintf(out, "usage: statserve [-h] SOURCE...\n");
+    fprintf(out, "usage: statserve [-h] [-P PAGESIZE] SOURCE...\n");
 }
 
 static void listenloop(struct muth *muth, va_list args)
@@ -84,13 +103,31 @@ static void listenloop(struct muth *muth, va_list args)
     }
 }
 
+static void sigterm(int sig)
+{
+    shutdown(0, SHUT_RDWR);
+}
+
+static void closeall(void)
+{
+    struct source *src;
+    
+    for(src = sources; src != NULL; src = src->next) {
+       if(src->close)
+           src->close(src);
+    }
+}
+
 int main(int argc, char **argv)
 {
     int c;
     struct source *last, *src;
     
-    while((c = getopt(argc, argv, "+h")) >= 0) {
+    while((c = getopt(argc, argv, "+hP:")) >= 0) {
        switch(c) {
+       case 'P':
+           dbpagesize = atoi(optarg);
+           break;
        case 'h':
            usage(stdout);
            return(0);
@@ -101,7 +138,10 @@ int main(int argc, char **argv)
     }
     last = NULL;
     while(optind < argc) {
-       src = parsesource(argv[optind++]);
+       if((src = parsesource(argv[optind++])) == NULL) {
+           closeall();
+           return(1);
+       }
        if(!sources)
            sources = src;
        if(last)
@@ -110,9 +150,13 @@ int main(int argc, char **argv)
     }
     if(!sources) {
        usage(stderr);
+       closeall();
        return(1);
     }
     mustart(listenloop, 0);
+    signal(SIGINT, sigterm);
+    signal(SIGTERM, sigterm);
     ioloop();
+    closeall();
     return(0);
 }