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;