tinywebd

diff src/main.c @ 1:f425a9805d17

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 14 Apr 2015 08:32:51 +0300
parents 9c9e24956d99
children 852a745503cf
line diff
     1.1 --- a/src/main.c	Tue Apr 14 02:13:29 2015 +0300
     1.2 +++ b/src/main.c	Tue Apr 14 08:32:51 2015 +0300
     1.3 @@ -8,6 +8,15 @@
     1.4  #include <sys/types.h>
     1.5  #include <sys/socket.h>
     1.6  #include <arpa/inet.h>
     1.7 +#include "http.h"
     1.8 +
     1.9 +/* HTTP version */
    1.10 +#define HTTP_VER_MAJOR	1
    1.11 +#define HTTP_VER_MINOR	1
    1.12 +#define HTTP_VER_STR	"1.1"
    1.13 +
    1.14 +/* maximum request length: 64mb */
    1.15 +#define MAX_REQ_LENGTH	(65536 * 1024)
    1.16  
    1.17  struct client {
    1.18  	int s;
    1.19 @@ -19,6 +28,8 @@
    1.20  int start_server(void);
    1.21  int accept_conn(int lis);
    1.22  int handle_client(struct client *c);
    1.23 +void respond_error(struct client *c, int errcode);
    1.24 +int parse_args(int argc, char **argv);
    1.25  
    1.26  static int lis;
    1.27  static int port = 8080;
    1.28 @@ -26,6 +37,10 @@
    1.29  
    1.30  int main(int argc, char **argv)
    1.31  {
    1.32 +	if(parse_args(argc, argv) == -1) {
    1.33 +		return 1;
    1.34 +	}
    1.35 +
    1.36  	if((lis = start_server()) == -1) {
    1.37  		return 1;
    1.38  	}
    1.39 @@ -128,37 +143,108 @@
    1.40  	return 0;
    1.41  }
    1.42  
    1.43 +void close_conn(struct client *c)
    1.44 +{
    1.45 +	close(c->s);
    1.46 +	c->s = -1;	/* mark it for removal */
    1.47 +	free(c->rcvbuf);
    1.48 +}
    1.49 +
    1.50 +static char *skip_space(char *s, char *endp)
    1.51 +{
    1.52 +	while(s < endp && *s && isspace(*s))
    1.53 +		++s;
    1.54 +	return s;
    1.55 +}
    1.56 +
    1.57  int handle_client(struct client *c)
    1.58  {
    1.59 +	char *reqp, *hdrp, *bodyp, *endp, *eol;
    1.60 +	char req_type[32];
    1.61  	static char buf[2048];
    1.62  	int rdsz;
    1.63  
    1.64  	while((rdsz = recv(c->s, buf, sizeof buf, 0)) > 0) {
    1.65  		if(c->rcvbuf) {
    1.66  			int newsz = c->bufsz + rdsz;
    1.67 -			char *newbuf = realloc(buf, newsz);
    1.68 +			if(newsz > MAX_REQ_LENGTH) {
    1.69 +				respond_error(c, 413);
    1.70 +				return -1;
    1.71 +			}
    1.72 +
    1.73 +			char *newbuf = realloc(buf, newsz + 1);
    1.74  			if(!newbuf) {
    1.75  				fprintf(stderr, "failed to allocate %d byte buffer\n", newsz);
    1.76 -				/* TODO http error */
    1.77 -				goto drop;
    1.78 +				respond_error(c, 503);
    1.79 +				return -1;
    1.80  			}
    1.81  
    1.82  			memcpy(newbuf + c->bufsz, buf, rdsz);
    1.83 +			newbuf[newsz] = 0;
    1.84  
    1.85  			c->rcvbuf = newbuf;
    1.86  			c->bufsz = newsz;
    1.87  		}
    1.88  	}
    1.89  
    1.90 +	endp = c->rcvbuf + c->bufsz;
    1.91 +	if((reqp = skip_space(buf, endp)) >= endp) {
    1.92 +		return 0;	/* incomplete have to read more ... */
    1.93 +	}
    1.94 +
    1.95 +
    1.96 +	/* we only support GET and HEAD at this point, so freak out on anything else */
    1.97 +
    1.98  	/* TODO: parse header, drop on invalid, determine if the request
    1.99  	 * is complete and process
   1.100  	 */
   1.101 +}
   1.102  
   1.103 -	if(rdsz == -1 && errno != EAGAIN) {
   1.104 -drop:
   1.105 -		close(c->s);
   1.106 -		c->s = -1;
   1.107 -		free(c->rcvbuf);
   1.108 +void respond_error(struct client *c, int errcode)
   1.109 +{
   1.110 +	char buf[512];
   1.111 +
   1.112 +	sprintf(buf, HTTP_VER_STR " %d %s\r\n\r\n", errcode, http_strmsg(errcode));
   1.113 +
   1.114 +	send(c->s, buf, strlen(buf), 0);
   1.115 +	close_conn(c);
   1.116 +}
   1.117 +
   1.118 +
   1.119 +static void print_help(const char *argv0)
   1.120 +{
   1.121 +	printf("Usage: %s [options]\n", argv0);
   1.122 +	printf("Options:\n");
   1.123 +	printf(" -p <port>  set the TCP/IP port number to use\n");
   1.124 +	printf(" -h         print usage help and exit\n");
   1.125 +}
   1.126 +
   1.127 +int parse_args(int argc, char **argv)
   1.128 +{
   1.129 +	int i;
   1.130 +
   1.131 +	for(i=1; i<argc; i++) {
   1.132 +		if(argv[i][0] == '-' && argv[i][2] == 0) {
   1.133 +			switch(argv[i][1]) {
   1.134 +			case 'p':
   1.135 +				if((port = atoi(argv[++i])) == 0) {
   1.136 +					fprintf(stderr, "-p must be followed by a valid port number\n");
   1.137 +					return -1;
   1.138 +				}
   1.139 +				break;
   1.140 +
   1.141 +			case 'h':
   1.142 +				print_help(argv[0]);
   1.143 +				exit(0);
   1.144 +
   1.145 +			default:
   1.146 +				fprintf(stderr, "unrecognized option: %s\n", argv[i]);
   1.147 +				return -1;
   1.148 +			}
   1.149 +		} else {
   1.150 +			fprintf(stderr, "unexpected argument: %s\n", argv[i]);
   1.151 +			return -1;
   1.152 +		}
   1.153  	}
   1.154  	return 0;
   1.155  }