tinywebd
diff src/main.c @ 5:def49a046566
serialization of responses
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 17 Apr 2015 01:57:00 +0300 |
parents | 9e054c002489 |
children | 5ec50ca0d071 |
line diff
1.1 --- a/src/main.c Thu Apr 16 17:34:15 2015 +0300 1.2 +++ b/src/main.c Fri Apr 17 01:57:00 2015 +0300 1.3 @@ -6,11 +6,14 @@ 1.4 #include <errno.h> 1.5 #include <unistd.h> 1.6 #include <fcntl.h> 1.7 +#include <sys/stat.h> 1.8 #include <sys/select.h> 1.9 +#include <sys/mman.h> 1.10 #include <sys/types.h> 1.11 #include <sys/socket.h> 1.12 #include <arpa/inet.h> 1.13 #include "http.h" 1.14 +#include "mime.h" 1.15 1.16 /* HTTP version */ 1.17 #define HTTP_VER_MAJOR 1 1.18 @@ -31,7 +34,7 @@ 1.19 int accept_conn(int lis); 1.20 void close_conn(struct client *c); 1.21 int handle_client(struct client *c); 1.22 -void do_get_head(struct client *c); 1.23 +int do_get(struct client *c, const char *uri, int with_body); 1.24 void respond_error(struct client *c, int errcode); 1.25 void sighandler(int s); 1.26 int parse_args(int argc, char **argv); 1.27 @@ -40,6 +43,14 @@ 1.28 static int port = 8080; 1.29 static struct client *clist; 1.30 1.31 +static const char *indexfiles[] = { 1.32 + "index.cgi", 1.33 + "index.html", 1.34 + "index.htm", 1.35 + 0 1.36 +}; 1.37 + 1.38 + 1.39 int main(int argc, char **argv) 1.40 { 1.41 if(parse_args(argc, argv) == -1) { 1.42 @@ -209,8 +220,11 @@ 1.43 /* we only support GET and HEAD at this point, so freak out on anything else */ 1.44 switch(hdr.method) { 1.45 case HTTP_GET: 1.46 + do_get(c, hdr.uri, 1); 1.47 + break; 1.48 + 1.49 case HTTP_HEAD: 1.50 - do_get_head(c); 1.51 + do_get(c, hdr.uri, 0); 1.52 break; 1.53 1.54 default: 1.55 @@ -222,8 +236,80 @@ 1.56 return 0; 1.57 } 1.58 1.59 -void do_get_head(struct client *c) 1.60 +int do_get(struct client *c, const char *uri, int with_body) 1.61 { 1.62 + const char *ptr; 1.63 + struct http_resp_header resp; 1.64 + 1.65 + if((ptr = strstr(uri, "://"))) { 1.66 + /* skip the host part */ 1.67 + if(!(uri = strchr(ptr + 3, '/'))) { 1.68 + respond_error(c, 404); 1.69 + return -1; 1.70 + } 1.71 + ++uri; 1.72 + } 1.73 + 1.74 + if(*uri) { 1.75 + struct stat st; 1.76 + char *path = 0; 1.77 + char *buf; 1.78 + const char *type; 1.79 + int fd, size; 1.80 + 1.81 + if(stat(uri, &st) == -1) { 1.82 + respond_error(c, 404); 1.83 + return -1; 1.84 + } 1.85 + 1.86 + if(S_ISDIR(st.st_mode)) { 1.87 + int i; 1.88 + path = alloca(strlen(uri) + 64); 1.89 + 1.90 + for(i=0; indexfiles[i]; i++) { 1.91 + sprintf(path, "%s/%s", uri, indexfiles[i]); 1.92 + if(stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) { 1.93 + break; 1.94 + } 1.95 + } 1.96 + 1.97 + if(indexfiles[i] == 0) { 1.98 + respond_error(c, 404); 1.99 + return -1; 1.100 + } 1.101 + } else { 1.102 + path = (char*)uri; 1.103 + } 1.104 + 1.105 + if((fd = open(path, O_RDONLY)) == -1) { 1.106 + respond_error(c, 403); 1.107 + return -1; 1.108 + } 1.109 + 1.110 + /* construct response header */ 1.111 + http_init_resp(&resp); 1.112 + http_add_resp_field(&resp, "Content-Length: %d", st.st_size); 1.113 + if((type = mime_type(path))) { 1.114 + http_add_resp_field(&resp, "Content-Type: %s", type); 1.115 + } 1.116 + 1.117 + size = http_serialize_resp(&resp, 0); 1.118 + buf = alloca(size); 1.119 + http_serialize_resp(&resp, buf); 1.120 + send(c->s, buf, size, 0); 1.121 + 1.122 + if(with_body) { 1.123 + char *cont = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 1.124 + if(cont == (void*)-1) { 1.125 + respond_error(c, 503); 1.126 + close(fd); 1.127 + return -1; 1.128 + } 1.129 + } 1.130 + 1.131 + close(fd); 1.132 + } 1.133 + return 0; 1.134 } 1.135 1.136 void respond_error(struct client *c, int errcode)