More work on http responses
This commit is contained in:
3
Makefile
3
Makefile
@@ -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
12
content/error.html
Normal 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>
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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
26
src/http/basicresponses.c
Normal 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
25
src/http/basicresponses.h
Normal 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 */
|
||||||
|
|
||||||
153
src/http/http.c
153
src/http/http.c
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
80
src/main.c
80
src/main.c
@@ -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;
|
||||||
|
}
|
||||||
19
src/main.h
19
src/main.h
@@ -14,13 +14,22 @@ extern "C" {
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
int main(int argc, char** argv);
|
typedef struct file_map {
|
||||||
|
char* map;
|
||||||
|
size_t size;
|
||||||
|
} file_map;
|
||||||
|
|
||||||
void fatal(char* msg);
|
int main(int argc, char** argv);
|
||||||
void warning(char* msg, bool showPError);
|
|
||||||
void info(char* msg, ...);
|
|
||||||
|
|
||||||
char** str_splitlines(char *str, size_t *line_count);
|
void fatal(char* msg);
|
||||||
|
void warning(char* msg, bool showPError);
|
||||||
|
void info(char* msg, ...);
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user