From 17693097a5b62e54621231cdf20c32acc97181b1 Mon Sep 17 00:00:00 2001 From: Sam Stevens Date: Sun, 27 Jul 2014 22:19:08 +0100 Subject: [PATCH] Added server config --- Makefile | 2 +- content/khttpd.ini | 10 ++ content/public_html/index.html | 11 ++ content/{ => public_html}/lorem.txt | 0 lib/ini.c | 186 +++++++++++++++++++++++++++ lib/ini.h | 77 +++++++++++ nbproject/Makefile-Debug.mk | 50 ++++--- nbproject/Makefile-Release.mk | 34 +++-- nbproject/configurations.xml | 80 +++++++++--- nbproject/private/configurations.xml | 2 +- nbproject/private/private.xml | 13 +- src/config.c | 142 ++++++++++++++++++++ src/config.h | 53 ++++++++ src/{http/parse.c => http-reader.c} | 13 +- src/{http/parse.h => http-reader.h} | 6 +- src/http-server.c | 6 + src/http-server.h | 26 ++++ src/{http => }/http.c | 4 +- src/{http => }/http.h | 0 src/main.c | 41 +++--- src/main.h | 2 +- src/socket.h | 2 +- 22 files changed, 680 insertions(+), 80 deletions(-) create mode 100644 content/khttpd.ini create mode 100644 content/public_html/index.html rename content/{ => public_html}/lorem.txt (100%) create mode 100644 lib/ini.c create mode 100644 lib/ini.h create mode 100644 src/config.c create mode 100644 src/config.h rename src/{http/parse.c => http-reader.c} (94%) rename src/{http/parse.h => http-reader.h} (92%) create mode 100644 src/http-server.c create mode 100644 src/http-server.h rename src/{http => }/http.c (99%) rename src/{http => }/http.h (100%) diff --git a/Makefile b/Makefile index 50dbf01..812f445 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ build: .build-post .build-post: .build-impl # Add your post 'build' code here... - cp --recursive --force ${CND_BASEDIR}/content ${CND_ARTIFACT_DIR_${CONF}}/ + cp --recursive --force ${CND_BASEDIR}/content/* ${CND_ARTIFACT_DIR_${CONF}}/ # clean clean: .clean-post diff --git a/content/khttpd.ini b/content/khttpd.ini new file mode 100644 index 0000000..43bd80e --- /dev/null +++ b/content/khttpd.ini @@ -0,0 +1,10 @@ +[Server] +name=test.example.com +admin=sam@xnet.tk +listen=8080 + +[Host] +name=orion.local +enabled=yes +default=yes +serve=public_html \ No newline at end of file diff --git a/content/public_html/index.html b/content/public_html/index.html new file mode 100644 index 0000000..7ef35a7 --- /dev/null +++ b/content/public_html/index.html @@ -0,0 +1,11 @@ + + + + TODO supply a title + + + + +
TODO write content
+ + diff --git a/content/lorem.txt b/content/public_html/lorem.txt similarity index 100% rename from content/lorem.txt rename to content/public_html/lorem.txt diff --git a/lib/ini.c b/lib/ini.c new file mode 100644 index 0000000..7a75eec --- /dev/null +++ b/lib/ini.c @@ -0,0 +1,186 @@ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +http://code.google.com/p/inih/ + + * Sam Stevens - 07/2014 - Modified to add callback when a new section is found + * +*/ + +#include +#include +#include + +#include "ini.h" + +#if !INI_USE_STACK +#include +#endif + +#define MAX_SECTION 50 +#define MAX_NAME 50 + +/* Strip whitespace chars off end of given string, in place. Return s. */ +static char* rstrip(char* s) +{ + char* p = s + strlen(s); + while (p > s && isspace((unsigned char)(*--p))) + *p = '\0'; + return s; +} + +/* Return pointer to first non-whitespace char in given string. */ +static char* lskip(const char* s) +{ + while (*s && isspace((unsigned char)(*s))) + s++; + return (char*)s; +} + +/* Return pointer to first char c or ';' comment in given string, or pointer to + null at end of string if neither found. ';' must be prefixed by a whitespace + character to register as a comment. */ +static char* find_char_or_comment(const char* s, char c) +{ + int was_whitespace = 0; + while (*s && *s != c && !(was_whitespace && *s == ';')) { + was_whitespace = isspace((unsigned char)(*s)); + s++; + } + return (char*)s; +} + +/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ +static char* strncpy0(char* dest, const char* src, size_t size) +{ + strncpy(dest, src, size); + dest[size - 1] = '\0'; + return dest; +} + +/* See documentation in header file. */ +int ini_parse_file(FILE* file, + int (*handler)(void*, const char*, const char*, + const char*), + void* user) +{ + /* Uses a fair bit of stack (use heap instead if you need to) */ +#if INI_USE_STACK + char line[INI_MAX_LINE]; +#else + char* line; +#endif + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + + char* start; + char* end; + char* name; + char* value; + int lineno = 0; + int error = 0; + +#if !INI_USE_STACK + line = (char*)malloc(INI_MAX_LINE); + if (!line) { + return -2; + } +#endif + + /* Scan through file line by line */ + while (fgets(line, INI_MAX_LINE, file) != NULL) { + lineno++; + + start = line; +#if INI_ALLOW_BOM + if (lineno == 1 && (unsigned char)start[0] == 0xEF && + (unsigned char)start[1] == 0xBB && + (unsigned char)start[2] == 0xBF) { + start += 3; + } +#endif + start = lskip(rstrip(start)); + + if (*start == ';' || *start == '#') { + /* Per Python ConfigParser, allow '#' comments at start of line */ + } +#if INI_ALLOW_MULTILINE + else if (*prev_name && *start && start > line) { + /* Non-black line with leading whitespace, treat as continuation + of previous name's value (as per Python ConfigParser). */ + if (!handler(user, section, prev_name, start) && !error) + error = lineno; + } +#endif + else if (*start == '[') { + /* A "[section]" line */ + end = find_char_or_comment(start + 1, ']'); + if (*end == ']') { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; + //MODIFIED - call with null name on new section + if (!handler(user, section, NULL, NULL) && !error) + error = lineno; + } + else if (!error) { + /* No ']' found on section line */ + error = lineno; + } + } + else if (*start && *start != ';') { + /* Not a comment, must be a name[=:]value pair */ + end = find_char_or_comment(start, '='); + if (*end != '=') { + end = find_char_or_comment(start, ':'); + } + if (*end == '=' || *end == ':') { + *end = '\0'; + name = rstrip(start); + value = lskip(end + 1); + end = find_char_or_comment(value, '\0'); + if (*end == ';') + *end = '\0'; + rstrip(value); + + /* Valid name[=:]value pair found, call handler */ + strncpy0(prev_name, name, sizeof(prev_name)); + if (!handler(user, section, name, value) && !error) + error = lineno; + } + else if (!error) { + /* No '=' or ':' found on name[=:]value line */ + error = lineno; + } + } + +#if INI_STOP_ON_FIRST_ERROR + if (error) + break; +#endif + } + +#if !INI_USE_STACK + free(line); +#endif + + return error; +} + +/* See documentation in header file. */ +int ini_parse(const char* filename, + int (*handler)(void*, const char*, const char*, const char*), + void* user) +{ + FILE* file; + int error; + + file = fopen(filename, "r"); + if (!file) + return -1; + error = ini_parse_file(file, handler, user); + fclose(file); + return error; +} diff --git a/lib/ini.h b/lib/ini.h new file mode 100644 index 0000000..b071cbf --- /dev/null +++ b/lib/ini.h @@ -0,0 +1,77 @@ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +http://code.google.com/p/inih/ + +*/ + +#ifndef __INI_H__ +#define __INI_H__ + +/* Make this header file easier to include in C++ code */ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Parse given INI-style file. May have [section]s, name=value pairs + (whitespace stripped), and comments starting with ';' (semicolon). Section + is "" if name=value pair parsed before any section heading. name:value + pairs are also supported as a concession to Python's ConfigParser. + + For each name=value pair parsed, call handler function with given user + pointer as well as section, name, and value (data only valid for duration + of handler call). Handler should return nonzero on success, zero on error. + + Returns 0 on success, line number of first error on parse error (doesn't + stop on first error), -1 on file open error, or -2 on memory allocation + error (only when INI_USE_STACK is zero). +*/ +int ini_parse(const char* filename, + int (*handler)(void* user, const char* section, + const char* name, const char* value), + void* user); + +/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't + close the file when it's finished -- the caller must do that. */ +int ini_parse_file(FILE* file, + int (*handler)(void* user, const char* section, + const char* name, const char* value), + void* user); + +/* Nonzero to allow multi-line value parsing, in the style of Python's + ConfigParser. If allowed, ini_parse() will call the handler with the same + name for each subsequent line parsed. */ +#ifndef INI_ALLOW_MULTILINE +#define INI_ALLOW_MULTILINE 1 +#endif + +/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of + the file. See http://code.google.com/p/inih/issues/detail?id=21 */ +#ifndef INI_ALLOW_BOM +#define INI_ALLOW_BOM 1 +#endif + +/* Nonzero to use stack, zero to use heap (malloc/free). */ +#ifndef INI_USE_STACK +#define INI_USE_STACK 1 +#endif + +/* Stop parsing on first error (default is to keep parsing). */ +#ifndef INI_STOP_ON_FIRST_ERROR +#define INI_STOP_ON_FIRST_ERROR 0 +#endif + +/* Maximum line length for any line in INI file. */ +#ifndef INI_MAX_LINE +#define INI_MAX_LINE 200 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __INI_H__ */ diff --git a/nbproject/Makefile-Debug.mk b/nbproject/Makefile-Debug.mk index b47109a..f8565e5 100644 --- a/nbproject/Makefile-Debug.mk +++ b/nbproject/Makefile-Debug.mk @@ -36,8 +36,11 @@ OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} # Object Files OBJECTFILES= \ ${OBJECTDIR}/lib/http_parser.o \ - ${OBJECTDIR}/src/http/http.o \ - ${OBJECTDIR}/src/http/parse.o \ + ${OBJECTDIR}/lib/ini.o \ + ${OBJECTDIR}/src/config.o \ + ${OBJECTDIR}/src/http-reader.o \ + ${OBJECTDIR}/src/http-server.o \ + ${OBJECTDIR}/src/http.o \ ${OBJECTDIR}/src/main.o \ ${OBJECTDIR}/src/socket.o @@ -66,30 +69,45 @@ ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/khttp: ${OBJECTFILES} ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} ${LINK.c} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/khttp ${OBJECTFILES} ${LDLIBSOPTIONS} -${OBJECTDIR}/lib/http_parser.o: lib/http_parser.c +${OBJECTDIR}/lib/http_parser.o: nbproject/Makefile-${CND_CONF}.mk lib/http_parser.c ${MKDIR} -p ${OBJECTDIR}/lib ${RM} "$@.d" - $(COMPILE.c) -g -Werror -Ilib -include lib/http_parser.h -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/lib/http_parser.o lib/http_parser.c + $(COMPILE.c) -g -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/lib/http_parser.o lib/http_parser.c -${OBJECTDIR}/src/http/http.o: src/http/http.c - ${MKDIR} -p ${OBJECTDIR}/src/http +${OBJECTDIR}/lib/ini.o: nbproject/Makefile-${CND_CONF}.mk lib/ini.c + ${MKDIR} -p ${OBJECTDIR}/lib ${RM} "$@.d" - $(COMPILE.c) -g -Werror -Ilib -include lib/http_parser.h -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/http.o src/http/http.c + $(COMPILE.c) -g -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/lib/ini.o lib/ini.c -${OBJECTDIR}/src/http/parse.o: src/http/parse.c - ${MKDIR} -p ${OBJECTDIR}/src/http - ${RM} "$@.d" - $(COMPILE.c) -g -Werror -Ilib -include lib/http_parser.h -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/parse.o src/http/parse.c - -${OBJECTDIR}/src/main.o: src/main.c +${OBJECTDIR}/src/config.o: nbproject/Makefile-${CND_CONF}.mk src/config.c ${MKDIR} -p ${OBJECTDIR}/src ${RM} "$@.d" - $(COMPILE.c) -g -Werror -Ilib -include lib/http_parser.h -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/main.o src/main.c + $(COMPILE.c) -g -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/config.o src/config.c -${OBJECTDIR}/src/socket.o: src/socket.c +${OBJECTDIR}/src/http-reader.o: nbproject/Makefile-${CND_CONF}.mk src/http-reader.c ${MKDIR} -p ${OBJECTDIR}/src ${RM} "$@.d" - $(COMPILE.c) -g -Werror -Ilib -include lib/http_parser.h -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/socket.o src/socket.c + $(COMPILE.c) -g -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http-reader.o src/http-reader.c + +${OBJECTDIR}/src/http-server.o: nbproject/Makefile-${CND_CONF}.mk src/http-server.c + ${MKDIR} -p ${OBJECTDIR}/src + ${RM} "$@.d" + $(COMPILE.c) -g -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http-server.o src/http-server.c + +${OBJECTDIR}/src/http.o: nbproject/Makefile-${CND_CONF}.mk src/http.c + ${MKDIR} -p ${OBJECTDIR}/src + ${RM} "$@.d" + $(COMPILE.c) -g -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http.o src/http.c + +${OBJECTDIR}/src/main.o: nbproject/Makefile-${CND_CONF}.mk src/main.c + ${MKDIR} -p ${OBJECTDIR}/src + ${RM} "$@.d" + $(COMPILE.c) -g -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/main.o src/main.c + +${OBJECTDIR}/src/socket.o: nbproject/Makefile-${CND_CONF}.mk src/socket.c + ${MKDIR} -p ${OBJECTDIR}/src + ${RM} "$@.d" + $(COMPILE.c) -g -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/socket.o src/socket.c # Subprojects .build-subprojects: diff --git a/nbproject/Makefile-Release.mk b/nbproject/Makefile-Release.mk index 859a9e1..05d17da 100644 --- a/nbproject/Makefile-Release.mk +++ b/nbproject/Makefile-Release.mk @@ -36,8 +36,11 @@ OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} # Object Files OBJECTFILES= \ ${OBJECTDIR}/lib/http_parser.o \ - ${OBJECTDIR}/src/http/http.o \ - ${OBJECTDIR}/src/http/parse.o \ + ${OBJECTDIR}/lib/ini.o \ + ${OBJECTDIR}/src/config.o \ + ${OBJECTDIR}/src/http-reader.o \ + ${OBJECTDIR}/src/http-server.o \ + ${OBJECTDIR}/src/http.o \ ${OBJECTDIR}/src/main.o \ ${OBJECTDIR}/src/socket.o @@ -71,15 +74,30 @@ ${OBJECTDIR}/lib/http_parser.o: lib/http_parser.c ${RM} "$@.d" $(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/lib/http_parser.o lib/http_parser.c -${OBJECTDIR}/src/http/http.o: src/http/http.c - ${MKDIR} -p ${OBJECTDIR}/src/http +${OBJECTDIR}/lib/ini.o: lib/ini.c + ${MKDIR} -p ${OBJECTDIR}/lib ${RM} "$@.d" - $(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/http.o src/http/http.c + $(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/lib/ini.o lib/ini.c -${OBJECTDIR}/src/http/parse.o: src/http/parse.c - ${MKDIR} -p ${OBJECTDIR}/src/http +${OBJECTDIR}/src/config.o: src/config.c + ${MKDIR} -p ${OBJECTDIR}/src ${RM} "$@.d" - $(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/parse.o src/http/parse.c + $(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/config.o src/config.c + +${OBJECTDIR}/src/http-reader.o: src/http-reader.c + ${MKDIR} -p ${OBJECTDIR}/src + ${RM} "$@.d" + $(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http-reader.o src/http-reader.c + +${OBJECTDIR}/src/http-server.o: src/http-server.c + ${MKDIR} -p ${OBJECTDIR}/src + ${RM} "$@.d" + $(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http-server.o src/http-server.c + +${OBJECTDIR}/src/http.o: src/http.c + ${MKDIR} -p ${OBJECTDIR}/src + ${RM} "$@.d" + $(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http.o src/http.c ${OBJECTDIR}/src/main.o: src/main.c ${MKDIR} -p ${OBJECTDIR}/src diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index a4e08a2..35b6d1f 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -4,10 +4,13 @@ - src/http/http.h + src/config.h + src/http-reader.h + src/http-server.h + src/http.h lib/http_parser.h + lib/ini.h src/main.h - src/http/parse.h src/socket.h - src/http/http.c + src/config.c + src/http-reader.c + src/http-server.c + src/http.c lib/http_parser.c + lib/ini.c src/main.c - src/http/parse.c src/socket.c Makefile content/error.html - content/lorem.txt + content/public_html/index.html + content/khttpd.ini + content/public_html/lorem.txt Makefile @@ -43,7 +51,7 @@ default true - false + true @@ -51,28 +59,46 @@ lib - - lib/http_parser.h - -O0 + + INI_ALLOW_BOM=0 + INI_ALLOW_MULTILINE=0 + _GNU_SOURCE + 3 - + + + + + - + - + - + - + + + + + + + + + + + + + @@ -105,19 +131,35 @@ - + + + + + - + - + - + - + + + + + + + + + + + + + diff --git a/nbproject/private/configurations.xml b/nbproject/private/configurations.xml index daa4a74..cb9d4e5 100644 --- a/nbproject/private/configurations.xml +++ b/nbproject/private/configurations.xml @@ -29,7 +29,7 @@ "${OUTPUT_PATH}" "${OUTPUT_PATH}" - + /home/sam/NetBeansProjects/KHttp/./dist/Debug/GNU-Linux-x86 true 0 0 diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml index 0d5ff72..358024c 100644 --- a/nbproject/private/private.xml +++ b/nbproject/private/private.xml @@ -8,17 +8,16 @@ file:/home/sam/NetBeansProjects/KHttp/src/socket.c - file:/home/sam/NetBeansProjects/KHttp/src/http/http.h - file:/home/sam/NetBeansProjects/KHttp/src/http/parse.c + file:/home/sam/NetBeansProjects/KHttp/src/http-server.h + file:/home/sam/NetBeansProjects/KHttp/src/http.c + file:/home/sam/NetBeansProjects/KHttp/src/http-reader.h file:/home/sam/NetBeansProjects/KHttp/src/main.h file:/home/sam/NetBeansProjects/KHttp/Makefile - file:/home/sam/NetBeansProjects/KHttp/lib/http_parser.h file:/home/sam/NetBeansProjects/KHttp/content/error.html - file:/home/sam/NetBeansProjects/KHttp/src/http/parse.h file:/home/sam/NetBeansProjects/KHttp/src/main.c - file:/home/sam/NetBeansProjects/KHttp/lib/http_parser.c - file:/home/sam/NetBeansProjects/KHttp/src/socket.h - file:/home/sam/NetBeansProjects/KHttp/src/http/http.c + file:/home/sam/NetBeansProjects/KHttp/src/http-server.c + file:/home/sam/NetBeansProjects/KHttp/src/http.h + file:/home/sam/NetBeansProjects/KHttp/src/http-reader.c diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..5d2da86 --- /dev/null +++ b/src/config.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "config.h" +#include "ini.h" + +const char *default_servername = "localhost"; +const char *default_administrator = "root@localhost"; + +config_server* config_server_new() { + config_server* config = calloc(1, sizeof(config_server)); + config->host_count = 0; + config->listen_port = 80; + + config->servername = calloc(128, sizeof(char)); + if (gethostname(config->servername, 128) < 0) { + warning("failed to get server hostname", true); + free(config->servername); + config->servername = strdup(default_servername); + } + config->servername = realloc(config->servername, (strlen(config->servername)+1)*sizeof(char)); + + config->administrator = strdup(default_servername); + + return config; +} +void config_server_addhost(config_server *config, config_host *host) { + if (config->host_count == 0) { + config->hosts = calloc(1, sizeof(config_server*)); + config->host_count++; + } else { + config->hosts = realloc(config->hosts, ++config->host_count * sizeof(config_server*)); + } + config->hosts[config->host_count-1] = host; +} +config_host* config_server_gethost(config_server *config, char *name) { + config_host *defaulthost=NULL; + config_host *host=NULL; + CONFIG_SERVER_FOREACH_HOST(config, host) { + if (strcasecmp(name, host->hostname) == 0) { + return host; + } + if (host->default_host == true) { + defaulthost = host; + } + } + return defaulthost; +} +void config_server_delete(config_server* config) { + if (config->administrator != NULL) free(config->administrator); + if (config->servername != NULL) free(config->servername); + config_host *host; + CONFIG_SERVER_FOREACH_HOST(config, host) { + config_host_delete(host); + } + if (config->hosts != NULL) free(config->hosts); + free(config); +} + +config_host* config_host_new() { + config_host *host = calloc(1, sizeof(config_host)); + host->default_host = false; + host->enabled = true; + host->hostname = NULL; + host->serve_dir = NULL; + + return host; +} +void config_host_delete(config_host *host) { + if (host->hostname != NULL) free(host->hostname); + if (host->serve_dir != NULL) free(host->serve_dir); + free(host); +} + +static int config_read_ini_cb(void* _config, const char* section, const char* name, + const char* value) { + config_server *config = (config_server*)_config; + static config_host *host = NULL; + +#define MATCH(s, n) strcasecmp(s, section) == 0 && strcasecmp(n, name) == 0 + + if (name == NULL && strcasecmp(section, "Host") == 0) { + host = config_host_new(); + config_server_addhost(config, host); + } else if (strcasecmp("Host", section) == 0 && host == NULL) { + return -1; + } else if (name != NULL) { + if (MATCH("Server", "name")) { + config->servername = strdup(value); + } else if (MATCH("Server", "admin")) { + config->administrator = strdup(value); + } else if (MATCH("Server", "listen")) { + errno = 0; + config->listen_port = (uint16_t)strtol(value, NULL, 10); + if (errno != 0) { + warning("Config: Invalid port number for [Server]listen", true); + } + return -1; + } else if (MATCH("Host", "name")) { + host->hostname = strdup(value); + } else if (MATCH("Host", "enabled")) { + if (strcasecmp(value, "yes") == 0) { + host->enabled = true; + } else if (strcasecmp(value, "no") == 0) { + host->enabled = false; + } + } else if (MATCH("Host", "default")) { + + if (strcasecmp(value, "yes") == 0) { + //Ensure there is only one default host + config_host *tmp; + CONFIG_SERVER_FOREACH_HOST(config, tmp) { + tmp->default_host = false; + } + host->default_host = true; + } else if (strcasecmp(value, "no") == 0) { + host->default_host = false; + } + } else if (MATCH("Host", "serve")) { + DIR *dir = opendir(value); + if (dir == NULL) { + warning("Config: host serve directory is invalid", true); + return -1; + } + closedir(dir); + host->serve_dir = strdup(value); + } + } +#undef MATCH + + return 1; +} + +int config_read_ini(const char* filename, config_server *config) { + return ini_parse(filename, config_read_ini_cb, config); +} \ No newline at end of file diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..ee76bcd --- /dev/null +++ b/src/config.h @@ -0,0 +1,53 @@ +/* + * File: config.h + * Author: sam + * + * Created on 27 July 2014, 18:47 + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "main.h" + +#define CONFIG_SERVER_FOREACH_HOST(config, elem) \ + elem = config->hosts[0]; \ + for(int i=0; i < config->host_count; elem=config->hosts[i++]) + + typedef struct config_host { + char *hostname; + bool default_host; + bool enabled; + char* serve_dir; + } config_host; + + typedef struct config_server { + char *servername; + char *administrator; + uint16_t listen_port; + + config_host **hosts; + size_t host_count; + } config_server; + + config_server* config_server_new(); + void config_server_addhost(config_server *config, config_host *host); + config_host* config_server_gethost(config_server *config, char* name); + void config_server_delete(config_server* config); + + config_host* config_host_new(); + void config_host_delete(config_host *host); + + int config_read_ini(const char* filename, config_server *config); + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_H */ + diff --git a/src/http/parse.c b/src/http-reader.c similarity index 94% rename from src/http/parse.c rename to src/http-reader.c index 52298a3..5b85443 100644 --- a/src/http/parse.c +++ b/src/http-reader.c @@ -1,12 +1,12 @@ #include #include #include -#include #include -#include "../main.h" +#include "main.h" #include "http.h" -#include "parse.h" +#include "http_parser.h" +#include "http-reader.h" #define GET_CB_STR(str, at, length) do { \ str = calloc(length+1, sizeof(char));\ @@ -30,6 +30,12 @@ http_parser_settings* parser_get_settings(skt_elem *elem) { } return parser_settings; } +void parser_free_settings() { + if (parser_settings != NULL) { + free(parser_settings); + parser_settings = NULL; + } +} int parser_cb_on_message_begin(http_parser* parser) { if (SKT(parser)->current_request != NULL) { @@ -83,6 +89,7 @@ int parser_cb_on_header_field(http_parser* parser, const char *at, size_t length http_header* header = SKT(parser)->parser_current_header; size_t newlen = strlen(header->name) + length +1; header->name = realloc(header->name, newlen * sizeof(char)); + strcat(header->name, str); } else { return 1; } diff --git a/src/http/parse.h b/src/http-reader.h similarity index 92% rename from src/http/parse.h rename to src/http-reader.h index b2144f0..4e11742 100644 --- a/src/http/parse.h +++ b/src/http-reader.h @@ -14,12 +14,10 @@ extern "C" { #include "http_parser.h" #include "http.h" -#include "../main.h" - - - void parser_set_currentskt(skt_elem *elem); +#include "main.h" http_parser_settings* parser_get_settings(skt_elem *elem); + void parser_free_settings(); int parser_cb_on_message_begin(http_parser* parser); int parser_cb_on_url(http_parser* parser, const char *at, size_t length); diff --git a/src/http-server.c b/src/http-server.c new file mode 100644 index 0000000..ce35a83 --- /dev/null +++ b/src/http-server.c @@ -0,0 +1,6 @@ +#include +#include + +#include "http.h" +#include "main.h" + diff --git a/src/http-server.h b/src/http-server.h new file mode 100644 index 0000000..a2c7f21 --- /dev/null +++ b/src/http-server.h @@ -0,0 +1,26 @@ +/* + * File: http-server.h + * Author: sam + * + * Created on 26 July 2014, 15:32 + */ + +#ifndef HTTP_SERVER_H +#define HTTP_SERVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "http.h" +#include "main.h" + + + + +#ifdef __cplusplus +} +#endif + +#endif /* HTTP_SERVER_H */ + diff --git a/src/http/http.c b/src/http.c similarity index 99% rename from src/http/http.c rename to src/http.c index f601b11..719b384 100644 --- a/src/http/http.c +++ b/src/http.c @@ -4,7 +4,7 @@ #include #include #include -#include "../main.h" +#include "main.h" #include "ut/utarray.h" #include "ut/utstring.h" #include "http.h" @@ -360,7 +360,7 @@ http_response* http_response_create_builtin(uint16_t code, char* errmsg) { http_header_list_add(resp->headers, http_header_new(HEADER_CONTENT_TYPE, "text/html"), false); - file_map* errorpage = file_map_new("content/error.html"); + file_map* errorpage = file_map_new("error.html"); if (errorpage != NULL) { http_response_append_body(resp, errorpage->map); file_map_delete(errorpage); diff --git a/src/http/http.h b/src/http.h similarity index 100% rename from src/http/http.h rename to src/http.h diff --git a/src/main.c b/src/main.c index 73831cf..13d0135 100644 --- a/src/main.c +++ b/src/main.c @@ -21,16 +21,22 @@ #include "ut/utarray.h" #include "main.h" #include "socket.h" -#include "http/http.h" -#include "http/parse.h" +#include "http.h" +#include "http-reader.h" +#include "config.h" int serverfd = 0; int main(int argc, char** argv) { + config_server *config = config_server_new(); + if (config_read_ini("khttpd.ini", config) < 0) { + return 1; + } + skt_elem *connections = NULL; serverfd = svr_create(); - svr_listen(serverfd, 1234); + svr_listen(serverfd, config->listen_port); while(1) { uint32_t counter; @@ -55,34 +61,35 @@ int main(int argc, char** argv) { //Process sockets LL_FOREACH(connections, elem) { if (utstring_len(elem->info->read) > 0) { + //Parse the incoming data int parsedcount = http_parser_execute( elem->parser, parser_get_settings(elem), utstring_body(elem->info->read), utstring_len(elem->info->read)); + //Check that all data was read if (parsedcount != utstring_len(elem->info->read)) { + //emit warning char warningmsg[2048] = {0}; snprintf(warningmsg, 2048, "error parsing request (%s: %s). closing connection", http_errno_name(elem->parser->http_errno), http_errno_description(elem->parser->http_errno)); warning(warningmsg, false); - elem->info->close = true; - } - utstring_clear(elem->info->read); - if (elem->request_complete == true) { - char* reqstr = http_request_write(elem->current_request); - info("\n%s\n", reqstr); - free(reqstr); - - http_response* resp = http_response_create_builtin(200, elem->current_request->req->uri); - utstring_printf(elem->info->write, "%s", http_response_write(resp)); - http_response_delete(resp); - elem->request_complete = false; - http_request_delete(elem->current_request); - elem->current_request = NULL; + //send 400 back and close connection + http_response *resp400 = http_response_create_builtin(400, "Request was invalid or could not be read"); + char *resp400str = http_response_write(resp400); + utstring_printf(elem->info->write, "%s", resp400str); + http_response_delete(resp400); + free(resp400str); elem->info->close_afterwrite = true; } + //Clear read data now that we have processed it + utstring_clear(elem->info->read); + //Process request if received + if (elem->request_complete == true) { + + } } } diff --git a/src/main.h b/src/main.h index cbf9ab9..683530c 100644 --- a/src/main.h +++ b/src/main.h @@ -15,7 +15,7 @@ extern "C" { #include #include "http_parser.h" #include "socket.h" -#include "http/http.h" +#include "http.h" typedef struct file_map { char* map; diff --git a/src/socket.h b/src/socket.h index e3ac468..1233f9a 100644 --- a/src/socket.h +++ b/src/socket.h @@ -17,7 +17,7 @@ extern "C" { #include #include #include -#include "http/http.h" +#include "http.h" #include "ut/utstring.h" typedef struct skt_info skt_info;