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)