Working on http thread loops
This commit is contained in:
@@ -112,7 +112,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item path="content/public_html/lorem.txt" ex="false" tool="3" flavor2="0">
|
<item path="content/public_html/lorem.txt" ex="false" tool="3" flavor2="0">
|
||||||
</item>
|
</item>
|
||||||
<folder path="TestFiles/f1">
|
<!--<folder path="TestFiles/f1">
|
||||||
<cTool>
|
<cTool>
|
||||||
<incDir>
|
<incDir>
|
||||||
<pElem>.</pElem>
|
<pElem>.</pElem>
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
<linkerOptionItem>-lcunit</linkerOptionItem>
|
<linkerOptionItem>-lcunit</linkerOptionItem>
|
||||||
</linkerLibItems>
|
</linkerLibItems>
|
||||||
</linkerTool>
|
</linkerTool>
|
||||||
</folder>
|
</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">
|
||||||
@@ -258,7 +258,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item path="content/public_html/lorem.txt" ex="false" tool="3" flavor2="0">
|
<item path="content/public_html/lorem.txt" ex="false" tool="3" flavor2="0">
|
||||||
</item>
|
</item>
|
||||||
<folder path="TestFiles/f1">
|
<!--<folder path="TestFiles/f1">
|
||||||
<cTool>
|
<cTool>
|
||||||
<incDir>
|
<incDir>
|
||||||
<pElem>.</pElem>
|
<pElem>.</pElem>
|
||||||
@@ -275,7 +275,7 @@
|
|||||||
<linkerOptionItem>-lcunit</linkerOptionItem>
|
<linkerOptionItem>-lcunit</linkerOptionItem>
|
||||||
</linkerLibItems>
|
</linkerLibItems>
|
||||||
</linkerTool>
|
</linkerTool>
|
||||||
</folder>
|
</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">
|
||||||
|
|||||||
199
src/http-body.c
199
src/http-body.c
@@ -5,11 +5,34 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <bits/stdio2.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ut/utstring.h"
|
#include "ut/utstring.h"
|
||||||
#include "http-body.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* http_body_new(http_body_type type, void* dataptr) {
|
||||||
http_body *body = calloc(1, sizeof(http_body));
|
http_body *body = calloc(1, sizeof(http_body));
|
||||||
ALLOC_CHECK(body);
|
ALLOC_CHECK(body);
|
||||||
@@ -36,9 +59,8 @@ http_body* http_body_new(http_body_type type, void* dataptr) {
|
|||||||
|
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
void http_body_delete(http_body *body) {
|
void http_body_clear(http_body *body) {
|
||||||
assert(body!=NULL);
|
assert(body!=NULL);
|
||||||
|
|
||||||
switch(body->type) {
|
switch(body->type) {
|
||||||
case BODY_NONE:
|
case BODY_NONE:
|
||||||
break;
|
break;
|
||||||
@@ -62,6 +84,11 @@ void http_body_delete(http_body *body) {
|
|||||||
fatal("Invalid http body type");
|
fatal("Invalid http body type");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
void http_body_delete(http_body *body) {
|
||||||
|
assert(body!=NULL);
|
||||||
|
|
||||||
|
http_body_clear(body);
|
||||||
free(body);
|
free(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +138,13 @@ size_t http_body_len(http_body *body) {
|
|||||||
}
|
}
|
||||||
return len;
|
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) {
|
http_body_write_result http_body_writeto_fd(http_body *body, int fd) {
|
||||||
assert(body!=NULL);
|
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);
|
assert(body->data.ptr!=NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* buffer=NULL;
|
|
||||||
const size_t buffer_len = 16*1024;
|
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)) {
|
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;
|
errno = EINVAL;
|
||||||
ssize_t result = -1;
|
ssize_t written = -1;
|
||||||
|
http_body_write_result result = HBWRITE_MORE;
|
||||||
|
|
||||||
switch(body->type) {
|
switch(body->type) {
|
||||||
case BODY_STRING:
|
case BODY_STRING:
|
||||||
result = write(fd, body->data.str+body->rOffset, write_len);
|
written = write(fd, body->data.str+body->rOffset, write_len);
|
||||||
break;
|
break;
|
||||||
case BODY_FILEMAP:
|
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;
|
break;
|
||||||
case BODY_FILE:
|
case BODY_FILE:;
|
||||||
if (buffer==NULL) {
|
size_t read_count = write_len;
|
||||||
buffer = calloc(buffer_len, sizeof(char));
|
http_body_write_result read_res = _http_body_file_fill_buffer(buffer, buffer_len, &read_count, body->data.file);
|
||||||
ALLOC_CHECK(buffer);
|
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) {
|
if (read_count > 0) {
|
||||||
result = write(fd, buffer, read_count);
|
written = write(fd, buffer, read_count);
|
||||||
}
|
}
|
||||||
if (feof(body->data.file) != 0) {
|
if (read_res == HBWRITE_DONE) {
|
||||||
body->rOffset += result;
|
result = read_res; break;
|
||||||
free(buffer);
|
|
||||||
return HBWRITE_DONE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}//switch body->type
|
}//switch body->type
|
||||||
|
|
||||||
if (result < 0) {
|
if (written < 0 || result == HBWRITE_ERROR) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
return HBWRITE_BLOCKED;
|
return HBWRITE_BLOCKED;
|
||||||
}
|
}
|
||||||
warning(true, "Error writing http body");
|
|
||||||
return HBWRITE_ERROR;
|
return HBWRITE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
body->rOffset += result;
|
body->rOffset += written;
|
||||||
|
if (result == HBWRITE_DONE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}//While data remaining
|
}//While data remaining
|
||||||
|
|
||||||
if (buffer != NULL) {
|
if (buffer != NULL) {
|
||||||
@@ -178,7 +206,7 @@ http_body_write_result http_body_writeto_fd(http_body *body, int fd) {
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
return HBWRITE_DONE;
|
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);
|
assert(body!=NULL);
|
||||||
if (body->type!=BODY_NONE) {
|
if (body->type!=BODY_NONE) {
|
||||||
assert(body->data.ptr!=NULL);
|
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;
|
char* buffer=NULL;
|
||||||
const size_t buffer_len = 16*1024;
|
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)) {
|
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;
|
||||||
@@ -197,53 +229,106 @@ http_body_write_result http_body_writeto_str(http_body *body, const char** str)
|
|||||||
}
|
}
|
||||||
ALLOC_CHECK(*str);
|
ALLOC_CHECK(*str);
|
||||||
|
|
||||||
errno = EINVAL;
|
ssize_t written = -1;
|
||||||
ssize_t result = -1;
|
http_body_write_result result = HBWRITE_MORE;
|
||||||
|
|
||||||
switch(body->type) {
|
switch(body->type) {
|
||||||
case BODY_STRING:
|
case BODY_STRING:
|
||||||
case BODY_FILEMAP:
|
case BODY_FILEMAP:;
|
||||||
char* src = (body->type==BODY_STRING) ? body->data.str : body->data.filemap->map;
|
char* src = (body->type==BODY_STRING) ? body->data.str : body->data.filemap->map;
|
||||||
strncat(*str, src+body->rOffset, write_len);
|
strncat(*str, src+body->rOffset, write_len);
|
||||||
result = write_len;
|
written = write_len;
|
||||||
break;
|
break;
|
||||||
case BODY_FILE:
|
case BODY_FILE:;
|
||||||
if (buffer==NULL) {
|
size_t read_count = write_len;
|
||||||
buffer = calloc(buffer_len, sizeof(char));
|
http_body_write_result read_res = _http_body_file_fill_buffer(buffer, buffer_len, &read_count, body->data.file);
|
||||||
ALLOC_CHECK(buffer);
|
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) {
|
if (read_count > 0) {
|
||||||
strncat(*str, buffer, read_count);
|
strncat(*str, buffer, read_count);
|
||||||
result = read_count;
|
written = read_count;
|
||||||
}
|
}
|
||||||
if (feof(body->data.file) != 0) {
|
if (read_res == HBWRITE_DONE) {
|
||||||
body->rOffset += result;
|
result = read_res; break;
|
||||||
free(buffer);
|
|
||||||
return HBWRITE_DONE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}//Switch body->type
|
}//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
|
}//while data remaining
|
||||||
|
|
||||||
if (buffer != NULL) {
|
if (buffer != NULL) {
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
errno = 0;
|
|
||||||
return HBWRITE_DONE;
|
return HBWRITE_DONE;
|
||||||
}
|
}
|
||||||
http_body_write_result http_body_writeto_utstring(http_body *body, UT_string *utstr) {
|
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* http_body_new(http_body_type type, void* dataptr);
|
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);
|
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);
|
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_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);
|
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) {
|
if (host_config == NULL) {
|
||||||
//host not found and default not found
|
//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);
|
http_header_list_add(response->headers, http_header_new(HEADER_CONNECTION, "close"), false);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@@ -152,9 +152,19 @@ http_response* server_process_request(config_server* config, http_request *reque
|
|||||||
free(buffer);
|
free(buffer);
|
||||||
free(filepath);
|
free(filepath);
|
||||||
|
|
||||||
|
bool close_connection = false;
|
||||||
//Check to see if client requested the connection be closed
|
//Check to see if client requested the connection be closed
|
||||||
http_header* request_connection = http_header_list_get(request->headers, HEADER_CONNECTION);
|
http_header* request_connection = http_header_list_get(request->headers, HEADER_CONNECTION);
|
||||||
if (request_connection != NULL && strcasecmp(request_connection->content, "close") == 0) {
|
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);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stat *pathstat = calloc(1, sizeof(struct stat));
|
struct stat pathstat;
|
||||||
if (stat(filepath_actual, pathstat) < 0) {
|
if (stat(filepath_actual, &pathstat) < 0) {
|
||||||
server_file_result_seterror(result, 404, "File not found");
|
server_file_result_seterror(result, 404, "File not found");
|
||||||
free(filepath_actual);
|
free(filepath_actual);
|
||||||
free(pathstat);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
//If directory
|
//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);
|
char* dir_index = server_find_directory_index(hconfig, filepath_actual);
|
||||||
if (hconfig->index_files_count > 0 && dir_index != NULL) {
|
if (hconfig->index_files_count > 0 && dir_index != NULL) {
|
||||||
//Use the directory index
|
//Use the directory index
|
||||||
@@ -197,10 +206,9 @@ server_file_result* server_determine_file(config_host* hconfig, const char* requ
|
|||||||
} else {
|
} else {
|
||||||
server_file_result_seterror(result, 403, "No index file was found and directory indexes are disabled");
|
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);
|
result->path = strdup(filepath_actual);
|
||||||
}
|
}
|
||||||
free(pathstat);
|
|
||||||
free(filepath_actual);
|
free(filepath_actual);
|
||||||
return result;
|
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 {
|
} else {
|
||||||
req->method_other = NULL;
|
req->method_other = NULL;
|
||||||
}
|
}
|
||||||
|
req->version = HTTPXX;
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
void http_request_line_delete(http_request_line *req) {
|
void http_request_line_delete(http_request_line *req) {
|
||||||
@@ -252,20 +253,15 @@ http_request *http_request_new() {
|
|||||||
ALLOC_CHECK(req);
|
ALLOC_CHECK(req);
|
||||||
req->headers = http_header_list_new();
|
req->headers = http_header_list_new();
|
||||||
req->parsestatus = PARSE_REQUESTLINE;
|
req->parsestatus = PARSE_REQUESTLINE;
|
||||||
|
req->body = http_body_new(BODY_NONE, NULL);
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
void http_request_append_body(http_request *req, const char* body) {
|
void http_request_append_body(http_request *req, const char* body) {
|
||||||
assert(req!=NULL);
|
assert(req!=NULL);
|
||||||
assert(body!=NULL);
|
assert(body!=NULL);
|
||||||
|
assert(req->body->type == BODY_STRING);
|
||||||
|
|
||||||
uint32_t bodylen = 0;
|
http_body_append_str(req->body, body, strlen(body));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
char* http_request_write(http_request *req) {
|
char* http_request_write(http_request *req) {
|
||||||
assert(req!=NULL);
|
assert(req!=NULL);
|
||||||
@@ -289,15 +285,8 @@ char* http_request_write(http_request *req) {
|
|||||||
|
|
||||||
utstring_printf(output, "\r\n");
|
utstring_printf(output, "\r\n");
|
||||||
|
|
||||||
if (req->body_type == BODY_STRING) {
|
http_body_writeto_utstring(req->body, output);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char* result = utstring_body(output);
|
char* result = utstring_body(output);
|
||||||
free(output);
|
free(output);
|
||||||
return result;
|
return result;
|
||||||
@@ -309,11 +298,7 @@ void http_request_delete(http_request *req) {
|
|||||||
http_request_line_delete(req->req);
|
http_request_line_delete(req->req);
|
||||||
}
|
}
|
||||||
http_header_list_delete(req->headers);
|
http_header_list_delete(req->headers);
|
||||||
if (req->body_type == BODY_STRING) {
|
http_body_delete(req->body);
|
||||||
free(req->body.str);
|
|
||||||
} else if (req->body_type == BODY_FILE && req->body.file != NULL) {
|
|
||||||
file_map_delete(req->body.file);
|
|
||||||
}
|
|
||||||
free(req);
|
free(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,42 +306,26 @@ http_response* http_response_new(http_response_line *resp) {
|
|||||||
assert(resp!=NULL);
|
assert(resp!=NULL);
|
||||||
|
|
||||||
http_response *response = calloc(1, sizeof(http_response));
|
http_response *response = calloc(1, sizeof(http_response));
|
||||||
ALLOC_CHECK(response);
|
ALLOC_CHECK(resp);
|
||||||
response->resp = resp;
|
response->resp = resp;
|
||||||
response->headers = http_header_list_new();
|
response->headers = http_header_list_new();
|
||||||
response->body_chunked = false;
|
response->body_chunked = false;
|
||||||
response->body_type = BODY_NONE;
|
response->body = http_body_new(BODY_NONE, NULL);
|
||||||
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) {
|
||||||
assert(resp!=NULL);
|
assert(resp!=NULL);
|
||||||
assert(body!=NULL);
|
assert(body!=NULL);
|
||||||
assert(resp->body_type == BODY_STRING);
|
assert(resp->body->type == BODY_STRING);
|
||||||
|
|
||||||
size_t bodylen = 0;
|
http_body_append_str(resp->body, body, strlen(body));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
void http_response_delete(http_response *resp) {
|
void http_response_delete(http_response *resp) {
|
||||||
assert(resp!=NULL);
|
assert(resp!=NULL);
|
||||||
|
|
||||||
http_response_line_delete(resp->resp);
|
http_response_line_delete(resp->resp);
|
||||||
http_header_list_delete(resp->headers);
|
http_header_list_delete(resp->headers);
|
||||||
if (resp->body_type == BODY_STRING) {
|
http_body_delete(resp->body);
|
||||||
free(resp->body.str);
|
|
||||||
} else if (resp->body_type == BODY_FILE && resp->body.file != NULL) {
|
|
||||||
file_map_delete(resp->body.file);
|
|
||||||
}
|
|
||||||
free(resp);
|
free(resp);
|
||||||
}
|
}
|
||||||
char* http_response_write(http_response *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->resp->code != 100) { //No additional headers for Continue messages
|
||||||
if (resp->body_chunked == false) {
|
if (resp->body_chunked == false) {
|
||||||
//Add content length header
|
//Add content length header
|
||||||
uint32_t messageLength = 0;
|
uint32_t messageLength = http_body_len(resp->body);
|
||||||
if (resp->body_type == BODY_STRING) {
|
|
||||||
messageLength = strlen(resp->body.str);
|
|
||||||
} else if (resp->body_type == BODY_FILE) {
|
|
||||||
messageLength = resp->body.file->size;
|
|
||||||
}
|
|
||||||
char messageLengthStr[100];
|
char messageLengthStr[100];
|
||||||
snprintf(messageLengthStr, 99, "%u", messageLength);
|
snprintf(messageLengthStr, 99, "%u", messageLength);
|
||||||
http_header_list_add(resp->headers, http_header_new(HEADER_CONTENT_LENGTH, messageLengthStr), true);
|
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");
|
utstring_printf(output, "\r\n");
|
||||||
|
|
||||||
//Write the request (if string)
|
//Write the request (if string)
|
||||||
if (resp->body_type == BODY_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_chunked == false) {
|
if (resp->body_chunked == false) {
|
||||||
file_map_copyto_utstring(resp->body.file, output);
|
http_body_writeto_utstring(resp->body, output);
|
||||||
} else {
|
}
|
||||||
http_chunks_write(resp->body.file->map, output);
|
if (resp->body_chunked == true) {
|
||||||
|
http_chunks_write(resp->body->data.str, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char* outputStr = utstring_body(output);
|
char* outputStr = utstring_body(output);
|
||||||
free(output);
|
free(output);
|
||||||
return outputStr;
|
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* http_response_create_builtin(uint16_t code, const char* errmsg) {
|
||||||
http_response *resp = http_response_new(http_response_line_new(code));
|
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);
|
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);
|
char* title_message = http_response_line_get_message(resp->resp);
|
||||||
snprintf(buffer, 1023, "%s %hu - %s", (code >= 400) ? "Error" : "Response Code", code, title_message);
|
snprintf(buffer, 1023, "%s %hu - %s", (code >= 400) ? "Error" : "Response Code", code, title_message);
|
||||||
|
|
||||||
resp->body.str = str_replace(resp->body.str, "{{title}}", buffer);
|
char* str = resp->body->data.str;
|
||||||
resp->body.str = str_replace(resp->body.str, "{{body_title}}", buffer);
|
|
||||||
resp->body.str = str_replace(resp->body.str, "{{message}}", errmsg);
|
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;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ extern "C" {
|
|||||||
} http_request_method;
|
} http_request_method;
|
||||||
|
|
||||||
typedef enum http_version {
|
typedef enum http_version {
|
||||||
HTTP10, HTTP11
|
HTTP10, HTTP11, HTTPXX
|
||||||
} http_version;
|
} http_version;
|
||||||
|
|
||||||
typedef struct http_request_line {
|
typedef struct http_request_line {
|
||||||
@@ -83,18 +83,15 @@ extern "C" {
|
|||||||
http_request_line *req;
|
http_request_line *req;
|
||||||
http_request_parsestatus parsestatus;
|
http_request_parsestatus parsestatus;
|
||||||
http_header_list *headers;
|
http_header_list *headers;
|
||||||
http_body_type body_type;
|
http_body *body;
|
||||||
http_body body;
|
|
||||||
struct http_request *next;
|
struct http_request *next;
|
||||||
} http_request;
|
} http_request;
|
||||||
|
|
||||||
|
|
||||||
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_type body_type;
|
http_body *body;
|
||||||
http_body body;
|
|
||||||
struct http_response *next;
|
struct http_response *next;
|
||||||
} http_response;
|
} http_response;
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ extern "C" {
|
|||||||
#define CONN_LOCK(c) pthread_mutex_lock(&c->mutex)
|
#define CONN_LOCK(c) pthread_mutex_lock(&c->mutex)
|
||||||
#define CONN_UNLOCK(c) pthread_mutex_unlock(&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 {
|
typedef enum server_parse_header_state {
|
||||||
HSTATE_NONE, HSTATE_VALUE, HSTATE_FIELD
|
HSTATE_NONE, HSTATE_VALUE, HSTATE_FIELD
|
||||||
} server_parse_header_state;
|
} server_parse_header_state;
|
||||||
|
|||||||
@@ -69,14 +69,18 @@ void* server_loop_read(void* arg) {
|
|||||||
//Request has been read successfully, notify worker queue
|
//Request has been read successfully, notify worker queue
|
||||||
LL_APPEND(conn->pending_requests, conn->parse_state->current_request);
|
LL_APPEND(conn->pending_requests, conn->parse_state->current_request);
|
||||||
server_parser_status_reset(conn->parse_state);
|
server_parser_status_reset(conn->parse_state);
|
||||||
queue_add(conn->server->pools[POOL_WORKER]->queue, queue_item_new2("REQ", (void*)conn));
|
CONN_ENQUEUE(conn, POOL_WORKER, "REQ");
|
||||||
} else if (conn->parse_state->current_request != NULL && conn->parse_state->current_request->req!=NULL) {
|
} 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
|
//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) {
|
if (error = true) {
|
||||||
//Write any error directly, this will also close the connection
|
//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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "ut/utlist.h"
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -9,7 +11,35 @@
|
|||||||
#include "server-connection.h"
|
#include "server-connection.h"
|
||||||
#include "server-state.h"
|
#include "server-state.h"
|
||||||
#include "server-loop.h"
|
#include "server-loop.h"
|
||||||
|
#include "http.h"
|
||||||
|
#include "http-server.h"
|
||||||
|
|
||||||
void* server_loop_worker(void* arg) {
|
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-connection.h"
|
||||||
#include "server-state.h"
|
#include "server-state.h"
|
||||||
#include "server-loop.h"
|
#include "server-loop.h"
|
||||||
|
#include "http.h"
|
||||||
|
#include "http-body.h"
|
||||||
|
|
||||||
void* server_loop_write(void* arg) {
|
void* server_loop_write(void* arg) {
|
||||||
thread *th = (thread*)arg;
|
thread *th = (thread*)arg;
|
||||||
@@ -26,35 +28,7 @@ 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);
|
||||||
|
|
||||||
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);
|
CONN_UNLOCK(conn);
|
||||||
queue_return_item(th->pool->queue, item, item->blocked == false);
|
queue_return_item(th->pool->queue, item, item->blocked == false);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <bits/stdio2.h>
|
|
||||||
|
|
||||||
#include "ut/utstring.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) {
|
void file_map_copyto_utstring(file_map* map, UT_string* string) {
|
||||||
assert(map!=NULL);
|
assert(map!=NULL);
|
||||||
assert(str!=NULL);
|
assert(string!=NULL);
|
||||||
|
|
||||||
utstring_bincpy(string, map->map, map->size);
|
utstring_bincpy(string, map->map, map->size);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user