Done the basics of http server
Added mime type detection Lots still todo, directory index files auto indexing(?)
This commit is contained in:
@@ -42,6 +42,7 @@ OBJECTFILES= \
|
|||||||
${OBJECTDIR}/src/http-server.o \
|
${OBJECTDIR}/src/http-server.o \
|
||||||
${OBJECTDIR}/src/http.o \
|
${OBJECTDIR}/src/http.o \
|
||||||
${OBJECTDIR}/src/main.o \
|
${OBJECTDIR}/src/main.o \
|
||||||
|
${OBJECTDIR}/src/mime.o \
|
||||||
${OBJECTDIR}/src/socket.o
|
${OBJECTDIR}/src/socket.o
|
||||||
|
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ FFLAGS=
|
|||||||
ASFLAGS=
|
ASFLAGS=
|
||||||
|
|
||||||
# Link Libraries and Options
|
# Link Libraries and Options
|
||||||
LDLIBSOPTIONS=
|
LDLIBSOPTIONS=-lmagic
|
||||||
|
|
||||||
# Build Targets
|
# Build Targets
|
||||||
.build-conf: ${BUILD_SUBPROJECTS}
|
.build-conf: ${BUILD_SUBPROJECTS}
|
||||||
@@ -104,6 +105,11 @@ ${OBJECTDIR}/src/main.o: nbproject/Makefile-${CND_CONF}.mk src/main.c
|
|||||||
${RM} "$@.d"
|
${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
|
$(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/mime.o: nbproject/Makefile-${CND_CONF}.mk src/mime.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/mime.o src/mime.c
|
||||||
|
|
||||||
${OBJECTDIR}/src/socket.o: nbproject/Makefile-${CND_CONF}.mk src/socket.c
|
${OBJECTDIR}/src/socket.o: nbproject/Makefile-${CND_CONF}.mk src/socket.c
|
||||||
${MKDIR} -p ${OBJECTDIR}/src
|
${MKDIR} -p ${OBJECTDIR}/src
|
||||||
${RM} "$@.d"
|
${RM} "$@.d"
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ OBJECTFILES= \
|
|||||||
${OBJECTDIR}/src/http-server.o \
|
${OBJECTDIR}/src/http-server.o \
|
||||||
${OBJECTDIR}/src/http.o \
|
${OBJECTDIR}/src/http.o \
|
||||||
${OBJECTDIR}/src/main.o \
|
${OBJECTDIR}/src/main.o \
|
||||||
|
${OBJECTDIR}/src/mime.o \
|
||||||
${OBJECTDIR}/src/socket.o
|
${OBJECTDIR}/src/socket.o
|
||||||
|
|
||||||
|
|
||||||
@@ -104,6 +105,11 @@ ${OBJECTDIR}/src/main.o: src/main.c
|
|||||||
${RM} "$@.d"
|
${RM} "$@.d"
|
||||||
$(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/main.o src/main.c
|
$(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/main.o src/main.c
|
||||||
|
|
||||||
|
${OBJECTDIR}/src/mime.o: src/mime.c
|
||||||
|
${MKDIR} -p ${OBJECTDIR}/src
|
||||||
|
${RM} "$@.d"
|
||||||
|
$(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/mime.o src/mime.c
|
||||||
|
|
||||||
${OBJECTDIR}/src/socket.o: src/socket.c
|
${OBJECTDIR}/src/socket.o: src/socket.c
|
||||||
${MKDIR} -p ${OBJECTDIR}/src
|
${MKDIR} -p ${OBJECTDIR}/src
|
||||||
${RM} "$@.d"
|
${RM} "$@.d"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<itemPath>lib/http_parser.h</itemPath>
|
<itemPath>lib/http_parser.h</itemPath>
|
||||||
<itemPath>lib/ini.h</itemPath>
|
<itemPath>lib/ini.h</itemPath>
|
||||||
<itemPath>src/main.h</itemPath>
|
<itemPath>src/main.h</itemPath>
|
||||||
|
<itemPath>src/mime.h</itemPath>
|
||||||
<itemPath>src/socket.h</itemPath>
|
<itemPath>src/socket.h</itemPath>
|
||||||
</logicalFolder>
|
</logicalFolder>
|
||||||
<logicalFolder name="ResourceFiles"
|
<logicalFolder name="ResourceFiles"
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
<itemPath>lib/http_parser.c</itemPath>
|
<itemPath>lib/http_parser.c</itemPath>
|
||||||
<itemPath>lib/ini.c</itemPath>
|
<itemPath>lib/ini.c</itemPath>
|
||||||
<itemPath>src/main.c</itemPath>
|
<itemPath>src/main.c</itemPath>
|
||||||
|
<itemPath>src/mime.c</itemPath>
|
||||||
<itemPath>src/socket.c</itemPath>
|
<itemPath>src/socket.c</itemPath>
|
||||||
</logicalFolder>
|
</logicalFolder>
|
||||||
<logicalFolder name="TestFiles"
|
<logicalFolder name="TestFiles"
|
||||||
@@ -67,6 +69,11 @@
|
|||||||
</preprocessorList>
|
</preprocessorList>
|
||||||
<warningLevel>3</warningLevel>
|
<warningLevel>3</warningLevel>
|
||||||
</cTool>
|
</cTool>
|
||||||
|
<linkerTool>
|
||||||
|
<linkerLibItems>
|
||||||
|
<linkerLibLibItem>magic</linkerLibLibItem>
|
||||||
|
</linkerLibItems>
|
||||||
|
</linkerTool>
|
||||||
</compileType>
|
</compileType>
|
||||||
<item path="content/error.html" ex="false" tool="3" flavor2="0">
|
<item path="content/error.html" ex="false" tool="3" flavor2="0">
|
||||||
</item>
|
</item>
|
||||||
@@ -104,6 +111,10 @@
|
|||||||
</item>
|
</item>
|
||||||
<item path="src/main.h" ex="false" tool="3" flavor2="0">
|
<item path="src/main.h" ex="false" tool="3" flavor2="0">
|
||||||
</item>
|
</item>
|
||||||
|
<item path="src/mime.c" ex="false" tool="0" flavor2="0">
|
||||||
|
</item>
|
||||||
|
<item path="src/mime.h" ex="false" tool="3" flavor2="0">
|
||||||
|
</item>
|
||||||
<item path="src/socket.c" ex="false" tool="0" flavor2="0">
|
<item path="src/socket.c" ex="false" tool="0" flavor2="0">
|
||||||
</item>
|
</item>
|
||||||
<item path="src/socket.h" ex="false" tool="3" flavor2="0">
|
<item path="src/socket.h" ex="false" tool="3" flavor2="0">
|
||||||
@@ -165,6 +176,10 @@
|
|||||||
</item>
|
</item>
|
||||||
<item path="src/main.h" ex="false" tool="3" flavor2="0">
|
<item path="src/main.h" ex="false" tool="3" flavor2="0">
|
||||||
</item>
|
</item>
|
||||||
|
<item path="src/mime.c" ex="false" tool="0" flavor2="0">
|
||||||
|
</item>
|
||||||
|
<item path="src/mime.h" ex="false" tool="3" flavor2="0">
|
||||||
|
</item>
|
||||||
<item path="src/socket.c" ex="false" tool="0" flavor2="0">
|
<item path="src/socket.c" ex="false" tool="0" flavor2="0">
|
||||||
</item>
|
</item>
|
||||||
<item path="src/socket.h" ex="false" tool="3" flavor2="0">
|
<item path="src/socket.h" ex="false" tool="3" flavor2="0">
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
||||||
<group>
|
<group>
|
||||||
<file>file:/home/sam/NetBeansProjects/KHttp/src/socket.c</file>
|
<file>file:/home/sam/NetBeansProjects/KHttp/src/socket.c</file>
|
||||||
|
<file>file:/home/sam/NetBeansProjects/KHttp/content/khttpd.ini</file>
|
||||||
|
<file>file:/home/sam/NetBeansProjects/KHttp/src/config.c</file>
|
||||||
<file>file:/home/sam/NetBeansProjects/KHttp/src/http-server.h</file>
|
<file>file:/home/sam/NetBeansProjects/KHttp/src/http-server.h</file>
|
||||||
<file>file:/home/sam/NetBeansProjects/KHttp/src/http.c</file>
|
<file>file:/home/sam/NetBeansProjects/KHttp/src/http.c</file>
|
||||||
<file>file:/home/sam/NetBeansProjects/KHttp/src/http-reader.h</file>
|
<file>file:/home/sam/NetBeansProjects/KHttp/src/http-reader.h</file>
|
||||||
@@ -16,8 +18,10 @@
|
|||||||
<file>file:/home/sam/NetBeansProjects/KHttp/content/error.html</file>
|
<file>file:/home/sam/NetBeansProjects/KHttp/content/error.html</file>
|
||||||
<file>file:/home/sam/NetBeansProjects/KHttp/src/main.c</file>
|
<file>file:/home/sam/NetBeansProjects/KHttp/src/main.c</file>
|
||||||
<file>file:/home/sam/NetBeansProjects/KHttp/src/http-server.c</file>
|
<file>file:/home/sam/NetBeansProjects/KHttp/src/http-server.c</file>
|
||||||
|
<file>file:/home/sam/NetBeansProjects/KHttp/lib/ini.c</file>
|
||||||
<file>file:/home/sam/NetBeansProjects/KHttp/src/http.h</file>
|
<file>file:/home/sam/NetBeansProjects/KHttp/src/http.h</file>
|
||||||
<file>file:/home/sam/NetBeansProjects/KHttp/src/http-reader.c</file>
|
<file>file:/home/sam/NetBeansProjects/KHttp/src/http-reader.c</file>
|
||||||
|
<file>file:/home/sam/NetBeansProjects/KHttp/src/config.h</file>
|
||||||
</group>
|
</group>
|
||||||
</open-files>
|
</open-files>
|
||||||
</project-private>
|
</project-private>
|
||||||
|
|||||||
12
src/config.c
12
src/config.c
@@ -43,7 +43,7 @@ config_host* config_server_gethost(config_server *config, char *name) {
|
|||||||
config_host *defaulthost=NULL;
|
config_host *defaulthost=NULL;
|
||||||
config_host *host=NULL;
|
config_host *host=NULL;
|
||||||
CONFIG_SERVER_FOREACH_HOST(config, host) {
|
CONFIG_SERVER_FOREACH_HOST(config, host) {
|
||||||
if (strcasecmp(name, host->hostname) == 0) {
|
if (name != NULL && strcasecmp(name, host->hostname) == 0) {
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
if (host->default_host == true) {
|
if (host->default_host == true) {
|
||||||
@@ -123,13 +123,19 @@ static int config_read_ini_cb(void* _config, const char* section, const char* na
|
|||||||
host->default_host = false;
|
host->default_host = false;
|
||||||
}
|
}
|
||||||
} else if (MATCH("Host", "serve")) {
|
} else if (MATCH("Host", "serve")) {
|
||||||
DIR *dir = opendir(value);
|
char* serve_dir = realpath(value, NULL);
|
||||||
|
if (serve_dir == NULL) {
|
||||||
|
warning("Config: host serve directory is invalid", true);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
DIR* dir = opendir(serve_dir);
|
||||||
if (dir == NULL) {
|
if (dir == NULL) {
|
||||||
|
free(serve_dir);
|
||||||
warning("Config: host serve directory is invalid", true);
|
warning("Config: host serve directory is invalid", true);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
host->serve_dir = strdup(value);
|
host->serve_dir = serve_dir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#undef MATCH
|
#undef MATCH
|
||||||
|
|||||||
@@ -11,12 +11,11 @@
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
#define CONFIG_SERVER_FOREACH_HOST(config, elem) \
|
#define CONFIG_SERVER_FOREACH_HOST(config, elem) \
|
||||||
elem = config->hosts[0]; \
|
elem = config->hosts != NULL ? config->hosts[0] : NULL; \
|
||||||
for(int i=0; i < config->host_count; elem=config->hosts[i++])
|
for(int i=0; i < config->host_count; elem=config->hosts[i++])
|
||||||
|
|
||||||
typedef struct config_host {
|
typedef struct config_host {
|
||||||
|
|||||||
@@ -1,6 +1,145 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <magic.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "http_parser.h"
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "http-server.h"
|
||||||
|
#include "mime.h"
|
||||||
|
|
||||||
|
http_response* server_process_request(config_server* config, http_request *request) {
|
||||||
|
http_response* response = NULL;
|
||||||
|
//Determin host
|
||||||
|
char* hostname=NULL;
|
||||||
|
if (request->req->version == HTTP11) {
|
||||||
|
http_header *hostheader = http_header_list_get(request->headers, HEADER_HOST);
|
||||||
|
if (hostheader != NULL) {
|
||||||
|
hostname = strdup(hostheader->content);
|
||||||
|
} else {
|
||||||
|
response = http_response_create_builtin(400, "Host header required");
|
||||||
|
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//hostname may be null, this indicates that the default host should be used
|
||||||
|
config_host* host_config = config_server_gethost(config, hostname);
|
||||||
|
if (hostname != NULL) {
|
||||||
|
free(hostname);
|
||||||
|
hostname = NULL;
|
||||||
|
}
|
||||||
|
if (host_config == NULL) {
|
||||||
|
//host not found and default not found
|
||||||
|
response = http_response_create_builtin(500, "Server configuration error (host/default not found)");
|
||||||
|
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validate request method
|
||||||
|
http_request_method acceptable_methods[] = {METHOD_GET, METHOD_HEAD, METHOD_POST};
|
||||||
|
bool valid_method = false;
|
||||||
|
for(int i=0; i<sizeof(acceptable_methods)/sizeof(http_request_method); i++) {
|
||||||
|
if (request->req->method == acceptable_methods[i]) {
|
||||||
|
valid_method = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (valid_method == false) {
|
||||||
|
response = http_response_create_builtin(411, "Method is not valid");
|
||||||
|
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Parse the request uri
|
||||||
|
struct http_parser_url *url = calloc(1, sizeof(struct http_parser_url));
|
||||||
|
if (http_parser_parse_url(request->req->uri, strlen(request->req->uri), false, url) < 0) {
|
||||||
|
response = http_response_create_builtin(400, "Invalid request");
|
||||||
|
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the uri/path
|
||||||
|
char* uri = NULL;
|
||||||
|
if ((url->field_set & (1 << UF_PATH)) != 0) {
|
||||||
|
uri = calloc(url->field_data[UF_PATH].len+1, sizeof(char));
|
||||||
|
strncpy(uri, request->req->uri+url->field_data[UF_PATH].off, url->field_data[UF_PATH].len);
|
||||||
|
} else {
|
||||||
|
//Not found (for some reason)
|
||||||
|
response = http_response_create_builtin(400, "URI is required or was invalid");
|
||||||
|
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Build actual path to file requested
|
||||||
|
char* filepath_requested = NULL;
|
||||||
|
size_t totallen = strlen(host_config->serve_dir) + strlen(uri) + 2;
|
||||||
|
filepath_requested = calloc(totallen, sizeof(char));
|
||||||
|
strcat(filepath_requested, host_config->serve_dir);
|
||||||
|
strcat(filepath_requested, "/");
|
||||||
|
strcat(filepath_requested, uri);
|
||||||
|
|
||||||
|
//Check that the file exists
|
||||||
|
char* filepath_actual = realpath(filepath_requested, NULL);
|
||||||
|
if (filepath_actual == NULL) {
|
||||||
|
warning("realpath: not found/error", true);
|
||||||
|
response = http_response_create_builtin(404, "File not found");
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
//Check that the file is within the server directory of the host
|
||||||
|
if (strncmp(host_config->serve_dir, filepath_actual, strlen(host_config->serve_dir)) != 0) {
|
||||||
|
//file is outside the server directory :S
|
||||||
|
response = http_response_create_builtin(400, "URI is required or was invalid");
|
||||||
|
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat *pathstat = calloc(1, sizeof(struct stat));
|
||||||
|
if (stat(filepath_actual, pathstat) < 0) {
|
||||||
|
warning("stat failed", true);
|
||||||
|
response = http_response_create_builtin(400, "URI is required or was invalid");
|
||||||
|
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
//Is is a directory?
|
||||||
|
if (S_ISDIR(pathstat->st_mode) != 0) {
|
||||||
|
response = http_response_create_builtin(200, "Directory listing not implemented");
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Open file
|
||||||
|
FILE *file = fopen(filepath_actual, "r");
|
||||||
|
if (file == NULL) {
|
||||||
|
warning("failed to open file for reading", true);
|
||||||
|
response = http_response_create_builtin(404, "File not found");
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
//File is ok and can be served to the client
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
size_t filesize = ftell(file);
|
||||||
|
rewind(file);
|
||||||
|
|
||||||
|
//Read file into response
|
||||||
|
//TODO: send file directly from the write loop
|
||||||
|
char* buffer = calloc(filesize, sizeof(char));
|
||||||
|
if (fread(buffer, sizeof(char), filesize, file) != filesize) {
|
||||||
|
warning("failed to read file into memory", true);
|
||||||
|
response = http_response_create_builtin(500, "Could not read file");
|
||||||
|
} else {
|
||||||
|
response = http_response_new(http_response_line_new(200));
|
||||||
|
response->resp->version = request->req->version;
|
||||||
|
http_header_list_add(response->headers, http_header_new(HEADER_CONTENT_TYPE, mime_get_type(filepath_actual, DEFAULT_CONTENT_TYPE)), false);
|
||||||
|
http_response_append_body(response, buffer);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
free(buffer);
|
||||||
|
free(filepath_requested);
|
||||||
|
free(filepath_actual);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
@@ -14,8 +14,9 @@ extern "C" {
|
|||||||
|
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
http_response* server_process_request(config_server* config, http_request *request);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
18
src/http.c
18
src/http.c
@@ -429,3 +429,21 @@ char* http_chunks_terminate(http_header_list *footers) {
|
|||||||
free(output);
|
free(output);
|
||||||
return outputstr;
|
return outputstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
http_response_list* http_response_list_new() {
|
||||||
|
http_response_list *list = calloc(1, sizeof(http_response_list));
|
||||||
|
list->responses = NULL;
|
||||||
|
list->count = 0;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
void http_response_list_append(http_response_list *list, http_response* response) {
|
||||||
|
list->responses = realloc(list->responses, (++list->count)*sizeof(http_response*));
|
||||||
|
list->responses[list->count-1] = response;
|
||||||
|
}
|
||||||
|
void http_response_list_delete(http_response_list *list) {
|
||||||
|
http_response *elem;
|
||||||
|
HTTP_RESPONSE_LIST_FOREACH(list, elem) {
|
||||||
|
http_response_delete(elem);
|
||||||
|
}
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
12
src/http.h
12
src/http.h
@@ -89,6 +89,14 @@ extern "C" {
|
|||||||
char* body;
|
char* body;
|
||||||
} http_response;
|
} http_response;
|
||||||
|
|
||||||
|
#define HTTP_RESPONSE_LIST_FOREACH(list, elem) \
|
||||||
|
elem = list->count == 0 ? NULL : list->responses[0]; \
|
||||||
|
for(int i=0; i<list->count; elem=list->responses[++i])
|
||||||
|
|
||||||
|
typedef struct http_response_list {
|
||||||
|
http_response **responses;
|
||||||
|
size_t count;
|
||||||
|
} http_response_list;
|
||||||
|
|
||||||
char* http_method_getstring(http_request_method method, char* method_other);
|
char* http_method_getstring(http_request_method method, char* method_other);
|
||||||
http_request_method http_method_fromstring(const char* method);
|
http_request_method http_method_fromstring(const char* method);
|
||||||
@@ -125,6 +133,10 @@ extern "C" {
|
|||||||
char* http_chunks_write(char* source);
|
char* http_chunks_write(char* source);
|
||||||
char* http_chunks_terminate(http_header_list *footers);
|
char* http_chunks_terminate(http_header_list *footers);
|
||||||
|
|
||||||
|
http_response_list* http_response_list_new();
|
||||||
|
void http_response_list_append(http_response_list *list, http_response* response);
|
||||||
|
void http_response_list_delete(http_response_list *list);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
42
src/main.c
42
src/main.c
@@ -24,10 +24,13 @@
|
|||||||
#include "http.h"
|
#include "http.h"
|
||||||
#include "http-reader.h"
|
#include "http-reader.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "http-server.h"
|
||||||
|
#include "mime.h"
|
||||||
|
|
||||||
int serverfd = 0;
|
int serverfd = 0;
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
mime_load(NULL);
|
||||||
config_server *config = config_server_new();
|
config_server *config = config_server_new();
|
||||||
if (config_read_ini("khttpd.ini", config) < 0) {
|
if (config_read_ini("khttpd.ini", config) < 0) {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -78,17 +81,23 @@ int main(int argc, char** argv) {
|
|||||||
warning(warningmsg, false);
|
warning(warningmsg, false);
|
||||||
//send 400 back and close connection
|
//send 400 back and close connection
|
||||||
http_response *resp400 = http_response_create_builtin(400, "Request was invalid or could not be read");
|
http_response *resp400 = http_response_create_builtin(400, "Request was invalid or could not be read");
|
||||||
char *resp400str = http_response_write(resp400);
|
http_header_list_add(resp400->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||||
utstring_printf(elem->info->write, "%s", resp400str);
|
skt_elem_write_response(elem, resp400, false);
|
||||||
http_response_delete(resp400);
|
http_response_delete(resp400);
|
||||||
free(resp400str);
|
skt_elem_reset(elem);
|
||||||
elem->info->close_afterwrite = true;
|
|
||||||
}
|
}
|
||||||
//Clear read data now that we have processed it
|
//Clear read data now that we have processed it
|
||||||
utstring_clear(elem->info->read);
|
utstring_clear(elem->info->read);
|
||||||
//Process request if received
|
//Process request if received
|
||||||
if (elem->request_complete == true) {
|
if (elem->request_complete == true) {
|
||||||
|
http_response *response = server_process_request(config, elem->current_request);
|
||||||
|
if (response == NULL) {
|
||||||
|
response = http_response_create_builtin(500, "Request could not be processed");
|
||||||
|
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||||
|
}
|
||||||
|
skt_elem_write_response(elem, response, true);
|
||||||
|
|
||||||
|
skt_elem_reset(elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,6 +138,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mime_free();
|
||||||
svr_release(serverfd);
|
svr_release(serverfd);
|
||||||
serverfd = 0;
|
serverfd = 0;
|
||||||
|
|
||||||
@@ -145,6 +155,30 @@ skt_elem* skt_elem_new(skt_info *info) {
|
|||||||
elem->request_complete = false;
|
elem->request_complete = false;
|
||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
void skt_elem_reset(skt_elem *elem) {
|
||||||
|
if (elem->current_request != NULL) {
|
||||||
|
http_request_delete(elem->current_request);
|
||||||
|
elem->current_request = NULL;
|
||||||
|
}
|
||||||
|
if (elem->parser_current_header != NULL) {
|
||||||
|
http_header_delete(elem->parser_current_header);
|
||||||
|
}
|
||||||
|
elem->parser_current_header = NULL;
|
||||||
|
elem->parser_header_state = HSTATE_NONE;
|
||||||
|
elem->request_complete = false;
|
||||||
|
}
|
||||||
|
void skt_elem_write_response(skt_elem *elem, http_response *response, bool dispose) {
|
||||||
|
char *response_str = http_response_write(response);
|
||||||
|
utstring_printf(elem->info->write, "%s", response_str);
|
||||||
|
free(response_str);
|
||||||
|
if (dispose == true) {
|
||||||
|
http_response_delete(response);
|
||||||
|
}
|
||||||
|
http_header* connection_header = http_header_list_get(response->headers, HEADER_CONNECTION);
|
||||||
|
if (connection_header != NULL && strcasecmp(connection_header->content, "close") == 0) {
|
||||||
|
elem->info->close_afterwrite = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
void skt_elem_delete(skt_elem* elem) {
|
void skt_elem_delete(skt_elem* elem) {
|
||||||
if (elem->info!=NULL) skt_delete(elem->info);
|
if (elem->info!=NULL) skt_delete(elem->info);
|
||||||
if (elem->current_request!=NULL) http_request_delete(elem->current_request);
|
if (elem->current_request!=NULL) http_request_delete(elem->current_request);
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ extern "C" {
|
|||||||
} skt_elem;
|
} skt_elem;
|
||||||
|
|
||||||
skt_elem* skt_elem_new(skt_info *info);
|
skt_elem* skt_elem_new(skt_info *info);
|
||||||
|
void skt_elem_reset(skt_elem *elem);
|
||||||
|
void skt_elem_write_response(skt_elem *skt, http_response *response, bool dispose);
|
||||||
void skt_elem_delete(skt_elem* elem);
|
void skt_elem_delete(skt_elem* elem);
|
||||||
|
|
||||||
int main(int argc, char** argv);
|
int main(int argc, char** argv);
|
||||||
|
|||||||
96
src/mime.c
Normal file
96
src/mime.c
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <magic.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ut/utlist.h"
|
||||||
|
#include "mime.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
mime_type *mime_list;
|
||||||
|
|
||||||
|
int mime_load(const char* file) {
|
||||||
|
FILE *mimetypes = fopen(file == NULL ? MIME_DEFAULT_FILE : file, "r");
|
||||||
|
if (mimetypes == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t count = 1024;
|
||||||
|
char* buffer = calloc(count, sizeof(char));
|
||||||
|
ssize_t linelength;
|
||||||
|
while((linelength = getline(&buffer, &count, mimetypes)) >= 0) {
|
||||||
|
|
||||||
|
if (linelength == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (buffer[0] == '#' || buffer[0] == '\n') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char* line = strndup(buffer, linelength);
|
||||||
|
char mime[512], extstr[512];
|
||||||
|
if (sscanf(line, "%511s%*[ \t]%511[a-z0-9 \t]", mime, extstr) == 2) {
|
||||||
|
char* saveptr=NULL;
|
||||||
|
char* ext = strtok_r(extstr, " \t", &saveptr);
|
||||||
|
while(ext != NULL) {
|
||||||
|
mime_type *new = calloc(1, sizeof(mime_type));
|
||||||
|
new->extension = strdup(ext);
|
||||||
|
new->mime = strdup(mime);
|
||||||
|
LL_APPEND(mime_list, new);
|
||||||
|
ext = strtok_r(NULL, " \t", &saveptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
fclose(mimetypes);
|
||||||
|
count = 0;
|
||||||
|
mime_type *elem;
|
||||||
|
LL_COUNT(mime_list, elem, count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
void mime_free() {
|
||||||
|
mime_type *elem, *tmp;
|
||||||
|
LL_FOREACH_SAFE(mime_list, elem, tmp) {
|
||||||
|
free(elem->extension);
|
||||||
|
free(elem->mime);
|
||||||
|
free(elem);
|
||||||
|
}
|
||||||
|
mime_list = NULL;
|
||||||
|
}
|
||||||
|
void mime_print_all() {
|
||||||
|
mime_type *elem;
|
||||||
|
LL_FOREACH(mime_list, elem) {
|
||||||
|
printf("%s\t\t%s\n", elem->mime, elem->extension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* mime_get_type(const char* filename, const char* fallback) {
|
||||||
|
char *ext = strrchr(filename, '.');
|
||||||
|
if (ext != NULL && strlen(ext) > 1) {
|
||||||
|
ext++; //Skip .
|
||||||
|
mime_type *elem;
|
||||||
|
LL_FOREACH(mime_list, elem) {
|
||||||
|
if (strcmp(ext, elem->extension) == 0) {
|
||||||
|
return elem->mime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mime_get_type_magic(filename, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* mime_get_type_magic(const char* filename, const char* fallback) {
|
||||||
|
magic_t magic;
|
||||||
|
|
||||||
|
magic = magic_open(MAGIC_MIME_TYPE);
|
||||||
|
magic_load(magic, NULL);
|
||||||
|
magic_compile(magic, NULL);
|
||||||
|
|
||||||
|
const char* mime = magic_file(magic, filename);
|
||||||
|
magic_close(magic);
|
||||||
|
|
||||||
|
if (mime != NULL) {
|
||||||
|
return mime;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
39
src/mime.h
Normal file
39
src/mime.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* File: mime.h
|
||||||
|
* Author: sam
|
||||||
|
*
|
||||||
|
* Created on 29 July 2014, 19:38
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIME_H
|
||||||
|
#define MIME_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ut/utlist.h"
|
||||||
|
|
||||||
|
#define MIME_DEFAULT_FILE "/etc/mime.types"
|
||||||
|
|
||||||
|
typedef struct mime_type {
|
||||||
|
char* mime;
|
||||||
|
char* extension;
|
||||||
|
struct mime_type *next;
|
||||||
|
} mime_type;
|
||||||
|
|
||||||
|
extern mime_type *mime_list;
|
||||||
|
|
||||||
|
int mime_load(const char* file);
|
||||||
|
void mime_free();
|
||||||
|
void mime_print_all();
|
||||||
|
|
||||||
|
const char* mime_get_type(const char* filename, const char* fallback);
|
||||||
|
const char* mime_get_type_magic(const char* filename, const char* fallback);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* MIME_H */
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
GET /testing123 HTTP/1.1
|
GET /index.html HTTP/1.1
|
||||||
Host: example.com
|
Host: example.com
|
||||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||||
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
|
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
|
||||||
|
|||||||
Reference in New Issue
Block a user