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; }