More work on http responses

This commit is contained in:
2014-07-20 21:25:53 +01:00
parent e56f8f3715
commit b51ca6262a
14 changed files with 419 additions and 53 deletions

View File

@@ -58,7 +58,7 @@ build: .build-post
.build-post: .build-impl .build-post: .build-impl
# Add your post 'build' code here... # Add your post 'build' code here...
cp --recursive --force ${CND_BASEDIR}/content ${CND_ARTIFACT_DIR_${CONF}}/
# clean # clean
clean: .clean-post clean: .clean-post
@@ -69,7 +69,6 @@ clean: .clean-post
.clean-post: .clean-impl .clean-post: .clean-impl
# Add your post 'clean' code here... # Add your post 'clean' code here...
# clobber # clobber
clobber: .clobber-post clobber: .clobber-post

12
content/error.html Normal file
View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>{{body_title}}</h1>
<p>{{message}}</p>
</body>
</html>

View File

@@ -35,6 +35,7 @@ OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}
# Object Files # Object Files
OBJECTFILES= \ OBJECTFILES= \
${OBJECTDIR}/src/http/basicresponses.o \
${OBJECTDIR}/src/http/http.o \ ${OBJECTDIR}/src/http/http.o \
${OBJECTDIR}/src/http/request.o \ ${OBJECTDIR}/src/http/request.o \
${OBJECTDIR}/src/main.o \ ${OBJECTDIR}/src/main.o \
@@ -42,7 +43,7 @@ OBJECTFILES= \
# C Compiler Flags # C Compiler Flags
CFLAGS= CFLAGS=-O0
# CC Compiler Flags # CC Compiler Flags
CCFLAGS= CCFLAGS=
@@ -55,7 +56,7 @@ FFLAGS=
ASFLAGS= ASFLAGS=
# Link Libraries and Options # Link Libraries and Options
LDLIBSOPTIONS= LDLIBSOPTIONS=-lpthread
# Build Targets # Build Targets
.build-conf: ${BUILD_SUBPROJECTS} .build-conf: ${BUILD_SUBPROJECTS}
@@ -65,25 +66,30 @@ ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/khttp: ${OBJECTFILES}
${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}
${LINK.c} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/khttp ${OBJECTFILES} ${LDLIBSOPTIONS} ${LINK.c} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/khttp ${OBJECTFILES} ${LDLIBSOPTIONS}
${OBJECTDIR}/src/http/basicresponses.o: src/http/basicresponses.c
${MKDIR} -p ${OBJECTDIR}/src/http
${RM} "$@.d"
$(COMPILE.c) -g -Werror -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/basicresponses.o src/http/basicresponses.c
${OBJECTDIR}/src/http/http.o: src/http/http.c ${OBJECTDIR}/src/http/http.o: src/http/http.c
${MKDIR} -p ${OBJECTDIR}/src/http ${MKDIR} -p ${OBJECTDIR}/src/http
${RM} "$@.d" ${RM} "$@.d"
$(COMPILE.c) -g -Wall -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/http.o src/http/http.c $(COMPILE.c) -g -Werror -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/http.o src/http/http.c
${OBJECTDIR}/src/http/request.o: src/http/request.c ${OBJECTDIR}/src/http/request.o: src/http/request.c
${MKDIR} -p ${OBJECTDIR}/src/http ${MKDIR} -p ${OBJECTDIR}/src/http
${RM} "$@.d" ${RM} "$@.d"
$(COMPILE.c) -g -Wall -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/request.o src/http/request.c $(COMPILE.c) -g -Werror -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/request.o src/http/request.c
${OBJECTDIR}/src/main.o: src/main.c ${OBJECTDIR}/src/main.o: src/main.c
${MKDIR} -p ${OBJECTDIR}/src ${MKDIR} -p ${OBJECTDIR}/src
${RM} "$@.d" ${RM} "$@.d"
$(COMPILE.c) -g -Wall -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/main.o src/main.c $(COMPILE.c) -g -Werror -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/main.o src/main.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"
$(COMPILE.c) -g -Wall -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/socket.o src/socket.c $(COMPILE.c) -g -Werror -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/socket.o src/socket.c
# Subprojects # Subprojects
.build-subprojects: .build-subprojects:

View File

@@ -35,6 +35,7 @@ OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}
# Object Files # Object Files
OBJECTFILES= \ OBJECTFILES= \
${OBJECTDIR}/src/http/basicresponses.o \
${OBJECTDIR}/src/http/http.o \ ${OBJECTDIR}/src/http/http.o \
${OBJECTDIR}/src/http/request.o \ ${OBJECTDIR}/src/http/request.o \
${OBJECTDIR}/src/main.o \ ${OBJECTDIR}/src/main.o \
@@ -65,6 +66,11 @@ ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/khttp: ${OBJECTFILES}
${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}
${LINK.c} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/khttp ${OBJECTFILES} ${LDLIBSOPTIONS} ${LINK.c} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/khttp ${OBJECTFILES} ${LDLIBSOPTIONS}
${OBJECTDIR}/src/http/basicresponses.o: src/http/basicresponses.c
${MKDIR} -p ${OBJECTDIR}/src/http
${RM} "$@.d"
$(COMPILE.c) -O2 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/basicresponses.o src/http/basicresponses.c
${OBJECTDIR}/src/http/http.o: src/http/http.c ${OBJECTDIR}/src/http/http.o: src/http/http.c
${MKDIR} -p ${OBJECTDIR}/src/http ${MKDIR} -p ${OBJECTDIR}/src/http
${RM} "$@.d" ${RM} "$@.d"

View File

@@ -4,6 +4,7 @@
<logicalFolder name="HeaderFiles" <logicalFolder name="HeaderFiles"
displayName="Header Files" displayName="Header Files"
projectFiles="true"> projectFiles="true">
<itemPath>src/http/basicresponses.h</itemPath>
<itemPath>src/http/http.h</itemPath> <itemPath>src/http/http.h</itemPath>
<itemPath>src/main.h</itemPath> <itemPath>src/main.h</itemPath>
<itemPath>src/http/request.h</itemPath> <itemPath>src/http/request.h</itemPath>
@@ -16,6 +17,7 @@
<logicalFolder name="SourceFiles" <logicalFolder name="SourceFiles"
displayName="Source Files" displayName="Source Files"
projectFiles="true"> projectFiles="true">
<itemPath>src/http/basicresponses.c</itemPath>
<itemPath>src/http/http.c</itemPath> <itemPath>src/http/http.c</itemPath>
<itemPath>src/main.c</itemPath> <itemPath>src/main.c</itemPath>
<itemPath>src/http/request.c</itemPath> <itemPath>src/http/request.c</itemPath>
@@ -32,6 +34,10 @@
kind="IMPORTANT_FILES_FOLDER"> kind="IMPORTANT_FILES_FOLDER">
<itemPath>Makefile</itemPath> <itemPath>Makefile</itemPath>
</logicalFolder> </logicalFolder>
<itemPath>content/responses/400.html</itemPath>
<itemPath>dist/Debug/GNU-Linux-x86/content/blah</itemPath>
<itemPath>content/error.html</itemPath>
<itemPath>content/test.txt</itemPath>
</logicalFolder> </logicalFolder>
<sourceRootList> <sourceRootList>
<Elem>include</Elem> <Elem>include</Elem>
@@ -47,9 +53,30 @@
<compileType> <compileType>
<cTool> <cTool>
<standard>3</standard> <standard>3</standard>
<warningLevel>2</warningLevel> <commandLine>-O0</commandLine>
<warningLevel>3</warningLevel>
</cTool> </cTool>
<linkerTool>
<linkerLibItems>
<linkerLibStdlibItem>PosixThreads</linkerLibStdlibItem>
</linkerLibItems>
</linkerTool>
</compileType> </compileType>
<item path="content/error.html" ex="false" tool="3" flavor2="0">
</item>
<item path="content/responses/400.html" ex="false" tool="3" flavor2="0">
</item>
<item path="content/test.txt" ex="false" tool="3" flavor2="0">
</item>
<item path="dist/Debug/GNU-Linux-x86/content/blah"
ex="false"
tool="3"
flavor2="0">
</item>
<item path="src/http/basicresponses.c" ex="false" tool="0" flavor2="0">
</item>
<item path="src/http/basicresponses.h" ex="false" tool="3" flavor2="0">
</item>
<item path="src/http/http.c" ex="false" tool="0" flavor2="0"> <item path="src/http/http.c" ex="false" tool="0" flavor2="0">
</item> </item>
<item path="src/http/http.h" ex="false" tool="3" flavor2="0"> <item path="src/http/http.h" ex="false" tool="3" flavor2="0">
@@ -87,6 +114,21 @@
<developmentMode>5</developmentMode> <developmentMode>5</developmentMode>
</asmTool> </asmTool>
</compileType> </compileType>
<item path="content/error.html" ex="false" tool="3" flavor2="0">
</item>
<item path="content/responses/400.html" ex="false" tool="3" flavor2="0">
</item>
<item path="content/test.txt" ex="false" tool="3" flavor2="0">
</item>
<item path="dist/Debug/GNU-Linux-x86/content/blah"
ex="false"
tool="3"
flavor2="0">
</item>
<item path="src/http/basicresponses.c" ex="false" tool="0" flavor2="0">
</item>
<item path="src/http/basicresponses.h" ex="false" tool="3" flavor2="0">
</item>
<item path="src/http/http.c" ex="false" tool="0" flavor2="0"> <item path="src/http/http.c" ex="false" tool="0" flavor2="0">
</item> </item>
<item path="src/http/http.h" ex="false" tool="3" flavor2="0"> <item path="src/http/http.h" ex="false" tool="3" flavor2="0">

View File

@@ -7,14 +7,17 @@
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/> <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
<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/http/http.h</file> <file>file:/home/sam/NetBeansProjects/KHttp/src/http/http.h</file>
<file>file:/home/sam/NetBeansProjects/KHttp/src/ut/utarray.h</file>
<file>file:/home/sam/NetBeansProjects/KHttp/src/main.h</file> <file>file:/home/sam/NetBeansProjects/KHttp/src/main.h</file>
<file>file:/home/sam/NetBeansProjects/KHttp/Makefile</file>
<file>file:/home/sam/NetBeansProjects/KHttp/src/http/request.h</file> <file>file:/home/sam/NetBeansProjects/KHttp/src/http/request.h</file>
<file>file:/home/sam/NetBeansProjects/KHttp/content/error.html</file>
<file>file:/home/sam/NetBeansProjects/KHttp/src/http/basicresponses.h</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/socket.h</file>
<file>file:/home/sam/NetBeansProjects/KHttp/src/http/request.c</file> <file>file:/home/sam/NetBeansProjects/KHttp/src/http/request.c</file>
<file>file:/home/sam/NetBeansProjects/KHttp/src/http/http.c</file> <file>file:/home/sam/NetBeansProjects/KHttp/src/http/http.c</file>
<file>file:/home/sam/NetBeansProjects/KHttp/src/http/basicresponses.c</file>
</group> </group>
</open-files> </open-files>
</project-private> </project-private>

26
src/http/basicresponses.c Normal file
View File

@@ -0,0 +1,26 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "http.h"
#include "../main.h"
http_response* response_create_builtin(uint16_t code, char* errmsg) {
http_response *resp = http_response_new(http_response_line_new(code));
http_header_list_add(resp->headers, http_header_new(HEADER_CONTENT_TYPE, "text/html"), false);
file_map* errorpage = map_file("content/error.html");
http_response_append_body(resp, errorpage->map);
free_mapped_file(errorpage);
char buffer[1024] = {0};
char* title_message = http_response_line_get_message(resp->resp);
snprintf(buffer, 1023, "%s %hu - %s", (code >= 400) ? "Error" : "Response Code", code, title_message);
resp->body = str_replace(resp->body, "{{title}}", buffer);
resp->body = str_replace(resp->body, "{{body_title}}", buffer);
resp->body = str_replace(resp->body, "{{message}}", errmsg);
return resp;
}

25
src/http/basicresponses.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* File: basicresponses.h
* Author: sam
*
* Created on 20 July 2014, 15:19
*/
#ifndef BASICRESPONSES_H
#define BASICRESPONSES_H
#ifdef __cplusplus
extern "C" {
#endif
#include "http.h"
#include "../main.h"
http_response* response_create_builtin(uint16_t code, char* errmsg);
#ifdef __cplusplus
}
#endif
#endif /* BASICRESPONSES_H */

View File

@@ -2,8 +2,12 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "http.h" #include <stdbool.h>
#include <time.h>
#include "../main.h" #include "../main.h"
#include "../ut/utarray.h"
#include "http.h"
#include "basicresponses.h"
/* /*
* METHOD_GET, METHOD_POST, METHOD_HEAD, METHOD_PUT, * METHOD_GET, METHOD_POST, METHOD_HEAD, METHOD_PUT,
@@ -11,6 +15,8 @@
METHOD_CONNECT, METHOD_OTHER METHOD_CONNECT, METHOD_OTHER
*/ */
UT_icd http_header_icd = {sizeof(http_header), NULL, NULL, NULL};
char* http_method_getstring(http_method method, char* method_other) { char* http_method_getstring(http_method method, char* method_other) {
switch(method) { switch(method) {
case METHOD_GET: return "GET"; case METHOD_GET: return "GET";
@@ -117,12 +123,12 @@ char* http_response_line_get_message(http_response_line *resp) {
default: return ""; default: return "";
} }
} }
void http_reponse_line_delete(http_response_line *resp) { void http_response_line_delete(http_response_line *resp) {
free(resp->custom_message); free(resp->custom_message);
free(resp); free(resp);
} }
http_header *http_header_new(const char* name) { http_header *http_header_new(const char* name, const char* content) {
http_header *header = calloc(1, sizeof(http_header)); http_header *header = calloc(1, sizeof(http_header));
if (header == NULL) { if (header == NULL) {
fatal("calloc failed"); fatal("calloc failed");
@@ -130,6 +136,10 @@ http_header *http_header_new(const char* name) {
header->name = calloc(strlen(name)+1, sizeof(char)); header->name = calloc(strlen(name)+1, sizeof(char));
strcpy(header->name, name); strcpy(header->name, name);
if (content != NULL) {
http_header_append_content(header, content);
}
return header; return header;
} }
void http_header_append_content(http_header *header, const char* content) { void http_header_append_content(http_header *header, const char* content) {
@@ -154,25 +164,69 @@ void http_header_delete(http_header *header) {
free(header); free(header);
} }
http_header_list* http_header_list_new() {
http_header_list* list = NULL;
utarray_new(list, &http_header_icd);
return list;
}
void http_header_list_add(http_header_list* list, http_header *header, bool replace) {
if (replace == true) {
http_header_list_remove(list, header->name);
}
utarray_push_back(list, header);
free(header);
}
http_header* http_header_list_get(http_header_list* list, const char* name) {
HTTP_HEADER_FOREACH(list, elem) {
if (strcmp(elem->name, name) == 0) {
return elem;
}
}
return NULL;
}
http_header** http_header_list_getall(http_header_list* list, const char* name, size_t *out_header_count) {
http_header **headers = NULL;
size_t count = 0;
HTTP_HEADER_FOREACH(list, elem) {
if (strcmp(elem->name, name) == 0) {
count++;
headers = realloc(headers, count * sizeof(http_header*));
headers[count-1] = elem;
}
}
*out_header_count = count;
return headers;
}
void http_header_list_remove(http_header_list *list, const char* name) {
http_header **headers;
size_t count;
headers = http_header_list_getall(list, name, &count);
for(int i=0; i<count; i++) {
int pos = utarray_eltidx(list,headers[i]);
free(headers[i]->name);
free(headers[i]->content);
utarray_erase(list, pos, 1);
}
free(headers);
}
void http_header_list_delete(http_header_list *list) {
HTTP_HEADER_FOREACH(list, elem) {
free(elem->name);
free(elem->content);
}
utarray_free(list);
}
http_request *http_request_new() { http_request *http_request_new() {
http_request *req = calloc(1, sizeof(http_request)); http_request *req = calloc(1, sizeof(http_request));
if (req == NULL) { if (req == NULL) {
fatal("calloc failed"); fatal("calloc failed");
} }
req->header_count = 0; req->headers = http_header_list_new();
req->body = NULL;
req->parsestatus = PARSE_REQUESTLINE; req->parsestatus = PARSE_REQUESTLINE;
return req; return req;
} }
void http_request_add_header(http_request *req, http_header *header) { void http_request_append_body(http_request *req, const char* body) {
req->header_count++;
req->headers = realloc(req->headers, req->header_count * sizeof(http_header*));
if (req->headers == NULL) {
fatal("calloc failed");
}
req->headers[req->header_count-1] = header;
}
void http_request_apppend_body(http_request *req, const char* body) {
uint32_t bodylen = 0; uint32_t bodylen = 0;
if (req->body != NULL) { if (req->body != NULL) {
bodylen = strlen(req->body); bodylen = strlen(req->body);
@@ -186,10 +240,73 @@ void http_request_apppend_body(http_request *req, const char* body) {
} }
void http_request_delete(http_request *req) { void http_request_delete(http_request *req) {
http_request_line_delete(req->req); http_request_line_delete(req->req);
for(int i =0; i < req->header_count; i++) { http_header_list_delete(req->headers);
http_header_delete(req->headers[i]);
}
free(req->headers);
free(req->body); free(req->body);
free(req); free(req);
} }
http_response* http_response_new(http_response_line *resp) {
http_response *response = calloc(1, sizeof(http_response));
response->resp = resp;
response->headers = http_header_list_new();
response->body = NULL;
return response;
}
void http_response_append_body(http_response *resp, const char* body) {
uint32_t bodylen = 0;
if (resp->body != NULL) {
bodylen = strlen(resp->body);
}
bodylen += strlen(body) + 1;
if (resp->body == NULL) {
resp->body = calloc(bodylen, sizeof(char));
} else {
resp->body = realloc(resp->body, bodylen * sizeof(char));
}
strcat(resp->body, body);
}
void http_response_delete(http_response *resp) {
http_response_line_delete(resp->resp);
http_header_list_delete(resp->headers);
free(resp->body);
free(resp);
}
void http_response_write(FILE *target, http_response *resp) {
if (resp->resp->version == HTTP10) {
fprintf(target, "HTTP/1.0 ");
} else if (resp->resp->version == HTTP11) {
fprintf(target, "HTTP/1.1 ");
}
//Write the response line
fprintf(target, "%hu %s\r\n", resp->resp->code, http_response_line_get_message(resp->resp));
if (resp->resp->code != 100) { //No additional headers for Continue messages
//Add content length header
uint32_t messageLength = 0;
if (resp->body != NULL) {
messageLength = strlen(resp->body);
}
char messageLengthStr[100];
snprintf(messageLengthStr, 99, "%u", messageLength);
http_header_list_add(resp->headers, http_header_new(HEADER_CONTENT_LENGTH, messageLengthStr), true);
//Add date header
time_t timenow = time(NULL);
struct tm * timeinfo = gmtime(&timenow);
char dateStr[100] = {0};
strftime(dateStr, 99, FORMAT_HEADER_DATE, timeinfo);
http_header_list_add(resp->headers, http_header_new(HEADER_DATE, dateStr), true);
}
//write headers
HTTP_HEADER_FOREACH(resp->headers, elem) {
fprintf(target, "%s: %s\r\n", elem->name, elem->content);
}
fprintf(target, "\r\n");
//Write the request
//TODO: chunked support for output
if (resp->body != NULL) {
fprintf(target, "%s", resp->body);
}
}

View File

@@ -13,6 +13,23 @@ extern "C" {
#endif #endif
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include "../ut/utarray.h"
#define HEADER_CONTENT_TYPE "Content-Type"
#define HEADER_CONTENT_LENGTH "Content-Length"
#define HEADER_USER_AGENT "User-Agent"
#define HEADER_SERVER "Server"
#define HEADER_LAST_MODIFIED "Last-Modified"
#define HEADER_LOCATION "Location"
#define HEADER_HOST "Host"
#define HEADER_TRANSFER_ENCODING "Transfer-Encoding"
#define HEADER_DATE "Date"
#define HEADER_CONNECTION "Connection"
#define HEADER_IF_MODIFIED_SINCE "If-Modified-Since"
#define HEADER_IF_UNMODIFIED_SINCE "If-Unmodified-Since"
#define FORMAT_HEADER_DATE "%a, %e %h %Y %T %Z"
typedef enum http_method { typedef enum http_method {
METHOD_GET, METHOD_POST, METHOD_HEAD, METHOD_PUT, METHOD_GET, METHOD_POST, METHOD_HEAD, METHOD_PUT,
@@ -42,6 +59,15 @@ extern "C" {
char* content; char* content;
} http_header; } http_header;
typedef UT_array http_header_list;
extern UT_icd http_header_icd;
#define HTTP_HEADER_FOREACH(list, elem) \
for ( http_header *elem= (http_header*)utarray_front(list); \
elem!= NULL; \
elem=(http_header*)utarray_next(list,elem))
typedef enum http_request_parsestatus { typedef enum http_request_parsestatus {
PARSE_REQUESTLINE, PARSE_HEADERS, PARSE_BODY, PARSE_DONE, PARSE_FAIL PARSE_REQUESTLINE, PARSE_HEADERS, PARSE_BODY, PARSE_DONE, PARSE_FAIL
} http_request_parsestatus; } http_request_parsestatus;
@@ -49,11 +75,16 @@ extern "C" {
typedef struct http_request { typedef struct http_request {
http_request_line *req; http_request_line *req;
http_request_parsestatus parsestatus; http_request_parsestatus parsestatus;
http_header **headers; http_header_list *headers;
uint32_t header_count;
char *body; char *body;
} http_request; } http_request;
typedef struct http_response {
http_response_line *resp;
http_header_list *headers;
char* body;
} http_response;
char* http_method_getstring(http_method method, char* method_other); char* http_method_getstring(http_method method, char* method_other);
http_method http_method_fromstring(const char* method); http_method http_method_fromstring(const char* method);
@@ -63,17 +94,26 @@ extern "C" {
http_response_line* http_response_line_new(uint16_t code); http_response_line* http_response_line_new(uint16_t code);
char* http_response_line_get_message(http_response_line *resp); char* http_response_line_get_message(http_response_line *resp);
void http_reponse_line_delete(http_response_line *resp); void http_response_line_delete(http_response_line *resp);
http_header* http_header_new(const char* name); http_header* http_header_new(const char* name, const char* content);
void http_header_append_content(http_header *header, const char* content); void http_header_append_content(http_header *header, const char* content);
void http_header_delete(http_header *header); void http_header_delete(http_header *header);
http_request* http_request_new(); http_header_list* http_header_list_new();
void http_request_add_header(http_request *req, http_header *header); void http_header_list_add(http_header_list* list, http_header *header, bool replace);
void http_request_apppend_body(http_request *req, const char* body); http_header* http_header_list_get(http_header_list* list, const char* name);
void http_request_delete(http_request *req); http_header** http_header_list_getall(http_header_list* list, const char* name, size_t *out_header_count);
void http_header_list_remove(http_header_list *list, const char* name);
void http_header_list_delete(http_header_list *list);
http_request* http_request_new();
void http_request_append_body(http_request *req, const char* body);
void http_request_delete(http_request *req);
http_response* http_response_new(http_response_line *resp);
void http_response_append_body(http_response *resp, const char* body);
void http_response_delete(http_response *resp);
void http_response_write(FILE *target, http_response *resp);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -4,10 +4,12 @@
#include <strings.h> #include <strings.h>
#include "../main.h" #include "../main.h"
#include "http.h" #include "http.h"
#include "basicresponses.h"
char* parse_request(http_request *req, char *input) { http_response* parse_request(http_request *req, char *input) {
size_t line_count; size_t line_count;
char** lines = str_splitlines(input, &line_count); char** lines = str_splitlines(input, &line_count);
http_response* response = NULL;
switch(req->parsestatus) { switch(req->parsestatus) {
case PARSE_REQUESTLINE: case PARSE_REQUESTLINE:
@@ -23,19 +25,26 @@ char* parse_request(http_request *req, char *input) {
int count = sscanf(requestStr, "%19s%*[ \t]%1023s%*[ \t]%15s", methodStr, uriStr, versionStr); int count = sscanf(requestStr, "%19s%*[ \t]%1023s%*[ \t]%15s", methodStr, uriStr, versionStr);
if (count < 3) { if (count < 3) {
response = response_create_builtin(400, "Could not parse request line");
req->parsestatus = PARSE_FAIL; req->parsestatus = PARSE_FAIL;
break; break;
} }
http_method method = http_method_fromstring(methodStr); http_method method = http_method_fromstring(methodStr);
if (method == METHOD_INVALID) { if (method == METHOD_INVALID) {
response = response_create_builtin(405, "");
req->parsestatus = PARSE_FAIL; req->parsestatus = PARSE_FAIL;
break; break;
} }
http_version version; http_version version;
if (strcasecmp(versionStr, "HTTP/1.0") == 0) { version = HTTP10; } if (strcasecmp(versionStr, "HTTP/1.0") == 0) { version = HTTP10; }
if (strcasecmp(versionStr, "HTTP/1.1") == 0) { version = HTTP11; } else if (strcasecmp(versionStr, "HTTP/1.1") == 0) { version = HTTP11; }
else {
response = response_create_builtin(505, "");
req->parsestatus = PARSE_FAIL;
break;
}
http_request_line *request_line = http_request_line_new(method, NULL); http_request_line *request_line = http_request_line_new(method, NULL);
request_line->version = version; request_line->version = version;
@@ -47,6 +56,10 @@ char* parse_request(http_request *req, char *input) {
req->req = request_line; req->req = request_line;
req->parsestatus = PARSE_HEADERS; req->parsestatus = PARSE_HEADERS;
if (req->req->version == HTTP11) {
response = http_response_new(http_response_line_new(100));
}
break; break;
case PARSE_HEADERS: case PARSE_HEADERS:
break; break;
@@ -62,5 +75,5 @@ char* parse_request(http_request *req, char *input) {
free(lines); free(lines);
} }
return NULL; return response;
} }

View File

@@ -15,7 +15,7 @@ extern "C" {
#include "../ut/utstring.h" #include "../ut/utstring.h"
#include "http.h" #include "http.h"
char* parse_request(http_request *req, char *input); http_response *parse_request(http_request *req, char *input);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -10,6 +10,10 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "ut/utlist.h" #include "ut/utlist.h"
#include "ut/utarray.h" #include "ut/utarray.h"
@@ -17,21 +21,23 @@
#include "socket.h" #include "socket.h"
#include "http/http.h" #include "http/http.h"
#include "http/request.h" #include "http/request.h"
#include "http/basicresponses.h"
int serverfd = 0; int serverfd = 0;
char* teststr = "GET /testing/123 HTTP/1.1\r\n"; char* teststr = "testing testing 123 123 omg";
/* /*
* *
*/ */
int main(int argc, char** argv) { int main(int argc, char** argv) {
/*char *test = calloc(strlen(teststr)+1, sizeof(char));
strcpy(test, teststr);
http_request *req = http_request_new(); http_response* resp = response_create_builtin(404, "testing");
parse_request(req, test);
return 0;*/ http_response_write(stdout, resp);
http_response_delete(resp);
return 0;
skt_elem *connections = NULL; skt_elem *connections = NULL;
serverfd = svr_create(); serverfd = svr_create();
@@ -181,3 +187,65 @@ char** str_splitlines(char *str, size_t *line_count) {
return result; return result;
} }
file_map* map_file(const char* filename) {
int fd = open(filename, O_RDONLY);
if (fd < 0) {
fatal("Failed to open file for memory mapping");
}
size_t size = lseek(fd, 0L, SEEK_END);
void* map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) {
fatal("Failed to mmap file");
}
close(fd);
file_map* filemap = calloc(1, sizeof(file_map));
filemap->map = (char*)map;
filemap->size = size;
return filemap;
}
void free_mapped_file(file_map* file) {
if (munmap((void*)file->map, file->size) < 0) {
warning("failed to unmap file", true);
}
free(file);
}
char* str_replace(char *haystack, const char *search, const char *replacement) {
size_t haystacklen = strlen(haystack);
size_t searchlen = strlen(search);
size_t replacementlen = strlen(replacement);
char* result = haystack;
if (searchlen > haystacklen || searchlen == 0) {
return result;
}
if (strstr(replacement, search) != NULL) {
warning("str_replace: replacement should not contain the search criteria", false);
}
int count = 0;
while(count++ < 1000) {
char* pos = strstr(result, search);
if (pos == NULL) {
break;
}
uint32_t start = (pos - result) / sizeof(char);
uint32_t end = start + searchlen;
size_t resultlen = strlen(result);
size_t newlen = resultlen + replacementlen - searchlen;
char* newstr = calloc(newlen+1, sizeof(char));
strncpy(newstr, result, start);
strcat(newstr, replacement);
strcat(newstr, pos+(searchlen*sizeof(char)));
free(result);
result = newstr;
}
return result;
}

View File

@@ -14,6 +14,11 @@ extern "C" {
#include <stdbool.h> #include <stdbool.h>
typedef struct file_map {
char* map;
size_t size;
} file_map;
int main(int argc, char** argv); int main(int argc, char** argv);
void fatal(char* msg); void fatal(char* msg);
@@ -21,6 +26,10 @@ void warning(char* msg, bool showPError);
void info(char* msg, ...); void info(char* msg, ...);
char** str_splitlines(char *str, size_t *line_count); char** str_splitlines(char *str, size_t *line_count);
char* str_replace(char *str, const char *search, const char *replacement);
file_map* map_file(const char* filename);
void free_mapped_file(file_map* map);
#ifdef __cplusplus #ifdef __cplusplus