Working on http thread loops
This commit is contained in:
@@ -112,7 +112,7 @@
|
||||
</item>
|
||||
<item path="content/public_html/lorem.txt" ex="false" tool="3" flavor2="0">
|
||||
</item>
|
||||
<folder path="TestFiles/f1">
|
||||
<!--<folder path="TestFiles/f1">
|
||||
<cTool>
|
||||
<incDir>
|
||||
<pElem>.</pElem>
|
||||
@@ -129,7 +129,7 @@
|
||||
<linkerOptionItem>-lcunit</linkerOptionItem>
|
||||
</linkerLibItems>
|
||||
</linkerTool>
|
||||
</folder>
|
||||
</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">
|
||||
@@ -258,7 +258,7 @@
|
||||
</item>
|
||||
<item path="content/public_html/lorem.txt" ex="false" tool="3" flavor2="0">
|
||||
</item>
|
||||
<folder path="TestFiles/f1">
|
||||
<!--<folder path="TestFiles/f1">
|
||||
<cTool>
|
||||
<incDir>
|
||||
<pElem>.</pElem>
|
||||
@@ -275,7 +275,7 @@
|
||||
<linkerOptionItem>-lcunit</linkerOptionItem>
|
||||
</linkerLibItems>
|
||||
</linkerTool>
|
||||
</folder>
|
||||
</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">
|
||||
|
||||
201
src/http-body.c
201
src/http-body.c
@@ -5,11 +5,34 @@
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <bits/stdio2.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "ut/utstring.h"
|
||||
#include "http-body.h"
|
||||
|
||||
http_body_write_result _http_body_file_fill_buffer(char *buffer, size_t buf_len, size_t *read_len, FILE *src) {
|
||||
assert(buffer!=NULL);
|
||||
assert(buf_len>0);
|
||||
assert(src!=NULL);
|
||||
assert(read_len!=NULL);
|
||||
|
||||
if (*read_len > buf_len) {
|
||||
*read_len = buf_len;
|
||||
}
|
||||
size_t read_count = fread(buffer, sizeof(char), *read_len, src);
|
||||
if (read_count < *read_len) {
|
||||
if (ferror(src) != 0) {
|
||||
return HBWRITE_ERROR;
|
||||
}
|
||||
}
|
||||
*read_len = read_count;
|
||||
if (feof(src) != 0) {
|
||||
return HBWRITE_DONE;
|
||||
}
|
||||
return HBWRITE_MORE;
|
||||
}
|
||||
|
||||
http_body* http_body_new(http_body_type type, void* dataptr) {
|
||||
http_body *body = calloc(1, sizeof(http_body));
|
||||
ALLOC_CHECK(body);
|
||||
@@ -36,9 +59,8 @@ http_body* http_body_new(http_body_type type, void* dataptr) {
|
||||
|
||||
return body;
|
||||
}
|
||||
void http_body_delete(http_body *body) {
|
||||
void http_body_clear(http_body *body) {
|
||||
assert(body!=NULL);
|
||||
|
||||
switch(body->type) {
|
||||
case BODY_NONE:
|
||||
break;
|
||||
@@ -62,6 +84,11 @@ void http_body_delete(http_body *body) {
|
||||
fatal("Invalid http body type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
void http_body_delete(http_body *body) {
|
||||
assert(body!=NULL);
|
||||
|
||||
http_body_clear(body);
|
||||
free(body);
|
||||
}
|
||||
|
||||
@@ -111,6 +138,13 @@ size_t http_body_len(http_body *body) {
|
||||
}
|
||||
return len;
|
||||
}
|
||||
void http_body_set_type(http_body *body, http_body_type newtype) {
|
||||
assert(body!=NULL);
|
||||
http_body_clear(body);
|
||||
body->type = newtype;
|
||||
}
|
||||
|
||||
//TODO: replace these with single function w/callbacks
|
||||
|
||||
http_body_write_result http_body_writeto_fd(http_body *body, int fd) {
|
||||
assert(body!=NULL);
|
||||
@@ -118,58 +152,52 @@ http_body_write_result http_body_writeto_fd(http_body *body, int fd) {
|
||||
assert(body->data.ptr!=NULL);
|
||||
}
|
||||
|
||||
char* buffer=NULL;
|
||||
const size_t buffer_len = 16*1024;
|
||||
char* buffer= NULL;
|
||||
if (body->type == BODY_FILE) {
|
||||
buffer = calloc(buffer_len, sizeof(char));
|
||||
ALLOC_CHECK(buffer);
|
||||
}
|
||||
|
||||
while(body->rOffset<http_body_len(body)) {
|
||||
size_t write_len = http_body_len(body) - body->rOffset;
|
||||
errno = EINVAL;
|
||||
ssize_t result = -1;
|
||||
ssize_t written = -1;
|
||||
http_body_write_result result = HBWRITE_MORE;
|
||||
|
||||
switch(body->type) {
|
||||
case BODY_STRING:
|
||||
result = write(fd, body->data.str+body->rOffset, write_len);
|
||||
written = write(fd, body->data.str+body->rOffset, write_len);
|
||||
break;
|
||||
case BODY_FILEMAP:
|
||||
result = write(fd, body->data.filemap->map+body->rOffset, write_len);
|
||||
written = write(fd, body->data.filemap->map+body->rOffset, write_len);
|
||||
break;
|
||||
case BODY_FILE:
|
||||
if (buffer==NULL) {
|
||||
buffer = calloc(buffer_len, sizeof(char));
|
||||
ALLOC_CHECK(buffer);
|
||||
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);
|
||||
if (read_res == HBWRITE_ERROR) {
|
||||
result = read_res; break;
|
||||
}
|
||||
errno=0;
|
||||
if (write_len > buffer_len) {
|
||||
write_len = buffer_len;
|
||||
}
|
||||
size_t read_count = fread(buffer, sizeof(char), write_len, body->data.file);
|
||||
if (read_count < write_len) {
|
||||
if (ferror(body->data.file) != 0) {
|
||||
free(buffer);
|
||||
return HBWRITE_ERROR;
|
||||
}
|
||||
}
|
||||
result = 0;
|
||||
if (read_count > 0) {
|
||||
result = write(fd, buffer, read_count);
|
||||
written = write(fd, buffer, read_count);
|
||||
}
|
||||
if (feof(body->data.file) != 0) {
|
||||
body->rOffset += result;
|
||||
free(buffer);
|
||||
return HBWRITE_DONE;
|
||||
if (read_res == HBWRITE_DONE) {
|
||||
result = read_res; break;
|
||||
}
|
||||
break;
|
||||
}//switch body->type
|
||||
|
||||
if (result < 0) {
|
||||
if (written < 0 || result == HBWRITE_ERROR) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return HBWRITE_BLOCKED;
|
||||
}
|
||||
warning(true, "Error writing http body");
|
||||
return HBWRITE_ERROR;
|
||||
}
|
||||
|
||||
body->rOffset += result;
|
||||
body->rOffset += written;
|
||||
if (result == HBWRITE_DONE) {
|
||||
break;
|
||||
}
|
||||
}//While data remaining
|
||||
|
||||
if (buffer != NULL) {
|
||||
@@ -178,7 +206,7 @@ http_body_write_result http_body_writeto_fd(http_body *body, int fd) {
|
||||
errno = 0;
|
||||
return HBWRITE_DONE;
|
||||
}
|
||||
http_body_write_result http_body_writeto_str(http_body *body, const char** str) {
|
||||
http_body_write_result http_body_writeto_str(http_body *body, char** str) {
|
||||
assert(body!=NULL);
|
||||
if (body->type!=BODY_NONE) {
|
||||
assert(body->data.ptr!=NULL);
|
||||
@@ -187,6 +215,10 @@ http_body_write_result http_body_writeto_str(http_body *body, const char** str)
|
||||
|
||||
char* buffer=NULL;
|
||||
const size_t buffer_len = 16*1024;
|
||||
if (body->type == BODY_FILE) {
|
||||
buffer = calloc(buffer_len, sizeof(char));
|
||||
ALLOC_CHECK(buffer);
|
||||
}
|
||||
|
||||
while(body->rOffset<http_body_len(body)) {
|
||||
size_t write_len = http_body_len(body) - body->rOffset;
|
||||
@@ -197,53 +229,106 @@ http_body_write_result http_body_writeto_str(http_body *body, const char** str)
|
||||
}
|
||||
ALLOC_CHECK(*str);
|
||||
|
||||
errno = EINVAL;
|
||||
ssize_t result = -1;
|
||||
ssize_t written = -1;
|
||||
http_body_write_result result = HBWRITE_MORE;
|
||||
|
||||
switch(body->type) {
|
||||
case BODY_STRING:
|
||||
case BODY_FILEMAP:
|
||||
case BODY_FILEMAP:;
|
||||
char* src = (body->type==BODY_STRING) ? body->data.str : body->data.filemap->map;
|
||||
strncat(*str, src+body->rOffset, write_len);
|
||||
result = write_len;
|
||||
written = write_len;
|
||||
break;
|
||||
case BODY_FILE:
|
||||
if (buffer==NULL) {
|
||||
buffer = calloc(buffer_len, sizeof(char));
|
||||
ALLOC_CHECK(buffer);
|
||||
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);
|
||||
if (read_res == HBWRITE_ERROR) {
|
||||
result = read_res; break;
|
||||
}
|
||||
if (write_len > buffer_len) {
|
||||
write_len = buffer_len;
|
||||
}
|
||||
size_t read_count = fread(buffer, sizeof(char), write_len, body->data.file);
|
||||
if (read_count < write_len) {
|
||||
if (ferror(body->data.file) != 0) {
|
||||
free(buffer);
|
||||
return HBWRITE_ERROR;
|
||||
}
|
||||
}
|
||||
result = 0;
|
||||
if (read_count > 0) {
|
||||
strncat(*str, buffer, read_count);
|
||||
result = read_count;
|
||||
written = read_count;
|
||||
}
|
||||
if (feof(body->data.file) != 0) {
|
||||
body->rOffset += result;
|
||||
free(buffer);
|
||||
return HBWRITE_DONE;
|
||||
if (read_res == HBWRITE_DONE) {
|
||||
result = read_res; break;
|
||||
}
|
||||
break;
|
||||
}//Switch body->type
|
||||
|
||||
body->rOffset += result;
|
||||
body->rOffset += written;
|
||||
if (result == HBWRITE_ERROR) {
|
||||
if (buffer != NULL) {
|
||||
free(buffer);
|
||||
}
|
||||
return HBWRITE_ERROR;
|
||||
}
|
||||
if (result == HBWRITE_DONE) {
|
||||
break;
|
||||
}
|
||||
}//while data remaining
|
||||
|
||||
if (buffer != NULL) {
|
||||
free(buffer);
|
||||
}
|
||||
errno = 0;
|
||||
return HBWRITE_DONE;
|
||||
}
|
||||
http_body_write_result http_body_writeto_utstring(http_body *body, UT_string *utstr) {
|
||||
|
||||
assert(body!=NULL);
|
||||
if (body->type!=BODY_NONE) {
|
||||
assert(body->data.ptr!=NULL);
|
||||
}
|
||||
assert(utstr!=NULL);
|
||||
|
||||
char* buffer=NULL;
|
||||
const size_t buffer_len = 16*1024;
|
||||
if (body->type == BODY_FILE) {
|
||||
buffer = calloc(buffer_len, sizeof(char));
|
||||
ALLOC_CHECK(buffer);
|
||||
}
|
||||
|
||||
while(body->rOffset<http_body_len(body)) {
|
||||
size_t write_len = http_body_len(body) - body->rOffset;
|
||||
|
||||
ssize_t written = -1;
|
||||
http_body_write_result result = HBWRITE_MORE;
|
||||
|
||||
switch(body->type) {
|
||||
case BODY_STRING:
|
||||
case BODY_FILEMAP:;
|
||||
char* src = (body->type==BODY_STRING) ? body->data.str : body->data.filemap->map;
|
||||
utstring_bincpy(utstr, src, write_len);
|
||||
written = write_len;
|
||||
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);
|
||||
if (read_res == HBWRITE_ERROR) {
|
||||
result = read_res; break;
|
||||
}
|
||||
if (read_count > 0) {
|
||||
utstring_bincpy(utstr, src, write_len);
|
||||
written = read_count;
|
||||
}
|
||||
if (read_res == HBWRITE_DONE) {
|
||||
result = read_res; break;
|
||||
}
|
||||
break;
|
||||
}//Switch body->type
|
||||
|
||||
body->rOffset += written;
|
||||
if (result == HBWRITE_ERROR) {
|
||||
if (buffer != NULL) {
|
||||
free(buffer);
|
||||
}
|
||||
return HBWRITE_ERROR;
|
||||
}
|
||||
if (result == HBWRITE_DONE) {
|
||||
break;
|
||||
}
|
||||
}//while data remaining
|
||||
|
||||
if (buffer != NULL) {
|
||||
free(buffer);
|
||||
}
|
||||
return HBWRITE_DONE;
|
||||
}
|
||||
|
||||
@@ -38,13 +38,15 @@ extern "C" {
|
||||
} http_body;
|
||||
|
||||
http_body* http_body_new(http_body_type type, void* dataptr);
|
||||
void http_body_clear(http_body *body);
|
||||
void http_body_delete(http_body *body);
|
||||
|
||||
size_t http_body_append_str(http_body *body, const char** str_ptr);
|
||||
size_t http_body_append_str(http_body *body, const char* str, ssize_t str_len);
|
||||
size_t http_body_len(http_body *body);
|
||||
void http_body_set_type(http_body *body, http_body_type newtype);
|
||||
|
||||
http_body_write_result http_body_writeto_fd(http_body *body, int fd);
|
||||
http_body_write_result http_body_writeto_str(http_body *body, const char* str, size_t str_len);
|
||||
http_body_write_result http_body_writeto_str(http_body *body, char** str);
|
||||
http_body_write_result http_body_writeto_utstring(http_body *body, UT_string *utstr);
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ http_response* server_process_request(config_server* config, http_request *reque
|
||||
}
|
||||
if (host_config == NULL) {
|
||||
//host not found and default not found
|
||||
response = http_response_create_builtin(500, "Server configuration error (host/default not found)");
|
||||
response = http_response_create_builtin(500, "Server configuration error. Host not provided and default not found.");
|
||||
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||
return response;
|
||||
}
|
||||
@@ -152,9 +152,19 @@ http_response* server_process_request(config_server* config, http_request *reque
|
||||
free(buffer);
|
||||
free(filepath);
|
||||
|
||||
bool close_connection = false;
|
||||
//Check to see if client requested the connection be closed
|
||||
http_header* request_connection = http_header_list_get(request->headers, HEADER_CONNECTION);
|
||||
if (request_connection != NULL && strcasecmp(request_connection->content, "close") == 0) {
|
||||
close_connection = true;
|
||||
}
|
||||
//Close a http/1.0 unless the client requested keep-alive
|
||||
if (close_connection == false && request->req->version == HTTP10 && request_connection != NULL) {
|
||||
if (strcasecmp(request_connection->content, "Keep-Alive") != 0) {
|
||||
close_connection = true;
|
||||
}
|
||||
}
|
||||
if (close_connection == true) {
|
||||
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||
}
|
||||
|
||||
@@ -177,15 +187,14 @@ server_file_result* server_determine_file(config_host* hconfig, const char* requ
|
||||
return result;
|
||||
}
|
||||
|
||||
struct stat *pathstat = calloc(1, sizeof(struct stat));
|
||||
if (stat(filepath_actual, pathstat) < 0) {
|
||||
struct stat pathstat;
|
||||
if (stat(filepath_actual, &pathstat) < 0) {
|
||||
server_file_result_seterror(result, 404, "File not found");
|
||||
free(filepath_actual);
|
||||
free(pathstat);
|
||||
return result;
|
||||
}
|
||||
//If directory
|
||||
if (S_ISDIR(pathstat->st_mode) != 0) {
|
||||
if (S_ISDIR(pathstat.st_mode) != 0) {
|
||||
char* dir_index = server_find_directory_index(hconfig, filepath_actual);
|
||||
if (hconfig->index_files_count > 0 && dir_index != NULL) {
|
||||
//Use the directory index
|
||||
@@ -197,10 +206,9 @@ server_file_result* server_determine_file(config_host* hconfig, const char* requ
|
||||
} else {
|
||||
server_file_result_seterror(result, 403, "No index file was found and directory indexes are disabled");
|
||||
}
|
||||
} else if (S_ISREG(pathstat->st_mode) != 0) {
|
||||
} else if (S_ISREG(pathstat.st_mode) != 0) {
|
||||
result->path = strdup(filepath_actual);
|
||||
}
|
||||
free(pathstat);
|
||||
free(filepath_actual);
|
||||
return result;
|
||||
}
|
||||
|
||||
95
src/http.c
95
src/http.c
@@ -69,6 +69,7 @@ http_request_line *http_request_line_new(http_request_method method, const char*
|
||||
} else {
|
||||
req->method_other = NULL;
|
||||
}
|
||||
req->version = HTTPXX;
|
||||
return req;
|
||||
}
|
||||
void http_request_line_delete(http_request_line *req) {
|
||||
@@ -252,20 +253,15 @@ http_request *http_request_new() {
|
||||
ALLOC_CHECK(req);
|
||||
req->headers = http_header_list_new();
|
||||
req->parsestatus = PARSE_REQUESTLINE;
|
||||
req->body = http_body_new(BODY_NONE, NULL);
|
||||
return req;
|
||||
}
|
||||
void http_request_append_body(http_request *req, const char* body) {
|
||||
assert(req!=NULL);
|
||||
assert(body!=NULL);
|
||||
assert(req->body->type == BODY_STRING);
|
||||
|
||||
uint32_t bodylen = 0;
|
||||
if (req->body != NULL) {
|
||||
bodylen = strlen(req->body);
|
||||
}
|
||||
bodylen += strlen(body) + 1;
|
||||
req->body = realloc(req->body, bodylen * sizeof(char));
|
||||
ALLOC_CHECK(req->body);
|
||||
strcat(req->body, body);
|
||||
http_body_append_str(req->body, body, strlen(body));
|
||||
}
|
||||
char* http_request_write(http_request *req) {
|
||||
assert(req!=NULL);
|
||||
@@ -289,15 +285,8 @@ char* http_request_write(http_request *req) {
|
||||
|
||||
utstring_printf(output, "\r\n");
|
||||
|
||||
if (req->body_type == BODY_STRING) {
|
||||
if (req->body.str != NULL) {
|
||||
utstring_printf(output, "%s\r\n", req->body);
|
||||
}
|
||||
} else if (req->body_type == BODY_FILE) {
|
||||
if (req->body.file != NULL) {
|
||||
utstring_printf(output, "%s\r\n", req->body.file->map);
|
||||
}
|
||||
}
|
||||
http_body_writeto_utstring(req->body, output);
|
||||
|
||||
char* result = utstring_body(output);
|
||||
free(output);
|
||||
return result;
|
||||
@@ -309,11 +298,7 @@ void http_request_delete(http_request *req) {
|
||||
http_request_line_delete(req->req);
|
||||
}
|
||||
http_header_list_delete(req->headers);
|
||||
if (req->body_type == BODY_STRING) {
|
||||
free(req->body.str);
|
||||
} else if (req->body_type == BODY_FILE && req->body.file != NULL) {
|
||||
file_map_delete(req->body.file);
|
||||
}
|
||||
http_body_delete(req->body);
|
||||
free(req);
|
||||
}
|
||||
|
||||
@@ -321,42 +306,26 @@ http_response* http_response_new(http_response_line *resp) {
|
||||
assert(resp!=NULL);
|
||||
|
||||
http_response *response = calloc(1, sizeof(http_response));
|
||||
ALLOC_CHECK(response);
|
||||
ALLOC_CHECK(resp);
|
||||
response->resp = resp;
|
||||
response->headers = http_header_list_new();
|
||||
response->body_chunked = false;
|
||||
response->body_type = BODY_NONE;
|
||||
response->body = http_body_new(BODY_NONE, NULL);
|
||||
return response;
|
||||
}
|
||||
void http_response_append_body(http_response *resp, const char* body) {
|
||||
assert(resp!=NULL);
|
||||
assert(body!=NULL);
|
||||
assert(resp->body_type == BODY_STRING);
|
||||
assert(resp->body->type == BODY_STRING);
|
||||
|
||||
size_t bodylen = 0;
|
||||
if (resp->body.str != NULL) {
|
||||
bodylen = strlen(resp->body.str);
|
||||
}
|
||||
bodylen += strlen(body) + 1;
|
||||
if (resp->body.str == NULL) {
|
||||
resp->body.str = calloc(bodylen, sizeof(char));
|
||||
ALLOC_CHECK(resp->body.str);
|
||||
} else {
|
||||
resp->body.str = realloc(resp->body.str, bodylen * sizeof(char));
|
||||
ALLOC_CHECK(resp->body.str);
|
||||
}
|
||||
strcat(resp->body.str, body);
|
||||
http_body_append_str(resp->body, body, strlen(body));
|
||||
}
|
||||
void http_response_delete(http_response *resp) {
|
||||
assert(resp!=NULL);
|
||||
|
||||
http_response_line_delete(resp->resp);
|
||||
http_header_list_delete(resp->headers);
|
||||
if (resp->body_type == BODY_STRING) {
|
||||
free(resp->body.str);
|
||||
} else if (resp->body_type == BODY_FILE && resp->body.file != NULL) {
|
||||
file_map_delete(resp->body.file);
|
||||
}
|
||||
http_body_delete(resp->body);
|
||||
free(resp);
|
||||
}
|
||||
char* http_response_write(http_response *resp) {
|
||||
@@ -378,12 +347,7 @@ char* http_response_write(http_response *resp) {
|
||||
if (resp->resp->code != 100) { //No additional headers for Continue messages
|
||||
if (resp->body_chunked == false) {
|
||||
//Add content length header
|
||||
uint32_t messageLength = 0;
|
||||
if (resp->body_type == BODY_STRING) {
|
||||
messageLength = strlen(resp->body.str);
|
||||
} else if (resp->body_type == BODY_FILE) {
|
||||
messageLength = resp->body.file->size;
|
||||
}
|
||||
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);
|
||||
@@ -416,21 +380,14 @@ char* http_response_write(http_response *resp) {
|
||||
utstring_printf(output, "\r\n");
|
||||
|
||||
//Write the request (if string)
|
||||
if (resp->body_type == BODY_STRING) {
|
||||
if (resp->body_chunked == false && resp->body.str != NULL) {
|
||||
utstring_printf(output, "%s\r\n", resp->body.str);
|
||||
}
|
||||
if (resp->body_chunked == true && resp->body.str != NULL) {
|
||||
http_chunks_write(resp->body.str, output);
|
||||
}
|
||||
} else if (resp->body_type == BODY_FILE) {
|
||||
if (resp->body->type == BODY_STRING) {
|
||||
if (resp->body_chunked == false) {
|
||||
file_map_copyto_utstring(resp->body.file, output);
|
||||
} else {
|
||||
http_chunks_write(resp->body.file->map, output);
|
||||
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;
|
||||
@@ -438,7 +395,7 @@ char* http_response_write(http_response *resp) {
|
||||
|
||||
http_response* http_response_create_builtin(uint16_t code, const char* errmsg) {
|
||||
http_response *resp = http_response_new(http_response_line_new(code));
|
||||
resp->body_type = BODY_STRING;
|
||||
http_body_set_type(resp->body, BODY_STRING);
|
||||
|
||||
http_header_list_add(resp->headers, http_header_new(HEADER_CONTENT_TYPE, "text/html"), false);
|
||||
|
||||
@@ -456,9 +413,17 @@ http_response* http_response_create_builtin(uint16_t code, const char* errmsg) {
|
||||
char* title_message = http_response_line_get_message(resp->resp);
|
||||
snprintf(buffer, 1023, "%s %hu - %s", (code >= 400) ? "Error" : "Response Code", code, title_message);
|
||||
|
||||
resp->body.str = str_replace(resp->body.str, "{{title}}", buffer);
|
||||
resp->body.str = str_replace(resp->body.str, "{{body_title}}", buffer);
|
||||
resp->body.str = str_replace(resp->body.str, "{{message}}", errmsg);
|
||||
char* str = resp->body->data.str;
|
||||
|
||||
str = str_replace(str, "{{title}}", buffer);
|
||||
str = str_replace(str, "{{body_title}}", buffer);
|
||||
if (errmsg == NULL) {
|
||||
errmsg = "";
|
||||
}
|
||||
str = str_replace(str, "{{message}}", errmsg);
|
||||
|
||||
|
||||
resp->body->data.str = str;
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ extern "C" {
|
||||
} http_request_method;
|
||||
|
||||
typedef enum http_version {
|
||||
HTTP10, HTTP11
|
||||
HTTP10, HTTP11, HTTPXX
|
||||
} http_version;
|
||||
|
||||
typedef struct http_request_line {
|
||||
@@ -83,18 +83,15 @@ extern "C" {
|
||||
http_request_line *req;
|
||||
http_request_parsestatus parsestatus;
|
||||
http_header_list *headers;
|
||||
http_body_type body_type;
|
||||
http_body body;
|
||||
http_body *body;
|
||||
struct http_request *next;
|
||||
} http_request;
|
||||
|
||||
|
||||
typedef struct http_response {
|
||||
http_response_line *resp;
|
||||
http_header_list *headers;
|
||||
bool body_chunked;
|
||||
http_body_type body_type;
|
||||
http_body body;
|
||||
http_body *body;
|
||||
struct http_response *next;
|
||||
} http_response;
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ extern "C" {
|
||||
#define CONN_LOCK(c) pthread_mutex_lock(&c->mutex)
|
||||
#define CONN_UNLOCK(c) pthread_mutex_unlock(&c->mutex)
|
||||
|
||||
#define CONN_ENQUEUE(conn, pool, name) queue_add(conn->server->pools[pool]->queue, queue_item_new2(name, (void*)conn))
|
||||
|
||||
typedef enum server_parse_header_state {
|
||||
HSTATE_NONE, HSTATE_VALUE, HSTATE_FIELD
|
||||
} server_parse_header_state;
|
||||
|
||||
@@ -69,14 +69,18 @@ void* server_loop_read(void* arg) {
|
||||
//Request has been read successfully, notify worker queue
|
||||
LL_APPEND(conn->pending_requests, conn->parse_state->current_request);
|
||||
server_parser_status_reset(conn->parse_state);
|
||||
queue_add(conn->server->pools[POOL_WORKER]->queue, queue_item_new2("REQ", (void*)conn));
|
||||
} else if (conn->parse_state->current_request != NULL && conn->parse_state->current_request->req!=NULL) {
|
||||
CONN_ENQUEUE(conn, POOL_WORKER, "REQ");
|
||||
} else if (conn->parse_state->current_request != NULL &&
|
||||
conn->parse_state->current_request->req!=NULL &&
|
||||
conn->parse_state->current_request->req->version == HTTP11) {
|
||||
//Send 100 Continue message
|
||||
|
||||
http_response *resp = http_response_new(http_response_line_new(100));
|
||||
http_response_list_append(conn->pending_responses, resp);
|
||||
CONN_ENQUEUE(conn, POOL_WRITE, "RESP");
|
||||
}
|
||||
if (error = true) {
|
||||
//Write any error directly, this will also close the connection
|
||||
queue_add(conn->server->pools[POOL_WRITE]->queue, queue_item_new2("RESP", (void*)conn));
|
||||
CONN_ENQUEUE(conn, POOL_WRITE, "RESP");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "ut/utlist.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
@@ -9,7 +11,35 @@
|
||||
#include "server-connection.h"
|
||||
#include "server-state.h"
|
||||
#include "server-loop.h"
|
||||
#include "http.h"
|
||||
#include "http-server.h"
|
||||
|
||||
void* server_loop_worker(void* arg) {
|
||||
thread *th = (thread*)arg;
|
||||
|
||||
while(th->stop == false) {
|
||||
queue_item *item = queue_fetchone(th->pool->queue, true);
|
||||
if (item == NULL) {
|
||||
continue;
|
||||
}
|
||||
server_connection *conn = (server_connection*)item->data;
|
||||
CONN_LOCK(conn);
|
||||
|
||||
while (conn->pending_requests != NULL) {
|
||||
http_request *request = conn->pending_requests;
|
||||
http_response *resp = server_process_request(conn->server->config, request);
|
||||
LL_DELETE(conn->pending_requests, request);
|
||||
http_request_delete(request);
|
||||
if (resp == NULL) {
|
||||
LOG(LERROR, "Request did not generate a response");
|
||||
resp = http_response_create_builtin(500, "Request did not complete successfully");
|
||||
http_header_list_add(resp->headers, http_header_new(HEADER_CONNECTION, "Close"), false);
|
||||
}
|
||||
http_response_list_append(conn->pending_responses, resp);
|
||||
CONN_ENQUEUE(conn, POOL_WRITE, "RESP");
|
||||
}
|
||||
|
||||
CONN_UNLOCK(conn);
|
||||
queue_return_item(th->pool->queue, item, true);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "server-connection.h"
|
||||
#include "server-state.h"
|
||||
#include "server-loop.h"
|
||||
#include "http.h"
|
||||
#include "http-body.h"
|
||||
|
||||
void* server_loop_write(void* arg) {
|
||||
thread *th = (thread*)arg;
|
||||
@@ -26,35 +28,7 @@ void* server_loop_write(void* arg) {
|
||||
server_connection *conn = (server_connection*)item->data;
|
||||
CONN_LOCK(conn);
|
||||
|
||||
size_t count = 0;
|
||||
while(conn->pending_writes->first != NULL) {
|
||||
BUFFER_LIST_RD_LOCK(conn->pending_writes);
|
||||
data_buffer *next = conn->pending_writes->first;
|
||||
|
||||
count = write(conn->skt->fd, next->buffer+next->rOffset, next->wOffset - next->rOffset);
|
||||
if (count < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
item->blocked = true;
|
||||
break;
|
||||
} else {
|
||||
if (errno != EBADF) {
|
||||
char address[INET_ADDRSTRLEN];
|
||||
skt_clientaddr(conn->skt, address, INET_ADDRSTRLEN);
|
||||
warning(true, "[#%lu %s] write error", conn->id, address);
|
||||
}
|
||||
conn->skt->error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
next->rOffset += count;
|
||||
|
||||
if (next->rOffset >= next->wOffset) {
|
||||
LL_DELETE(conn->pending_writes->first, next);
|
||||
data_buffer_free(next);
|
||||
}
|
||||
|
||||
BUFFER_LIST_RD_UNLOCK(conn->pending_writes);
|
||||
}
|
||||
|
||||
CONN_UNLOCK(conn);
|
||||
queue_return_item(th->pool->queue, item, item->blocked == false);
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <bits/stdio2.h>
|
||||
|
||||
#include "ut/utstring.h"
|
||||
|
||||
@@ -220,7 +219,7 @@ char* file_map_copyto_string(file_map* map, char* str, size_t str_len) {
|
||||
}
|
||||
void file_map_copyto_utstring(file_map* map, UT_string* string) {
|
||||
assert(map!=NULL);
|
||||
assert(str!=NULL);
|
||||
assert(string!=NULL);
|
||||
|
||||
utstring_bincpy(string, map->map, map->size);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user