From 3bf7db9bb657794ee08251be512b54361ff3d69d Mon Sep 17 00:00:00 2001 From: Samuel Vishesh Paul Date: Mon, 28 Oct 2024 21:50:20 +0530 Subject: [PATCH] Add comprehensive request header parsing and testing Enhanced HTTP request parsing by properly handling and storing headers. Updated tests to include comprehensive assertions for the parsed headers, ensuring robustness and correctness in the parsing logic. Added the new test case to the CMake build configuration. Took 52 minutes --- CMakeLists.txt | 2 ++ src/tiny_http/tiny_http_server_lib.c | 54 +++++++++++++++++++++++++++- src/tiny_http/tiny_http_server_lib.h | 2 +- test/assert_tiny_http_server_lib.c | 18 +++++++++- 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0519900..82fe803 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,3 +21,5 @@ add_library(tiny_http_server_lib src/tiny_http/tiny_http_server_lib.c src/tiny_h add_executable(assert_tiny_http_server_lib test/assert_tiny_http_server_lib.c) target_link_libraries(assert_tiny_http_server_lib tiny_http_server_lib) + +add_test(test_tiny_http_server_lib assert_tiny_http_server_lib) diff --git a/src/tiny_http/tiny_http_server_lib.c b/src/tiny_http/tiny_http_server_lib.c index f88e464..ce2781f 100644 --- a/src/tiny_http/tiny_http_server_lib.c +++ b/src/tiny_http/tiny_http_server_lib.c @@ -67,7 +67,59 @@ http_request *parse_http_request(const uint8_t *const http_packet, const size_t free(request); return nullptr; } - // TODO parse the rest + + if (ptr >= http_packet_len || ptr + 2 >= http_packet_len) { + return request; + } + + ptr += 2; // '\r\n' + for (size_t i = 0; ptr < http_packet_len; i++) { + if (ptr + 2 >= http_packet_len) { + break; + } + http_header *header = calloc(1, sizeof(http_header)); + const size_t header_name_start_ptr = ptr; + size_t header_name_len = 0; + for (; ptr < http_packet_len; ptr++) { + if (http_packet[ptr] == ' ') { + header_name_len = ptr - header_name_start_ptr; + break; + } + } + if (header_name_len == 0) { + fprintf(stderr, "misformed header"); + fflush(stderr); + free(request->url); + free(request); + free(header); + return nullptr; + } + header->name = strndup((char *) http_packet + ptr - header_name_len, header_name_len - 1); + + for (; ptr < http_packet_len; ptr++) { + if (http_packet[ptr] != ' ') { + break; + } + } + const size_t header_value_start = ptr; + size_t header_value_len = 0; + for (; ptr < http_packet_len; ptr++) { + if (http_packet[ptr] == '\r' && http_packet[ptr + 1] == '\n') { + header_value_len = ptr - header_value_start; + break; + } + } + header->value = strndup((char *) http_packet + ptr - header_value_len, header_value_len); + if (request->headers == NULL) { + request->headers = calloc(1, sizeof(http_header*)); + } else { + const http_header **new_headers = realloc(request->headers, sizeof(http_header*) * (i + 1)); + request->headers = new_headers; + } + request->headers[i] = header; + request->headers_cnt = i + 1; + ptr += 2; + } return request; } diff --git a/src/tiny_http/tiny_http_server_lib.h b/src/tiny_http/tiny_http_server_lib.h index 279a50f..feb4c72 100644 --- a/src/tiny_http/tiny_http_server_lib.h +++ b/src/tiny_http/tiny_http_server_lib.h @@ -24,7 +24,7 @@ typedef struct http_request { http_version version; http_method method; char *url; - http_header *headers; + http_header **headers; size_t headers_cnt; uint8_t *body; size_t body_len; diff --git a/test/assert_tiny_http_server_lib.c b/test/assert_tiny_http_server_lib.c index e84cf3f..b84e196 100644 --- a/test/assert_tiny_http_server_lib.c +++ b/test/assert_tiny_http_server_lib.c @@ -3,8 +3,9 @@ // #include +#include #include -#include <_stdlib.h> +#include #include "../src/tiny_http/tiny_http_server_lib.h" @@ -13,6 +14,21 @@ int main() { const uint8_t request[] = "GET / HTTP/1.0\r\nHost: localhost:8085\r\nUser-Agent: curl/8.7.1\r\nAccept: */*\r\n\r\n"; const http_request* http_req = parse_http_request(request, strlen((char *)request)); assert(http_req != nullptr); + assert(http_req->method == GET); + assert(http_req->version == HTTP_1_0); + assert(strncmp(http_req->url, "/", 1) == 0); + assert(http_req->headers_cnt == 3); + printf("Header 1: '%s': '%s'\n", http_req->headers[0]->name, http_req->headers[0]->value); + assert(strncmp(http_req->headers[0]->name , "Host", 255) == 0); + assert(strncmp(http_req->headers[0]->value, "localhost:8085", 255) == 0); + printf("Header 2: '%s': '%s'\n", http_req->headers[1]->name, http_req->headers[1]->value); + assert(strncmp(http_req->headers[1]->name, "User-Agent", 255) == 0); + assert(strncmp(http_req->headers[1]->value, "curl/8.7.1", 255) == 0); + printf("Header 3: '%s': '%s'\n", http_req->headers[2]->name, http_req->headers[2]->value); + assert(strncmp(http_req->headers[2]->name, "Accept", 255) == 0); + assert(strncmp(http_req->headers[2]->value, "*/*", 255) == 0); + assert(http_req->body == nullptr); + assert(http_req->body_len == 0); return EXIT_SUCCESS; }