tinywebd
changeset 5:def49a046566
serialization of responses
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 17 Apr 2015 01:57:00 +0300 |
parents | 9e054c002489 |
children | 4f191dbfac7e |
files | src/http.c src/http.h src/main.c |
diffstat | 3 files changed, 187 insertions(+), 3 deletions(-) [+] |
line diff
1.1 --- a/src/http.c Thu Apr 16 17:34:15 2015 +0300 1.2 +++ b/src/http.c Fri Apr 17 01:57:00 2015 +0300 1.3 @@ -1,6 +1,7 @@ 1.4 #include <stdio.h> 1.5 #include <stdlib.h> 1.6 #include <string.h> 1.7 +#include <stdarg.h> 1.8 #include <ctype.h> 1.9 #include <alloca.h> 1.10 #include "http.h" 1.11 @@ -195,6 +196,91 @@ 1.12 free(hdr->uri); 1.13 } 1.14 1.15 +int http_init_resp(struct http_resp_header *resp) 1.16 +{ 1.17 + memset(resp, 0, sizeof *resp); 1.18 + resp->status = 200; 1.19 + resp->ver_major = resp->ver_minor = 1; 1.20 + resp->fields = 0; 1.21 + resp->num_fields = 0; 1.22 + 1.23 + return 0; 1.24 +} 1.25 + 1.26 +int http_add_resp_field(struct http_resp_header *resp, const char *fmt, ...) 1.27 +{ 1.28 + int sz; 1.29 + va_list ap; 1.30 + char *field, *newarr, tmp; 1.31 + 1.32 + va_start(ap, fmt); 1.33 + sz = vsnprintf(&tmp, 0, fmt, ap); 1.34 + va_end(ap); 1.35 + 1.36 + if(sz <= 0) sz = 1023; 1.37 + if(!(field = malloc(sz + 1))) { 1.38 + return -1; 1.39 + } 1.40 + va_start(ap, fmt); 1.41 + vsnprintf(field, sz + 1, fmt, ap); 1.42 + va_end(ap); 1.43 + 1.44 + if(!(newarr = realloc(resp->fields, (resp->num_fields + 1) * sizeof *resp->fields))) { 1.45 + free(field); 1.46 + return -1; 1.47 + } 1.48 + resp->fields[resp->num_fields++] = newarr; 1.49 + return 0; 1.50 +} 1.51 + 1.52 +void http_destroy_resp(struct http_resp_header *resp) 1.53 +{ 1.54 + int i; 1.55 + if(resp->fields) { 1.56 + for(i=0; i<resp->num_fields; i++) { 1.57 + free(resp->fields[i]); 1.58 + } 1.59 + free(resp->fields); 1.60 + resp->fields = 0; 1.61 + } 1.62 + resp->num_fields = 0; 1.63 +} 1.64 + 1.65 +int http_serialize_resp(struct http_resp_header *resp, char *buf) 1.66 +{ 1.67 + int i, stsize, size, *fsize; 1.68 + char *ptr, tmp; 1.69 + 1.70 + stsize = snprintf(&tmp, 0, "HTTP/%d.%d %d %s\r\n", resp->ver_major, resp->ver_minor, 1.71 + resp->status, http_strmsg(resp->status)); 1.72 + 1.73 + fsize = alloca(resp->num_fields * sizeof *fsize); 1.74 + 1.75 + size = stsize; 1.76 + for(i=0; i<resp->num_fields; i++) { 1.77 + int len = strlen(resp->fields[i]) + 2; 1.78 + fsize[i] = len; 1.79 + size += len; 1.80 + } 1.81 + size += 2; /* CRLF and null */ 1.82 + 1.83 + if(buf) { 1.84 + sprintf(buf, "HTTP/%d.%d %d %s\r\n", resp->ver_major, resp->ver_minor, 1.85 + resp->status, http_strmsg(resp->status)); 1.86 + 1.87 + ptr = buf + stsize; 1.88 + for(i=0; i<resp->num_fields; i++) { 1.89 + sprintf(ptr, "%s\r\n", resp->fields[i]); 1.90 + ptr += fsize[i]; 1.91 + } 1.92 + *ptr++ = '\r'; 1.93 + *ptr++ = '\n'; 1.94 + *ptr++ = 0; 1.95 + } 1.96 + 1.97 + return size; 1.98 +} 1.99 + 1.100 const char *http_strmsg(int code) 1.101 { 1.102 static const char **msgxxx[] = {
2.1 --- a/src/http.h Thu Apr 16 17:34:15 2015 +0300 2.2 +++ b/src/http.h Fri Apr 17 01:57:00 2015 +0300 2.3 @@ -24,6 +24,13 @@ 2.4 int body_offset; 2.5 }; 2.6 2.7 +struct http_resp_header { 2.8 + int status; 2.9 + int ver_major, ver_minor; 2.10 + char **fields; 2.11 + int num_fields; 2.12 +}; 2.13 + 2.14 #define HTTP_HDR_OK 0 2.15 #define HTTP_HDR_INVALID -1 2.16 #define HTTP_HDR_NOMEM -2 2.17 @@ -33,6 +40,11 @@ 2.18 void http_print_header(struct http_req_header *hdr); 2.19 void http_destroy_header(struct http_req_header *hdr); 2.20 2.21 +int http_init_resp(struct http_resp_header *resp); 2.22 +int http_add_resp_field(struct http_resp_header *resp, const char *fmt, ...); 2.23 +void http_destroy_resp(struct http_resp_header *resp); 2.24 +int http_serialize_resp(struct http_resp_header *resp, char *buf); 2.25 + 2.26 const char *http_strmsg(int code); 2.27 2.28 #endif /* HTTP_H_ */
3.1 --- a/src/main.c Thu Apr 16 17:34:15 2015 +0300 3.2 +++ b/src/main.c Fri Apr 17 01:57:00 2015 +0300 3.3 @@ -6,11 +6,14 @@ 3.4 #include <errno.h> 3.5 #include <unistd.h> 3.6 #include <fcntl.h> 3.7 +#include <sys/stat.h> 3.8 #include <sys/select.h> 3.9 +#include <sys/mman.h> 3.10 #include <sys/types.h> 3.11 #include <sys/socket.h> 3.12 #include <arpa/inet.h> 3.13 #include "http.h" 3.14 +#include "mime.h" 3.15 3.16 /* HTTP version */ 3.17 #define HTTP_VER_MAJOR 1 3.18 @@ -31,7 +34,7 @@ 3.19 int accept_conn(int lis); 3.20 void close_conn(struct client *c); 3.21 int handle_client(struct client *c); 3.22 -void do_get_head(struct client *c); 3.23 +int do_get(struct client *c, const char *uri, int with_body); 3.24 void respond_error(struct client *c, int errcode); 3.25 void sighandler(int s); 3.26 int parse_args(int argc, char **argv); 3.27 @@ -40,6 +43,14 @@ 3.28 static int port = 8080; 3.29 static struct client *clist; 3.30 3.31 +static const char *indexfiles[] = { 3.32 + "index.cgi", 3.33 + "index.html", 3.34 + "index.htm", 3.35 + 0 3.36 +}; 3.37 + 3.38 + 3.39 int main(int argc, char **argv) 3.40 { 3.41 if(parse_args(argc, argv) == -1) { 3.42 @@ -209,8 +220,11 @@ 3.43 /* we only support GET and HEAD at this point, so freak out on anything else */ 3.44 switch(hdr.method) { 3.45 case HTTP_GET: 3.46 + do_get(c, hdr.uri, 1); 3.47 + break; 3.48 + 3.49 case HTTP_HEAD: 3.50 - do_get_head(c); 3.51 + do_get(c, hdr.uri, 0); 3.52 break; 3.53 3.54 default: 3.55 @@ -222,8 +236,80 @@ 3.56 return 0; 3.57 } 3.58 3.59 -void do_get_head(struct client *c) 3.60 +int do_get(struct client *c, const char *uri, int with_body) 3.61 { 3.62 + const char *ptr; 3.63 + struct http_resp_header resp; 3.64 + 3.65 + if((ptr = strstr(uri, "://"))) { 3.66 + /* skip the host part */ 3.67 + if(!(uri = strchr(ptr + 3, '/'))) { 3.68 + respond_error(c, 404); 3.69 + return -1; 3.70 + } 3.71 + ++uri; 3.72 + } 3.73 + 3.74 + if(*uri) { 3.75 + struct stat st; 3.76 + char *path = 0; 3.77 + char *buf; 3.78 + const char *type; 3.79 + int fd, size; 3.80 + 3.81 + if(stat(uri, &st) == -1) { 3.82 + respond_error(c, 404); 3.83 + return -1; 3.84 + } 3.85 + 3.86 + if(S_ISDIR(st.st_mode)) { 3.87 + int i; 3.88 + path = alloca(strlen(uri) + 64); 3.89 + 3.90 + for(i=0; indexfiles[i]; i++) { 3.91 + sprintf(path, "%s/%s", uri, indexfiles[i]); 3.92 + if(stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) { 3.93 + break; 3.94 + } 3.95 + } 3.96 + 3.97 + if(indexfiles[i] == 0) { 3.98 + respond_error(c, 404); 3.99 + return -1; 3.100 + } 3.101 + } else { 3.102 + path = (char*)uri; 3.103 + } 3.104 + 3.105 + if((fd = open(path, O_RDONLY)) == -1) { 3.106 + respond_error(c, 403); 3.107 + return -1; 3.108 + } 3.109 + 3.110 + /* construct response header */ 3.111 + http_init_resp(&resp); 3.112 + http_add_resp_field(&resp, "Content-Length: %d", st.st_size); 3.113 + if((type = mime_type(path))) { 3.114 + http_add_resp_field(&resp, "Content-Type: %s", type); 3.115 + } 3.116 + 3.117 + size = http_serialize_resp(&resp, 0); 3.118 + buf = alloca(size); 3.119 + http_serialize_resp(&resp, buf); 3.120 + send(c->s, buf, size, 0); 3.121 + 3.122 + if(with_body) { 3.123 + char *cont = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 3.124 + if(cont == (void*)-1) { 3.125 + respond_error(c, 503); 3.126 + close(fd); 3.127 + return -1; 3.128 + } 3.129 + } 3.130 + 3.131 + close(fd); 3.132 + } 3.133 + return 0; 3.134 } 3.135 3.136 void respond_error(struct client *c, int errcode)