Finished basic server

This commit is contained in:
2014-09-12 19:15:59 +01:00
parent 565bb6df30
commit 98e5992c45
21 changed files with 336 additions and 165 deletions

View File

@@ -1,12 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>{{dirname}}</title>
<title>Index of {{dirname}}/</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>{{dirname}}</h1>
<h1>{{dirname}}/</h1>
<table>
<thead>
<tr>

View File

@@ -1,4 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--<folder path="TestFiles/f1">
<cTool>
<incDir>
<pElem>.</pElem>
</incDir>
</cTool>
<ccTool>
<incDir>
<pElem>.</pElem>
</incDir>
</ccTool>
<linkerTool>
<output>${TESTDIR}/TestFiles/f1</output>
<linkerLibItems>
<linkerOptionItem>-lcunit</linkerOptionItem>
</linkerLibItems>
</linkerTool>
</folder>-->
<configurationDescriptor version="94">
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
<logicalFolder name="HeaderFiles"
@@ -72,7 +90,7 @@
<itemPath>content/error.html</itemPath>
<itemPath>content/public_html/index.html</itemPath>
<itemPath>content/khttpd.ini</itemPath>
<itemPath>content/public_html/lorem.txt</itemPath>
<itemPath>content/public_html/test/lorem.txt</itemPath>
</logicalFolder>
<projectmakefile>Makefile</projectmakefile>
<confs>
@@ -110,26 +128,8 @@
</item>
<item path="content/public_html/index.html" ex="false" tool="3" flavor2="0">
</item>
<item path="content/public_html/lorem.txt" ex="false" tool="3" flavor2="0">
<item path="content/public_html/test/lorem.txt" ex="false" tool="3" flavor2="0">
</item>
<!--<folder path="TestFiles/f1">
<cTool>
<incDir>
<pElem>.</pElem>
</incDir>
</cTool>
<ccTool>
<incDir>
<pElem>.</pElem>
</incDir>
</ccTool>
<linkerTool>
<output>${TESTDIR}/TestFiles/f1</output>
<linkerLibItems>
<linkerOptionItem>-lcunit</linkerOptionItem>
</linkerLibItems>
</linkerTool>
</folder>-->
<item path="lib/http_parser.c" ex="false" tool="0" flavor2="0">
</item>
<item path="lib/http_parser.h" ex="false" tool="3" flavor2="0">
@@ -256,26 +256,8 @@
</item>
<item path="content/public_html/index.html" ex="false" tool="3" flavor2="0">
</item>
<item path="content/public_html/lorem.txt" ex="false" tool="3" flavor2="0">
<item path="content/public_html/test/lorem.txt" ex="false" tool="3" flavor2="0">
</item>
<!--<folder path="TestFiles/f1">
<cTool>
<incDir>
<pElem>.</pElem>
</incDir>
</cTool>
<ccTool>
<incDir>
<pElem>.</pElem>
</incDir>
</ccTool>
<linkerTool>
<output>${TESTDIR}/TestFiles/f1</output>
<linkerLibItems>
<linkerOptionItem>-lcunit</linkerOptionItem>
</linkerLibItems>
</linkerTool>
</folder>-->
<item path="lib/http_parser.c" ex="false" tool="0" flavor2="0">
</item>
<item path="lib/http_parser.h" ex="false" tool="3" flavor2="0">

View File

@@ -5,30 +5,29 @@
#include <pthread.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "ut/utlist.h"
#include "data-buffer.h"
#include "util.h"
data_buffer_list* data_buffer_list_new() {
data_buffer_list *list = calloc(1, sizeof(data_buffer_list));
list->first = NULL;
list->wrlock = calloc(1, sizeof(pthread_mutex_t));
pthread_mutex_init(list->wrlock, NULL);
list->rdlock = calloc(1, sizeof(pthread_mutex_t));
pthread_mutex_init(list->rdlock, NULL);
pthread_mutex_init(&list->rdlock, NULL);
pthread_mutex_init(&list->wrlock, NULL);
return list;
}
void data_buffer_list_delete(data_buffer_list *list) {
assert(list!=NULL);
pthread_mutex_destroy(list->wrlock);
pthread_mutex_destroy(list->rdlock);
pthread_mutex_destroy(&list->wrlock);
pthread_mutex_destroy(&list->rdlock);
data_buffer *elem, *tmp;
LL_FOREACH_SAFE(list->first, elem, tmp) {
LL_DELETE(list->first, elem);
data_buffer_free(elem);
data_buffer_delete(elem);
}
free(list->wrlock);
free(list->rdlock);
free(list);
}
void data_buffer_list_append(data_buffer_list *list, const char* src, size_t n) {
@@ -36,48 +35,103 @@ void data_buffer_list_append(data_buffer_list *list, const char* src, size_t n)
assert(src!=NULL && n>0);
BUFFER_LIST_WR_LOCK(list);
int blocks = 1;
data_buffer *newbuf = data_buffer_new(DATA_BUFFER_SIZE);
while(blocks * DATA_BUFFER_SIZE < n) {
blocks++;
LL_PREPEND(newbuf, data_buffer_new(DATA_BUFFER_SIZE));
//Fetch last buffer in list, in case it has space left
data_buffer *newbuf = NULL, *elem = NULL;
bool first_is_new = false;
LL_FOREACH(list->first, elem) {
if (elem->next == NULL) {
newbuf = elem;
}
}
//Use a new buffer if list empty or last buffer is full
if (newbuf == NULL || newbuf->wOffset == newbuf->size) {
newbuf = data_buffer_new(DATA_BUFFER_SIZE);
first_is_new = true;
}
//Add new buffers until we have enough allocated
size_t allocated = newbuf->size - newbuf->wOffset;
while(allocated < n) {
data_buffer *buffer = data_buffer_new(DATA_BUFFER_SIZE);
allocated += buffer->size;
LL_APPEND(newbuf, buffer);
}
//Add data to the buffers
size_t offset = 0;
data_buffer *elem;
elem = NULL;
LL_FOREACH(newbuf, elem) {
size_t copy_count = n - offset;
if (copy_count > elem->size) {
copy_count = elem->size;
if (copy_count > (elem->size - elem->wOffset)) {
copy_count = (elem->size - elem->wOffset);
}
memcpy(elem->buffer, src+offset, copy_count);
memcpy(elem->buffer+elem->wOffset, src+offset, copy_count);
offset += copy_count;
elem->wOffset += copy_count;
}
//Don't re-append the last buffer
if (first_is_new == false) {
LL_DELETE(newbuf, newbuf);
}
LL_CONCAT(list->first, newbuf);
BUFFER_LIST_WR_UNLOCK(list);
}
void data_buffer_list_lock(data_buffer_list *list, bool rd, bool wr) {
assert(list != NULL);
if (wr == true) pthread_mutex_lock(list->wrlock);
if (rd == true) pthread_mutex_lock(list->rdlock);
if (wr == true) pthread_mutex_lock(&list->wrlock);
if (rd == true) pthread_mutex_lock(&list->rdlock);
}
void data_buffer_list_unlock(data_buffer_list *list, bool rd, bool wr) {
assert(list != NULL);
if (rd == true) pthread_mutex_unlock(list->rdlock);
if (wr == true) pthread_mutex_unlock(list->wrlock);
if (rd == true) pthread_mutex_unlock(&list->rdlock);
if (wr == true) pthread_mutex_unlock(&list->wrlock);
}
ssize_t data_buffer_list_writeto_fd(data_buffer_list *list, int fd) {
assert(list != NULL);
ssize_t result = 0;
BUFFER_LIST_RD_LOCK(list);
data_buffer *next = list->first;
while(next != NULL) {
size_t write_count = next->wOffset - next->rOffset;
if (write_count > 0) {
ssize_t written = write(fd, next->buffer+next->rOffset, write_count);
if (written <= 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
result = -1;
goto DONE;
}
if (written < 0) {
result = -1;
goto DONE;
}
}
result += written;
next->rOffset += written;
} else {
LL_DELETE(list->first, next);
data_buffer_delete(next);
next = list->first;
}
}
DONE:
BUFFER_LIST_RD_UNLOCK(list);
return result;
}
data_buffer* data_buffer_new(size_t size) {
assert(size > 0);
data_buffer* buf = calloc(1, sizeof(data_buffer));
ALLOC_CHECK(buf);
buf->buffer = calloc(size, sizeof(char));
ALLOC_CHECK(buf->buffer);
buf->size = size;
return buf;
}
void data_buffer_free(data_buffer *buf) {
void data_buffer_delete(data_buffer *buf) {
assert(buf != NULL);
free(buf->buffer);

View File

@@ -27,7 +27,8 @@ extern "C" {
typedef struct data_buffer_list {
struct data_buffer *first;
pthread_mutex_t *wrlock, *rdlock;
pthread_mutex_t wrlock;
pthread_mutex_t rdlock;
} data_buffer_list;
typedef struct data_buffer {
@@ -43,9 +44,10 @@ extern "C" {
void data_buffer_list_append(data_buffer_list *list, const char* src, size_t n);
void data_buffer_list_lock(data_buffer_list *list, bool rd, bool wr);
void data_buffer_list_unlock(data_buffer_list *list, bool rd, bool wr);
ssize_t data_buffer_list_writeto_fd(data_buffer_list *list, int fd);
data_buffer* data_buffer_new(size_t size);
void data_buffer_free(data_buffer *buffer);
void data_buffer_delete(data_buffer *buffer);
#ifdef __cplusplus
}

View File

@@ -10,8 +10,9 @@
#include "util.h"
#include "ut/utstring.h"
#include "http-body.h"
#include "log.h"
http_body_write_result _http_body_file_fill_buffer(char *buffer, size_t buf_len, size_t *read_len, FILE *src) {
http_body_write_result _http_body_file_fill_buffer(char *buffer, size_t buf_len, size_t *read_len, FILE *src, size_t offset) {
assert(buffer!=NULL);
assert(buf_len>0);
assert(src!=NULL);
@@ -20,6 +21,7 @@ http_body_write_result _http_body_file_fill_buffer(char *buffer, size_t buf_len,
if (*read_len > buf_len) {
*read_len = buf_len;
}
fseek(src, offset, SEEK_SET);
size_t read_count = fread(buffer, sizeof(char), *read_len, src);
if (read_count < *read_len) {
if (ferror(src) != 0) {
@@ -84,6 +86,7 @@ void http_body_clear(http_body *body) {
fatal("Invalid http body type");
break;
}
body->rOffset = 0;
}
void http_body_delete(http_body *body) {
assert(body!=NULL);
@@ -99,9 +102,15 @@ size_t http_body_append_str(http_body *body, const char* str, ssize_t str_len) {
if (str_len == 0) {
return 0;
}
size_t new_len = strlen(body->data.str)+str_len+1;
body->data.str = realloc(body->data.str, new_len);
size_t new_len = str_len+1;
if (body->data.str != NULL) {
new_len += strlen(body->data.str);
}
if (body->data.str == NULL) {
body->data.str = calloc(new_len, sizeof(char));
} else {
body->data.str = realloc(body->data.str, new_len);
}
ALLOC_CHECK(body->data.str);
body->data.str[new_len-1] = '\0';
strncat(body->data.str, str, new_len-1);
@@ -161,7 +170,7 @@ http_body_write_result http_body_writeto_fd(http_body *body, int fd) {
while(body->rOffset<http_body_len(body)) {
size_t write_len = http_body_len(body) - body->rOffset;
errno = EINVAL;
ssize_t written = -1;
http_body_write_result result = HBWRITE_MORE;
@@ -174,7 +183,7 @@ http_body_write_result http_body_writeto_fd(http_body *body, int fd) {
break;
case BODY_FILE:;
size_t read_count = write_len;
http_body_write_result read_res = _http_body_file_fill_buffer(buffer, buffer_len, &read_count, body->data.file);
http_body_write_result read_res = _http_body_file_fill_buffer(buffer, buffer_len, &read_count, body->data.file, body->rOffset);
if (read_res == HBWRITE_ERROR) {
result = read_res; break;
}
@@ -190,8 +199,10 @@ http_body_write_result http_body_writeto_fd(http_body *body, int fd) {
if (written < 0 || result == HBWRITE_ERROR) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return HBWRITE_BLOCKED;
} else {
perror("Write Error");
return HBWRITE_ERROR;
}
return HBWRITE_ERROR;
}
body->rOffset += written;
@@ -241,7 +252,7 @@ http_body_write_result http_body_writeto_str(http_body *body, char** str) {
break;
case BODY_FILE:;
size_t read_count = write_len;
http_body_write_result read_res = _http_body_file_fill_buffer(buffer, buffer_len, &read_count, body->data.file);
http_body_write_result read_res = _http_body_file_fill_buffer(buffer, buffer_len, &read_count, body->data.file, body->rOffset);
if (read_res == HBWRITE_ERROR) {
result = read_res; break;
}
@@ -301,12 +312,12 @@ http_body_write_result http_body_writeto_utstring(http_body *body, UT_string *ut
break;
case BODY_FILE:;
size_t read_count = write_len;
http_body_write_result read_res = _http_body_file_fill_buffer(buffer, buffer_len, &read_count, body->data.file);
http_body_write_result read_res = _http_body_file_fill_buffer(buffer, buffer_len, &read_count, body->data.file, body->rOffset);
if (read_res == HBWRITE_ERROR) {
result = read_res; break;
}
if (read_count > 0) {
utstring_bincpy(utstr, src, write_len);
utstring_bincpy(utstr, buffer, read_count);
written = read_count;
}
if (read_res == HBWRITE_DONE) {

View File

@@ -127,29 +127,22 @@ http_response* server_process_request(config_server* config, http_request *reque
return response;
}
//File is ok and can be served to the client
fseek(file, 0, SEEK_END);
size_t filesize = ftell(file);
rewind(file);
//Read file into response
//TODO: send file directly from the write loop
char* buffer = calloc(filesize+1, sizeof(char));
if (fread(buffer, sizeof(char), filesize, file) != filesize) {
warning(true, "failed to read file into memory");
response = http_response_create_builtin(500, "Could not read file");
} else {
response = http_response_new(http_response_line_new(200));
response->resp->version = request->req->version;
const char* mime_type = "text/html";
if (filepath != NULL) {
mime_type = mime_get_type(filepath, DEFAULT_CONTENT_TYPE);
}
http_header_list_add(response->headers, http_header_new(HEADER_CONTENT_TYPE, mime_type), false);
http_response_append_body(response, buffer);
response = http_response_new(http_response_line_new(200));
response->resp->version = request->req->version;
const char* mime_type = "text/html";
if (filepath != NULL) {
mime_type = mime_get_type(filepath, DEFAULT_CONTENT_TYPE);
}
fclose(file);
free(buffer);
http_header_list_add(response->headers, http_header_new(HEADER_CONTENT_TYPE, mime_type), false);
if (request->req->method == METHOD_HEAD) {
fclose(file);
http_body_set_type(response->body, BODY_NONE);
} else {
http_body_set_type(response->body, BODY_FILE);
response->body->data.file = file;
}
free(filepath);
bool close_connection = false;
@@ -275,9 +268,12 @@ FILE * server_generate_directory_index(config_host *hconfig, const char* dirpath
char* file_mod_time = calloc(32, sizeof(char));
ctime_r(&file_mtime, file_mod_time);
utstring_printf(index, "<tr><td><a href=\"%s\">%s</a></td><td>%s</td><td>%s</td></tr>\r\n", uri, uri,
char *file_basename = basename_r(uri);
utstring_printf(index, "<tr><td><a href=\"%s\">%s</a></td><td>%s</td><td>%s</td></tr>\r\n", uri, file_basename,
(filesize!=NULL)?filesize:"N/A",
(file_mod_time!=NULL)?file_mod_time:"N/A");
free(file_basename);
free(file_mod_time);
free(filepath);
free(filesize);
@@ -286,7 +282,7 @@ FILE * server_generate_directory_index(config_host *hconfig, const char* dirpath
closedir(dir);
free(filestat);
char *dirname = strdup(dirpath);
dirname = str_replace(dirname, hconfig->serve_dir, "/");
dirname = str_replace(dirname, hconfig->serve_dir, "");
file_map *dirindex_map = file_map_new("dirindex.html");
if (dirindex_map == NULL) {

View File

@@ -74,8 +74,9 @@ http_request_line *http_request_line_new(http_request_method method, const char*
}
void http_request_line_delete(http_request_line *req) {
assert(req!=NULL);
free(req->method_other);
if (req->method == METHOD_OTHER) {
free(req->method_other);
}
free(req->uri);
free(req);
}
@@ -311,6 +312,7 @@ http_response* http_response_new(http_response_line *resp) {
response->headers = http_header_list_new();
response->body_chunked = false;
response->body = http_body_new(BODY_NONE, NULL);
response->send_status = SEND_RESPONSE_LINE;
return response;
}
void http_response_append_body(http_response *resp, const char* body) {
@@ -332,62 +334,64 @@ char* http_response_write(http_response *resp) {
assert(resp!=NULL);
assert(resp->resp !=NULL);
if (resp->send_status == SEND_BODY || resp->send_status == SEND_DONE) {
return NULL;
}
UT_string *output = calloc(1, sizeof(UT_string));
ALLOC_CHECK(output);
utstring_init(output);
if (resp->resp->version == HTTP10) {
utstring_printf(output, "HTTP/1.0 ");
} else if (resp->resp->version == HTTP11) {
utstring_printf(output, "HTTP/1.1 ");
}
//Write the response line
utstring_printf(output, "%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
if (resp->body_chunked == false) {
//Add content length header
uint32_t messageLength = http_body_len(resp->body);
char messageLengthStr[100];
snprintf(messageLengthStr, 99, "%u", messageLength);
http_header_list_add(resp->headers, http_header_new(HEADER_CONTENT_LENGTH, messageLengthStr), true);
} else { //Chunked encoding
http_header_list_add(resp->headers, http_header_new(HEADER_TRANSFER_ENCODING, "chunked"), true);
if (resp->send_status == SEND_RESPONSE_LINE) {
if (resp->resp->version == HTTP10) {
utstring_printf(output, "HTTP/1.0 ");
} else if (resp->resp->version == HTTP11) {
utstring_printf(output, "HTTP/1.1 ");
}
//Write the response line
utstring_printf(output, "%hu %s\r\n", resp->resp->code, http_response_line_get_message(resp->resp));
//Add content type if not defined
http_header* contenttype = http_header_list_get(resp->headers, HEADER_CONTENT_TYPE);
if (contenttype == NULL) {
http_header_list_add(resp->headers, http_header_new(HEADER_CONTENT_TYPE, DEFAULT_CONTENT_TYPE), false);
}
//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);
//Add server identifier header
http_header_list_add(resp->headers, http_header_new(HEADER_SERVER, SERVER_NAME), true);
resp->send_status = SEND_HEADERS;
}
//write headers
http_header *elem;
HTTP_HEADER_FOREACH(resp->headers, elem) {
utstring_printf(output, "%s: %s\r\n", elem->name, elem->content);
if (resp->send_status == SEND_HEADERS) {
if (resp->resp->code != 100) { //No additional headers for Continue messages
if (resp->body_chunked == false) {
//Add content length header
uint32_t messageLength = http_body_len(resp->body);
char messageLengthStr[100];
snprintf(messageLengthStr, 99, "%u", messageLength);
http_header_list_add(resp->headers, http_header_new(HEADER_CONTENT_LENGTH, messageLengthStr), true);
} else { //Chunked encoding
http_header_list_add(resp->headers, http_header_new(HEADER_TRANSFER_ENCODING, "chunked"), true);
}
//Add content type if not defined
http_header* contenttype = http_header_list_get(resp->headers, HEADER_CONTENT_TYPE);
if (contenttype == NULL) {
http_header_list_add(resp->headers, http_header_new(HEADER_CONTENT_TYPE, DEFAULT_CONTENT_TYPE), false);
}
//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);
//Add server identifier header
http_header_list_add(resp->headers, http_header_new(HEADER_SERVER, SERVER_NAME), true);
}
//write headers
http_header *elem;
HTTP_HEADER_FOREACH(resp->headers, elem) {
utstring_printf(output, "%s: %s\r\n", elem->name, elem->content);
}
utstring_printf(output, "\r\n");
resp->send_status = SEND_BODY;
}
utstring_printf(output, "\r\n");
//Write the request (if string)
if (resp->body->type == BODY_STRING) {
if (resp->body_chunked == false) {
http_body_writeto_utstring(resp->body, output);
}
if (resp->body_chunked == true) {
http_chunks_write(resp->body->data.str, output);
}
}
char* outputStr = utstring_body(output);
free(output);
return outputStr;
@@ -482,10 +486,16 @@ void http_response_list_append(http_response_list *list, http_response* response
LL_APPEND(list->first, response);
}
void http_response_list_remove(http_response_list *list, http_response* response) {
assert(list != NULL);
assert(response != NULL);
LL_DELETE(list->first, response);
}
http_response* http_response_list_next(http_response_list *list) {
assert(list != NULL);
return http_response_list_next2(list, true);
return http_response_list_next2(list, false);
}
http_response* http_response_list_next2(http_response_list *list, bool remove) {
assert(list != NULL);
@@ -503,8 +513,8 @@ http_response* http_response_list_next2(http_response_list *list, bool remove) {
void http_response_list_delete(http_response_list *list) {
assert(list != NULL);
http_response *elem;
HTTP_RESPONSE_LIST_FOREACH(list, elem) {
http_response *elem, *tmp;
HTTP_RESPONSE_LIST_FOREACH_SAFE(list, elem, tmp) {
http_response_delete(elem);
}
free(list);

View File

@@ -87,15 +87,21 @@ extern "C" {
struct http_request *next;
} http_request;
typedef enum http_response_send_status {
SEND_RESPONSE_LINE, SEND_HEADERS, SEND_BODY, SEND_DONE
} http_response_send_status;
typedef struct http_response {
http_response_line *resp;
http_header_list *headers;
bool body_chunked;
http_body *body;
http_response_send_status send_status;
struct http_response *next;
} http_response;
#define HTTP_RESPONSE_LIST_FOREACH(list, elem) LL_FOREACH(list->first, elem)
#define HTTP_RESPONSE_LIST_FOREACH_SAFE(list, elem, tmp) LL_FOREACH_SAFE(list->first, elem, tmp)
typedef struct http_response_list {
http_response *first;
@@ -138,6 +144,7 @@ extern "C" {
http_response_list* http_response_list_new();
void http_response_list_append(http_response_list *list, http_response* response);
void http_response_list_remove(http_response_list *list, http_response* response);
http_response* http_response_list_next(http_response_list *list);
http_response* http_response_list_next2(http_response_list *list, bool remove);
void http_response_list_delete(http_response_list *list);

View File

@@ -80,7 +80,7 @@ void*log_loop(void* arg) {
void** buf = calloc(1, sizeof(void*));
char* timestr = calloc(32, sizeof(char));
time_t ctime;
struct tm *tinfo = calloc(1,sizeof(struct tm));
struct tm tinfo = {0};
while(true) {
//Read next message pointer from pipe
if (read(l->pRead, buf, sizeof(void*)) <= 0) {
@@ -95,8 +95,8 @@ void*log_loop(void* arg) {
break;
}
ctime = time(NULL);
localtime_r(&ctime, tinfo);
if (strftime(timestr, 32, "%F %R", tinfo) == 0) {
localtime_r(&ctime, &tinfo);
if (strftime(timestr, 32, "%F %R", &tinfo) == 0) {
strcpy(timestr, "N/A");
}
log_msg* msg = (log_msg*)(*buf);

View File

@@ -15,13 +15,22 @@
#include <sys/mman.h>
#include <ctype.h>
#include <signal.h>
#include <bits/stdio2.h>
#include <errno.h>
#include "util.h"
#include "log.h"
#include "main.h"
#include "server.h"
#include "server-state.h"
static server_state *current_state = NULL;
static void signal_handle(int sig) {
if (current_state != NULL) {
current_state->shutdown_requested = true;
}
}
int main(int argc, char** argv) {
//Load the config
@@ -32,8 +41,22 @@ int main(int argc, char** argv) {
server_state *state = server_status_new(config);
current_state = state;
char sig_error_buf[128];
if (signal(SIGINT, signal_handle) == SIG_ERR) {
char *errstr = strerror_r(errno, sig_error_buf, 127);
LOG(LERROR, "Failed to attach signal handler to SIGINT: %s", errstr);
}
if (signal(SIGTERM, signal_handle) == SIG_ERR) {
char *errstr = strerror_r(errno, sig_error_buf, 127);
LOG(LERROR, "Failed to attach signal handler to SIGTERM: %s", errstr);
}
//Run the server
server_start(state);
current_state = NULL;
server_status_delete(state);
return (EXIT_SUCCESS);
}

View File

@@ -48,6 +48,7 @@ server_parse_status* server_parse_status_new() {
state->parser_header_state = HSTATE_NONE;
state->parser = calloc(1, sizeof(http_parser));
http_parser_init(state->parser, HTTP_REQUEST);
state->parser->data = (void*)state;
return state;
}
@@ -67,7 +68,7 @@ void server_parse_status_delete(server_parse_status* state) {
}
void server_parser_status_reset(server_parse_status* state) {
assert(state!=NULL);
state->current_request = NULL;
state->request_complete = false;
state->parser_header_state = HSTATE_NONE;
if (state->parser_current_header != NULL) {

View File

@@ -28,7 +28,66 @@ void* server_loop_write(void* arg) {
server_connection *conn = (server_connection*)item->data;
CONN_LOCK(conn);
if (conn->pending_writes->first != NULL) {
errno = 0;
if (data_buffer_list_writeto_fd(conn->pending_writes, conn->skt->fd) < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
item->blocked = true;
} else {
char address[INET_ADDRSTRLEN];
skt_clientaddr(conn->skt, address, INET_ADDRSTRLEN);
warning(true, "[#%lu %s] write error", conn->id, address);
conn->skt->error = true;
}
}
}
if (conn->pending_writes->first == NULL) {
http_response *response = http_response_list_next(conn->pending_responses);
while (response != NULL) {
char* resp_str = http_response_write(response);
if (resp_str != NULL) {
data_buffer_list_append(conn->pending_writes, resp_str, strlen(resp_str));
free(resp_str);
}
if (conn->pending_writes->first != NULL) {
errno = 0;
if (data_buffer_list_writeto_fd(conn->pending_writes, conn->skt->fd) < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
item->blocked = true;
} else {
char address[INET_ADDRSTRLEN];
skt_clientaddr(conn->skt, address, INET_ADDRSTRLEN);
warning(true, "[#%lu %s] write error", conn->id, address);
conn->skt->error = true;
}
}
}
if (conn->skt->error == false &&
conn->pending_writes->first == NULL) {
if (response->send_status == SEND_BODY) {
if (response->body->type == BODY_NONE) {
response->send_status = SEND_DONE;
} else {
http_body_write_result result = http_body_writeto_fd(response->body, conn->skt->fd);
if (result == HBWRITE_DONE) {
response->send_status = SEND_DONE;
} else if (result == HBWRITE_ERROR) {
conn->skt->error = true;
response->send_status = SEND_DONE;
} else if (result == HBWRITE_BLOCKED || result == HBWRITE_MORE) {
response = NULL;
}
}
}
if (response != NULL && response->send_status == SEND_DONE) {
http_response_list_remove(conn->pending_responses, response);
http_response_delete(response);
response = http_response_list_next(conn->pending_responses);
}
}
} //response != null
}//if no pending writes
CONN_UNLOCK(conn);
queue_return_item(th->pool->queue, item, item->blocked == false);

View File

@@ -73,12 +73,14 @@ void server_socket_release(int fd) {
}
socket_info* server_socket_accept(int fd, int flags) {
assert(fd>=0);
struct sockaddr_in* clientaddr = calloc(1, sizeof(struct sockaddr_in));
int clientfd=0;
struct sockaddr_in* clientaddr = calloc(1, sizeof(struct sockaddr_in));
socklen_t clientaddr_len = (socklen_t)sizeof(struct sockaddr_in);
int clientfd=0;
clientfd = accept4(fd, (struct sockaddr*)clientaddr, &clientaddr_len, flags);
if (clientfd < 0) {
free(clientaddr);
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return NULL;
}

View File

@@ -75,6 +75,7 @@ void server_stop_pools(server_state *status) {
thread_pool_stop(status->pools[i]);
queue_delete(status->pools[i]->queue);
thread_pool_stop(status->pools[i]);
thread_pool_delete(status->pools[i]);
}
memset(status->pools, 0, sizeof(status->pools));
}

View File

@@ -72,7 +72,9 @@ void server_teardown(server_state *status) {
//Close server socket
close(status->epollfd);
status->epollfd = 0;
server_socket_release(status->sfd);
status->sfd = 0;
//Free mime data
mime_destroy();
@@ -82,6 +84,5 @@ void server_teardown(server_state *status) {
//Delete config
config_server_delete(status->config);
server_status_delete(status);
status->config = NULL;
}

View File

@@ -93,7 +93,7 @@ int skt_data_buffer(socket_info *skt, data_buffer_list *list) {
BUFFER_LIST_WRONLY_LOCK(list);
LL_DELETE(list->first, elem);
BUFFER_LIST_WRONLY_UNLOCK(list);
data_buffer_free(elem);
data_buffer_delete(elem);
}
BUFFER_LIST_RD_UNLOCK(list);
} while(list->first != NULL);
@@ -128,7 +128,7 @@ char* skt_clientaddr(socket_info *skt, char* address, size_t address_len) {
inet_ntop(AF_INET, &skt->clientaddr->sin_addr, address, address_len);
if (address == NULL) {
warning(true, "error fetching client address");
free(address);
address[0] = '\0';
}
return address;
}

View File

@@ -85,7 +85,9 @@ void thread_pool_stop(thread_pool *pool) {
pool->shutdown = true;
void* ret;
if (pthread_join(pool->management_thread->pthread, &ret) != 0) {
fatal("Could not join thread pool manager");
if (errno != EINTR) {
fatal("Could not join thread pool manager");
}
}
}
void thread_pool_add_thread(thread_pool *pool, thread *th) {

View File

@@ -11,6 +11,7 @@
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <pthread.h>
#include "ut/utstring.h"
@@ -180,6 +181,24 @@ char* str_replace(char *haystack, const char *search, const char *replacement) {
return result;
}
char* basename_r(char* path) {
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
char* response = NULL;
pthread_mutex_lock(&mutex);
char* tmp = basename(path);
response = calloc(strlen(tmp)+1, sizeof(char));
ALLOC_CHECK(response);
strcpy(response, tmp);
pthread_mutex_unlock(&mutex);
return response;
}
file_map* file_map_new(const char* filename) {
int fd = open(filename, O_RDONLY);

View File

@@ -36,6 +36,8 @@ extern "C" {
char* str_trimwhitespace(char *str);
char** str_splitlines(char *str, size_t *line_count);
char* str_replace(char *str, const char *search, const char *replacement);
char* basename_r(char* path);
file_map* file_map_new(const char* filename);
void file_map_delete(file_map* map);

View File

@@ -4,5 +4,4 @@ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
Referer: https://www.google.co.uk/
Accept-Language: en-US,en;q=0.8
Connection: close