http server working
Some checks failed
CodeQL / Analyze (${{ matrix.language }}) (autobuild, c-cpp) (push) Has been cancelled
Microsoft C++ Code Analysis / Analyze (push) Has been cancelled

This commit is contained in:
Dennis Eichhorn 2025-06-20 19:34:07 +00:00
parent 2059cc6e77
commit 98ca778dfc
5 changed files with 133 additions and 21 deletions

View File

@ -251,11 +251,8 @@ HttpRequest* http_request_create(ThreadedChunkMemory* mem)
request->size = request_buffer_count;
request->protocol = HTTP_PROTOCOL_1_1;
// Create content length placehoder, this header element is always required
http_header_value_set(&request, HTTP_HEADER_KEY_CONTENT_LENGTH, " ", mem);
// Prepare the chunked sub-regions
request->header_available_count = 16;
request->header_available_count = 25;
request->header_available_size = 4 * 256 * sizeof(char);
request->body_offset = request->header_available_count * sizeof(HttpHeaderElement) + request->header_available_size;
@ -268,6 +265,22 @@ HttpRequest* http_request_create(ThreadedChunkMemory* mem)
return request;
}
FORCE_INLINE
void http_request_free(HttpRequest** request, ThreadedChunkMemory* mem)
{
thrd_chunk_free_elements(mem, (*request)->id, (*request)->size);
*request = NULL;
}
inline
uint32 http_request_free_body_space(const HttpRequest* request, ThreadedChunkMemory* mem)
{
return request->size * mem->chunk_size
- request->body_offset
- request->body_used_size
- sizeof(HttpRequest);
}
inline
const char* http_request_body(const HttpRequest* request) {
return ((const char *) (request + 1)) + request->body_offset;
@ -356,30 +369,36 @@ void http_header_parse(HttpRequest** http_request, const char* request, Threaded
http_req->method = HTTP_METHOD_UNKNOWN;
}
// @bug the uri offsets are wrong (they miss the header elements)
// however, if we put them after the header elements we would also have to grow this if we ever need to grow the heder element array
int32 header_count_bytes = http_req->header_available_count * sizeof(HttpHeaderElement);
// Parse reuqest path
str_move_past(&request, ' ');
http_req->uri.path_offset = request - request_start;
http_req->uri.path_offset = request - request_start + header_count_bytes;
str_skip_until_list(&request, ":?# ");
http_req->uri.path_length = (request - request_start) - http_req->uri.path_offset;
http_req->uri.path_length = (request - request_start + header_count_bytes) - http_req->uri.path_offset;
// Parse port
if (*request == ':') {
http_req->uri.port = (uint16) str_to_int(request, &request);
str_skip_until_list(&request, "?# ");
}
// Parse query parameters
if (*request == '?') {
http_req->uri.parameter_offset = request - request_start;
http_req->uri.parameter_offset = request - request_start + header_count_bytes;
str_skip_until_list(&request, "# ");
//http_req->uri.parameter_length = (request - request_start) - http_req->uri.parameter_offset;
}
// Parse fragment
if (*request == '#') {
http_req->uri.fragment_offset = request - request_start;
http_req->uri.fragment_offset = request - request_start + header_count_bytes;
str_move_to(&request, ' ');
http_req->uri.fragment_length = (request - request_start) - http_req->uri.fragment_offset;
http_req->uri.fragment_length = (request - request_start + header_count_bytes) - http_req->uri.fragment_offset;
}
// Parse protocol
@ -406,7 +425,53 @@ void http_header_parse(HttpRequest** http_request, const char* request, Threaded
// Parsing HTTP headers
//////////////////////////////////////////////////
// The HTTP headers end with \r\n\r\n (= one empty line/element)
HttpHeaderElement* elements = (HttpHeaderElement *) (http_req + 1);
int32 i = 0;
while (request[0] != '\r' && request[1] != '\n' && request[2] != '\r' && request[3] != '\n') {
if (i >= http_req->header_available_count) {
// Ideally this if body almost never gets executed since the initial area is sufficiently large
// @todo consider to log actual usage to possibly reduce the size from 50 to maybe 25?
http_request_grow(http_request, 1, mem);
http_req = *http_request;
int32 offset = 50 * sizeof(HttpHeaderElement);
int32 request_offset = request - request_start;
// Grow header element area
memmove(
((char *) (http_req + 1)) + http_req->body_offset + offset,
((char *) (http_req + 1)) + http_req->body_offset,
http_req->header_available_size + http_req->body_used_size
);
// Re-adjust uri as well
http_req->uri.path_offset += offset;
if (http_req->uri.parameter_offset) {
http_req->uri.parameter_offset += offset;
}
if (http_req->uri.fragment_offset) {
http_req->uri.fragment_offset += offset;
}
// Reset request after moving
request = ((char *) (http_req + 1)) + request_offset;
// Adjust value offsets
elements = (HttpHeaderElement *) (http_req + 1);
for (int32 j = 0; j < http_req->header_used_count; ++j) {
elements[j].value_offset += offset;
}
http_req->body_offset += offset;
// Reset request start position
request_start = ((const char *) (http_req + 1)) + http_req->header_available_count * sizeof(HttpHeaderElement);
}
str_move_past(&request, '\n');
const char* key = request;
@ -415,8 +480,27 @@ void http_header_parse(HttpRequest** http_request, const char* request, Threaded
const char* value = request;
str_move_to(&request, '\r');
http_header_value_set(http_request, http_header_key_text(key), value, mem, request - value);
elements[i].key = http_header_key_text(key);
elements[i].value_offset = http_req->header_available_count * sizeof(HttpHeaderElement)
+ ((uintptr_t) value - (uintptr_t) (http_req + 1));
elements[i].value_length = request - value;
++i;
}
http_req->header_used_count = i;
http_req->header_available_size = 0;
http_req->header_used_size = 0;
if (i > 0) {
// Available size = used size
http_req->header_available_size = (request - request_start);
http_req->header_used_size = http_req->header_available_size;
}
http_req->body_offset = http_req->header_available_count * sizeof(HttpHeaderElement)
+ http_req->header_available_size
+ 4; // skipping \r\n\r\n
}
void parse_multipart_data(const char *body, const char *boundary) {

View File

@ -221,7 +221,7 @@ void http_header_value_set(
// Set value
memcpy(((char *) (resp + 1)) + element->value_offset, value, value_length);
resp->body_used_size += value_length;
// resp->body_used_size += value_length; // @bug Why was this here?
resp->header_used_size += (uint16) value_length;
++resp->header_used_count;
@ -239,11 +239,8 @@ HttpResponse* http_response_create(ThreadedChunkMemory* mem)
response->protocol = HTTP_PROTOCOL_1_1;
response->status_code = HTTP_STATUS_CODE_200;
// Create content length placehoder, this header element is always required
http_header_value_set(&response, HTTP_HEADER_KEY_CONTENT_LENGTH, " ", mem);
// Prepare the chunked sub-regions
response->header_available_count = 16;
response->header_available_count = 25;
response->header_available_size = 4 * 256 * sizeof(char);
response->body_offset = response->header_available_count * sizeof(HttpHeaderElement) + response->header_available_size;
@ -256,6 +253,22 @@ HttpResponse* http_response_create(ThreadedChunkMemory* mem)
return response;
}
FORCE_INLINE
void http_response_free(HttpResponse** response, ThreadedChunkMemory* mem)
{
thrd_chunk_free_elements(mem, (*response)->id, (*response)->size);
*response = NULL;
}
inline
uint32 http_response_free_body_space(const HttpResponse* response, ThreadedChunkMemory* mem)
{
return response->size * mem->chunk_size
- response->body_offset
- response->body_used_size
- sizeof(HttpResponse);
}
inline
const char* http_response_body(const HttpResponse* response) {
return ((const char *) (response + 1)) + response->body_offset;
@ -282,7 +295,11 @@ const char* http_header_value_get(const HttpResponse* response, const HttpHeader
// @todo we need a streamed response version http_response_stream()
// WARNING: We expect response to already contain a header element called content-length
void http_response_send(const SocketConnection* __restrict socket, HttpResponse* __restrict response)
void http_response_send(
const SocketConnection* __restrict socket,
HttpResponse* __restrict response,
ThreadedChunkMemory* mem
)
{
char header[4096];
char* header_ref;
@ -293,13 +310,15 @@ void http_response_send(const SocketConnection* __restrict socket, HttpResponse*
header_ref += str_copy(header_ref, http_protocol_text(response->protocol));
*header_ref++ = ' ';
header_ref += int_to_str(response->status_code, header_ref);
*header_ref++ = ' ';
header_ref += str_copy(header_ref, http_status_text(response->status_code));
*header_ref++ = '\r';
*header_ref++ = '\n';
char content_length[12];
int_to_str(response->body_used_size, content_length);
http_header_value_set(&response, HTTP_HEADER_KEY_CONTENT_LENGTH, content_length, NULL);
http_header_value_set(&response, HTTP_HEADER_KEY_CONTENT_LENGTH, content_length, mem);
const HttpHeaderElement* elements = (HttpHeaderElement *) (response + 1);
@ -308,9 +327,11 @@ void http_response_send(const SocketConnection* __restrict socket, HttpResponse*
const HttpHeaderElement* element = &elements[i];
header_ref += str_copy(header_ref, http_header_key_text(element->key));
*header_ref++ = ':';
*header_ref++ = ' ';
memcpy(header_ref, (const char *) elements + element->value_offset, element->value_length);
// @bug What if the header array cannot fit the data from the memcpy?
memcpy(header_ref, ((const char *) elements) + element->value_offset, element->value_length);
header_ref += element->value_length;
*header_ref++ = '\r';
@ -338,7 +359,7 @@ void http_response_send(const SocketConnection* __restrict socket, HttpResponse*
send(socket->sd, header, header_ref - header, 0);
// Do we have data remaining to be sent?
if (response->body_offset && response->body_used_size - body_size_to_add > 0) {
if (response->body_used_size - body_size_to_add > 0) {
// @question Do we need chunked sends?
send(
socket->sd,
@ -365,7 +386,12 @@ void http_response_body_add(HttpResponse** response, const char* __restrict body
response_body = (char*) (resp + 1);
}
memcpy(response_body + resp->body_used_size, body, length);
memcpy(
response_body + resp->body_offset + resp->body_used_size,
body,
length
);
resp->body_used_size += length;
}

View File

@ -18,6 +18,7 @@
#include <sys/syscall.h>
#define THREAD_RETURN int32
#define THREAD_RETURN_BODY int32
typedef THREAD_RETURN (*ThreadJobFunc)(void*);
struct mutex {

View File

@ -14,6 +14,7 @@
#include <windows.h>
#define THREAD_RETURN DWORD WINAPI
#define THREAD_RETURN_BODY DWORD
typedef DWORD (WINAPI *ThreadJobFunc)(void*);
typedef CRITICAL_SECTION mutex;
typedef void mutexattr_t;

View File

@ -1165,7 +1165,7 @@ bool str_contains(const char* __restrict haystack, const char* __restrict needle
inline constexpr
bool str_contains(const char* __restrict haystack, const char* __restrict needle, size_t length) noexcept
{
while (*haystack != '\0' && length > 0) {
while (*haystack != '\0' || length > 0) {
const char* p1 = haystack;
const char* p2 = needle;
size_t remaining = length;