Finished basic server
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>{{dirname}}</title>
|
<title>Index of {{dirname}}/</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>{{dirname}}</h1>
|
<h1>{{dirname}}/</h1>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -1,4 +1,22 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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">
|
<configurationDescriptor version="94">
|
||||||
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
|
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
|
||||||
<logicalFolder name="HeaderFiles"
|
<logicalFolder name="HeaderFiles"
|
||||||
@@ -72,7 +90,7 @@
|
|||||||
<itemPath>content/error.html</itemPath>
|
<itemPath>content/error.html</itemPath>
|
||||||
<itemPath>content/public_html/index.html</itemPath>
|
<itemPath>content/public_html/index.html</itemPath>
|
||||||
<itemPath>content/khttpd.ini</itemPath>
|
<itemPath>content/khttpd.ini</itemPath>
|
||||||
<itemPath>content/public_html/lorem.txt</itemPath>
|
<itemPath>content/public_html/test/lorem.txt</itemPath>
|
||||||
</logicalFolder>
|
</logicalFolder>
|
||||||
<projectmakefile>Makefile</projectmakefile>
|
<projectmakefile>Makefile</projectmakefile>
|
||||||
<confs>
|
<confs>
|
||||||
@@ -110,26 +128,8 @@
|
|||||||
</item>
|
</item>
|
||||||
<item path="content/public_html/index.html" ex="false" tool="3" flavor2="0">
|
<item path="content/public_html/index.html" ex="false" tool="3" flavor2="0">
|
||||||
</item>
|
</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>
|
</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 path="lib/http_parser.c" ex="false" tool="0" flavor2="0">
|
||||||
</item>
|
</item>
|
||||||
<item path="lib/http_parser.h" ex="false" tool="3" flavor2="0">
|
<item path="lib/http_parser.h" ex="false" tool="3" flavor2="0">
|
||||||
@@ -256,26 +256,8 @@
|
|||||||
</item>
|
</item>
|
||||||
<item path="content/public_html/index.html" ex="false" tool="3" flavor2="0">
|
<item path="content/public_html/index.html" ex="false" tool="3" flavor2="0">
|
||||||
</item>
|
</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>
|
</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 path="lib/http_parser.c" ex="false" tool="0" flavor2="0">
|
||||||
</item>
|
</item>
|
||||||
<item path="lib/http_parser.h" ex="false" tool="3" flavor2="0">
|
<item path="lib/http_parser.h" ex="false" tool="3" flavor2="0">
|
||||||
|
|||||||
@@ -5,30 +5,29 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "ut/utlist.h"
|
#include "ut/utlist.h"
|
||||||
#include "data-buffer.h"
|
#include "data-buffer.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
data_buffer_list* data_buffer_list_new() {
|
data_buffer_list* data_buffer_list_new() {
|
||||||
data_buffer_list *list = calloc(1, sizeof(data_buffer_list));
|
data_buffer_list *list = calloc(1, sizeof(data_buffer_list));
|
||||||
list->first = NULL;
|
list->first = NULL;
|
||||||
list->wrlock = calloc(1, sizeof(pthread_mutex_t));
|
pthread_mutex_init(&list->rdlock, NULL);
|
||||||
pthread_mutex_init(list->wrlock, NULL);
|
pthread_mutex_init(&list->wrlock, NULL);
|
||||||
list->rdlock = calloc(1, sizeof(pthread_mutex_t));
|
|
||||||
pthread_mutex_init(list->rdlock, NULL);
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
void data_buffer_list_delete(data_buffer_list *list) {
|
void data_buffer_list_delete(data_buffer_list *list) {
|
||||||
assert(list!=NULL);
|
assert(list!=NULL);
|
||||||
pthread_mutex_destroy(list->wrlock);
|
pthread_mutex_destroy(&list->wrlock);
|
||||||
pthread_mutex_destroy(list->rdlock);
|
pthread_mutex_destroy(&list->rdlock);
|
||||||
data_buffer *elem, *tmp;
|
data_buffer *elem, *tmp;
|
||||||
LL_FOREACH_SAFE(list->first, elem, tmp) {
|
LL_FOREACH_SAFE(list->first, elem, tmp) {
|
||||||
LL_DELETE(list->first, elem);
|
LL_DELETE(list->first, elem);
|
||||||
data_buffer_free(elem);
|
data_buffer_delete(elem);
|
||||||
}
|
}
|
||||||
free(list->wrlock);
|
|
||||||
free(list->rdlock);
|
|
||||||
free(list);
|
free(list);
|
||||||
}
|
}
|
||||||
void data_buffer_list_append(data_buffer_list *list, const char* src, size_t n) {
|
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);
|
assert(src!=NULL && n>0);
|
||||||
BUFFER_LIST_WR_LOCK(list);
|
BUFFER_LIST_WR_LOCK(list);
|
||||||
|
|
||||||
int blocks = 1;
|
//Fetch last buffer in list, in case it has space left
|
||||||
data_buffer *newbuf = data_buffer_new(DATA_BUFFER_SIZE);
|
data_buffer *newbuf = NULL, *elem = NULL;
|
||||||
while(blocks * DATA_BUFFER_SIZE < n) {
|
bool first_is_new = false;
|
||||||
blocks++;
|
LL_FOREACH(list->first, elem) {
|
||||||
LL_PREPEND(newbuf, data_buffer_new(DATA_BUFFER_SIZE));
|
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;
|
size_t offset = 0;
|
||||||
data_buffer *elem;
|
elem = NULL;
|
||||||
LL_FOREACH(newbuf, elem) {
|
LL_FOREACH(newbuf, elem) {
|
||||||
size_t copy_count = n - offset;
|
size_t copy_count = n - offset;
|
||||||
if (copy_count > elem->size) {
|
if (copy_count > (elem->size - elem->wOffset)) {
|
||||||
copy_count = elem->size;
|
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;
|
offset += copy_count;
|
||||||
elem->wOffset += 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);
|
LL_CONCAT(list->first, newbuf);
|
||||||
BUFFER_LIST_WR_UNLOCK(list);
|
BUFFER_LIST_WR_UNLOCK(list);
|
||||||
}
|
}
|
||||||
void data_buffer_list_lock(data_buffer_list *list, bool rd, bool wr) {
|
void data_buffer_list_lock(data_buffer_list *list, bool rd, bool wr) {
|
||||||
assert(list != NULL);
|
assert(list != NULL);
|
||||||
if (wr == true) pthread_mutex_lock(list->wrlock);
|
if (wr == true) pthread_mutex_lock(&list->wrlock);
|
||||||
if (rd == true) pthread_mutex_lock(list->rdlock);
|
if (rd == true) pthread_mutex_lock(&list->rdlock);
|
||||||
}
|
}
|
||||||
void data_buffer_list_unlock(data_buffer_list *list, bool rd, bool wr) {
|
void data_buffer_list_unlock(data_buffer_list *list, bool rd, bool wr) {
|
||||||
assert(list != NULL);
|
assert(list != NULL);
|
||||||
if (rd == true) pthread_mutex_unlock(list->rdlock);
|
if (rd == true) pthread_mutex_unlock(&list->rdlock);
|
||||||
if (wr == true) pthread_mutex_unlock(list->wrlock);
|
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) {
|
data_buffer* data_buffer_new(size_t size) {
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
|
|
||||||
data_buffer* buf = calloc(1, sizeof(data_buffer));
|
data_buffer* buf = calloc(1, sizeof(data_buffer));
|
||||||
|
ALLOC_CHECK(buf);
|
||||||
buf->buffer = calloc(size, sizeof(char));
|
buf->buffer = calloc(size, sizeof(char));
|
||||||
|
ALLOC_CHECK(buf->buffer);
|
||||||
buf->size = size;
|
buf->size = size;
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
void data_buffer_free(data_buffer *buf) {
|
void data_buffer_delete(data_buffer *buf) {
|
||||||
assert(buf != NULL);
|
assert(buf != NULL);
|
||||||
|
|
||||||
free(buf->buffer);
|
free(buf->buffer);
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ extern "C" {
|
|||||||
|
|
||||||
typedef struct data_buffer_list {
|
typedef struct data_buffer_list {
|
||||||
struct data_buffer *first;
|
struct data_buffer *first;
|
||||||
pthread_mutex_t *wrlock, *rdlock;
|
pthread_mutex_t wrlock;
|
||||||
|
pthread_mutex_t rdlock;
|
||||||
} data_buffer_list;
|
} data_buffer_list;
|
||||||
|
|
||||||
typedef struct data_buffer {
|
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_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_lock(data_buffer_list *list, bool rd, bool wr);
|
||||||
void data_buffer_list_unlock(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);
|
data_buffer* data_buffer_new(size_t size);
|
||||||
void data_buffer_free(data_buffer *buffer);
|
void data_buffer_delete(data_buffer *buffer);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,9 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ut/utstring.h"
|
#include "ut/utstring.h"
|
||||||
#include "http-body.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(buffer!=NULL);
|
||||||
assert(buf_len>0);
|
assert(buf_len>0);
|
||||||
assert(src!=NULL);
|
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) {
|
if (*read_len > buf_len) {
|
||||||
*read_len = buf_len;
|
*read_len = buf_len;
|
||||||
}
|
}
|
||||||
|
fseek(src, offset, SEEK_SET);
|
||||||
size_t read_count = fread(buffer, sizeof(char), *read_len, src);
|
size_t read_count = fread(buffer, sizeof(char), *read_len, src);
|
||||||
if (read_count < *read_len) {
|
if (read_count < *read_len) {
|
||||||
if (ferror(src) != 0) {
|
if (ferror(src) != 0) {
|
||||||
@@ -84,6 +86,7 @@ void http_body_clear(http_body *body) {
|
|||||||
fatal("Invalid http body type");
|
fatal("Invalid http body type");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
body->rOffset = 0;
|
||||||
}
|
}
|
||||||
void http_body_delete(http_body *body) {
|
void http_body_delete(http_body *body) {
|
||||||
assert(body!=NULL);
|
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) {
|
if (str_len == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
size_t new_len = strlen(body->data.str)+str_len+1;
|
size_t new_len = str_len+1;
|
||||||
|
if (body->data.str != NULL) {
|
||||||
body->data.str = realloc(body->data.str, new_len);
|
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);
|
ALLOC_CHECK(body->data.str);
|
||||||
body->data.str[new_len-1] = '\0';
|
body->data.str[new_len-1] = '\0';
|
||||||
strncat(body->data.str, str, new_len-1);
|
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)) {
|
while(body->rOffset<http_body_len(body)) {
|
||||||
size_t write_len = http_body_len(body) - body->rOffset;
|
size_t write_len = http_body_len(body) - body->rOffset;
|
||||||
errno = EINVAL;
|
|
||||||
ssize_t written = -1;
|
ssize_t written = -1;
|
||||||
http_body_write_result result = HBWRITE_MORE;
|
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;
|
break;
|
||||||
case BODY_FILE:;
|
case BODY_FILE:;
|
||||||
size_t read_count = write_len;
|
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) {
|
if (read_res == HBWRITE_ERROR) {
|
||||||
result = read_res; break;
|
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 (written < 0 || result == HBWRITE_ERROR) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
return HBWRITE_BLOCKED;
|
return HBWRITE_BLOCKED;
|
||||||
|
} else {
|
||||||
|
perror("Write Error");
|
||||||
|
return HBWRITE_ERROR;
|
||||||
}
|
}
|
||||||
return HBWRITE_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body->rOffset += written;
|
body->rOffset += written;
|
||||||
@@ -241,7 +252,7 @@ http_body_write_result http_body_writeto_str(http_body *body, char** str) {
|
|||||||
break;
|
break;
|
||||||
case BODY_FILE:;
|
case BODY_FILE:;
|
||||||
size_t read_count = write_len;
|
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) {
|
if (read_res == HBWRITE_ERROR) {
|
||||||
result = read_res; break;
|
result = read_res; break;
|
||||||
}
|
}
|
||||||
@@ -301,12 +312,12 @@ http_body_write_result http_body_writeto_utstring(http_body *body, UT_string *ut
|
|||||||
break;
|
break;
|
||||||
case BODY_FILE:;
|
case BODY_FILE:;
|
||||||
size_t read_count = write_len;
|
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) {
|
if (read_res == HBWRITE_ERROR) {
|
||||||
result = read_res; break;
|
result = read_res; break;
|
||||||
}
|
}
|
||||||
if (read_count > 0) {
|
if (read_count > 0) {
|
||||||
utstring_bincpy(utstr, src, write_len);
|
utstring_bincpy(utstr, buffer, read_count);
|
||||||
written = read_count;
|
written = read_count;
|
||||||
}
|
}
|
||||||
if (read_res == HBWRITE_DONE) {
|
if (read_res == HBWRITE_DONE) {
|
||||||
|
|||||||
@@ -127,29 +127,22 @@ http_response* server_process_request(config_server* config, http_request *reque
|
|||||||
return response;
|
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
|
//Read file into response
|
||||||
//TODO: send file directly from the write loop
|
response = http_response_new(http_response_line_new(200));
|
||||||
char* buffer = calloc(filesize+1, sizeof(char));
|
response->resp->version = request->req->version;
|
||||||
if (fread(buffer, sizeof(char), filesize, file) != filesize) {
|
const char* mime_type = "text/html";
|
||||||
warning(true, "failed to read file into memory");
|
if (filepath != NULL) {
|
||||||
response = http_response_create_builtin(500, "Could not read file");
|
mime_type = mime_get_type(filepath, DEFAULT_CONTENT_TYPE);
|
||||||
} 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);
|
|
||||||
}
|
}
|
||||||
fclose(file);
|
http_header_list_add(response->headers, http_header_new(HEADER_CONTENT_TYPE, mime_type), false);
|
||||||
free(buffer);
|
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);
|
free(filepath);
|
||||||
|
|
||||||
bool close_connection = false;
|
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));
|
char* file_mod_time = calloc(32, sizeof(char));
|
||||||
ctime_r(&file_mtime, file_mod_time);
|
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",
|
(filesize!=NULL)?filesize:"N/A",
|
||||||
(file_mod_time!=NULL)?file_mod_time:"N/A");
|
(file_mod_time!=NULL)?file_mod_time:"N/A");
|
||||||
|
free(file_basename);
|
||||||
free(file_mod_time);
|
free(file_mod_time);
|
||||||
free(filepath);
|
free(filepath);
|
||||||
free(filesize);
|
free(filesize);
|
||||||
@@ -286,7 +282,7 @@ FILE * server_generate_directory_index(config_host *hconfig, const char* dirpath
|
|||||||
closedir(dir);
|
closedir(dir);
|
||||||
free(filestat);
|
free(filestat);
|
||||||
char *dirname = strdup(dirpath);
|
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");
|
file_map *dirindex_map = file_map_new("dirindex.html");
|
||||||
if (dirindex_map == NULL) {
|
if (dirindex_map == NULL) {
|
||||||
|
|||||||
108
src/http.c
108
src/http.c
@@ -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) {
|
void http_request_line_delete(http_request_line *req) {
|
||||||
assert(req!=NULL);
|
assert(req!=NULL);
|
||||||
|
if (req->method == METHOD_OTHER) {
|
||||||
free(req->method_other);
|
free(req->method_other);
|
||||||
|
}
|
||||||
free(req->uri);
|
free(req->uri);
|
||||||
free(req);
|
free(req);
|
||||||
}
|
}
|
||||||
@@ -311,6 +312,7 @@ http_response* http_response_new(http_response_line *resp) {
|
|||||||
response->headers = http_header_list_new();
|
response->headers = http_header_list_new();
|
||||||
response->body_chunked = false;
|
response->body_chunked = false;
|
||||||
response->body = http_body_new(BODY_NONE, NULL);
|
response->body = http_body_new(BODY_NONE, NULL);
|
||||||
|
response->send_status = SEND_RESPONSE_LINE;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
void http_response_append_body(http_response *resp, const char* body) {
|
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!=NULL);
|
||||||
assert(resp->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));
|
UT_string *output = calloc(1, sizeof(UT_string));
|
||||||
ALLOC_CHECK(output);
|
ALLOC_CHECK(output);
|
||||||
utstring_init(output);
|
utstring_init(output);
|
||||||
|
|
||||||
if (resp->resp->version == HTTP10) {
|
if (resp->send_status == SEND_RESPONSE_LINE) {
|
||||||
utstring_printf(output, "HTTP/1.0 ");
|
if (resp->resp->version == HTTP10) {
|
||||||
} else if (resp->resp->version == HTTP11) {
|
utstring_printf(output, "HTTP/1.0 ");
|
||||||
utstring_printf(output, "HTTP/1.1 ");
|
} 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);
|
|
||||||
}
|
}
|
||||||
|
//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
|
resp->send_status = SEND_HEADERS;
|
||||||
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
|
if (resp->send_status == SEND_HEADERS) {
|
||||||
http_header *elem;
|
if (resp->resp->code != 100) { //No additional headers for Continue messages
|
||||||
HTTP_HEADER_FOREACH(resp->headers, elem) {
|
if (resp->body_chunked == false) {
|
||||||
utstring_printf(output, "%s: %s\r\n", elem->name, elem->content);
|
//Add content length header
|
||||||
}
|
uint32_t messageLength = http_body_len(resp->body);
|
||||||
utstring_printf(output, "\r\n");
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
//Write the request (if string)
|
//Add content type if not defined
|
||||||
if (resp->body->type == BODY_STRING) {
|
http_header* contenttype = http_header_list_get(resp->headers, HEADER_CONTENT_TYPE);
|
||||||
if (resp->body_chunked == false) {
|
if (contenttype == NULL) {
|
||||||
http_body_writeto_utstring(resp->body, output);
|
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);
|
||||||
}
|
}
|
||||||
if (resp->body_chunked == true) {
|
//write headers
|
||||||
http_chunks_write(resp->body->data.str, output);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* outputStr = utstring_body(output);
|
char* outputStr = utstring_body(output);
|
||||||
free(output);
|
free(output);
|
||||||
return outputStr;
|
return outputStr;
|
||||||
@@ -482,10 +486,16 @@ void http_response_list_append(http_response_list *list, http_response* response
|
|||||||
|
|
||||||
LL_APPEND(list->first, 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) {
|
http_response* http_response_list_next(http_response_list *list) {
|
||||||
assert(list != NULL);
|
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) {
|
http_response* http_response_list_next2(http_response_list *list, bool remove) {
|
||||||
assert(list != NULL);
|
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) {
|
void http_response_list_delete(http_response_list *list) {
|
||||||
assert(list != NULL);
|
assert(list != NULL);
|
||||||
|
|
||||||
http_response *elem;
|
http_response *elem, *tmp;
|
||||||
HTTP_RESPONSE_LIST_FOREACH(list, elem) {
|
HTTP_RESPONSE_LIST_FOREACH_SAFE(list, elem, tmp) {
|
||||||
http_response_delete(elem);
|
http_response_delete(elem);
|
||||||
}
|
}
|
||||||
free(list);
|
free(list);
|
||||||
|
|||||||
@@ -87,15 +87,21 @@ extern "C" {
|
|||||||
struct http_request *next;
|
struct http_request *next;
|
||||||
} http_request;
|
} 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 {
|
typedef struct http_response {
|
||||||
http_response_line *resp;
|
http_response_line *resp;
|
||||||
http_header_list *headers;
|
http_header_list *headers;
|
||||||
bool body_chunked;
|
bool body_chunked;
|
||||||
http_body *body;
|
http_body *body;
|
||||||
|
http_response_send_status send_status;
|
||||||
struct http_response *next;
|
struct http_response *next;
|
||||||
} http_response;
|
} http_response;
|
||||||
|
|
||||||
#define HTTP_RESPONSE_LIST_FOREACH(list, elem) LL_FOREACH(list->first, elem)
|
#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 {
|
typedef struct http_response_list {
|
||||||
http_response *first;
|
http_response *first;
|
||||||
@@ -138,6 +144,7 @@ extern "C" {
|
|||||||
|
|
||||||
http_response_list* http_response_list_new();
|
http_response_list* http_response_list_new();
|
||||||
void http_response_list_append(http_response_list *list, http_response* response);
|
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_next(http_response_list *list);
|
||||||
http_response* http_response_list_next2(http_response_list *list, bool remove);
|
http_response* http_response_list_next2(http_response_list *list, bool remove);
|
||||||
void http_response_list_delete(http_response_list *list);
|
void http_response_list_delete(http_response_list *list);
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ void*log_loop(void* arg) {
|
|||||||
void** buf = calloc(1, sizeof(void*));
|
void** buf = calloc(1, sizeof(void*));
|
||||||
char* timestr = calloc(32, sizeof(char));
|
char* timestr = calloc(32, sizeof(char));
|
||||||
time_t ctime;
|
time_t ctime;
|
||||||
struct tm *tinfo = calloc(1,sizeof(struct tm));
|
struct tm tinfo = {0};
|
||||||
while(true) {
|
while(true) {
|
||||||
//Read next message pointer from pipe
|
//Read next message pointer from pipe
|
||||||
if (read(l->pRead, buf, sizeof(void*)) <= 0) {
|
if (read(l->pRead, buf, sizeof(void*)) <= 0) {
|
||||||
@@ -95,8 +95,8 @@ void*log_loop(void* arg) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ctime = time(NULL);
|
ctime = time(NULL);
|
||||||
localtime_r(&ctime, tinfo);
|
localtime_r(&ctime, &tinfo);
|
||||||
if (strftime(timestr, 32, "%F %R", tinfo) == 0) {
|
if (strftime(timestr, 32, "%F %R", &tinfo) == 0) {
|
||||||
strcpy(timestr, "N/A");
|
strcpy(timestr, "N/A");
|
||||||
}
|
}
|
||||||
log_msg* msg = (log_msg*)(*buf);
|
log_msg* msg = (log_msg*)(*buf);
|
||||||
|
|||||||
25
src/main.c
25
src/main.c
@@ -15,13 +15,22 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <bits/stdio2.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "log.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "server-state.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) {
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
//Load the config
|
//Load the config
|
||||||
@@ -32,8 +41,22 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
server_state *state = server_status_new(config);
|
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
|
//Run the server
|
||||||
server_start(state);
|
server_start(state);
|
||||||
|
|
||||||
|
current_state = NULL;
|
||||||
|
server_status_delete(state);
|
||||||
|
|
||||||
return (EXIT_SUCCESS);
|
return (EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
@@ -48,6 +48,7 @@ server_parse_status* server_parse_status_new() {
|
|||||||
state->parser_header_state = HSTATE_NONE;
|
state->parser_header_state = HSTATE_NONE;
|
||||||
state->parser = calloc(1, sizeof(http_parser));
|
state->parser = calloc(1, sizeof(http_parser));
|
||||||
http_parser_init(state->parser, HTTP_REQUEST);
|
http_parser_init(state->parser, HTTP_REQUEST);
|
||||||
|
state->parser->data = (void*)state;
|
||||||
|
|
||||||
return 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) {
|
void server_parser_status_reset(server_parse_status* state) {
|
||||||
assert(state!=NULL);
|
assert(state!=NULL);
|
||||||
|
state->current_request = NULL;
|
||||||
state->request_complete = false;
|
state->request_complete = false;
|
||||||
state->parser_header_state = HSTATE_NONE;
|
state->parser_header_state = HSTATE_NONE;
|
||||||
if (state->parser_current_header != NULL) {
|
if (state->parser_current_header != NULL) {
|
||||||
|
|||||||
@@ -28,7 +28,66 @@ void* server_loop_write(void* arg) {
|
|||||||
server_connection *conn = (server_connection*)item->data;
|
server_connection *conn = (server_connection*)item->data;
|
||||||
CONN_LOCK(conn);
|
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);
|
CONN_UNLOCK(conn);
|
||||||
queue_return_item(th->pool->queue, item, item->blocked == false);
|
queue_return_item(th->pool->queue, item, item->blocked == false);
|
||||||
|
|||||||
@@ -73,12 +73,14 @@ void server_socket_release(int fd) {
|
|||||||
}
|
}
|
||||||
socket_info* server_socket_accept(int fd, int flags) {
|
socket_info* server_socket_accept(int fd, int flags) {
|
||||||
assert(fd>=0);
|
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);
|
socklen_t clientaddr_len = (socklen_t)sizeof(struct sockaddr_in);
|
||||||
|
int clientfd=0;
|
||||||
|
|
||||||
clientfd = accept4(fd, (struct sockaddr*)clientaddr, &clientaddr_len, flags);
|
clientfd = accept4(fd, (struct sockaddr*)clientaddr, &clientaddr_len, flags);
|
||||||
if (clientfd < 0) {
|
if (clientfd < 0) {
|
||||||
|
free(clientaddr);
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ void server_stop_pools(server_state *status) {
|
|||||||
thread_pool_stop(status->pools[i]);
|
thread_pool_stop(status->pools[i]);
|
||||||
queue_delete(status->pools[i]->queue);
|
queue_delete(status->pools[i]->queue);
|
||||||
thread_pool_stop(status->pools[i]);
|
thread_pool_stop(status->pools[i]);
|
||||||
|
thread_pool_delete(status->pools[i]);
|
||||||
}
|
}
|
||||||
memset(status->pools, 0, sizeof(status->pools));
|
memset(status->pools, 0, sizeof(status->pools));
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,9 @@ void server_teardown(server_state *status) {
|
|||||||
|
|
||||||
//Close server socket
|
//Close server socket
|
||||||
close(status->epollfd);
|
close(status->epollfd);
|
||||||
|
status->epollfd = 0;
|
||||||
server_socket_release(status->sfd);
|
server_socket_release(status->sfd);
|
||||||
|
status->sfd = 0;
|
||||||
|
|
||||||
//Free mime data
|
//Free mime data
|
||||||
mime_destroy();
|
mime_destroy();
|
||||||
@@ -82,6 +84,5 @@ void server_teardown(server_state *status) {
|
|||||||
|
|
||||||
//Delete config
|
//Delete config
|
||||||
config_server_delete(status->config);
|
config_server_delete(status->config);
|
||||||
|
status->config = NULL;
|
||||||
server_status_delete(status);
|
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ int skt_data_buffer(socket_info *skt, data_buffer_list *list) {
|
|||||||
BUFFER_LIST_WRONLY_LOCK(list);
|
BUFFER_LIST_WRONLY_LOCK(list);
|
||||||
LL_DELETE(list->first, elem);
|
LL_DELETE(list->first, elem);
|
||||||
BUFFER_LIST_WRONLY_UNLOCK(list);
|
BUFFER_LIST_WRONLY_UNLOCK(list);
|
||||||
data_buffer_free(elem);
|
data_buffer_delete(elem);
|
||||||
}
|
}
|
||||||
BUFFER_LIST_RD_UNLOCK(list);
|
BUFFER_LIST_RD_UNLOCK(list);
|
||||||
} while(list->first != NULL);
|
} 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);
|
inet_ntop(AF_INET, &skt->clientaddr->sin_addr, address, address_len);
|
||||||
if (address == NULL) {
|
if (address == NULL) {
|
||||||
warning(true, "error fetching client address");
|
warning(true, "error fetching client address");
|
||||||
free(address);
|
address[0] = '\0';
|
||||||
}
|
}
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,9 @@ void thread_pool_stop(thread_pool *pool) {
|
|||||||
pool->shutdown = true;
|
pool->shutdown = true;
|
||||||
void* ret;
|
void* ret;
|
||||||
if (pthread_join(pool->management_thread->pthread, &ret) != 0) {
|
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) {
|
void thread_pool_add_thread(thread_pool *pool, thread *th) {
|
||||||
|
|||||||
19
src/util.c
19
src/util.c
@@ -11,6 +11,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
#include "ut/utstring.h"
|
#include "ut/utstring.h"
|
||||||
|
|
||||||
@@ -180,6 +181,24 @@ char* str_replace(char *haystack, const char *search, const char *replacement) {
|
|||||||
return result;
|
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) {
|
file_map* file_map_new(const char* filename) {
|
||||||
|
|
||||||
int fd = open(filename, O_RDONLY);
|
int fd = open(filename, O_RDONLY);
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ extern "C" {
|
|||||||
char** str_splitlines(char *str, size_t *line_count);
|
char** str_splitlines(char *str, size_t *line_count);
|
||||||
char* str_replace(char *str, const char *search, const char *replacement);
|
char* str_replace(char *str, const char *search, const char *replacement);
|
||||||
|
|
||||||
|
char* basename_r(char* path);
|
||||||
|
|
||||||
file_map* file_map_new(const char* filename);
|
file_map* file_map_new(const char* filename);
|
||||||
void file_map_delete(file_map* map);
|
void file_map_delete(file_map* map);
|
||||||
char* file_map_copyto_string(file_map* map, char* str, size_t str_len);
|
char* file_map_copyto_string(file_map* map, char* str, size_t str_len);
|
||||||
|
|||||||
@@ -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
|
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/
|
Referer: https://www.google.co.uk/
|
||||||
Accept-Language: en-US,en;q=0.8
|
Accept-Language: en-US,en;q=0.8
|
||||||
Connection: close
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user