diff --git a/content/dirindex.html b/content/dirindex.html
index 7859534..cbcac73 100644
--- a/content/dirindex.html
+++ b/content/dirindex.html
@@ -1,12 +1,12 @@
- {{dirname}}
+ Index of {{dirname}}/
- {{dirname}}
+ {{dirname}}/
diff --git a/content/public_html/lorem.txt b/content/public_html/test/lorem.txt
similarity index 100%
rename from content/public_html/lorem.txt
rename to content/public_html/test/lorem.txt
diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml
index ad1194c..9acec3a 100644
--- a/nbproject/configurations.xml
+++ b/nbproject/configurations.xml
@@ -1,4 +1,22 @@
+
content/error.html
content/public_html/index.html
content/khttpd.ini
- content/public_html/lorem.txt
+ content/public_html/test/lorem.txt
Makefile
@@ -110,26 +128,8 @@
-
- -
+
-
-
-
-
@@ -256,26 +256,8 @@
-
- -
+
-
-
-
-
diff --git a/src/data-buffer.c b/src/data-buffer.c
index 2813aa4..dec3248 100644
--- a/src/data-buffer.c
+++ b/src/data-buffer.c
@@ -5,30 +5,29 @@
#include
#include
#include
+#include
+#include
#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);
diff --git a/src/data-buffer.h b/src/data-buffer.h
index e659eb9..99e32e6 100644
--- a/src/data-buffer.h
+++ b/src/data-buffer.h
@@ -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
}
diff --git a/src/http-body.c b/src/http-body.c
index 96bed82..22dee58 100644
--- a/src/http-body.c
+++ b/src/http-body.c
@@ -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->rOffsetrOffset;
- 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) {
diff --git a/src/http-server.c b/src/http-server.c
index 8e360e7..d0891a4 100644
--- a/src/http-server.c
+++ b/src/http-server.c
@@ -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, "
| %s | %s | %s |
\r\n", uri, uri,
+ char *file_basename = basename_r(uri);
+
+ utstring_printf(index, "| %s | %s | %s |
\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) {
diff --git a/src/http.c b/src/http.c
index c2efe3e..275d89c 100644
--- a/src/http.c
+++ b/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) {
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);
diff --git a/src/http.h b/src/http.h
index 8dccc17..6ce7527 100644
--- a/src/http.h
+++ b/src/http.h
@@ -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);
diff --git a/src/log.c b/src/log.c
index 5fc058b..a40cd75 100644
--- a/src/log.c
+++ b/src/log.c
@@ -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);
diff --git a/src/main.c b/src/main.c
index 5bfae3f..6aa9125 100644
--- a/src/main.c
+++ b/src/main.c
@@ -15,13 +15,22 @@
#include
#include
#include
-#include
+#include
#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);
}
\ No newline at end of file
diff --git a/src/server-connection.c b/src/server-connection.c
index 39578a3..7f80469 100644
--- a/src/server-connection.c
+++ b/src/server-connection.c
@@ -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) {
diff --git a/src/server-loop-write.c b/src/server-loop-write.c
index 8120e2a..412e234 100644
--- a/src/server-loop-write.c
+++ b/src/server-loop-write.c
@@ -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);
diff --git a/src/server-socket.c b/src/server-socket.c
index e92ac66..2028753 100644
--- a/src/server-socket.c
+++ b/src/server-socket.c
@@ -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;
}
diff --git a/src/server-state.c b/src/server-state.c
index fb387a9..5e4ebb6 100644
--- a/src/server-state.c
+++ b/src/server-state.c
@@ -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));
}
\ No newline at end of file
diff --git a/src/server.c b/src/server.c
index 1ce3034..1c3e5c1 100644
--- a/src/server.c
+++ b/src/server.c
@@ -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;
}
\ No newline at end of file
diff --git a/src/socket.c b/src/socket.c
index d8f593d..4070809 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -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;
}
\ No newline at end of file
diff --git a/src/thread-pool.c b/src/thread-pool.c
index aa9d8f7..cf11b79 100644
--- a/src/thread-pool.c
+++ b/src/thread-pool.c
@@ -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) {
diff --git a/src/util.c b/src/util.c
index 17f392c..5d6a709 100644
--- a/src/util.c
+++ b/src/util.c
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#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);
diff --git a/src/util.h b/src/util.h
index 351a1a0..e46f40a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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);
diff --git a/testreq.txt b/testreq.txt
index 7b7f32c..43f35b0 100644
--- a/testreq.txt
+++ b/testreq.txt
@@ -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