Initial work on http request/response processing
This commit is contained in:
170
src/http/http.c
Normal file
170
src/http/http.c
Normal 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
78
src/http/http.h
Normal 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
6
src/http/request.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "http.h"
|
||||
|
||||
|
||||
25
src/http/request.h
Normal file
25
src/http/request.h
Normal 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 */
|
||||
|
||||
16
src/main.c
16
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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user