Added a really basic sendfile implementation.
[ashd.git] / src / sendfile.c
1 /*
2     ashd - A Sane HTTP Daemon
3     Copyright (C) 2008  Fredrik Tolf <fredrik@dolda2000.com>
4
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.
9
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.
14
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/>.
17 */
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <sys/stat.h>
26 #include <stdint.h>
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <utils.h>
32 #include <log.h>
33 #include <resp.h>
34
35 static void passdata(int in, int out)
36 {
37     int ret, len, off;
38     char *buf;
39     
40     buf = smalloc(65536);
41     while(1) {
42         len = read(in, buf, 65536);
43         if(len < 0) {
44             flog(LOG_ERR, "sendfile: could not read input: %s", strerror(errno));
45             break;
46         }
47         if(len == 0)
48             break;
49         for(off = 0; off < len; off += ret) {
50             ret = write(out, buf + off, len - off);
51             if(ret < 0) {
52                 flog(LOG_ERR, "sendfile: could not write output: %s", strerror(errno));
53                 break;
54             }
55         }
56     }
57     free(buf);
58 }
59
60 static int strrcmp(char *str, char *end)
61 {
62     return(strcmp(str + strlen(str) - strlen(end), end));
63 }
64
65 static char *getmimetype(char *file, struct stat *sb)
66 {
67     /* Rewrite with libmagic. */
68     if(!strrcmp(file, ".html"))
69         return("text/html");
70     if(!strrcmp(file, ".xhtml"))
71         return("application/xhtml+xml");
72     if(!strrcmp(file, ".txt"))
73         return("text/plain");
74     return("application/octet-stream");
75 }
76
77 int main(int argc, char **argv)
78 {
79     char *file;
80     struct stat sb;
81     int fd;
82     
83     if(argc < 4) {
84         flog(LOG_ERR, "usage: sendfile METHOD URL REST");
85         exit(1);
86     }
87     if((file = getenv("REQ_X_ASH_FILE")) == NULL) {
88         flog(LOG_ERR, "sendfile: needs to be called with the X-Ash-File header");
89         exit(1);
90     }
91     if(*argv[3]) {
92         simpleerror(1, 404, "Not Found", "The requested URL has no corresponding resource.");
93         exit(0);
94     }
95     if(stat(file, &sb) || ((fd = open(file, O_RDONLY)) < 0)) {
96         flog(LOG_ERR, "sendfile: could not stat input file %s: %s", file, strerror(errno));
97         simpleerror(1, 500, "Internal Error", "The server could not access its own data.");
98         exit(1);
99     }
100     
101     printf("HTTP/1.1 200 OK\r\n");
102     printf("Content-Type: %s\r\n", getmimetype(file, &sb));
103     printf("Content-Length: %ji\r\n", (intmax_t)sb.st_size);
104     printf("\r\n");
105     fflush(stdout);
106     if(strcasecmp(argv[1], "head"))
107         passdata(fd, 1);
108     return(0);
109 }