Initial work on http request/response processing

This commit is contained in:
2014-07-18 16:52:50 +01:00
parent d556df830f
commit 6d3ca314d4
15 changed files with 351 additions and 12 deletions

5
.dep.inc Normal file
View File

@@ -0,0 +1,5 @@
# This code depends on make tool being used
DEPFILES=$(wildcard $(addsuffix .d, ${OBJECTFILES}))
ifneq (${DEPFILES},)
include ${DEPFILES}
endif

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/build
/dist

BIN
dist/Debug/GNU-Linux-x86/khttp vendored Executable file

Binary file not shown.

View File

@@ -35,6 +35,8 @@ OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}
# Object Files
OBJECTFILES= \
${OBJECTDIR}/src/http/http.o \
${OBJECTDIR}/src/http/request.o \
${OBJECTDIR}/src/main.o \
${OBJECTDIR}/src/socket.o
@@ -63,6 +65,16 @@ ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/khttp: ${OBJECTFILES}
${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}
${LINK.c} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/khttp ${OBJECTFILES} ${LDLIBSOPTIONS}
${OBJECTDIR}/src/http/http.o: src/http/http.c
${MKDIR} -p ${OBJECTDIR}/src/http
${RM} "$@.d"
$(COMPILE.c) -g -Wall -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
${MKDIR} -p ${OBJECTDIR}/src/http
${RM} "$@.d"
$(COMPILE.c) -g -Wall -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http/request.o src/http/request.c
${OBJECTDIR}/src/main.o: src/main.c
${MKDIR} -p ${OBJECTDIR}/src
${RM} "$@.d"

View File

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

View File

@@ -4,7 +4,9 @@
<logicalFolder name="HeaderFiles"
displayName="Header Files"
projectFiles="true">
<itemPath>src/http/http.h</itemPath>
<itemPath>src/main.h</itemPath>
<itemPath>src/http/request.h</itemPath>
<itemPath>src/socket.h</itemPath>
</logicalFolder>
<logicalFolder name="ResourceFiles"
@@ -14,7 +16,9 @@
<logicalFolder name="SourceFiles"
displayName="Source Files"
projectFiles="true">
<itemPath>src/http/http.c</itemPath>
<itemPath>src/main.c</itemPath>
<itemPath>src/http/request.c</itemPath>
<itemPath>src/socket.c</itemPath>
</logicalFolder>
<logicalFolder name="TestFiles"
@@ -46,6 +50,14 @@
<warningLevel>2</warningLevel>
</cTool>
</compileType>
<item path="src/http/http.c" ex="false" tool="0" flavor2="0">
</item>
<item path="src/http/http.h" ex="false" tool="3" flavor2="0">
</item>
<item path="src/http/request.c" ex="false" tool="0" flavor2="0">
</item>
<item path="src/http/request.h" ex="false" tool="3" flavor2="0">
</item>
<item path="src/main.c" ex="false" tool="0" flavor2="0">
</item>
<item path="src/main.h" ex="false" tool="3" flavor2="0">
@@ -75,6 +87,14 @@
<developmentMode>5</developmentMode>
</asmTool>
</compileType>
<item path="src/http/http.c" ex="false" tool="0" flavor2="0">
</item>
<item path="src/http/http.h" ex="false" tool="3" flavor2="0">
</item>
<item path="src/http/request.c" ex="false" tool="0" flavor2="0">
</item>
<item path="src/http/request.h" ex="false" tool="3" flavor2="0">
</item>
<item path="src/main.c" ex="false" tool="0" flavor2="0">
</item>
<item path="src/main.h" ex="false" tool="3" flavor2="0">

View File

@@ -13,8 +13,6 @@
<gdb_interceptlist>
<gdbinterceptoptions gdb_all="false" gdb_unhandled="true" gdb_unexpected="true"/>
</gdb_interceptlist>
<gdb_signals>
</gdb_signals>
<gdb_options>
<DebugOptions>
</DebugOptions>

View File

@@ -8,10 +8,13 @@
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<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/main.h</file>
<file>file:/home/sam/NetBeansProjects/KHttp/src/http/request.h</file>
<file>file:/home/sam/NetBeansProjects/KHttp/src/main.c</file>
<file>file:/home/sam/NetBeansProjects/KHttp/src/ut/utlist.h</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/http.c</file>
</group>
</open-files>
</project-private>

170
src/http/http.c Normal file
View File

@@ -0,0 +1,170 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "http.h"
/*
* METHOD_GET, METHOD_POST, METHOD_HEAD, METHOD_PUT,
METHOD_DELETE, METHOD_OPTIONS, METHOD_TRACE,
METHOD_CONNECT, METHOD_OTHER
*/
char* http_method_getstring(http_method method, char* method_other) {
switch(method) {
case METHOD_GET: return "GET";
case METHOD_POST: return "POST";
case METHOD_HEAD: return "HEAD";
case METHOD_PUT: return "PUT";
case METHOD_DELETE: return "DELETE";
case METHOD_OPTIONS:return "OPTIONS";
case METHOD_TRACE: return "TRACE";
case METHOD_CONNECT:return "CONNECT";
case METHOD_INVALID:return "<INVALID>";
case METHOD_OTHER: return method_other;
default: return "<INVALID#>";
}
}
http_method http_method_fromstring(const char* method) {
http_method methods[] = {METHOD_GET, METHOD_POST, METHOD_HEAD, METHOD_PUT,
METHOD_DELETE, METHOD_OPTIONS, METHOD_TRACE,
METHOD_CONNECT};
size_t count = sizeof(methods) / sizeof(http_method);
for(int i; i < count; i++) {
if (strcmp(http_method_getstring(methods[i],NULL), method) == 0) {
return methods[i];
}
}
return METHOD_INVALID;
}
http_request_line *http_request_line_new(http_method method, const char* other) {
http_request_line *req = calloc(1, sizeof(http_request_line));
req->method = method;
if (req->method == METHOD_OTHER) {
req->method_other = calloc(strlen(other)+1, sizeof(char));
strcpy(req->method_other, other);
} else {
req->method_other = NULL;
}
return req;
}
void http_request_line_delete(http_request_line *req) {
free(req->method_other);
free(req->uri);
free(req);
}
http_response_line *http_response_line_new(uint16_t code) {
http_response_line *resp = calloc(1, sizeof(http_response_line));
resp->code = code;
resp->version = HTTP11;
return resp;
}
char* http_response_line_get_message(http_response_line *resp) {
if (resp->custom_message != NULL) {
return resp->custom_message;
}
switch(resp->code) {
case 100: return "Continue";
case 101: return "Switching Protocols";
case 200: return "OK";
case 201: return "Created";
case 202: return "Accepted";
case 203: return "Non-Authoritative Information";
case 204: return "No Content";
case 205: return "Reset Content";
case 206: return "Partial Content";
case 300: return "Multiple Choices";
case 301: return "Moved Permanently";
case 302: return "Found";
case 303: return "See Other";
case 304: return "Not Modified";
case 305: return "Use Proxy";
case 307: return "Temporary Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
case 403: return "Forbidden";
case 404: return "Not Found";
case 405: return "Method Not Allowed";
case 406: return "Not Acceptable";
case 407: return "Proxy Authentication Required";
case 408: return "Request Timeout";
case 409: return "Conflict";
case 410: return "Gone";
case 411: return "Length Required";
case 412: return "Precondition Failed";
case 413: return "Request Entity Too Large";
case 414: return "Request-URI Too Long";
case 415: return "Unsupported Media Type";
case 416: return "Requested Range Not Satisfiable";
case 417: return "Expectation Failed";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
case 502: return "Bad Gateway";
case 503: return "Service Unavailable";
case 504: return "Gateway Timeout";
case 505: return "HTTP Version Not Supported";
default: return "";
}
}
void http_reponse_line_delete(http_response_line *resp) {
free(resp->custom_message);
free(resp);
}
http_header *http_header_new(const char* name) {
http_header *header = calloc(1, sizeof(http_header));
header->name = calloc(strlen(name)+1, sizeof(char));
strcpy(header->name, name);
return header;
}
void http_header_append_content(http_header *header, const char* content) {
if (header->content == NULL) {
header->content = calloc(strlen(content)+1, sizeof(char));
strcpy(header->content, content);
} else {
uint32_t newlen = strlen(header->content) + strlen(content) + 1;
header->content = realloc(header->content, newlen);
strcat(header->content, content);
}
}
void http_header_delete(http_header *header) {
free(header->name);
free(header->content);
free(header);
}
http_request *http_request_new() {
http_request *req = calloc(1, sizeof(http_request));
req->header_count = 0;
req->body = NULL;
return req;
}
void http_request_add_header(http_request *req, http_header *header) {
req->header_count++;
req->headers = realloc(req->headers, req->header_count * sizeof(http_header*));
req->headers[req->header_count-1] = header;
}
void http_request_apppend_body(http_request *req, const char* body) {
uint32_t bodylen = 0;
if (req->body != NULL) {
bodylen = strlen(req->body);
}
bodylen += strlen(body) + 1;
req->body = realloc(req->body, bodylen * sizeof(char));
strcat(req->body, body);
}
void http_request_delete(http_request *req) {
http_request_line_delete(req->req);
for(int i =0; i < req->header_count; i++) {
http_header_delete(req->headers[i]);
}
free(req->headers);
free(req->body);
free(req);
}

78
src/http/http.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* File: http.h
* Author: sam
*
* Created on 18 July 2014, 14:15
*/
#ifndef HTTP_H
#define HTTP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "request.h"
typedef enum http_method {
METHOD_GET, METHOD_POST, METHOD_HEAD, METHOD_PUT,
METHOD_DELETE, METHOD_OPTIONS, METHOD_TRACE,
METHOD_CONNECT, METHOD_OTHER, METHOD_INVALID
} http_method;
typedef enum http_version {
HTTP10, HTTP11
} http_version;
typedef struct http_request_line {
http_method method;
char* method_other;
char* uri;
http_version version;
} http_request_line;
typedef struct http_response_line {
http_version version;
uint16_t code;
char* custom_message;
} http_response_line;
typedef struct http_header {
char* name;
char* content;
} http_header;
typedef struct http_request {
http_request_line *req;
http_header **headers;
uint32_t header_count;
char *body;
} http_request;
char* http_method_getstring(http_method method, char* method_other);
http_method http_method_fromstring(const char* method);
http_request_line* http_request_line_new(http_method method, const char* other);
void http_request_line_delete(http_request_line *req);
http_response_line* http_response_line_new(uint16_t code);
char* http_response_line_get_message(http_response_line *resp);
void http_reponse_line_delete(http_response_line *resp);
http_header* http_header_new(const char* name);
void http_header_append_content(http_header *header, const char* content);
void http_header_delete(http_header *header);
http_request* http_request_new();
void http_request_add_header(http_request *req, http_header *header);
void http_request_apppend_body(http_request *req, const char* body);
void http_request_delete(http_request *req);
#ifdef __cplusplus
}
#endif
#endif /* HTTP_H */

6
src/http/request.c Normal file
View File

@@ -0,0 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "http.h"

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

@@ -0,0 +1,25 @@
/*
* File: request.h
* Author: sam
*
* Created on 18 July 2014, 14:43
*/
#ifndef REQUEST_H
#define REQUEST_H
#ifdef __cplusplus
extern "C" {
#endif
#include "http.h"
#ifdef __cplusplus
}
#endif
#endif /* REQUEST_H */

View File

@@ -28,8 +28,12 @@ int main(int argc, char** argv) {
svr_listen(serverfd, 1234);
while(1) {
uint32_t counter;
skt_elem *elem, *tmp;
//Accept new connections
while(svr_canaccept(serverfd)) {
LL_COUNT(connections, elem, counter);
while(counter < 100 && svr_canaccept(serverfd)) {
skt_info *info = svr_accept(serverfd);
if (info != NULL) {
skt_elem* newconn = calloc(1, sizeof(skt_elem));
@@ -38,7 +42,6 @@ int main(int argc, char** argv) {
}
}
skt_elem *elem, *tmp;
//Read from connections
LL_FOREACH(connections, elem) {
if (skt_canread(elem->info)) {
@@ -63,16 +66,19 @@ int main(int argc, char** argv) {
}
time_t current = time(NULL);
time_t timeout = 5;
time_t timeout = 30;
time_t maxlife = 500;
//Close where needed
LL_FOREACH(connections, elem) {
if (current - elem->info->last_act > timeout) {
info("[#%lu %s] Timeout", elem->info->id, skt_addr(elem->info));
info("[#%lu %s] Timeout", elem->info->id, skt_clientaddr(elem->info));
elem->info->close = true;
}
if (current - elem->info->time_opened> maxlife) {
info("[#%lu %s] Reached max life", elem->info->id, skt_addr(elem->info));
info("[#%lu %s] Reached max life", elem->info->id, skt_clientaddr(elem->info));
elem->info->close = true;
}
if (elem->info->close_afterwrite && utstring_len(elem->info->write) == 0) {
elem->info->close = true;
}
if (elem->info->close == true) {

View File

@@ -27,6 +27,7 @@ skt_info* skt_new(int fd) {
utstring_new(skt->read);
utstring_new(skt->write);
skt->close = false;
skt->close_afterwrite = false;
skt->closed = false;
return skt;
@@ -94,13 +95,13 @@ void skt_close(skt_info* skt) {
if (skt->closed == true) {
return;
}
info("[#%lu %s] Closed", skt->id, skt_addr(skt));
info("[#%lu %s] Closed", skt->id, skt_clientaddr(skt));
if (close(skt->fd) < 0) {
warning("error closing socket", true);
}
skt->closed = true;
}
char* skt_addr(skt_info *skt) {
char* skt_clientaddr(skt_info *skt) {
char* address = inet_ntoa(skt->clientaddr->sin_addr);
return address;
}
@@ -167,7 +168,7 @@ skt_info* svr_accept(int fd) {
skt->clientaddr = clientaddr;
skt->fd = clientfd;
info("[#%lu %s] New Connection", skt->id, skt_addr(skt));
info("[#%lu %s] New Connection", skt->id, skt_clientaddr(skt));
return skt;

View File

@@ -29,6 +29,7 @@ extern "C" {
UT_string *read;
UT_string *write;
bool close;
bool close_afterwrite;
bool closed;
struct sockaddr_in* clientaddr;
};
@@ -46,7 +47,7 @@ extern "C" {
uint32_t skt_read(skt_info *skt);
uint32_t skt_write(skt_info *skt);
void skt_close(skt_info *skt);
char* skt_addr(skt_info *skt);
char* skt_clientaddr(skt_info *skt);
int svr_create();
void svr_listen(int fd, uint16_t port);