diff --git a/.dep.inc b/.dep.inc new file mode 100644 index 0000000..4560e55 --- /dev/null +++ b/.dep.inc @@ -0,0 +1,5 @@ +# This code depends on make tool being used +DEPFILES=$(wildcard $(addsuffix .d, ${OBJECTFILES})) +ifneq (${DEPFILES},) +include ${DEPFILES} +endif diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2247d5f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/build +/dist diff --git a/dist/Debug/GNU-Linux-x86/khttp b/dist/Debug/GNU-Linux-x86/khttp new file mode 100755 index 0000000..923439d Binary files /dev/null and b/dist/Debug/GNU-Linux-x86/khttp differ diff --git a/nbproject/Makefile-Debug.mk b/nbproject/Makefile-Debug.mk index aecd631..69013e7 100644 --- a/nbproject/Makefile-Debug.mk +++ b/nbproject/Makefile-Debug.mk @@ -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" diff --git a/nbproject/Makefile-Release.mk b/nbproject/Makefile-Release.mk index 676d3bd..b96724e 100644 --- a/nbproject/Makefile-Release.mk +++ b/nbproject/Makefile-Release.mk @@ -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" diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index f147ed1..b277912 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -4,7 +4,9 @@ + src/http/http.h src/main.h + src/http/request.h src/socket.h + src/http/http.c src/main.c + src/http/request.c src/socket.c 2 + + + + + + + + @@ -75,6 +87,14 @@ 5 + + + + + + + + diff --git a/nbproject/private/configurations.xml b/nbproject/private/configurations.xml index daa4a74..a0dea49 100644 --- a/nbproject/private/configurations.xml +++ b/nbproject/private/configurations.xml @@ -13,8 +13,6 @@ - - diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml index c6aa339..873fa0e 100644 --- a/nbproject/private/private.xml +++ b/nbproject/private/private.xml @@ -8,10 +8,13 @@ file:/home/sam/NetBeansProjects/KHttp/src/socket.c + file:/home/sam/NetBeansProjects/KHttp/src/http/http.h file:/home/sam/NetBeansProjects/KHttp/src/main.h + file:/home/sam/NetBeansProjects/KHttp/src/http/request.h file:/home/sam/NetBeansProjects/KHttp/src/main.c - file:/home/sam/NetBeansProjects/KHttp/src/ut/utlist.h file:/home/sam/NetBeansProjects/KHttp/src/socket.h + file:/home/sam/NetBeansProjects/KHttp/src/http/request.c + file:/home/sam/NetBeansProjects/KHttp/src/http/http.c diff --git a/src/http/http.c b/src/http/http.c new file mode 100644 index 0000000..203f949 --- /dev/null +++ b/src/http/http.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#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 ""; + case METHOD_OTHER: return method_other; + default: return ""; + } +} + +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); +} \ No newline at end of file diff --git a/src/http/http.h b/src/http/http.h new file mode 100644 index 0000000..1ca2ec7 --- /dev/null +++ b/src/http/http.h @@ -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 +#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 */ + diff --git a/src/http/request.c b/src/http/request.c new file mode 100644 index 0000000..aded04b --- /dev/null +++ b/src/http/request.c @@ -0,0 +1,6 @@ +#include +#include +#include +#include "http.h" + + diff --git a/src/http/request.h b/src/http/request.h new file mode 100644 index 0000000..bde8df1 --- /dev/null +++ b/src/http/request.h @@ -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 */ + diff --git a/src/main.c b/src/main.c index 7c1c5de..26f0e13 100644 --- a/src/main.c +++ b/src/main.c @@ -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) { diff --git a/src/socket.c b/src/socket.c index 4fe62c5..0939802 100644 --- a/src/socket.c +++ b/src/socket.c @@ -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; diff --git a/src/socket.h b/src/socket.h index 5854672..e6cfb4b 100644 --- a/src/socket.h +++ b/src/socket.h @@ -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);