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_ */