tinywebd

changeset 10:0dd50a23f3dd

separated all the tinyweb functionality out as a library
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 18 Apr 2015 22:47:57 +0300
parents 0244b08cc9d3
children b13fda5c01bc
files .hgignore Makefile libtinyweb/Makefile libtinyweb/src/http.c libtinyweb/src/http.h libtinyweb/src/logger.c libtinyweb/src/logger.h libtinyweb/src/mime.c libtinyweb/src/mime.h libtinyweb/src/rbtree.c libtinyweb/src/rbtree.h libtinyweb/src/tinyweb.c libtinyweb/src/tinyweb.h src/http.c src/http.h src/logger.c src/logger.h src/mime.c src/mime.h src/rbtree.c src/rbtree.h src/tinyweb.c src/tinyweb.h
diffstat 23 files changed, 1573 insertions(+), 1483 deletions(-) [+]
line diff
     1.1 --- a/.hgignore	Sat Apr 18 21:36:07 2015 +0300
     1.2 +++ b/.hgignore	Sat Apr 18 22:47:57 2015 +0300
     1.3 @@ -1,4 +1,7 @@
     1.4  \.o$
     1.5  \.d$
     1.6  \.swp$
     1.7 +\.a$
     1.8 +\.so$
     1.9 +\.so\.
    1.10  ^tinywebd$
     2.1 --- a/Makefile	Sat Apr 18 21:36:07 2015 +0300
     2.2 +++ b/Makefile	Sat Apr 18 22:47:57 2015 +0300
     2.3 @@ -2,12 +2,17 @@
     2.4  obj = $(src:.c=.o)
     2.5  dep = $(obj:.o=.d)
     2.6  bin = tinywebd
     2.7 +weblib = libtinyweb/libtinyweb.so
     2.8  
     2.9 -CFLAGS = -pedantic -Wall -g
    2.10 +CFLAGS = -pedantic -Wall -g -Ilibtinyweb/src
    2.11 +LDFLAGS = -Llibtinyweb -Wl,-rpath=libtinyweb -ltinyweb
    2.12  
    2.13 -$(bin): $(obj)
    2.14 +$(bin): $(obj) $(weblib)
    2.15  	$(CC) -o $@ $(obj) $(LDFLAGS)
    2.16  
    2.17 +$(weblib):
    2.18 +	$(MAKE) -C libtinyweb
    2.19 +
    2.20  -include $(dep)
    2.21  
    2.22  %.d: %.c
    2.23 @@ -16,3 +21,12 @@
    2.24  .PHONY: clean
    2.25  clean:
    2.26  	rm -f $(obj) $(bin)
    2.27 +
    2.28 +.PHONY: install
    2.29 +install: $(bin)
    2.30 +	mkdir -p $(PREFIX)/bin
    2.31 +	cp $(bin) $(DESTDIR)$(PREFIX)/bin/$(bin)
    2.32 +
    2.33 +.PHONY: uninstall
    2.34 +uninstall:
    2.35 +	rm -f $(DESTDIR)$(PREFIX)/bin/$(bin)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/libtinyweb/Makefile	Sat Apr 18 22:47:57 2015 +0300
     3.3 @@ -0,0 +1,73 @@
     3.4 +PREFIX ?= /usr/local
     3.5 +
     3.6 +src = $(wildcard src/*.c)
     3.7 +obj = $(src:.c=.o)
     3.8 +dep = $(obj:.o=.d)
     3.9 +name = tinyweb
    3.10 +
    3.11 +CFLAGS = -pedantic -Wall -g $(pic)
    3.12 +
    3.13 +sys = $(shell uname -s)
    3.14 +
    3.15 +so_major = 0
    3.16 +so_minor = 1
    3.17 +alib = lib$(name).a
    3.18 +
    3.19 +ifeq ($(sys), Darwin)
    3.20 +	solib = lib$(name).dylib
    3.21 +	shared = -dynamiclib
    3.22 +else
    3.23 +	ldname = lib$(name).so
    3.24 +	soname = lib$(name).so.$(so_major)
    3.25 +	solib = lib$(name).so.$(so_major).$(so_minor)
    3.26 +	shared = -shared -Wl,-soname=$(soname)
    3.27 +	pic = -fPIC
    3.28 +endif
    3.29 +
    3.30 +.PHONY: all
    3.31 +all: $(alib) $(solib)
    3.32 +
    3.33 +$(solib): $(obj)
    3.34 +	$(CC) -o $@ $(shared) $(obj) $(LDFLAGS)
    3.35 +	[ -n "$(soname)" ] && \
    3.36 +		ln -s $(solib) $(soname) && \
    3.37 +		ln -s $(soname) $(ldname) || true
    3.38 +
    3.39 +$(alib): $(obj)
    3.40 +	$(AR) rcs $@ $(obj)
    3.41 +
    3.42 +-include $(dep)
    3.43 +
    3.44 +%.d: %.c
    3.45 +	@$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
    3.46 +
    3.47 +.PHONY: clean
    3.48 +clean:
    3.49 +	rm -f $(obj) $(alib) $(solib)
    3.50 +
    3.51 +.PHONY: cleandep
    3.52 +cleandep:
    3.53 +	rm -f $(dep)
    3.54 +
    3.55 +.PHONY: install
    3.56 +install: $(alib) $(solib)
    3.57 +	mkdir -p $(DESTDIR)$(PREFIX)/lib $(DESTDIR)$(PREFIX)/include
    3.58 +	cp src/tinyweb.h $(DESTDIR)$(PREFIX)/include/tinyweb.h
    3.59 +	cp $(alib) $(DESTDIR)$(PREFIX)/lib/$(alib)
    3.60 +	cp $(solib) $(DESTDIR)$(PREFIX)/lib/$(solib)
    3.61 +	[ -n "$(soname)" ] && \
    3.62 +		cd $(DESTDIR)$(PREFIX)/lib && \
    3.63 +		ln -s $(solib) $(soname) && \
    3.64 +		ln -s $(soname) $(ldname) || \
    3.65 +		true
    3.66 +
    3.67 +.PHONY: uninstall
    3.68 +uninstall:
    3.69 +	rm -f $(DESTDIR)$(PREFIX)/include/tinyweb.h
    3.70 +	rm -f $(DESTDIR)$(PREFIX)/lib/$(alib)
    3.71 +	rm -f $(DESTDIR)$(PREFIX)/lib/$(solib)
    3.72 +	[ -n "$(soname)" ] && \
    3.73 +		rm -f $(DESTDIR)$(PREFIX)/lib/$(soname) && \
    3.74 +		rm -f $(DESTDIR)$(PREFIX)/lib/$(ldname) || \
    3.75 +		true
    3.76 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/libtinyweb/src/http.c	Sat Apr 18 22:47:57 2015 +0300
     4.3 @@ -0,0 +1,324 @@
     4.4 +#include <stdio.h>
     4.5 +#include <stdlib.h>
     4.6 +#include <string.h>
     4.7 +#include <stdarg.h>
     4.8 +#include <ctype.h>
     4.9 +#include <alloca.h>
    4.10 +#include "http.h"
    4.11 +#include "logger.h"
    4.12 +
    4.13 +
    4.14 +static const char *http_method_str[] = {
    4.15 +	"<unknown>",
    4.16 +	"OPTIONS",
    4.17 +	"GET",
    4.18 +	"HEAD",
    4.19 +	"POST",
    4.20 +	"PUT",
    4.21 +	"DELETE",
    4.22 +	"TRACE",
    4.23 +	"CONNECT",
    4.24 +	0
    4.25 +};
    4.26 +
    4.27 +
    4.28 +/* HTTP 1xx message strings */
    4.29 +static const char *http_msg1xx[] = {
    4.30 +	"Continue",					/* 100 */
    4.31 +	"Switching Protocols"		/* 101 */
    4.32 +};
    4.33 +
    4.34 +/* HTTP 2xx message strings */
    4.35 +static const char *http_msg2xx[] = {
    4.36 +	"OK",						/* 200 */
    4.37 +	"Created",					/* 201 */
    4.38 +	"Accepted",					/* 202 */
    4.39 +	"Non-Authoritative Information",	/* 203 */
    4.40 +	"No Content",				/* 204 */
    4.41 +	"Reset Content",			/* 205 */
    4.42 +	"Partial Content"			/* 206 */
    4.43 +};
    4.44 +
    4.45 +/* HTTP 3xx message strings */
    4.46 +static const char *http_msg3xx[] = {
    4.47 +	"Multiple Choices",			/* 300 */
    4.48 +	"Moved Permanently",		/* 301 */
    4.49 +	"Found",					/* 302 */
    4.50 +	"See Other",				/* 303 */
    4.51 +	"Not Modified",				/* 304 */
    4.52 +	"Use Proxy",				/* 305 */
    4.53 +	"<unknown>",				/* 306 is undefined? */
    4.54 +	"Temporary Redirect"		/* 307 */
    4.55 +};
    4.56 +
    4.57 +/* HTTP 4xx error strings */
    4.58 +static const char *http_msg4xx[] = {
    4.59 +	"Bad Request",				/* 400 */
    4.60 +	"Unauthorized",				/* 401 */
    4.61 +	"What the Fuck?",			/* 402 */
    4.62 +	"Forbidden",				/* 403 */
    4.63 +	"Not Found",				/* 404 */
    4.64 +	"Method Not Allowed",		/* 405 */
    4.65 +	"Not Acceptable",			/* 406 */
    4.66 +	"Proxy Authentication Required",	/* 407 */
    4.67 +	"Request Time-out",			/* 408 */
    4.68 +	"Conflict",					/* 409 */
    4.69 +	"Gone",						/* 410 */
    4.70 +	"Length Required",			/* 411 */
    4.71 +	"Precondition Failed",		/* 412 */
    4.72 +	"Request Entity Too Large", /* 413 */
    4.73 +	"Request-URI Too Large",	/* 414 */
    4.74 +	"Unsupported Media Type",	/* 415 */
    4.75 +	"Request range not satisfiable", /* 416 */
    4.76 +	"Expectation Failed"		/* 417 */
    4.77 +};
    4.78 +
    4.79 +/* HTTP 5xx error strings */
    4.80 +static const char *http_msg5xx[] = {
    4.81 +	"Internal Server Error",	/* 500 */
    4.82 +	"Not Implemented",			/* 501 */
    4.83 +	"Bad Gateway",				/* 502 */
    4.84 +	"Service Unavailable",		/* 503 */
    4.85 +	"Gateway Time-out",			/* 504 */
    4.86 +	"HTTP Version not supported"	/* 505 */
    4.87 +};
    4.88 +
    4.89 +
    4.90 +static enum http_method parse_method(const char *s);
    4.91 +
    4.92 +
    4.93 +int http_parse_request(struct http_req_header *hdr, const char *buf, int bufsz)
    4.94 +{
    4.95 +	int i, nlines = 0;
    4.96 +	char *rqline = 0;
    4.97 +	char *method, *uri, *version, *ptr;
    4.98 +	const char *startln, *endln;
    4.99 +
   4.100 +	memset(hdr, 0, sizeof *hdr);
   4.101 +
   4.102 +	for(i=1; i<bufsz; i++) {
   4.103 +		if(buf[i] == '\n' && buf[i - 1] == '\r') {
   4.104 +			if(!rqline) {
   4.105 +				rqline = alloca(i);
   4.106 +				memcpy(rqline, buf, i - 1);
   4.107 +				rqline[i - 1] = 0;
   4.108 +			}
   4.109 +			++nlines;
   4.110 +
   4.111 +			if(i > 4 && buf[i - 2] == '\n' && buf[i - 3] == '\r') {
   4.112 +				hdr->body_offset = i + 1;
   4.113 +				break;
   4.114 +			}
   4.115 +		}
   4.116 +	}
   4.117 +
   4.118 +	if(!rqline) {
   4.119 +		return HTTP_HDR_PARTIAL;
   4.120 +	}
   4.121 +
   4.122 +	ptr = rqline;
   4.123 +	while(*ptr && isspace(*ptr)) ++ptr;
   4.124 +	method = ptr;
   4.125 +
   4.126 +	/* parse the request line */
   4.127 +	while(*ptr && !isspace(*ptr)) ++ptr;
   4.128 +	while(*ptr && isspace(*ptr)) *ptr++ = 0;
   4.129 +
   4.130 +	uri = ptr;
   4.131 +	while(*ptr && !isspace(*ptr)) ++ptr;
   4.132 +	while(*ptr && isspace(*ptr)) *ptr++ = 0;
   4.133 +
   4.134 +	version = ptr;
   4.135 +	while(*ptr && !isspace(*ptr)) ++ptr;
   4.136 +	while(*ptr && isspace(*ptr)) *ptr++ = 0;
   4.137 +
   4.138 +	hdr->method = parse_method(method);
   4.139 +	hdr->uri = strdup(uri);
   4.140 +	if(sscanf(version, "HTTP/%d.%d", &hdr->ver_major, &hdr->ver_minor) != 2) {
   4.141 +		fprintf(stderr, "warning: failed to parse HTTP version \"%s\"\n", version);
   4.142 +		hdr->ver_major = 1;
   4.143 +		hdr->ver_minor = 1;
   4.144 +	}
   4.145 +
   4.146 +	if(!(hdr->hdrfields = malloc(nlines * sizeof *hdr->hdrfields))) {
   4.147 +		perror("failed to allocate memory for the header fields");
   4.148 +		return HTTP_HDR_NOMEM;
   4.149 +	}
   4.150 +	hdr->num_hdrfields = 0;
   4.151 +
   4.152 +	startln = buf;
   4.153 +	endln = buf;
   4.154 +	for(i=1; i<hdr->body_offset - 2; i++) {
   4.155 +		if(buf[i] == '\n' && buf[i - 1] == '\r') {
   4.156 +			int linesz;
   4.157 +
   4.158 +			endln = buf + i - 1;
   4.159 +			linesz = endln - startln;
   4.160 +
   4.161 +			if(startln > buf) {	/* skip first line */
   4.162 +				int idx = hdr->num_hdrfields++;
   4.163 +				hdr->hdrfields[idx] = malloc(linesz + 1);
   4.164 +				memcpy(hdr->hdrfields[idx], startln, linesz);
   4.165 +				hdr->hdrfields[idx][linesz] = 0;
   4.166 +			}
   4.167 +			startln = endln = buf + i + 1;
   4.168 +		}
   4.169 +	}
   4.170 +
   4.171 +	return HTTP_HDR_OK;
   4.172 +}
   4.173 +
   4.174 +void http_log_request(struct http_req_header *hdr)
   4.175 +{
   4.176 +	int i;
   4.177 +
   4.178 +	logmsg("HTTP request header\n");
   4.179 +	logmsg(" method: %s\n", http_method_str[hdr->method]);
   4.180 +	logmsg(" uri: %s\n", hdr->uri);
   4.181 +	logmsg(" version: %d.%d\n", hdr->ver_major, hdr->ver_minor);
   4.182 +	logmsg(" fields (%d):\n", hdr->num_hdrfields);
   4.183 +
   4.184 +	for(i=0; i<hdr->num_hdrfields; i++) {
   4.185 +		logmsg("   %s\n", hdr->hdrfields[i]);
   4.186 +	}
   4.187 +	logmsg("\n");
   4.188 +}
   4.189 +
   4.190 +void http_destroy_request(struct http_req_header *hdr)
   4.191 +{
   4.192 +	int i;
   4.193 +
   4.194 +	if(hdr->hdrfields) {
   4.195 +		for(i=0; i<hdr->num_hdrfields; i++) {
   4.196 +			free(hdr->hdrfields[i]);
   4.197 +		}
   4.198 +		free(hdr->hdrfields);
   4.199 +	}
   4.200 +	free(hdr->uri);
   4.201 +}
   4.202 +
   4.203 +int http_init_resp(struct http_resp_header *resp)
   4.204 +{
   4.205 +	memset(resp, 0, sizeof *resp);
   4.206 +	resp->status = 200;
   4.207 +	resp->ver_major = resp->ver_minor = 1;
   4.208 +	resp->fields = 0;
   4.209 +	resp->num_fields = 0;
   4.210 +
   4.211 +	return 0;
   4.212 +}
   4.213 +
   4.214 +int http_add_resp_field(struct http_resp_header *resp, const char *fmt, ...)
   4.215 +{
   4.216 +	int sz;
   4.217 +	va_list ap;
   4.218 +	char *field, **newarr, tmp;
   4.219 +
   4.220 +	va_start(ap, fmt);
   4.221 +	sz = vsnprintf(&tmp, 0, fmt, ap);
   4.222 +	va_end(ap);
   4.223 +
   4.224 +	if(sz <= 0) sz = 1023;
   4.225 +	if(!(field = malloc(sz + 1))) {
   4.226 +		return -1;
   4.227 +	}
   4.228 +	va_start(ap, fmt);
   4.229 +	vsnprintf(field, sz + 1, fmt, ap);
   4.230 +	va_end(ap);
   4.231 +
   4.232 +	if(!(newarr = realloc(resp->fields, (resp->num_fields + 1) * sizeof *resp->fields))) {
   4.233 +		free(field);
   4.234 +		return -1;
   4.235 +	}
   4.236 +	resp->fields = newarr;
   4.237 +
   4.238 +	resp->fields[resp->num_fields++] = field;
   4.239 +	return 0;
   4.240 +}
   4.241 +
   4.242 +void http_destroy_resp(struct http_resp_header *resp)
   4.243 +{
   4.244 +	int i;
   4.245 +	if(resp->fields) {
   4.246 +		for(i=0; i<resp->num_fields; i++) {
   4.247 +			free(resp->fields[i]);
   4.248 +		}
   4.249 +		free(resp->fields);
   4.250 +		resp->fields = 0;
   4.251 +	}
   4.252 +	resp->num_fields = 0;
   4.253 +}
   4.254 +
   4.255 +int http_serialize_resp(struct http_resp_header *resp, char *buf)
   4.256 +{
   4.257 +	int i, stsize, size, *fsize;
   4.258 +	char *ptr, tmp;
   4.259 +
   4.260 +	stsize = snprintf(&tmp, 0, "HTTP/%d.%d %d %s\r\n", resp->ver_major, resp->ver_minor,
   4.261 +			resp->status, http_strmsg(resp->status));
   4.262 +
   4.263 +	fsize = alloca(resp->num_fields * sizeof *fsize);
   4.264 +
   4.265 +	size = stsize;
   4.266 +	for(i=0; i<resp->num_fields; i++) {
   4.267 +		int len = strlen(resp->fields[i]) + 2;
   4.268 +		fsize[i] = len;
   4.269 +		size += len;
   4.270 +	}
   4.271 +	size += 2;	/* CRLF and null */
   4.272 +
   4.273 +	if(buf) {
   4.274 +		sprintf(buf, "HTTP/%d.%d %d %s\r\n", resp->ver_major, resp->ver_minor,
   4.275 +				resp->status, http_strmsg(resp->status));
   4.276 +
   4.277 +		ptr = buf + stsize;
   4.278 +		for(i=0; i<resp->num_fields; i++) {
   4.279 +			sprintf(ptr, "%s\r\n", resp->fields[i]);
   4.280 +			ptr += fsize[i];
   4.281 +		}
   4.282 +		*ptr++ = '\r';
   4.283 +		*ptr++ = '\n';
   4.284 +		*ptr++ = 0;
   4.285 +	}
   4.286 +
   4.287 +	return size;
   4.288 +}
   4.289 +
   4.290 +const char *http_strmsg(int code)
   4.291 +{
   4.292 +	static const char **msgxxx[] = {
   4.293 +		0, http_msg1xx, http_msg2xx, http_msg3xx, http_msg4xx, http_msg5xx
   4.294 +	};
   4.295 +	static int msgcount[] = {
   4.296 +		0,
   4.297 +		sizeof http_msg1xx / sizeof *http_msg1xx,
   4.298 +		sizeof http_msg2xx / sizeof *http_msg2xx,
   4.299 +		sizeof http_msg3xx / sizeof *http_msg3xx,
   4.300 +		sizeof http_msg4xx / sizeof *http_msg4xx,
   4.301 +		sizeof http_msg5xx / sizeof *http_msg5xx
   4.302 +	};
   4.303 +
   4.304 +	int type = code / 100;
   4.305 +	int idx = code % 100;
   4.306 +
   4.307 +	if(type < 1 || type >= sizeof msgxxx / sizeof *msgxxx) {
   4.308 +		return "Invalid HTTP Status";
   4.309 +	}
   4.310 +
   4.311 +	if(idx < 0 || idx >= msgcount[type]) {
   4.312 +		return "Unknown HTTP Status";
   4.313 +	}
   4.314 +
   4.315 +	return msgxxx[type][idx];
   4.316 +}
   4.317 +
   4.318 +static enum http_method parse_method(const char *s)
   4.319 +{
   4.320 +	int i;
   4.321 +	for(i=0; http_method_str[i]; i++) {
   4.322 +		if(strcmp(s, http_method_str[i]) == 0) {
   4.323 +			return (enum http_method)i;
   4.324 +		}
   4.325 +	}
   4.326 +	return HTTP_UNKNOWN;
   4.327 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/libtinyweb/src/http.h	Sat Apr 18 22:47:57 2015 +0300
     5.3 @@ -0,0 +1,50 @@
     5.4 +#ifndef HTTP_H_
     5.5 +#define HTTP_H_
     5.6 +
     5.7 +enum http_method {
     5.8 +	HTTP_UNKNOWN,
     5.9 +	HTTP_OPTIONS,
    5.10 +	HTTP_GET,
    5.11 +	HTTP_HEAD,
    5.12 +	HTTP_POST,
    5.13 +	HTTP_PUT,
    5.14 +	HTTP_DELETE,
    5.15 +	HTTP_TRACE,
    5.16 +	HTTP_CONNECT,
    5.17 +
    5.18 +	NUM_HTTP_METHODS
    5.19 +};
    5.20 +
    5.21 +struct http_req_header {
    5.22 +	enum http_method method;
    5.23 +	char *uri;
    5.24 +	int ver_major, ver_minor;	/* http version */
    5.25 +	char **hdrfields;
    5.26 +	int num_hdrfields;
    5.27 +	int body_offset;
    5.28 +};
    5.29 +
    5.30 +struct http_resp_header {
    5.31 +	int status;
    5.32 +	int ver_major, ver_minor;
    5.33 +	char **fields;
    5.34 +	int num_fields;
    5.35 +};
    5.36 +
    5.37 +#define HTTP_HDR_OK			0
    5.38 +#define HTTP_HDR_INVALID	-1
    5.39 +#define HTTP_HDR_NOMEM		-2
    5.40 +#define HTTP_HDR_PARTIAL	-3
    5.41 +
    5.42 +int http_parse_request(struct http_req_header *hdr, const char *buf, int bufsz);
    5.43 +void http_log_request(struct http_req_header *hdr);
    5.44 +void http_destroy_request(struct http_req_header *hdr);
    5.45 +
    5.46 +int http_init_resp(struct http_resp_header *resp);
    5.47 +int http_add_resp_field(struct http_resp_header *resp, const char *fmt, ...);
    5.48 +void http_destroy_resp(struct http_resp_header *resp);
    5.49 +int http_serialize_resp(struct http_resp_header *resp, char *buf);
    5.50 +
    5.51 +const char *http_strmsg(int code);
    5.52 +
    5.53 +#endif	/* HTTP_H_ */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/libtinyweb/src/logger.c	Sat Apr 18 22:47:57 2015 +0300
     6.3 @@ -0,0 +1,34 @@
     6.4 +#include <stdio.h>
     6.5 +#include <stdlib.h>
     6.6 +#include <string.h>
     6.7 +#include <stdarg.h>
     6.8 +#include <errno.h>
     6.9 +#include "logger.h"
    6.10 +
    6.11 +static FILE *logfile;
    6.12 +
    6.13 +int set_log_file(const char *fname)
    6.14 +{
    6.15 +	FILE *fp;
    6.16 +
    6.17 +	if(!(fp = fopen(fname, "w"))) {
    6.18 +		fprintf(stderr, "failed to open logfile: %s: %s\n", fname, strerror(errno));
    6.19 +		return -1;
    6.20 +	}
    6.21 +	setvbuf(fp, 0, _IONBF, 0);
    6.22 +	logfile = fp;
    6.23 +	return 0;
    6.24 +}
    6.25 +
    6.26 +void logmsg(const char *fmt, ...)
    6.27 +{
    6.28 +	va_list ap;
    6.29 +
    6.30 +	if(!logfile) {
    6.31 +		logfile = stderr;
    6.32 +	}
    6.33 +
    6.34 +	va_start(ap, fmt);
    6.35 +	vfprintf(logfile, fmt, ap);
    6.36 +	va_end(ap);
    6.37 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/libtinyweb/src/logger.h	Sat Apr 18 22:47:57 2015 +0300
     7.3 @@ -0,0 +1,8 @@
     7.4 +#ifndef LOGGER_H_
     7.5 +#define LOGGER_H_
     7.6 +
     7.7 +int set_log_file(const char *fname);
     7.8 +
     7.9 +void logmsg(const char *fname, ...);
    7.10 +
    7.11 +#endif	/* LOGGER_H_ */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/libtinyweb/src/mime.c	Sat Apr 18 22:47:57 2015 +0300
     8.3 @@ -0,0 +1,72 @@
     8.4 +#include <stdlib.h>
     8.5 +#include <string.h>
     8.6 +#include "mime.h"
     8.7 +#include "rbtree.h"
     8.8 +
     8.9 +/* TODO: do proper content detection */
    8.10 +struct mime_type {
    8.11 +	const char *suffix, *type;
    8.12 +};
    8.13 +
    8.14 +static struct mime_type def_types[] = {
    8.15 +	{"txt", "text/plain"},
    8.16 +	{"htm", "text/html"},
    8.17 +	{"html", "text/html"},
    8.18 +	{"png", "image/png"},
    8.19 +	{"jpg", "image/jpeg"},
    8.20 +	{"jpeg", "image/jpeg"},
    8.21 +	{"gif", "image/gif"},
    8.22 +	{"bmp", "image/bmp"},
    8.23 +	{"cgi", 0},
    8.24 +	{0, 0}
    8.25 +};
    8.26 +
    8.27 +static int init_types(void);
    8.28 +static void del_func(struct rbnode *node, void *cls);
    8.29 +
    8.30 +static struct rbtree *types;
    8.31 +
    8.32 +static int init_types(void)
    8.33 +{
    8.34 +	int i;
    8.35 +
    8.36 +	if(types) return 0;
    8.37 +
    8.38 +	if(!(types = rb_create(RB_KEY_STRING))) {
    8.39 +		return -1;
    8.40 +	}
    8.41 +	rb_set_delete_func(types, del_func, 0);
    8.42 +
    8.43 +	for(i=0; def_types[i].suffix; i++) {
    8.44 +		add_mime_type(def_types[i].suffix, def_types[i].type);
    8.45 +	}
    8.46 +	return 0;
    8.47 +}
    8.48 +
    8.49 +static void del_func(struct rbnode *node, void *cls)
    8.50 +{
    8.51 +	free(node->key);
    8.52 +	free(node->data);
    8.53 +}
    8.54 +
    8.55 +int add_mime_type(const char *suffix, const char *type)
    8.56 +{
    8.57 +	init_types();
    8.58 +
    8.59 +	return rb_insert(types, strdup(suffix), type ? strdup(type) : 0);
    8.60 +}
    8.61 +
    8.62 +const char *mime_type(const char *path)
    8.63 +{
    8.64 +	const char *suffix;
    8.65 +
    8.66 +	init_types();
    8.67 +
    8.68 +	if((suffix = strrchr(path, '.'))) {
    8.69 +		struct rbnode *node = rb_find(types, (void*)(suffix + 1));
    8.70 +		if(node) {
    8.71 +			return node->data;
    8.72 +		}
    8.73 +	}
    8.74 +	return "text/plain";
    8.75 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/libtinyweb/src/mime.h	Sat Apr 18 22:47:57 2015 +0300
     9.3 @@ -0,0 +1,7 @@
     9.4 +#ifndef MIME_H_
     9.5 +#define MIME_H_
     9.6 +
     9.7 +int add_mime_type(const char *suffix, const char *type);
     9.8 +const char *mime_type(const char *path);
     9.9 +
    9.10 +#endif	/* MIME_H_ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/libtinyweb/src/rbtree.c	Sat Apr 18 22:47:57 2015 +0300
    10.3 @@ -0,0 +1,501 @@
    10.4 +/*
    10.5 +rbtree - simple balanced binary search tree (red-black tree) library.
    10.6 +Copyright (C) 2011-2014  John Tsiombikas <nuclear@member.fsf.org>
    10.7 +
    10.8 +rbtree is free software, feel free to use, modify, and redistribute it, under
    10.9 +the terms of the 3-clause BSD license. See COPYING for details.
   10.10 + */
   10.11 +#include <stdio.h>
   10.12 +#include <stdlib.h>
   10.13 +#include <stdint.h>
   10.14 +#include <string.h>
   10.15 +#include "rbtree.h"
   10.16 +
   10.17 +#define INT2PTR(x)	((void*)(intptr_t)(x))
   10.18 +#define PTR2INT(x)	((int)(intptr_t)(x))
   10.19 +
   10.20 +struct rbtree {
   10.21 +	struct rbnode *root;
   10.22 +
   10.23 +	rb_alloc_func_t alloc;
   10.24 +	rb_free_func_t free;
   10.25 +
   10.26 +	rb_cmp_func_t cmp;
   10.27 +	rb_del_func_t del;
   10.28 +	void *del_cls;
   10.29 +
   10.30 +	struct rbnode *rstack, *iter;
   10.31 +};
   10.32 +
   10.33 +static int cmpaddr(const void *ap, const void *bp);
   10.34 +static int cmpint(const void *ap, const void *bp);
   10.35 +
   10.36 +static int count_nodes(struct rbnode *node);
   10.37 +static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls);
   10.38 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data);
   10.39 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key);
   10.40 +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key);*/
   10.41 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls);
   10.42 +
   10.43 +struct rbtree *rb_create(rb_cmp_func_t cmp_func)
   10.44 +{
   10.45 +	struct rbtree *rb;
   10.46 +
   10.47 +	if(!(rb = malloc(sizeof *rb))) {
   10.48 +		return 0;
   10.49 +	}
   10.50 +	if(rb_init(rb, cmp_func) == -1) {
   10.51 +		free(rb);
   10.52 +		return 0;
   10.53 +	}
   10.54 +	return rb;
   10.55 +}
   10.56 +
   10.57 +void rb_free(struct rbtree *rb)
   10.58 +{
   10.59 +	rb_destroy(rb);
   10.60 +	free(rb);
   10.61 +}
   10.62 +
   10.63 +
   10.64 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func)
   10.65 +{
   10.66 +	memset(rb, 0, sizeof *rb);
   10.67 +
   10.68 +	if(!cmp_func) {
   10.69 +		rb->cmp = cmpaddr;
   10.70 +	} else if(cmp_func == RB_KEY_INT) {
   10.71 +		rb->cmp = cmpint;
   10.72 +	} else if(cmp_func == RB_KEY_STRING) {
   10.73 +		rb->cmp = (rb_cmp_func_t)strcmp;
   10.74 +	} else {
   10.75 +		rb->cmp = cmp_func;
   10.76 +	}
   10.77 +
   10.78 +	rb->alloc = malloc;
   10.79 +	rb->free = free;
   10.80 +	return 0;
   10.81 +}
   10.82 +
   10.83 +void rb_destroy(struct rbtree *rb)
   10.84 +{
   10.85 +	del_tree(rb->root, rb->del, rb->del_cls);
   10.86 +}
   10.87 +
   10.88 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free)
   10.89 +{
   10.90 +	rb->alloc = alloc;
   10.91 +	rb->free = free;
   10.92 +}
   10.93 +
   10.94 +
   10.95 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func)
   10.96 +{
   10.97 +	rb->cmp = func;
   10.98 +}
   10.99 +
  10.100 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls)
  10.101 +{
  10.102 +	rb->del = func;
  10.103 +	rb->del_cls = cls;
  10.104 +}
  10.105 +
  10.106 +
  10.107 +void rb_clear(struct rbtree *rb)
  10.108 +{
  10.109 +	del_tree(rb->root, rb->del, rb->del_cls);
  10.110 +	rb->root = 0;
  10.111 +}
  10.112 +
  10.113 +int rb_copy(struct rbtree *dest, struct rbtree *src)
  10.114 +{
  10.115 +	struct rbnode *node;
  10.116 +
  10.117 +	rb_clear(dest);
  10.118 +	rb_begin(src);
  10.119 +	while((node = rb_next(src))) {
  10.120 +		if(rb_insert(dest, node->key, node->data) == -1) {
  10.121 +			return -1;
  10.122 +		}
  10.123 +	}
  10.124 +	return 0;
  10.125 +}
  10.126 +
  10.127 +int rb_size(struct rbtree *rb)
  10.128 +{
  10.129 +	return count_nodes(rb->root);
  10.130 +}
  10.131 +
  10.132 +int rb_insert(struct rbtree *rb, void *key, void *data)
  10.133 +{
  10.134 +	rb->root = insert(rb, rb->root, key, data);
  10.135 +	rb->root->red = 0;
  10.136 +	return 0;
  10.137 +}
  10.138 +
  10.139 +int rb_inserti(struct rbtree *rb, int key, void *data)
  10.140 +{
  10.141 +	rb->root = insert(rb, rb->root, INT2PTR(key), data);
  10.142 +	rb->root->red = 0;
  10.143 +	return 0;
  10.144 +}
  10.145 +
  10.146 +
  10.147 +int rb_delete(struct rbtree *rb, void *key)
  10.148 +{
  10.149 +	rb->root = delete(rb, rb->root, key);
  10.150 +	rb->root->red = 0;
  10.151 +	return 0;
  10.152 +}
  10.153 +
  10.154 +int rb_deletei(struct rbtree *rb, int key)
  10.155 +{
  10.156 +	rb->root = delete(rb, rb->root, INT2PTR(key));
  10.157 +	rb->root->red = 0;
  10.158 +	return 0;
  10.159 +}
  10.160 +
  10.161 +
  10.162 +struct rbnode *rb_find(struct rbtree *rb, void *key)
  10.163 +{
  10.164 +	struct rbnode *node = rb->root;
  10.165 +
  10.166 +	while(node) {
  10.167 +		int cmp = rb->cmp(key, node->key);
  10.168 +		if(cmp == 0) {
  10.169 +			return node;
  10.170 +		}
  10.171 +		node = cmp < 0 ? node->left : node->right;
  10.172 +	}
  10.173 +	return 0;
  10.174 +}
  10.175 +
  10.176 +struct rbnode *rb_findi(struct rbtree *rb, int key)
  10.177 +{
  10.178 +	return rb_find(rb, INT2PTR(key));
  10.179 +}
  10.180 +
  10.181 +
  10.182 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls)
  10.183 +{
  10.184 +	traverse(rb->root, func, cls);
  10.185 +}
  10.186 +
  10.187 +
  10.188 +struct rbnode *rb_root(struct rbtree *rb)
  10.189 +{
  10.190 +	return rb->root;
  10.191 +}
  10.192 +
  10.193 +void rb_begin(struct rbtree *rb)
  10.194 +{
  10.195 +	rb->rstack = 0;
  10.196 +	rb->iter = rb->root;
  10.197 +}
  10.198 +
  10.199 +#define push(sp, x)		((x)->next = (sp), (sp) = (x))
  10.200 +#define pop(sp)			((sp) = (sp)->next)
  10.201 +#define top(sp)			(sp)
  10.202 +
  10.203 +struct rbnode *rb_next(struct rbtree *rb)
  10.204 +{
  10.205 +	struct rbnode *res = 0;
  10.206 +
  10.207 +	while(rb->rstack || rb->iter) {
  10.208 +		if(rb->iter) {
  10.209 +			push(rb->rstack, rb->iter);
  10.210 +			rb->iter = rb->iter->left;
  10.211 +		} else {
  10.212 +			rb->iter = top(rb->rstack);
  10.213 +			pop(rb->rstack);
  10.214 +			res = rb->iter;
  10.215 +			rb->iter = rb->iter->right;
  10.216 +			break;
  10.217 +		}
  10.218 +	}
  10.219 +	return res;
  10.220 +}
  10.221 +
  10.222 +void *rb_node_key(struct rbnode *node)
  10.223 +{
  10.224 +	return node ? node->key : 0;
  10.225 +}
  10.226 +
  10.227 +int rb_node_keyi(struct rbnode *node)
  10.228 +{
  10.229 +	return node ? PTR2INT(node->key) : 0;
  10.230 +}
  10.231 +
  10.232 +void *rb_node_data(struct rbnode *node)
  10.233 +{
  10.234 +	return node ? node->data : 0;
  10.235 +}
  10.236 +
  10.237 +static int cmpaddr(const void *ap, const void *bp)
  10.238 +{
  10.239 +	return ap < bp ? -1 : (ap > bp ? 1 : 0);
  10.240 +}
  10.241 +
  10.242 +static int cmpint(const void *ap, const void *bp)
  10.243 +{
  10.244 +	return PTR2INT(ap) - PTR2INT(bp);
  10.245 +}
  10.246 +
  10.247 +
  10.248 +/* ---- left-leaning 2-3 red-black implementation ---- */
  10.249 +
  10.250 +/* helper prototypes */
  10.251 +static int is_red(struct rbnode *tree);
  10.252 +static void color_flip(struct rbnode *tree);
  10.253 +static struct rbnode *rot_left(struct rbnode *a);
  10.254 +static struct rbnode *rot_right(struct rbnode *a);
  10.255 +static struct rbnode *find_min(struct rbnode *tree);
  10.256 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree);
  10.257 +/*static struct rbnode *move_red_right(struct rbnode *tree);*/
  10.258 +static struct rbnode *move_red_left(struct rbnode *tree);
  10.259 +static struct rbnode *fix_up(struct rbnode *tree);
  10.260 +
  10.261 +static int count_nodes(struct rbnode *node)
  10.262 +{
  10.263 +	if(!node)
  10.264 +		return 0;
  10.265 +
  10.266 +	return 1 + count_nodes(node->left) + count_nodes(node->right);
  10.267 +}
  10.268 +
  10.269 +static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls)
  10.270 +{
  10.271 +	if(!node)
  10.272 +		return;
  10.273 +
  10.274 +	del_tree(node->left, delfunc, cls);
  10.275 +	del_tree(node->right, delfunc, cls);
  10.276 +
  10.277 +	if(delfunc) {
  10.278 +		delfunc(node, cls);
  10.279 +	}
  10.280 +	free(node);
  10.281 +}
  10.282 +
  10.283 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data)
  10.284 +{
  10.285 +	int cmp;
  10.286 +
  10.287 +	if(!tree) {
  10.288 +		struct rbnode *node = rb->alloc(sizeof *node);
  10.289 +		node->red = 1;
  10.290 +		node->key = key;
  10.291 +		node->data = data;
  10.292 +		node->left = node->right = 0;
  10.293 +		return node;
  10.294 +	}
  10.295 +
  10.296 +	cmp = rb->cmp(key, tree->key);
  10.297 +
  10.298 +	if(cmp < 0) {
  10.299 +		tree->left = insert(rb, tree->left, key, data);
  10.300 +	} else if(cmp > 0) {
  10.301 +		tree->right = insert(rb, tree->right, key, data);
  10.302 +	} else {
  10.303 +		tree->data = data;
  10.304 +	}
  10.305 +
  10.306 +	/* fix right-leaning reds */
  10.307 +	if(is_red(tree->right)) {
  10.308 +		tree = rot_left(tree);
  10.309 +	}
  10.310 +	/* fix two reds in a row */
  10.311 +	if(is_red(tree->left) && is_red(tree->left->left)) {
  10.312 +		tree = rot_right(tree);
  10.313 +	}
  10.314 +
  10.315 +	/* if 4-node, split it by color inversion */
  10.316 +	if(is_red(tree->left) && is_red(tree->right)) {
  10.317 +		color_flip(tree);
  10.318 +	}
  10.319 +
  10.320 +	return tree;
  10.321 +}
  10.322 +
  10.323 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key)
  10.324 +{
  10.325 +	int cmp;
  10.326 +
  10.327 +	if(!tree) {
  10.328 +		return 0;
  10.329 +	}
  10.330 +
  10.331 +	cmp = rb->cmp(key, tree->key);
  10.332 +
  10.333 +	if(cmp < 0) {
  10.334 +		if(!is_red(tree->left) && !is_red(tree->left->left)) {
  10.335 +			tree = move_red_left(tree);
  10.336 +		}
  10.337 +		tree->left = delete(rb, tree->left, key);
  10.338 +	} else {
  10.339 +		/* need reds on the right */
  10.340 +		if(is_red(tree->left)) {
  10.341 +			tree = rot_right(tree);
  10.342 +		}
  10.343 +
  10.344 +		/* found it at the bottom (XXX what certifies left is null?) */
  10.345 +		if(cmp == 0 && !tree->right) {
  10.346 +			if(rb->del) {
  10.347 +				rb->del(tree, rb->del_cls);
  10.348 +			}
  10.349 +			rb->free(tree);
  10.350 +			return 0;
  10.351 +		}
  10.352 +
  10.353 +		if(!is_red(tree->right) && !is_red(tree->right->left)) {
  10.354 +			tree = move_red_left(tree);
  10.355 +		}
  10.356 +
  10.357 +		if(key == tree->key) {
  10.358 +			struct rbnode *rmin = find_min(tree->right);
  10.359 +			tree->key = rmin->key;
  10.360 +			tree->data = rmin->data;
  10.361 +			tree->right = del_min(rb, tree->right);
  10.362 +		} else {
  10.363 +			tree->right = delete(rb, tree->right, key);
  10.364 +		}
  10.365 +	}
  10.366 +
  10.367 +	return fix_up(tree);
  10.368 +}
  10.369 +
  10.370 +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key)
  10.371 +{
  10.372 +	int cmp;
  10.373 +
  10.374 +	if(!node)
  10.375 +		return 0;
  10.376 +
  10.377 +	if((cmp = rb->cmp(key, node->key)) == 0) {
  10.378 +		return node;
  10.379 +	}
  10.380 +	return find(rb, cmp < 0 ? node->left : node->right, key);
  10.381 +}*/
  10.382 +
  10.383 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls)
  10.384 +{
  10.385 +	if(!node)
  10.386 +		return;
  10.387 +
  10.388 +	traverse(node->left, func, cls);
  10.389 +	func(node, cls);
  10.390 +	traverse(node->right, func, cls);
  10.391 +}
  10.392 +
  10.393 +/* helpers */
  10.394 +
  10.395 +static int is_red(struct rbnode *tree)
  10.396 +{
  10.397 +	return tree && tree->red;
  10.398 +}
  10.399 +
  10.400 +static void color_flip(struct rbnode *tree)
  10.401 +{
  10.402 +	tree->red = !tree->red;
  10.403 +	tree->left->red = !tree->left->red;
  10.404 +	tree->right->red = !tree->right->red;
  10.405 +}
  10.406 +
  10.407 +static struct rbnode *rot_left(struct rbnode *a)
  10.408 +{
  10.409 +	struct rbnode *b = a->right;
  10.410 +	a->right = b->left;
  10.411 +	b->left = a;
  10.412 +	b->red = a->red;
  10.413 +	a->red = 1;
  10.414 +	return b;
  10.415 +}
  10.416 +
  10.417 +static struct rbnode *rot_right(struct rbnode *a)
  10.418 +{
  10.419 +	struct rbnode *b = a->left;
  10.420 +	a->left = b->right;
  10.421 +	b->right = a;
  10.422 +	b->red = a->red;
  10.423 +	a->red = 1;
  10.424 +	return b;
  10.425 +}
  10.426 +
  10.427 +static struct rbnode *find_min(struct rbnode *tree)
  10.428 +{
  10.429 +	if(!tree)
  10.430 +		return 0;
  10.431 +
  10.432 +	while(tree->left) {
  10.433 +		tree = tree->left;
  10.434 +	}
  10.435 +	return tree;
  10.436 +}
  10.437 +
  10.438 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree)
  10.439 +{
  10.440 +	if(!tree->left) {
  10.441 +		if(rb->del) {
  10.442 +			rb->del(tree->left, rb->del_cls);
  10.443 +		}
  10.444 +		rb->free(tree->left);
  10.445 +		return 0;
  10.446 +	}
  10.447 +
  10.448 +	/* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */
  10.449 +	if(!is_red(tree->left) && !is_red(tree->left->left)) {
  10.450 +		tree = move_red_left(tree);
  10.451 +	}
  10.452 +	tree->left = del_min(rb, tree->left);
  10.453 +
  10.454 +	/* fix right-reds, red-reds, and split 4-nodes on the way up */
  10.455 +	return fix_up(tree);
  10.456 +}
  10.457 +
  10.458 +#if 0
  10.459 +/* push a red link on this node to the right */
  10.460 +static struct rbnode *move_red_right(struct rbnode *tree)
  10.461 +{
  10.462 +	/* flipping it makes both children go red, so we have a red to the right */
  10.463 +	color_flip(tree);
  10.464 +
  10.465 +	/* if after the flip we've got a red-red situation to the left, fix it */
  10.466 +	if(is_red(tree->left->left)) {
  10.467 +		tree = rot_right(tree);
  10.468 +		color_flip(tree);
  10.469 +	}
  10.470 +	return tree;
  10.471 +}
  10.472 +#endif
  10.473 +
  10.474 +/* push a red link on this node to the left */
  10.475 +static struct rbnode *move_red_left(struct rbnode *tree)
  10.476 +{
  10.477 +	/* flipping it makes both children go red, so we have a red to the left */
  10.478 +	color_flip(tree);
  10.479 +
  10.480 +	/* if after the flip we've got a red-red on the right-left, fix it */
  10.481 +	if(is_red(tree->right->left)) {
  10.482 +		tree->right = rot_right(tree->right);
  10.483 +		tree = rot_left(tree);
  10.484 +		color_flip(tree);
  10.485 +	}
  10.486 +	return tree;
  10.487 +}
  10.488 +
  10.489 +static struct rbnode *fix_up(struct rbnode *tree)
  10.490 +{
  10.491 +	/* fix right-leaning */
  10.492 +	if(is_red(tree->right)) {
  10.493 +		tree = rot_left(tree);
  10.494 +	}
  10.495 +	/* change invalid red-red pairs into a proper 4-node */
  10.496 +	if(is_red(tree->left) && is_red(tree->left->left)) {
  10.497 +		tree = rot_right(tree);
  10.498 +	}
  10.499 +	/* split 4-nodes */
  10.500 +	if(is_red(tree->left) && is_red(tree->right)) {
  10.501 +		color_flip(tree);
  10.502 +	}
  10.503 +	return tree;
  10.504 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/libtinyweb/src/rbtree.h	Sat Apr 18 22:47:57 2015 +0300
    11.3 @@ -0,0 +1,78 @@
    11.4 +/*
    11.5 +rbtree - simple balanced binary search tree (red-black tree) library.
    11.6 +Copyright (C) 2011-2014  John Tsiombikas <nuclear@member.fsf.org>
    11.7 +
    11.8 +rbtree is free software, feel free to use, modify, and redistribute it, under
    11.9 +the terms of the 3-clause BSD license. See COPYING for details.
   11.10 + */
   11.11 +#ifndef RBTREE_H_
   11.12 +#define RBTREE_H_
   11.13 +
   11.14 +struct rbtree;
   11.15 +
   11.16 +
   11.17 +struct rbnode {
   11.18 +	void *key, *data;
   11.19 +	int red;
   11.20 +	struct rbnode *left, *right;
   11.21 +	struct rbnode *next;	/* for iterator stack */
   11.22 +};
   11.23 +
   11.24 +
   11.25 +typedef void *(*rb_alloc_func_t)(size_t);
   11.26 +typedef void (*rb_free_func_t)(void*);
   11.27 +
   11.28 +typedef int (*rb_cmp_func_t)(const void*, const void*);
   11.29 +typedef void (*rb_del_func_t)(struct rbnode*, void*);
   11.30 +
   11.31 +#define RB_KEY_ADDR		(rb_cmp_func_t)(0)
   11.32 +#define RB_KEY_INT		(rb_cmp_func_t)(1)
   11.33 +#define RB_KEY_STRING	(rb_cmp_func_t)(3)
   11.34 +
   11.35 +
   11.36 +#ifdef __cplusplus
   11.37 +extern "C" {
   11.38 +#endif
   11.39 +
   11.40 +struct rbtree *rb_create(rb_cmp_func_t cmp_func);
   11.41 +void rb_free(struct rbtree *rb);
   11.42 +
   11.43 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func);
   11.44 +void rb_destroy(struct rbtree *rb);
   11.45 +
   11.46 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free);
   11.47 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func);
   11.48 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls);
   11.49 +/* TODO add user deep copy function */
   11.50 +
   11.51 +void rb_clear(struct rbtree *rb);
   11.52 +int rb_copy(struct rbtree *dest, struct rbtree *src);
   11.53 +
   11.54 +int rb_size(struct rbtree *rb);
   11.55 +
   11.56 +int rb_insert(struct rbtree *rb, void *key, void *data);
   11.57 +int rb_inserti(struct rbtree *rb, int key, void *data);
   11.58 +
   11.59 +int rb_delete(struct rbtree *rb, void *key);
   11.60 +int rb_deletei(struct rbtree *rb, int key);
   11.61 +
   11.62 +struct rbnode *rb_find(struct rbtree *rb, void *key);
   11.63 +struct rbnode *rb_findi(struct rbtree *rb, int key);
   11.64 +
   11.65 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls);
   11.66 +
   11.67 +struct rbnode *rb_root(struct rbtree *rb);
   11.68 +
   11.69 +void rb_begin(struct rbtree *rb);
   11.70 +struct rbnode *rb_next(struct rbtree *rb);
   11.71 +
   11.72 +void *rb_node_key(struct rbnode *node);
   11.73 +int rb_node_keyi(struct rbnode *node);
   11.74 +void *rb_node_data(struct rbnode *node);
   11.75 +
   11.76 +#ifdef __cplusplus
   11.77 +}
   11.78 +#endif
   11.79 +
   11.80 +
   11.81 +#endif	/* RBTREE_H_ */
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/libtinyweb/src/tinyweb.c	Sat Apr 18 22:47:57 2015 +0300
    12.3 @@ -0,0 +1,391 @@
    12.4 +#include <stdio.h>
    12.5 +#include <stdlib.h>
    12.6 +#include <string.h>
    12.7 +#include <ctype.h>
    12.8 +#include <errno.h>
    12.9 +#include <unistd.h>
   12.10 +#include <fcntl.h>
   12.11 +#include <sys/stat.h>
   12.12 +#include <sys/select.h>
   12.13 +#include <sys/mman.h>
   12.14 +#include <sys/types.h>
   12.15 +#include <sys/socket.h>
   12.16 +#include <arpa/inet.h>
   12.17 +#include "tinyweb.h"
   12.18 +#include "http.h"
   12.19 +#include "mime.h"
   12.20 +#include "logger.h"
   12.21 +
   12.22 +/* HTTP version */
   12.23 +#define HTTP_VER_MAJOR	1
   12.24 +#define HTTP_VER_MINOR	1
   12.25 +#define HTTP_VER_STR	"1.1"
   12.26 +
   12.27 +/* maximum request length: 64mb */
   12.28 +#define MAX_REQ_LENGTH	(65536 * 1024)
   12.29 +
   12.30 +struct client {
   12.31 +	int s;
   12.32 +	char *rcvbuf;
   12.33 +	int bufsz;
   12.34 +	struct client *next;
   12.35 +};
   12.36 +
   12.37 +static int accept_conn(int lis);
   12.38 +static void close_conn(struct client *c);
   12.39 +static int handle_client(struct client *c);
   12.40 +static int do_get(struct client *c, const char *uri, int with_body);
   12.41 +static void respond_error(struct client *c, int errcode);
   12.42 +
   12.43 +static int lis = -1;
   12.44 +static int maxfd;
   12.45 +static int port = 8080;
   12.46 +static struct client *clist;
   12.47 +static int num_clients;
   12.48 +
   12.49 +static const char *indexfiles[] = {
   12.50 +	"index.cgi",
   12.51 +	"index.html",
   12.52 +	"index.htm",
   12.53 +	0
   12.54 +};
   12.55 +
   12.56 +void tw_set_port(int p)
   12.57 +{
   12.58 +	port = p;
   12.59 +}
   12.60 +
   12.61 +int tw_set_root(const char *path)
   12.62 +{
   12.63 +	return chdir(path);
   12.64 +}
   12.65 +
   12.66 +int tw_set_logfile(const char *fname)
   12.67 +{
   12.68 +	return set_log_file(fname);
   12.69 +}
   12.70 +
   12.71 +int tw_start(void)
   12.72 +{
   12.73 +	int s;
   12.74 +	struct sockaddr_in sa;
   12.75 +
   12.76 +	logmsg("starting server ...\n");
   12.77 +
   12.78 +	if(lis != -1) {
   12.79 +		logmsg("can't start tinyweb server: already running!\n");
   12.80 +		return -1;
   12.81 +	}
   12.82 +
   12.83 +	if((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
   12.84 +		logmsg("failed to create listening socket: %s\n", strerror(errno));
   12.85 +		return -1;
   12.86 +	}
   12.87 +	fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
   12.88 +
   12.89 +	memset(&sa, 0, sizeof sa);
   12.90 +	sa.sin_family = AF_INET;
   12.91 +	sa.sin_addr.s_addr = INADDR_ANY;
   12.92 +	sa.sin_port = htons(port);
   12.93 +
   12.94 +	if(bind(s, (struct sockaddr*)&sa, sizeof sa) == -1) {
   12.95 +		logmsg("failed to bind socket to port %d: %s\n", port, strerror(errno));
   12.96 +		return -1;
   12.97 +	}
   12.98 +	listen(s, 16);
   12.99 +
  12.100 +	lis = s;
  12.101 +	return s;
  12.102 +}
  12.103 +
  12.104 +int tw_stop(void)
  12.105 +{
  12.106 +	if(lis == -1) {
  12.107 +		return -1;
  12.108 +	}
  12.109 +
  12.110 +	logmsg("stopping server...\n");
  12.111 +
  12.112 +	close(lis);
  12.113 +	lis = -1;
  12.114 +
  12.115 +	while(clist) {
  12.116 +		struct client *c = clist;
  12.117 +		clist = clist->next;
  12.118 +		close_conn(c);
  12.119 +		free(c);
  12.120 +	}
  12.121 +	clist = 0;
  12.122 +
  12.123 +	return 0;
  12.124 +}
  12.125 +
  12.126 +int tw_get_sockets(int *socks)
  12.127 +{
  12.128 +	struct client *c, dummy;
  12.129 +
  12.130 +	/* first cleanup the clients marked for removal */
  12.131 +	dummy.next = clist;
  12.132 +	c = &dummy;
  12.133 +
  12.134 +	while(c->next) {
  12.135 +		struct client *n = c->next;
  12.136 +
  12.137 +		if(n->s == -1) {
  12.138 +			/* marked for removal */
  12.139 +			c->next = n->next;
  12.140 +			free(n);
  12.141 +			--num_clients;
  12.142 +		} else {
  12.143 +			c = c->next;
  12.144 +		}
  12.145 +	}
  12.146 +	clist = dummy.next;
  12.147 +
  12.148 +
  12.149 +	if(!socks) {
  12.150 +		/* just return the count */
  12.151 +		return num_clients + 1;	/* +1 for the listening socket */
  12.152 +	}
  12.153 +
  12.154 +	/* go through the client list and populate the array */
  12.155 +	maxfd = lis;
  12.156 +	*socks++ = lis;
  12.157 +
  12.158 +	c = clist;
  12.159 +	while(c) {
  12.160 +		*socks++ = c->s;
  12.161 +		if(c->s > maxfd) {
  12.162 +			maxfd = c->s;
  12.163 +		}
  12.164 +		c = c->next;
  12.165 +	}
  12.166 +	return num_clients + 1;	/* +1 for the listening socket */
  12.167 +}
  12.168 +
  12.169 +int tw_get_maxfd(void)
  12.170 +{
  12.171 +	return maxfd;
  12.172 +}
  12.173 +
  12.174 +int tw_handle_socket(int s)
  12.175 +{
  12.176 +	struct client *c;
  12.177 +
  12.178 +	if(s == lis) {
  12.179 +		return accept_conn(s);
  12.180 +	}
  12.181 +
  12.182 +	/* find which client corresponds to this socket */
  12.183 +	c = clist;
  12.184 +	while(c) {
  12.185 +		if(c->s == s) {
  12.186 +			return handle_client(c);
  12.187 +		}
  12.188 +		c = c->next;
  12.189 +	}
  12.190 +
  12.191 +	logmsg("socket %d doesn't correspond to any client\n");
  12.192 +	return -1;
  12.193 +}
  12.194 +
  12.195 +static int accept_conn(int lis)
  12.196 +{
  12.197 +	int s;
  12.198 +	struct client *c;
  12.199 +	struct sockaddr_in addr;
  12.200 +	socklen_t addr_sz = sizeof addr;
  12.201 +
  12.202 +	if((s = accept(lis, (struct sockaddr*)&addr, &addr_sz)) == -1) {
  12.203 +		logmsg("failed to accept incoming connection: %s\n", strerror(errno));
  12.204 +		return -1;
  12.205 +	}
  12.206 +	fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
  12.207 +
  12.208 +	if(!(c = malloc(sizeof *c))) {
  12.209 +		logmsg("failed to allocate memory while accepting connection: %s\n", strerror(errno));
  12.210 +		return -1;
  12.211 +	}
  12.212 +	c->s = s;
  12.213 +	c->rcvbuf = 0;
  12.214 +	c->bufsz = 0;
  12.215 +	c->next = clist;
  12.216 +	clist = c;
  12.217 +	++num_clients;
  12.218 +	return 0;
  12.219 +}
  12.220 +
  12.221 +static void close_conn(struct client *c)
  12.222 +{
  12.223 +	close(c->s);
  12.224 +	c->s = -1;	/* mark it for removal */
  12.225 +	free(c->rcvbuf);
  12.226 +	c->rcvbuf = 0;
  12.227 +}
  12.228 +
  12.229 +static int handle_client(struct client *c)
  12.230 +{
  12.231 +	struct http_req_header hdr;
  12.232 +	static char buf[2048];
  12.233 +	int rdsz, status;
  12.234 +
  12.235 +	while((rdsz = recv(c->s, buf, sizeof buf, 0)) > 0) {
  12.236 +		char *newbuf;
  12.237 +		int newsz = c->bufsz + rdsz;
  12.238 +		if(newsz > MAX_REQ_LENGTH) {
  12.239 +			respond_error(c, 413);
  12.240 +			return -1;
  12.241 +		}
  12.242 +
  12.243 +		if(!(newbuf = realloc(c->rcvbuf, newsz + 1))) {
  12.244 +			logmsg("failed to allocate %d byte buffer\n", newsz);
  12.245 +			respond_error(c, 503);
  12.246 +			return -1;
  12.247 +		}
  12.248 +
  12.249 +		memcpy(newbuf + c->bufsz, buf, rdsz);
  12.250 +		newbuf[newsz] = 0;
  12.251 +
  12.252 +		c->rcvbuf = newbuf;
  12.253 +		c->bufsz = newsz;
  12.254 +	}
  12.255 +
  12.256 +	if((status = http_parse_request(&hdr, c->rcvbuf, c->bufsz)) != HTTP_HDR_OK) {
  12.257 +		http_log_request(&hdr);
  12.258 +		switch(status) {
  12.259 +		case HTTP_HDR_INVALID:
  12.260 +			respond_error(c, 400);
  12.261 +			return -1;
  12.262 +
  12.263 +		case HTTP_HDR_NOMEM:
  12.264 +			respond_error(c, 503);
  12.265 +			return -1;
  12.266 +
  12.267 +		case HTTP_HDR_PARTIAL:
  12.268 +			return 0;	/* partial header, continue reading */
  12.269 +		}
  12.270 +	}
  12.271 +	http_log_request(&hdr);
  12.272 +
  12.273 +	/* we only support GET and HEAD at this point, so freak out on anything else */
  12.274 +	switch(hdr.method) {
  12.275 +	case HTTP_GET:
  12.276 +		if(do_get(c, hdr.uri, 1) == -1) {
  12.277 +			return -1;
  12.278 +		}
  12.279 +		break;
  12.280 +
  12.281 +	case HTTP_HEAD:
  12.282 +		if(do_get(c, hdr.uri, 0) == -1) {
  12.283 +			return -1;
  12.284 +		}
  12.285 +		break;
  12.286 +
  12.287 +	default:
  12.288 +		respond_error(c, 501);
  12.289 +		return -1;
  12.290 +	}
  12.291 +
  12.292 +	close_conn(c);
  12.293 +	return 0;
  12.294 +}
  12.295 +
  12.296 +static int do_get(struct client *c, const char *uri, int with_body)
  12.297 +{
  12.298 +	const char *ptr;
  12.299 +	struct http_resp_header resp;
  12.300 +
  12.301 +	if((ptr = strstr(uri, "://"))) {
  12.302 +		uri = ptr + 3;
  12.303 +	}
  12.304 +
  12.305 +	/* skip the host part and the first slash if it exists */
  12.306 +	if((ptr = strchr(uri, '/'))) {
  12.307 +		uri = ptr + 1;
  12.308 +	}
  12.309 +
  12.310 +	if(*uri) {
  12.311 +		struct stat st;
  12.312 +		char *path = 0;
  12.313 +		char *rsphdr;
  12.314 +		const char *type;
  12.315 +		int fd, rspsize;
  12.316 +
  12.317 +		if(stat(uri, &st) == -1) {
  12.318 +			respond_error(c, 404);
  12.319 +			return -1;
  12.320 +		}
  12.321 +
  12.322 +		if(S_ISDIR(st.st_mode)) {
  12.323 +			int i;
  12.324 +			path = alloca(strlen(uri) + 64);
  12.325 +
  12.326 +			for(i=0; indexfiles[i]; i++) {
  12.327 +				sprintf(path, "%s/%s", uri, indexfiles[i]);
  12.328 +				if(stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) {
  12.329 +					break;
  12.330 +				}
  12.331 +			}
  12.332 +
  12.333 +			if(indexfiles[i] == 0) {
  12.334 +				respond_error(c, 404);
  12.335 +				return -1;
  12.336 +			}
  12.337 +		} else {
  12.338 +			path = (char*)uri;
  12.339 +		}
  12.340 +
  12.341 +		if((fd = open(path, O_RDONLY)) == -1) {
  12.342 +			respond_error(c, 403);
  12.343 +			return -1;
  12.344 +		}
  12.345 +
  12.346 +		/* construct response header */
  12.347 +		http_init_resp(&resp);
  12.348 +		http_add_resp_field(&resp, "Content-Length: %d", st.st_size);
  12.349 +		if((type = mime_type(path))) {
  12.350 +			http_add_resp_field(&resp, "Content-Type: %s", type);
  12.351 +		}
  12.352 +
  12.353 +		rspsize = http_serialize_resp(&resp, 0);
  12.354 +		rsphdr = alloca(rspsize);
  12.355 +		http_serialize_resp(&resp, rsphdr);
  12.356 +
  12.357 +		if(with_body) {
  12.358 +			int cont_left = st.st_size;
  12.359 +			char *cont = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  12.360 +			if(cont == (void*)-1) {
  12.361 +				respond_error(c, 503);
  12.362 +				close(fd);
  12.363 +				return -1;
  12.364 +			}
  12.365 +			ptr = cont;
  12.366 +
  12.367 +			send(c->s, rsphdr, rspsize, 0);
  12.368 +			while(cont_left > 0) {
  12.369 +				int sz = cont_left < 4096 ? cont_left : 4096;
  12.370 +				send(c->s, ptr, sz, 0);
  12.371 +				ptr += sz;
  12.372 +				cont_left -= sz;
  12.373 +			}
  12.374 +
  12.375 +			munmap(cont, st.st_size);
  12.376 +		} else {
  12.377 +			send(c->s, rsphdr, rspsize, 0);
  12.378 +		}
  12.379 +
  12.380 +		close(fd);
  12.381 +	}
  12.382 +	return 0;
  12.383 +}
  12.384 +
  12.385 +static void respond_error(struct client *c, int errcode)
  12.386 +{
  12.387 +	char buf[512];
  12.388 +
  12.389 +	sprintf(buf, "HTTP/" HTTP_VER_STR " %d %s\r\n\r\n", errcode, http_strmsg(errcode));
  12.390 +
  12.391 +	send(c->s, buf, strlen(buf), 0);
  12.392 +	close_conn(c);
  12.393 +}
  12.394 +
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/libtinyweb/src/tinyweb.h	Sat Apr 18 22:47:57 2015 +0300
    13.3 @@ -0,0 +1,16 @@
    13.4 +#ifndef TINYWEB_H_
    13.5 +#define TINYWEB_H_
    13.6 +
    13.7 +void tw_set_port(int port);
    13.8 +int tw_set_root(const char *path);
    13.9 +int tw_set_logfile(const char *fname);
   13.10 +
   13.11 +int tw_start(void);
   13.12 +int tw_stop(void);
   13.13 +
   13.14 +int tw_get_sockets(int *socks);
   13.15 +int tw_get_maxfd(void);
   13.16 +int tw_handle_socket(int s);
   13.17 +
   13.18 +
   13.19 +#endif	/* TINYWEB_H_ */
    14.1 --- a/src/http.c	Sat Apr 18 21:36:07 2015 +0300
    14.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.3 @@ -1,324 +0,0 @@
    14.4 -#include <stdio.h>
    14.5 -#include <stdlib.h>
    14.6 -#include <string.h>
    14.7 -#include <stdarg.h>
    14.8 -#include <ctype.h>
    14.9 -#include <alloca.h>
   14.10 -#include "http.h"
   14.11 -#include "logger.h"
   14.12 -
   14.13 -
   14.14 -static const char *http_method_str[] = {
   14.15 -	"<unknown>",
   14.16 -	"OPTIONS",
   14.17 -	"GET",
   14.18 -	"HEAD",
   14.19 -	"POST",
   14.20 -	"PUT",
   14.21 -	"DELETE",
   14.22 -	"TRACE",
   14.23 -	"CONNECT",
   14.24 -	0
   14.25 -};
   14.26 -
   14.27 -
   14.28 -/* HTTP 1xx message strings */
   14.29 -static const char *http_msg1xx[] = {
   14.30 -	"Continue",					/* 100 */
   14.31 -	"Switching Protocols"		/* 101 */
   14.32 -};
   14.33 -
   14.34 -/* HTTP 2xx message strings */
   14.35 -static const char *http_msg2xx[] = {
   14.36 -	"OK",						/* 200 */
   14.37 -	"Created",					/* 201 */
   14.38 -	"Accepted",					/* 202 */
   14.39 -	"Non-Authoritative Information",	/* 203 */
   14.40 -	"No Content",				/* 204 */
   14.41 -	"Reset Content",			/* 205 */
   14.42 -	"Partial Content"			/* 206 */
   14.43 -};
   14.44 -
   14.45 -/* HTTP 3xx message strings */
   14.46 -static const char *http_msg3xx[] = {
   14.47 -	"Multiple Choices",			/* 300 */
   14.48 -	"Moved Permanently",		/* 301 */
   14.49 -	"Found",					/* 302 */
   14.50 -	"See Other",				/* 303 */
   14.51 -	"Not Modified",				/* 304 */
   14.52 -	"Use Proxy",				/* 305 */
   14.53 -	"<unknown>",				/* 306 is undefined? */
   14.54 -	"Temporary Redirect"		/* 307 */
   14.55 -};
   14.56 -
   14.57 -/* HTTP 4xx error strings */
   14.58 -static const char *http_msg4xx[] = {
   14.59 -	"Bad Request",				/* 400 */
   14.60 -	"Unauthorized",				/* 401 */
   14.61 -	"What the Fuck?",			/* 402 */
   14.62 -	"Forbidden",				/* 403 */
   14.63 -	"Not Found",				/* 404 */
   14.64 -	"Method Not Allowed",		/* 405 */
   14.65 -	"Not Acceptable",			/* 406 */
   14.66 -	"Proxy Authentication Required",	/* 407 */
   14.67 -	"Request Time-out",			/* 408 */
   14.68 -	"Conflict",					/* 409 */
   14.69 -	"Gone",						/* 410 */
   14.70 -	"Length Required",			/* 411 */
   14.71 -	"Precondition Failed",		/* 412 */
   14.72 -	"Request Entity Too Large", /* 413 */
   14.73 -	"Request-URI Too Large",	/* 414 */
   14.74 -	"Unsupported Media Type",	/* 415 */
   14.75 -	"Request range not satisfiable", /* 416 */
   14.76 -	"Expectation Failed"		/* 417 */
   14.77 -};
   14.78 -
   14.79 -/* HTTP 5xx error strings */
   14.80 -static const char *http_msg5xx[] = {
   14.81 -	"Internal Server Error",	/* 500 */
   14.82 -	"Not Implemented",			/* 501 */
   14.83 -	"Bad Gateway",				/* 502 */
   14.84 -	"Service Unavailable",		/* 503 */
   14.85 -	"Gateway Time-out",			/* 504 */
   14.86 -	"HTTP Version not supported"	/* 505 */
   14.87 -};
   14.88 -
   14.89 -
   14.90 -static enum http_method parse_method(const char *s);
   14.91 -
   14.92 -
   14.93 -int http_parse_request(struct http_req_header *hdr, const char *buf, int bufsz)
   14.94 -{
   14.95 -	int i, nlines = 0;
   14.96 -	char *rqline = 0;
   14.97 -	char *method, *uri, *version, *ptr;
   14.98 -	const char *startln, *endln;
   14.99 -
  14.100 -	memset(hdr, 0, sizeof *hdr);
  14.101 -
  14.102 -	for(i=1; i<bufsz; i++) {
  14.103 -		if(buf[i] == '\n' && buf[i - 1] == '\r') {
  14.104 -			if(!rqline) {
  14.105 -				rqline = alloca(i);
  14.106 -				memcpy(rqline, buf, i - 1);
  14.107 -				rqline[i - 1] = 0;
  14.108 -			}
  14.109 -			++nlines;
  14.110 -
  14.111 -			if(i > 4 && buf[i - 2] == '\n' && buf[i - 3] == '\r') {
  14.112 -				hdr->body_offset = i + 1;
  14.113 -				break;
  14.114 -			}
  14.115 -		}
  14.116 -	}
  14.117 -
  14.118 -	if(!rqline) {
  14.119 -		return HTTP_HDR_PARTIAL;
  14.120 -	}
  14.121 -
  14.122 -	ptr = rqline;
  14.123 -	while(*ptr && isspace(*ptr)) ++ptr;
  14.124 -	method = ptr;
  14.125 -
  14.126 -	/* parse the request line */
  14.127 -	while(*ptr && !isspace(*ptr)) ++ptr;
  14.128 -	while(*ptr && isspace(*ptr)) *ptr++ = 0;
  14.129 -
  14.130 -	uri = ptr;
  14.131 -	while(*ptr && !isspace(*ptr)) ++ptr;
  14.132 -	while(*ptr && isspace(*ptr)) *ptr++ = 0;
  14.133 -
  14.134 -	version = ptr;
  14.135 -	while(*ptr && !isspace(*ptr)) ++ptr;
  14.136 -	while(*ptr && isspace(*ptr)) *ptr++ = 0;
  14.137 -
  14.138 -	hdr->method = parse_method(method);
  14.139 -	hdr->uri = strdup(uri);
  14.140 -	if(sscanf(version, "HTTP/%d.%d", &hdr->ver_major, &hdr->ver_minor) != 2) {
  14.141 -		fprintf(stderr, "warning: failed to parse HTTP version \"%s\"\n", version);
  14.142 -		hdr->ver_major = 1;
  14.143 -		hdr->ver_minor = 1;
  14.144 -	}
  14.145 -
  14.146 -	if(!(hdr->hdrfields = malloc(nlines * sizeof *hdr->hdrfields))) {
  14.147 -		perror("failed to allocate memory for the header fields");
  14.148 -		return HTTP_HDR_NOMEM;
  14.149 -	}
  14.150 -	hdr->num_hdrfields = 0;
  14.151 -
  14.152 -	startln = buf;
  14.153 -	endln = buf;
  14.154 -	for(i=1; i<hdr->body_offset - 2; i++) {
  14.155 -		if(buf[i] == '\n' && buf[i - 1] == '\r') {
  14.156 -			int linesz;
  14.157 -
  14.158 -			endln = buf + i - 1;
  14.159 -			linesz = endln - startln;
  14.160 -
  14.161 -			if(startln > buf) {	/* skip first line */
  14.162 -				int idx = hdr->num_hdrfields++;
  14.163 -				hdr->hdrfields[idx] = malloc(linesz + 1);
  14.164 -				memcpy(hdr->hdrfields[idx], startln, linesz);
  14.165 -				hdr->hdrfields[idx][linesz] = 0;
  14.166 -			}
  14.167 -			startln = endln = buf + i + 1;
  14.168 -		}
  14.169 -	}
  14.170 -
  14.171 -	return HTTP_HDR_OK;
  14.172 -}
  14.173 -
  14.174 -void http_log_request(struct http_req_header *hdr)
  14.175 -{
  14.176 -	int i;
  14.177 -
  14.178 -	logmsg("HTTP request header\n");
  14.179 -	logmsg(" method: %s\n", http_method_str[hdr->method]);
  14.180 -	logmsg(" uri: %s\n", hdr->uri);
  14.181 -	logmsg(" version: %d.%d\n", hdr->ver_major, hdr->ver_minor);
  14.182 -	logmsg(" fields (%d):\n", hdr->num_hdrfields);
  14.183 -
  14.184 -	for(i=0; i<hdr->num_hdrfields; i++) {
  14.185 -		logmsg("   %s\n", hdr->hdrfields[i]);
  14.186 -	}
  14.187 -	logmsg("\n");
  14.188 -}
  14.189 -
  14.190 -void http_destroy_request(struct http_req_header *hdr)
  14.191 -{
  14.192 -	int i;
  14.193 -
  14.194 -	if(hdr->hdrfields) {
  14.195 -		for(i=0; i<hdr->num_hdrfields; i++) {
  14.196 -			free(hdr->hdrfields[i]);
  14.197 -		}
  14.198 -		free(hdr->hdrfields);
  14.199 -	}
  14.200 -	free(hdr->uri);
  14.201 -}
  14.202 -
  14.203 -int http_init_resp(struct http_resp_header *resp)
  14.204 -{
  14.205 -	memset(resp, 0, sizeof *resp);
  14.206 -	resp->status = 200;
  14.207 -	resp->ver_major = resp->ver_minor = 1;
  14.208 -	resp->fields = 0;
  14.209 -	resp->num_fields = 0;
  14.210 -
  14.211 -	return 0;
  14.212 -}
  14.213 -
  14.214 -int http_add_resp_field(struct http_resp_header *resp, const char *fmt, ...)
  14.215 -{
  14.216 -	int sz;
  14.217 -	va_list ap;
  14.218 -	char *field, **newarr, tmp;
  14.219 -
  14.220 -	va_start(ap, fmt);
  14.221 -	sz = vsnprintf(&tmp, 0, fmt, ap);
  14.222 -	va_end(ap);
  14.223 -
  14.224 -	if(sz <= 0) sz = 1023;
  14.225 -	if(!(field = malloc(sz + 1))) {
  14.226 -		return -1;
  14.227 -	}
  14.228 -	va_start(ap, fmt);
  14.229 -	vsnprintf(field, sz + 1, fmt, ap);
  14.230 -	va_end(ap);
  14.231 -
  14.232 -	if(!(newarr = realloc(resp->fields, (resp->num_fields + 1) * sizeof *resp->fields))) {
  14.233 -		free(field);
  14.234 -		return -1;
  14.235 -	}
  14.236 -	resp->fields = newarr;
  14.237 -
  14.238 -	resp->fields[resp->num_fields++] = field;
  14.239 -	return 0;
  14.240 -}
  14.241 -
  14.242 -void http_destroy_resp(struct http_resp_header *resp)
  14.243 -{
  14.244 -	int i;
  14.245 -	if(resp->fields) {
  14.246 -		for(i=0; i<resp->num_fields; i++) {
  14.247 -			free(resp->fields[i]);
  14.248 -		}
  14.249 -		free(resp->fields);
  14.250 -		resp->fields = 0;
  14.251 -	}
  14.252 -	resp->num_fields = 0;
  14.253 -}
  14.254 -
  14.255 -int http_serialize_resp(struct http_resp_header *resp, char *buf)
  14.256 -{
  14.257 -	int i, stsize, size, *fsize;
  14.258 -	char *ptr, tmp;
  14.259 -
  14.260 -	stsize = snprintf(&tmp, 0, "HTTP/%d.%d %d %s\r\n", resp->ver_major, resp->ver_minor,
  14.261 -			resp->status, http_strmsg(resp->status));
  14.262 -
  14.263 -	fsize = alloca(resp->num_fields * sizeof *fsize);
  14.264 -
  14.265 -	size = stsize;
  14.266 -	for(i=0; i<resp->num_fields; i++) {
  14.267 -		int len = strlen(resp->fields[i]) + 2;
  14.268 -		fsize[i] = len;
  14.269 -		size += len;
  14.270 -	}
  14.271 -	size += 2;	/* CRLF and null */
  14.272 -
  14.273 -	if(buf) {
  14.274 -		sprintf(buf, "HTTP/%d.%d %d %s\r\n", resp->ver_major, resp->ver_minor,
  14.275 -				resp->status, http_strmsg(resp->status));
  14.276 -
  14.277 -		ptr = buf + stsize;
  14.278 -		for(i=0; i<resp->num_fields; i++) {
  14.279 -			sprintf(ptr, "%s\r\n", resp->fields[i]);
  14.280 -			ptr += fsize[i];
  14.281 -		}
  14.282 -		*ptr++ = '\r';
  14.283 -		*ptr++ = '\n';
  14.284 -		*ptr++ = 0;
  14.285 -	}
  14.286 -
  14.287 -	return size;
  14.288 -}
  14.289 -
  14.290 -const char *http_strmsg(int code)
  14.291 -{
  14.292 -	static const char **msgxxx[] = {
  14.293 -		0, http_msg1xx, http_msg2xx, http_msg3xx, http_msg4xx, http_msg5xx
  14.294 -	};
  14.295 -	static int msgcount[] = {
  14.296 -		0,
  14.297 -		sizeof http_msg1xx / sizeof *http_msg1xx,
  14.298 -		sizeof http_msg2xx / sizeof *http_msg2xx,
  14.299 -		sizeof http_msg3xx / sizeof *http_msg3xx,
  14.300 -		sizeof http_msg4xx / sizeof *http_msg4xx,
  14.301 -		sizeof http_msg5xx / sizeof *http_msg5xx
  14.302 -	};
  14.303 -
  14.304 -	int type = code / 100;
  14.305 -	int idx = code % 100;
  14.306 -
  14.307 -	if(type < 1 || type >= sizeof msgxxx / sizeof *msgxxx) {
  14.308 -		return "Invalid HTTP Status";
  14.309 -	}
  14.310 -
  14.311 -	if(idx < 0 || idx >= msgcount[type]) {
  14.312 -		return "Unknown HTTP Status";
  14.313 -	}
  14.314 -
  14.315 -	return msgxxx[type][idx];
  14.316 -}
  14.317 -
  14.318 -static enum http_method parse_method(const char *s)
  14.319 -{
  14.320 -	int i;
  14.321 -	for(i=0; http_method_str[i]; i++) {
  14.322 -		if(strcmp(s, http_method_str[i]) == 0) {
  14.323 -			return (enum http_method)i;
  14.324 -		}
  14.325 -	}
  14.326 -	return HTTP_UNKNOWN;
  14.327 -}
    15.1 --- a/src/http.h	Sat Apr 18 21:36:07 2015 +0300
    15.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.3 @@ -1,50 +0,0 @@
    15.4 -#ifndef HTTP_H_
    15.5 -#define HTTP_H_
    15.6 -
    15.7 -enum http_method {
    15.8 -	HTTP_UNKNOWN,
    15.9 -	HTTP_OPTIONS,
   15.10 -	HTTP_GET,
   15.11 -	HTTP_HEAD,
   15.12 -	HTTP_POST,
   15.13 -	HTTP_PUT,
   15.14 -	HTTP_DELETE,
   15.15 -	HTTP_TRACE,
   15.16 -	HTTP_CONNECT,
   15.17 -
   15.18 -	NUM_HTTP_METHODS
   15.19 -};
   15.20 -
   15.21 -struct http_req_header {
   15.22 -	enum http_method method;
   15.23 -	char *uri;
   15.24 -	int ver_major, ver_minor;	/* http version */
   15.25 -	char **hdrfields;
   15.26 -	int num_hdrfields;
   15.27 -	int body_offset;
   15.28 -};
   15.29 -
   15.30 -struct http_resp_header {
   15.31 -	int status;
   15.32 -	int ver_major, ver_minor;
   15.33 -	char **fields;
   15.34 -	int num_fields;
   15.35 -};
   15.36 -
   15.37 -#define HTTP_HDR_OK			0
   15.38 -#define HTTP_HDR_INVALID	-1
   15.39 -#define HTTP_HDR_NOMEM		-2
   15.40 -#define HTTP_HDR_PARTIAL	-3
   15.41 -
   15.42 -int http_parse_request(struct http_req_header *hdr, const char *buf, int bufsz);
   15.43 -void http_log_request(struct http_req_header *hdr);
   15.44 -void http_destroy_request(struct http_req_header *hdr);
   15.45 -
   15.46 -int http_init_resp(struct http_resp_header *resp);
   15.47 -int http_add_resp_field(struct http_resp_header *resp, const char *fmt, ...);
   15.48 -void http_destroy_resp(struct http_resp_header *resp);
   15.49 -int http_serialize_resp(struct http_resp_header *resp, char *buf);
   15.50 -
   15.51 -const char *http_strmsg(int code);
   15.52 -
   15.53 -#endif	/* HTTP_H_ */
    16.1 --- a/src/logger.c	Sat Apr 18 21:36:07 2015 +0300
    16.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.3 @@ -1,34 +0,0 @@
    16.4 -#include <stdio.h>
    16.5 -#include <stdlib.h>
    16.6 -#include <string.h>
    16.7 -#include <stdarg.h>
    16.8 -#include <errno.h>
    16.9 -#include "logger.h"
   16.10 -
   16.11 -static FILE *logfile;
   16.12 -
   16.13 -int set_log_file(const char *fname)
   16.14 -{
   16.15 -	FILE *fp;
   16.16 -
   16.17 -	if(!(fp = fopen(fname, "w"))) {
   16.18 -		fprintf(stderr, "failed to open logfile: %s: %s\n", fname, strerror(errno));
   16.19 -		return -1;
   16.20 -	}
   16.21 -	setvbuf(fp, 0, _IONBF, 0);
   16.22 -	logfile = fp;
   16.23 -	return 0;
   16.24 -}
   16.25 -
   16.26 -void logmsg(const char *fmt, ...)
   16.27 -{
   16.28 -	va_list ap;
   16.29 -
   16.30 -	if(!logfile) {
   16.31 -		logfile = stderr;
   16.32 -	}
   16.33 -
   16.34 -	va_start(ap, fmt);
   16.35 -	vfprintf(logfile, fmt, ap);
   16.36 -	va_end(ap);
   16.37 -}
    17.1 --- a/src/logger.h	Sat Apr 18 21:36:07 2015 +0300
    17.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.3 @@ -1,8 +0,0 @@
    17.4 -#ifndef LOGGER_H_
    17.5 -#define LOGGER_H_
    17.6 -
    17.7 -int set_log_file(const char *fname);
    17.8 -
    17.9 -void logmsg(const char *fname, ...);
   17.10 -
   17.11 -#endif	/* LOGGER_H_ */
    18.1 --- a/src/mime.c	Sat Apr 18 21:36:07 2015 +0300
    18.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.3 @@ -1,72 +0,0 @@
    18.4 -#include <stdlib.h>
    18.5 -#include <string.h>
    18.6 -#include "mime.h"
    18.7 -#include "rbtree.h"
    18.8 -
    18.9 -/* TODO: do proper content detection */
   18.10 -struct mime_type {
   18.11 -	const char *suffix, *type;
   18.12 -};
   18.13 -
   18.14 -static struct mime_type def_types[] = {
   18.15 -	{"txt", "text/plain"},
   18.16 -	{"htm", "text/html"},
   18.17 -	{"html", "text/html"},
   18.18 -	{"png", "image/png"},
   18.19 -	{"jpg", "image/jpeg"},
   18.20 -	{"jpeg", "image/jpeg"},
   18.21 -	{"gif", "image/gif"},
   18.22 -	{"bmp", "image/bmp"},
   18.23 -	{"cgi", 0},
   18.24 -	{0, 0}
   18.25 -};
   18.26 -
   18.27 -static int init_types(void);
   18.28 -static void del_func(struct rbnode *node, void *cls);
   18.29 -
   18.30 -static struct rbtree *types;
   18.31 -
   18.32 -static int init_types(void)
   18.33 -{
   18.34 -	int i;
   18.35 -
   18.36 -	if(types) return 0;
   18.37 -
   18.38 -	if(!(types = rb_create(RB_KEY_STRING))) {
   18.39 -		return -1;
   18.40 -	}
   18.41 -	rb_set_delete_func(types, del_func, 0);
   18.42 -
   18.43 -	for(i=0; def_types[i].suffix; i++) {
   18.44 -		add_mime_type(def_types[i].suffix, def_types[i].type);
   18.45 -	}
   18.46 -	return 0;
   18.47 -}
   18.48 -
   18.49 -static void del_func(struct rbnode *node, void *cls)
   18.50 -{
   18.51 -	free(node->key);
   18.52 -	free(node->data);
   18.53 -}
   18.54 -
   18.55 -int add_mime_type(const char *suffix, const char *type)
   18.56 -{
   18.57 -	init_types();
   18.58 -
   18.59 -	return rb_insert(types, strdup(suffix), type ? strdup(type) : 0);
   18.60 -}
   18.61 -
   18.62 -const char *mime_type(const char *path)
   18.63 -{
   18.64 -	const char *suffix;
   18.65 -
   18.66 -	init_types();
   18.67 -
   18.68 -	if((suffix = strrchr(path, '.'))) {
   18.69 -		struct rbnode *node = rb_find(types, (void*)(suffix + 1));
   18.70 -		if(node) {
   18.71 -			return node->data;
   18.72 -		}
   18.73 -	}
   18.74 -	return "text/plain";
   18.75 -}
    19.1 --- a/src/mime.h	Sat Apr 18 21:36:07 2015 +0300
    19.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.3 @@ -1,7 +0,0 @@
    19.4 -#ifndef MIME_H_
    19.5 -#define MIME_H_
    19.6 -
    19.7 -int add_mime_type(const char *suffix, const char *type);
    19.8 -const char *mime_type(const char *path);
    19.9 -
   19.10 -#endif	/* MIME_H_ */
    20.1 --- a/src/rbtree.c	Sat Apr 18 21:36:07 2015 +0300
    20.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.3 @@ -1,501 +0,0 @@
    20.4 -/*
    20.5 -rbtree - simple balanced binary search tree (red-black tree) library.
    20.6 -Copyright (C) 2011-2014  John Tsiombikas <nuclear@member.fsf.org>
    20.7 -
    20.8 -rbtree is free software, feel free to use, modify, and redistribute it, under
    20.9 -the terms of the 3-clause BSD license. See COPYING for details.
   20.10 - */
   20.11 -#include <stdio.h>
   20.12 -#include <stdlib.h>
   20.13 -#include <stdint.h>
   20.14 -#include <string.h>
   20.15 -#include "rbtree.h"
   20.16 -
   20.17 -#define INT2PTR(x)	((void*)(intptr_t)(x))
   20.18 -#define PTR2INT(x)	((int)(intptr_t)(x))
   20.19 -
   20.20 -struct rbtree {
   20.21 -	struct rbnode *root;
   20.22 -
   20.23 -	rb_alloc_func_t alloc;
   20.24 -	rb_free_func_t free;
   20.25 -
   20.26 -	rb_cmp_func_t cmp;
   20.27 -	rb_del_func_t del;
   20.28 -	void *del_cls;
   20.29 -
   20.30 -	struct rbnode *rstack, *iter;
   20.31 -};
   20.32 -
   20.33 -static int cmpaddr(const void *ap, const void *bp);
   20.34 -static int cmpint(const void *ap, const void *bp);
   20.35 -
   20.36 -static int count_nodes(struct rbnode *node);
   20.37 -static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls);
   20.38 -static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data);
   20.39 -static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key);
   20.40 -/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key);*/
   20.41 -static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls);
   20.42 -
   20.43 -struct rbtree *rb_create(rb_cmp_func_t cmp_func)
   20.44 -{
   20.45 -	struct rbtree *rb;
   20.46 -
   20.47 -	if(!(rb = malloc(sizeof *rb))) {
   20.48 -		return 0;
   20.49 -	}
   20.50 -	if(rb_init(rb, cmp_func) == -1) {
   20.51 -		free(rb);
   20.52 -		return 0;
   20.53 -	}
   20.54 -	return rb;
   20.55 -}
   20.56 -
   20.57 -void rb_free(struct rbtree *rb)
   20.58 -{
   20.59 -	rb_destroy(rb);
   20.60 -	free(rb);
   20.61 -}
   20.62 -
   20.63 -
   20.64 -int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func)
   20.65 -{
   20.66 -	memset(rb, 0, sizeof *rb);
   20.67 -
   20.68 -	if(!cmp_func) {
   20.69 -		rb->cmp = cmpaddr;
   20.70 -	} else if(cmp_func == RB_KEY_INT) {
   20.71 -		rb->cmp = cmpint;
   20.72 -	} else if(cmp_func == RB_KEY_STRING) {
   20.73 -		rb->cmp = (rb_cmp_func_t)strcmp;
   20.74 -	} else {
   20.75 -		rb->cmp = cmp_func;
   20.76 -	}
   20.77 -
   20.78 -	rb->alloc = malloc;
   20.79 -	rb->free = free;
   20.80 -	return 0;
   20.81 -}
   20.82 -
   20.83 -void rb_destroy(struct rbtree *rb)
   20.84 -{
   20.85 -	del_tree(rb->root, rb->del, rb->del_cls);
   20.86 -}
   20.87 -
   20.88 -void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free)
   20.89 -{
   20.90 -	rb->alloc = alloc;
   20.91 -	rb->free = free;
   20.92 -}
   20.93 -
   20.94 -
   20.95 -void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func)
   20.96 -{
   20.97 -	rb->cmp = func;
   20.98 -}
   20.99 -
  20.100 -void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls)
  20.101 -{
  20.102 -	rb->del = func;
  20.103 -	rb->del_cls = cls;
  20.104 -}
  20.105 -
  20.106 -
  20.107 -void rb_clear(struct rbtree *rb)
  20.108 -{
  20.109 -	del_tree(rb->root, rb->del, rb->del_cls);
  20.110 -	rb->root = 0;
  20.111 -}
  20.112 -
  20.113 -int rb_copy(struct rbtree *dest, struct rbtree *src)
  20.114 -{
  20.115 -	struct rbnode *node;
  20.116 -
  20.117 -	rb_clear(dest);
  20.118 -	rb_begin(src);
  20.119 -	while((node = rb_next(src))) {
  20.120 -		if(rb_insert(dest, node->key, node->data) == -1) {
  20.121 -			return -1;
  20.122 -		}
  20.123 -	}
  20.124 -	return 0;
  20.125 -}
  20.126 -
  20.127 -int rb_size(struct rbtree *rb)
  20.128 -{
  20.129 -	return count_nodes(rb->root);
  20.130 -}
  20.131 -
  20.132 -int rb_insert(struct rbtree *rb, void *key, void *data)
  20.133 -{
  20.134 -	rb->root = insert(rb, rb->root, key, data);
  20.135 -	rb->root->red = 0;
  20.136 -	return 0;
  20.137 -}
  20.138 -
  20.139 -int rb_inserti(struct rbtree *rb, int key, void *data)
  20.140 -{
  20.141 -	rb->root = insert(rb, rb->root, INT2PTR(key), data);
  20.142 -	rb->root->red = 0;
  20.143 -	return 0;
  20.144 -}
  20.145 -
  20.146 -
  20.147 -int rb_delete(struct rbtree *rb, void *key)
  20.148 -{
  20.149 -	rb->root = delete(rb, rb->root, key);
  20.150 -	rb->root->red = 0;
  20.151 -	return 0;
  20.152 -}
  20.153 -
  20.154 -int rb_deletei(struct rbtree *rb, int key)
  20.155 -{
  20.156 -	rb->root = delete(rb, rb->root, INT2PTR(key));
  20.157 -	rb->root->red = 0;
  20.158 -	return 0;
  20.159 -}
  20.160 -
  20.161 -
  20.162 -struct rbnode *rb_find(struct rbtree *rb, void *key)
  20.163 -{
  20.164 -	struct rbnode *node = rb->root;
  20.165 -
  20.166 -	while(node) {
  20.167 -		int cmp = rb->cmp(key, node->key);
  20.168 -		if(cmp == 0) {
  20.169 -			return node;
  20.170 -		}
  20.171 -		node = cmp < 0 ? node->left : node->right;
  20.172 -	}
  20.173 -	return 0;
  20.174 -}
  20.175 -
  20.176 -struct rbnode *rb_findi(struct rbtree *rb, int key)
  20.177 -{
  20.178 -	return rb_find(rb, INT2PTR(key));
  20.179 -}
  20.180 -
  20.181 -
  20.182 -void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls)
  20.183 -{
  20.184 -	traverse(rb->root, func, cls);
  20.185 -}
  20.186 -
  20.187 -
  20.188 -struct rbnode *rb_root(struct rbtree *rb)
  20.189 -{
  20.190 -	return rb->root;
  20.191 -}
  20.192 -
  20.193 -void rb_begin(struct rbtree *rb)
  20.194 -{
  20.195 -	rb->rstack = 0;
  20.196 -	rb->iter = rb->root;
  20.197 -}
  20.198 -
  20.199 -#define push(sp, x)		((x)->next = (sp), (sp) = (x))
  20.200 -#define pop(sp)			((sp) = (sp)->next)
  20.201 -#define top(sp)			(sp)
  20.202 -
  20.203 -struct rbnode *rb_next(struct rbtree *rb)
  20.204 -{
  20.205 -	struct rbnode *res = 0;
  20.206 -
  20.207 -	while(rb->rstack || rb->iter) {
  20.208 -		if(rb->iter) {
  20.209 -			push(rb->rstack, rb->iter);
  20.210 -			rb->iter = rb->iter->left;
  20.211 -		} else {
  20.212 -			rb->iter = top(rb->rstack);
  20.213 -			pop(rb->rstack);
  20.214 -			res = rb->iter;
  20.215 -			rb->iter = rb->iter->right;
  20.216 -			break;
  20.217 -		}
  20.218 -	}
  20.219 -	return res;
  20.220 -}
  20.221 -
  20.222 -void *rb_node_key(struct rbnode *node)
  20.223 -{
  20.224 -	return node ? node->key : 0;
  20.225 -}
  20.226 -
  20.227 -int rb_node_keyi(struct rbnode *node)
  20.228 -{
  20.229 -	return node ? PTR2INT(node->key) : 0;
  20.230 -}
  20.231 -
  20.232 -void *rb_node_data(struct rbnode *node)
  20.233 -{
  20.234 -	return node ? node->data : 0;
  20.235 -}
  20.236 -
  20.237 -static int cmpaddr(const void *ap, const void *bp)
  20.238 -{
  20.239 -	return ap < bp ? -1 : (ap > bp ? 1 : 0);
  20.240 -}
  20.241 -
  20.242 -static int cmpint(const void *ap, const void *bp)
  20.243 -{
  20.244 -	return PTR2INT(ap) - PTR2INT(bp);
  20.245 -}
  20.246 -
  20.247 -
  20.248 -/* ---- left-leaning 2-3 red-black implementation ---- */
  20.249 -
  20.250 -/* helper prototypes */
  20.251 -static int is_red(struct rbnode *tree);
  20.252 -static void color_flip(struct rbnode *tree);
  20.253 -static struct rbnode *rot_left(struct rbnode *a);
  20.254 -static struct rbnode *rot_right(struct rbnode *a);
  20.255 -static struct rbnode *find_min(struct rbnode *tree);
  20.256 -static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree);
  20.257 -/*static struct rbnode *move_red_right(struct rbnode *tree);*/
  20.258 -static struct rbnode *move_red_left(struct rbnode *tree);
  20.259 -static struct rbnode *fix_up(struct rbnode *tree);
  20.260 -
  20.261 -static int count_nodes(struct rbnode *node)
  20.262 -{
  20.263 -	if(!node)
  20.264 -		return 0;
  20.265 -
  20.266 -	return 1 + count_nodes(node->left) + count_nodes(node->right);
  20.267 -}
  20.268 -
  20.269 -static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls)
  20.270 -{
  20.271 -	if(!node)
  20.272 -		return;
  20.273 -
  20.274 -	del_tree(node->left, delfunc, cls);
  20.275 -	del_tree(node->right, delfunc, cls);
  20.276 -
  20.277 -	if(delfunc) {
  20.278 -		delfunc(node, cls);
  20.279 -	}
  20.280 -	free(node);
  20.281 -}
  20.282 -
  20.283 -static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data)
  20.284 -{
  20.285 -	int cmp;
  20.286 -
  20.287 -	if(!tree) {
  20.288 -		struct rbnode *node = rb->alloc(sizeof *node);
  20.289 -		node->red = 1;
  20.290 -		node->key = key;
  20.291 -		node->data = data;
  20.292 -		node->left = node->right = 0;
  20.293 -		return node;
  20.294 -	}
  20.295 -
  20.296 -	cmp = rb->cmp(key, tree->key);
  20.297 -
  20.298 -	if(cmp < 0) {
  20.299 -		tree->left = insert(rb, tree->left, key, data);
  20.300 -	} else if(cmp > 0) {
  20.301 -		tree->right = insert(rb, tree->right, key, data);
  20.302 -	} else {
  20.303 -		tree->data = data;
  20.304 -	}
  20.305 -
  20.306 -	/* fix right-leaning reds */
  20.307 -	if(is_red(tree->right)) {
  20.308 -		tree = rot_left(tree);
  20.309 -	}
  20.310 -	/* fix two reds in a row */
  20.311 -	if(is_red(tree->left) && is_red(tree->left->left)) {
  20.312 -		tree = rot_right(tree);
  20.313 -	}
  20.314 -
  20.315 -	/* if 4-node, split it by color inversion */
  20.316 -	if(is_red(tree->left) && is_red(tree->right)) {
  20.317 -		color_flip(tree);
  20.318 -	}
  20.319 -
  20.320 -	return tree;
  20.321 -}
  20.322 -
  20.323 -static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key)
  20.324 -{
  20.325 -	int cmp;
  20.326 -
  20.327 -	if(!tree) {
  20.328 -		return 0;
  20.329 -	}
  20.330 -
  20.331 -	cmp = rb->cmp(key, tree->key);
  20.332 -
  20.333 -	if(cmp < 0) {
  20.334 -		if(!is_red(tree->left) && !is_red(tree->left->left)) {
  20.335 -			tree = move_red_left(tree);
  20.336 -		}
  20.337 -		tree->left = delete(rb, tree->left, key);
  20.338 -	} else {
  20.339 -		/* need reds on the right */
  20.340 -		if(is_red(tree->left)) {
  20.341 -			tree = rot_right(tree);
  20.342 -		}
  20.343 -
  20.344 -		/* found it at the bottom (XXX what certifies left is null?) */
  20.345 -		if(cmp == 0 && !tree->right) {
  20.346 -			if(rb->del) {
  20.347 -				rb->del(tree, rb->del_cls);
  20.348 -			}
  20.349 -			rb->free(tree);
  20.350 -			return 0;
  20.351 -		}
  20.352 -
  20.353 -		if(!is_red(tree->right) && !is_red(tree->right->left)) {
  20.354 -			tree = move_red_left(tree);
  20.355 -		}
  20.356 -
  20.357 -		if(key == tree->key) {
  20.358 -			struct rbnode *rmin = find_min(tree->right);
  20.359 -			tree->key = rmin->key;
  20.360 -			tree->data = rmin->data;
  20.361 -			tree->right = del_min(rb, tree->right);
  20.362 -		} else {
  20.363 -			tree->right = delete(rb, tree->right, key);
  20.364 -		}
  20.365 -	}
  20.366 -
  20.367 -	return fix_up(tree);
  20.368 -}
  20.369 -
  20.370 -/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key)
  20.371 -{
  20.372 -	int cmp;
  20.373 -
  20.374 -	if(!node)
  20.375 -		return 0;
  20.376 -
  20.377 -	if((cmp = rb->cmp(key, node->key)) == 0) {
  20.378 -		return node;
  20.379 -	}
  20.380 -	return find(rb, cmp < 0 ? node->left : node->right, key);
  20.381 -}*/
  20.382 -
  20.383 -static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls)
  20.384 -{
  20.385 -	if(!node)
  20.386 -		return;
  20.387 -
  20.388 -	traverse(node->left, func, cls);
  20.389 -	func(node, cls);
  20.390 -	traverse(node->right, func, cls);
  20.391 -}
  20.392 -
  20.393 -/* helpers */
  20.394 -
  20.395 -static int is_red(struct rbnode *tree)
  20.396 -{
  20.397 -	return tree && tree->red;
  20.398 -}
  20.399 -
  20.400 -static void color_flip(struct rbnode *tree)
  20.401 -{
  20.402 -	tree->red = !tree->red;
  20.403 -	tree->left->red = !tree->left->red;
  20.404 -	tree->right->red = !tree->right->red;
  20.405 -}
  20.406 -
  20.407 -static struct rbnode *rot_left(struct rbnode *a)
  20.408 -{
  20.409 -	struct rbnode *b = a->right;
  20.410 -	a->right = b->left;
  20.411 -	b->left = a;
  20.412 -	b->red = a->red;
  20.413 -	a->red = 1;
  20.414 -	return b;
  20.415 -}
  20.416 -
  20.417 -static struct rbnode *rot_right(struct rbnode *a)
  20.418 -{
  20.419 -	struct rbnode *b = a->left;
  20.420 -	a->left = b->right;
  20.421 -	b->right = a;
  20.422 -	b->red = a->red;
  20.423 -	a->red = 1;
  20.424 -	return b;
  20.425 -}
  20.426 -
  20.427 -static struct rbnode *find_min(struct rbnode *tree)
  20.428 -{
  20.429 -	if(!tree)
  20.430 -		return 0;
  20.431 -
  20.432 -	while(tree->left) {
  20.433 -		tree = tree->left;
  20.434 -	}
  20.435 -	return tree;
  20.436 -}
  20.437 -
  20.438 -static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree)
  20.439 -{
  20.440 -	if(!tree->left) {
  20.441 -		if(rb->del) {
  20.442 -			rb->del(tree->left, rb->del_cls);
  20.443 -		}
  20.444 -		rb->free(tree->left);
  20.445 -		return 0;
  20.446 -	}
  20.447 -
  20.448 -	/* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */
  20.449 -	if(!is_red(tree->left) && !is_red(tree->left->left)) {
  20.450 -		tree = move_red_left(tree);
  20.451 -	}
  20.452 -	tree->left = del_min(rb, tree->left);
  20.453 -
  20.454 -	/* fix right-reds, red-reds, and split 4-nodes on the way up */
  20.455 -	return fix_up(tree);
  20.456 -}
  20.457 -
  20.458 -#if 0
  20.459 -/* push a red link on this node to the right */
  20.460 -static struct rbnode *move_red_right(struct rbnode *tree)
  20.461 -{
  20.462 -	/* flipping it makes both children go red, so we have a red to the right */
  20.463 -	color_flip(tree);
  20.464 -
  20.465 -	/* if after the flip we've got a red-red situation to the left, fix it */
  20.466 -	if(is_red(tree->left->left)) {
  20.467 -		tree = rot_right(tree);
  20.468 -		color_flip(tree);
  20.469 -	}
  20.470 -	return tree;
  20.471 -}
  20.472 -#endif
  20.473 -
  20.474 -/* push a red link on this node to the left */
  20.475 -static struct rbnode *move_red_left(struct rbnode *tree)
  20.476 -{
  20.477 -	/* flipping it makes both children go red, so we have a red to the left */
  20.478 -	color_flip(tree);
  20.479 -
  20.480 -	/* if after the flip we've got a red-red on the right-left, fix it */
  20.481 -	if(is_red(tree->right->left)) {
  20.482 -		tree->right = rot_right(tree->right);
  20.483 -		tree = rot_left(tree);
  20.484 -		color_flip(tree);
  20.485 -	}
  20.486 -	return tree;
  20.487 -}
  20.488 -
  20.489 -static struct rbnode *fix_up(struct rbnode *tree)
  20.490 -{
  20.491 -	/* fix right-leaning */
  20.492 -	if(is_red(tree->right)) {
  20.493 -		tree = rot_left(tree);
  20.494 -	}
  20.495 -	/* change invalid red-red pairs into a proper 4-node */
  20.496 -	if(is_red(tree->left) && is_red(tree->left->left)) {
  20.497 -		tree = rot_right(tree);
  20.498 -	}
  20.499 -	/* split 4-nodes */
  20.500 -	if(is_red(tree->left) && is_red(tree->right)) {
  20.501 -		color_flip(tree);
  20.502 -	}
  20.503 -	return tree;
  20.504 -}
    21.1 --- a/src/rbtree.h	Sat Apr 18 21:36:07 2015 +0300
    21.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.3 @@ -1,78 +0,0 @@
    21.4 -/*
    21.5 -rbtree - simple balanced binary search tree (red-black tree) library.
    21.6 -Copyright (C) 2011-2014  John Tsiombikas <nuclear@member.fsf.org>
    21.7 -
    21.8 -rbtree is free software, feel free to use, modify, and redistribute it, under
    21.9 -the terms of the 3-clause BSD license. See COPYING for details.
   21.10 - */
   21.11 -#ifndef RBTREE_H_
   21.12 -#define RBTREE_H_
   21.13 -
   21.14 -struct rbtree;
   21.15 -
   21.16 -
   21.17 -struct rbnode {
   21.18 -	void *key, *data;
   21.19 -	int red;
   21.20 -	struct rbnode *left, *right;
   21.21 -	struct rbnode *next;	/* for iterator stack */
   21.22 -};
   21.23 -
   21.24 -
   21.25 -typedef void *(*rb_alloc_func_t)(size_t);
   21.26 -typedef void (*rb_free_func_t)(void*);
   21.27 -
   21.28 -typedef int (*rb_cmp_func_t)(const void*, const void*);
   21.29 -typedef void (*rb_del_func_t)(struct rbnode*, void*);
   21.30 -
   21.31 -#define RB_KEY_ADDR		(rb_cmp_func_t)(0)
   21.32 -#define RB_KEY_INT		(rb_cmp_func_t)(1)
   21.33 -#define RB_KEY_STRING	(rb_cmp_func_t)(3)
   21.34 -
   21.35 -
   21.36 -#ifdef __cplusplus
   21.37 -extern "C" {
   21.38 -#endif
   21.39 -
   21.40 -struct rbtree *rb_create(rb_cmp_func_t cmp_func);
   21.41 -void rb_free(struct rbtree *rb);
   21.42 -
   21.43 -int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func);
   21.44 -void rb_destroy(struct rbtree *rb);
   21.45 -
   21.46 -void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free);
   21.47 -void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func);
   21.48 -void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls);
   21.49 -/* TODO add user deep copy function */
   21.50 -
   21.51 -void rb_clear(struct rbtree *rb);
   21.52 -int rb_copy(struct rbtree *dest, struct rbtree *src);
   21.53 -
   21.54 -int rb_size(struct rbtree *rb);
   21.55 -
   21.56 -int rb_insert(struct rbtree *rb, void *key, void *data);
   21.57 -int rb_inserti(struct rbtree *rb, int key, void *data);
   21.58 -
   21.59 -int rb_delete(struct rbtree *rb, void *key);
   21.60 -int rb_deletei(struct rbtree *rb, int key);
   21.61 -
   21.62 -struct rbnode *rb_find(struct rbtree *rb, void *key);
   21.63 -struct rbnode *rb_findi(struct rbtree *rb, int key);
   21.64 -
   21.65 -void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls);
   21.66 -
   21.67 -struct rbnode *rb_root(struct rbtree *rb);
   21.68 -
   21.69 -void rb_begin(struct rbtree *rb);
   21.70 -struct rbnode *rb_next(struct rbtree *rb);
   21.71 -
   21.72 -void *rb_node_key(struct rbnode *node);
   21.73 -int rb_node_keyi(struct rbnode *node);
   21.74 -void *rb_node_data(struct rbnode *node);
   21.75 -
   21.76 -#ifdef __cplusplus
   21.77 -}
   21.78 -#endif
   21.79 -
   21.80 -
   21.81 -#endif	/* RBTREE_H_ */
    22.1 --- a/src/tinyweb.c	Sat Apr 18 21:36:07 2015 +0300
    22.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.3 @@ -1,391 +0,0 @@
    22.4 -#include <stdio.h>
    22.5 -#include <stdlib.h>
    22.6 -#include <string.h>
    22.7 -#include <ctype.h>
    22.8 -#include <errno.h>
    22.9 -#include <unistd.h>
   22.10 -#include <fcntl.h>
   22.11 -#include <sys/stat.h>
   22.12 -#include <sys/select.h>
   22.13 -#include <sys/mman.h>
   22.14 -#include <sys/types.h>
   22.15 -#include <sys/socket.h>
   22.16 -#include <arpa/inet.h>
   22.17 -#include "tinyweb.h"
   22.18 -#include "http.h"
   22.19 -#include "mime.h"
   22.20 -#include "logger.h"
   22.21 -
   22.22 -/* HTTP version */
   22.23 -#define HTTP_VER_MAJOR	1
   22.24 -#define HTTP_VER_MINOR	1
   22.25 -#define HTTP_VER_STR	"1.1"
   22.26 -
   22.27 -/* maximum request length: 64mb */
   22.28 -#define MAX_REQ_LENGTH	(65536 * 1024)
   22.29 -
   22.30 -struct client {
   22.31 -	int s;
   22.32 -	char *rcvbuf;
   22.33 -	int bufsz;
   22.34 -	struct client *next;
   22.35 -};
   22.36 -
   22.37 -static int accept_conn(int lis);
   22.38 -static void close_conn(struct client *c);
   22.39 -static int handle_client(struct client *c);
   22.40 -static int do_get(struct client *c, const char *uri, int with_body);
   22.41 -static void respond_error(struct client *c, int errcode);
   22.42 -
   22.43 -static int lis = -1;
   22.44 -static int maxfd;
   22.45 -static int port = 8080;
   22.46 -static struct client *clist;
   22.47 -static int num_clients;
   22.48 -
   22.49 -static const char *indexfiles[] = {
   22.50 -	"index.cgi",
   22.51 -	"index.html",
   22.52 -	"index.htm",
   22.53 -	0
   22.54 -};
   22.55 -
   22.56 -void tw_set_port(int p)
   22.57 -{
   22.58 -	port = p;
   22.59 -}
   22.60 -
   22.61 -int tw_set_root(const char *path)
   22.62 -{
   22.63 -	return chdir(path);
   22.64 -}
   22.65 -
   22.66 -int tw_set_logfile(const char *fname)
   22.67 -{
   22.68 -	return set_log_file(fname);
   22.69 -}
   22.70 -
   22.71 -int tw_start(void)
   22.72 -{
   22.73 -	int s;
   22.74 -	struct sockaddr_in sa;
   22.75 -
   22.76 -	logmsg("starting server ...\n");
   22.77 -
   22.78 -	if(lis != -1) {
   22.79 -		logmsg("can't start tinyweb server: already running!\n");
   22.80 -		return -1;
   22.81 -	}
   22.82 -
   22.83 -	if((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
   22.84 -		logmsg("failed to create listening socket: %s\n", strerror(errno));
   22.85 -		return -1;
   22.86 -	}
   22.87 -	fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
   22.88 -
   22.89 -	memset(&sa, 0, sizeof sa);
   22.90 -	sa.sin_family = AF_INET;
   22.91 -	sa.sin_addr.s_addr = INADDR_ANY;
   22.92 -	sa.sin_port = htons(port);
   22.93 -
   22.94 -	if(bind(s, (struct sockaddr*)&sa, sizeof sa) == -1) {
   22.95 -		logmsg("failed to bind socket to port %d: %s\n", port, strerror(errno));
   22.96 -		return -1;
   22.97 -	}
   22.98 -	listen(s, 16);
   22.99 -
  22.100 -	lis = s;
  22.101 -	return s;
  22.102 -}
  22.103 -
  22.104 -int tw_stop(void)
  22.105 -{
  22.106 -	if(lis == -1) {
  22.107 -		return -1;
  22.108 -	}
  22.109 -
  22.110 -	logmsg("stopping server...\n");
  22.111 -
  22.112 -	close(lis);
  22.113 -	lis = -1;
  22.114 -
  22.115 -	while(clist) {
  22.116 -		struct client *c = clist;
  22.117 -		clist = clist->next;
  22.118 -		close_conn(c);
  22.119 -		free(c);
  22.120 -	}
  22.121 -	clist = 0;
  22.122 -
  22.123 -	return 0;
  22.124 -}
  22.125 -
  22.126 -int tw_get_sockets(int *socks)
  22.127 -{
  22.128 -	struct client *c, dummy;
  22.129 -
  22.130 -	/* first cleanup the clients marked for removal */
  22.131 -	dummy.next = clist;
  22.132 -	c = &dummy;
  22.133 -
  22.134 -	while(c->next) {
  22.135 -		struct client *n = c->next;
  22.136 -
  22.137 -		if(n->s == -1) {
  22.138 -			/* marked for removal */
  22.139 -			c->next = n->next;
  22.140 -			free(n);
  22.141 -			--num_clients;
  22.142 -		} else {
  22.143 -			c = c->next;
  22.144 -		}
  22.145 -	}
  22.146 -	clist = dummy.next;
  22.147 -
  22.148 -
  22.149 -	if(!socks) {
  22.150 -		/* just return the count */
  22.151 -		return num_clients + 1;	/* +1 for the listening socket */
  22.152 -	}
  22.153 -
  22.154 -	/* go through the client list and populate the array */
  22.155 -	maxfd = lis;
  22.156 -	*socks++ = lis;
  22.157 -
  22.158 -	c = clist;
  22.159 -	while(c) {
  22.160 -		*socks++ = c->s;
  22.161 -		if(c->s > maxfd) {
  22.162 -			maxfd = c->s;
  22.163 -		}
  22.164 -		c = c->next;
  22.165 -	}
  22.166 -	return num_clients + 1;	/* +1 for the listening socket */
  22.167 -}
  22.168 -
  22.169 -int tw_get_maxfd(void)
  22.170 -{
  22.171 -	return maxfd;
  22.172 -}
  22.173 -
  22.174 -int tw_handle_socket(int s)
  22.175 -{
  22.176 -	struct client *c;
  22.177 -
  22.178 -	if(s == lis) {
  22.179 -		return accept_conn(s);
  22.180 -	}
  22.181 -
  22.182 -	/* find which client corresponds to this socket */
  22.183 -	c = clist;
  22.184 -	while(c) {
  22.185 -		if(c->s == s) {
  22.186 -			return handle_client(c);
  22.187 -		}
  22.188 -		c = c->next;
  22.189 -	}
  22.190 -
  22.191 -	logmsg("socket %d doesn't correspond to any client\n");
  22.192 -	return -1;
  22.193 -}
  22.194 -
  22.195 -static int accept_conn(int lis)
  22.196 -{
  22.197 -	int s;
  22.198 -	struct client *c;
  22.199 -	struct sockaddr_in addr;
  22.200 -	socklen_t addr_sz = sizeof addr;
  22.201 -
  22.202 -	if((s = accept(lis, (struct sockaddr*)&addr, &addr_sz)) == -1) {
  22.203 -		logmsg("failed to accept incoming connection: %s\n", strerror(errno));
  22.204 -		return -1;
  22.205 -	}
  22.206 -	fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
  22.207 -
  22.208 -	if(!(c = malloc(sizeof *c))) {
  22.209 -		logmsg("failed to allocate memory while accepting connection: %s\n", strerror(errno));
  22.210 -		return -1;
  22.211 -	}
  22.212 -	c->s = s;
  22.213 -	c->rcvbuf = 0;
  22.214 -	c->bufsz = 0;
  22.215 -	c->next = clist;
  22.216 -	clist = c;
  22.217 -	++num_clients;
  22.218 -	return 0;
  22.219 -}
  22.220 -
  22.221 -static void close_conn(struct client *c)
  22.222 -{
  22.223 -	close(c->s);
  22.224 -	c->s = -1;	/* mark it for removal */
  22.225 -	free(c->rcvbuf);
  22.226 -	c->rcvbuf = 0;
  22.227 -}
  22.228 -
  22.229 -static int handle_client(struct client *c)
  22.230 -{
  22.231 -	struct http_req_header hdr;
  22.232 -	static char buf[2048];
  22.233 -	int rdsz, status;
  22.234 -
  22.235 -	while((rdsz = recv(c->s, buf, sizeof buf, 0)) > 0) {
  22.236 -		char *newbuf;
  22.237 -		int newsz = c->bufsz + rdsz;
  22.238 -		if(newsz > MAX_REQ_LENGTH) {
  22.239 -			respond_error(c, 413);
  22.240 -			return -1;
  22.241 -		}
  22.242 -
  22.243 -		if(!(newbuf = realloc(c->rcvbuf, newsz + 1))) {
  22.244 -			logmsg("failed to allocate %d byte buffer\n", newsz);
  22.245 -			respond_error(c, 503);
  22.246 -			return -1;
  22.247 -		}
  22.248 -
  22.249 -		memcpy(newbuf + c->bufsz, buf, rdsz);
  22.250 -		newbuf[newsz] = 0;
  22.251 -
  22.252 -		c->rcvbuf = newbuf;
  22.253 -		c->bufsz = newsz;
  22.254 -	}
  22.255 -
  22.256 -	if((status = http_parse_request(&hdr, c->rcvbuf, c->bufsz)) != HTTP_HDR_OK) {
  22.257 -		http_log_request(&hdr);
  22.258 -		switch(status) {
  22.259 -		case HTTP_HDR_INVALID:
  22.260 -			respond_error(c, 400);
  22.261 -			return -1;
  22.262 -
  22.263 -		case HTTP_HDR_NOMEM:
  22.264 -			respond_error(c, 503);
  22.265 -			return -1;
  22.266 -
  22.267 -		case HTTP_HDR_PARTIAL:
  22.268 -			return 0;	/* partial header, continue reading */
  22.269 -		}
  22.270 -	}
  22.271 -	http_log_request(&hdr);
  22.272 -
  22.273 -	/* we only support GET and HEAD at this point, so freak out on anything else */
  22.274 -	switch(hdr.method) {
  22.275 -	case HTTP_GET:
  22.276 -		if(do_get(c, hdr.uri, 1) == -1) {
  22.277 -			return -1;
  22.278 -		}
  22.279 -		break;
  22.280 -
  22.281 -	case HTTP_HEAD:
  22.282 -		if(do_get(c, hdr.uri, 0) == -1) {
  22.283 -			return -1;
  22.284 -		}
  22.285 -		break;
  22.286 -
  22.287 -	default:
  22.288 -		respond_error(c, 501);
  22.289 -		return -1;
  22.290 -	}
  22.291 -
  22.292 -	close_conn(c);
  22.293 -	return 0;
  22.294 -}
  22.295 -
  22.296 -static int do_get(struct client *c, const char *uri, int with_body)
  22.297 -{
  22.298 -	const char *ptr;
  22.299 -	struct http_resp_header resp;
  22.300 -
  22.301 -	if((ptr = strstr(uri, "://"))) {
  22.302 -		uri = ptr + 3;
  22.303 -	}
  22.304 -
  22.305 -	/* skip the host part and the first slash if it exists */
  22.306 -	if((ptr = strchr(uri, '/'))) {
  22.307 -		uri = ptr + 1;
  22.308 -	}
  22.309 -
  22.310 -	if(*uri) {
  22.311 -		struct stat st;
  22.312 -		char *path = 0;
  22.313 -		char *rsphdr;
  22.314 -		const char *type;
  22.315 -		int fd, rspsize;
  22.316 -
  22.317 -		if(stat(uri, &st) == -1) {
  22.318 -			respond_error(c, 404);
  22.319 -			return -1;
  22.320 -		}
  22.321 -
  22.322 -		if(S_ISDIR(st.st_mode)) {
  22.323 -			int i;
  22.324 -			path = alloca(strlen(uri) + 64);
  22.325 -
  22.326 -			for(i=0; indexfiles[i]; i++) {
  22.327 -				sprintf(path, "%s/%s", uri, indexfiles[i]);
  22.328 -				if(stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) {
  22.329 -					break;
  22.330 -				}
  22.331 -			}
  22.332 -
  22.333 -			if(indexfiles[i] == 0) {
  22.334 -				respond_error(c, 404);
  22.335 -				return -1;
  22.336 -			}
  22.337 -		} else {
  22.338 -			path = (char*)uri;
  22.339 -		}
  22.340 -
  22.341 -		if((fd = open(path, O_RDONLY)) == -1) {
  22.342 -			respond_error(c, 403);
  22.343 -			return -1;
  22.344 -		}
  22.345 -
  22.346 -		/* construct response header */
  22.347 -		http_init_resp(&resp);
  22.348 -		http_add_resp_field(&resp, "Content-Length: %d", st.st_size);
  22.349 -		if((type = mime_type(path))) {
  22.350 -			http_add_resp_field(&resp, "Content-Type: %s", type);
  22.351 -		}
  22.352 -
  22.353 -		rspsize = http_serialize_resp(&resp, 0);
  22.354 -		rsphdr = alloca(rspsize);
  22.355 -		http_serialize_resp(&resp, rsphdr);
  22.356 -
  22.357 -		if(with_body) {
  22.358 -			int cont_left = st.st_size;
  22.359 -			char *cont = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  22.360 -			if(cont == (void*)-1) {
  22.361 -				respond_error(c, 503);
  22.362 -				close(fd);
  22.363 -				return -1;
  22.364 -			}
  22.365 -			ptr = cont;
  22.366 -
  22.367 -			send(c->s, rsphdr, rspsize, 0);
  22.368 -			while(cont_left > 0) {
  22.369 -				int sz = cont_left < 4096 ? cont_left : 4096;
  22.370 -				send(c->s, ptr, sz, 0);
  22.371 -				ptr += sz;
  22.372 -				cont_left -= sz;
  22.373 -			}
  22.374 -
  22.375 -			munmap(cont, st.st_size);
  22.376 -		} else {
  22.377 -			send(c->s, rsphdr, rspsize, 0);
  22.378 -		}
  22.379 -
  22.380 -		close(fd);
  22.381 -	}
  22.382 -	return 0;
  22.383 -}
  22.384 -
  22.385 -static void respond_error(struct client *c, int errcode)
  22.386 -{
  22.387 -	char buf[512];
  22.388 -
  22.389 -	sprintf(buf, "HTTP/" HTTP_VER_STR " %d %s\r\n\r\n", errcode, http_strmsg(errcode));
  22.390 -
  22.391 -	send(c->s, buf, strlen(buf), 0);
  22.392 -	close_conn(c);
  22.393 -}
  22.394 -
    23.1 --- a/src/tinyweb.h	Sat Apr 18 21:36:07 2015 +0300
    23.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.3 @@ -1,16 +0,0 @@
    23.4 -#ifndef TINYWEB_H_
    23.5 -#define TINYWEB_H_
    23.6 -
    23.7 -void tw_set_port(int port);
    23.8 -int tw_set_root(const char *path);
    23.9 -int tw_set_logfile(const char *fname);
   23.10 -
   23.11 -int tw_start(void);
   23.12 -int tw_stop(void);
   23.13 -
   23.14 -int tw_get_sockets(int *socks);
   23.15 -int tw_get_maxfd(void);
   23.16 -int tw_handle_socket(int s);
   23.17 -
   23.18 -
   23.19 -#endif	/* TINYWEB_H_ */