#include "test_framework.h" #include "../src/types.h" #include "../src/http.h" #include void test_http_find_header_value(void) { TEST_SUITE_BEGIN("HTTP Find Header Value"); const char *headers = "Host: example.com\r\n" "Content-Type: application/json\r\n" "Content-Length: 42\r\n" "X-Custom-Header: custom-value\r\n" "Connection: keep-alive\r\n" "\r\n"; size_t len = strlen(headers); char value[256]; int found = http_find_header_value(headers, len, "Host", value, sizeof(value)); TEST_ASSERT_EQ(1, found, "Host header found"); TEST_ASSERT_STR_EQ("example.com", value, "Host value correct"); found = http_find_header_value(headers, len, "Content-Type", value, sizeof(value)); TEST_ASSERT_EQ(1, found, "Content-Type header found"); TEST_ASSERT_STR_EQ("application/json", value, "Content-Type value correct"); found = http_find_header_value(headers, len, "Content-Length", value, sizeof(value)); TEST_ASSERT_EQ(1, found, "Content-Length header found"); TEST_ASSERT_STR_EQ("42", value, "Content-Length value correct"); found = http_find_header_value(headers, len, "X-Custom-Header", value, sizeof(value)); TEST_ASSERT_EQ(1, found, "Custom header found"); TEST_ASSERT_STR_EQ("custom-value", value, "Custom header value correct"); found = http_find_header_value(headers, len, "Non-Existent", value, sizeof(value)); TEST_ASSERT_EQ(0, found, "Non-existent header not found"); found = http_find_header_value(headers, len, "host", value, sizeof(value)); TEST_ASSERT_EQ(1, found, "Case-insensitive header search works"); TEST_SUITE_END(); } void test_http_is_textual_content_type(void) { TEST_SUITE_BEGIN("HTTP Textual Content Type Detection"); TEST_ASSERT_EQ(1, http_is_textual_content_type("text/html"), "text/html is textual"); TEST_ASSERT_EQ(1, http_is_textual_content_type("text/plain"), "text/plain is textual"); TEST_ASSERT_EQ(1, http_is_textual_content_type("text/css"), "text/css is textual"); TEST_ASSERT_EQ(1, http_is_textual_content_type("text/javascript"), "text/javascript is textual"); TEST_ASSERT_EQ(1, http_is_textual_content_type("application/json"), "application/json is textual"); TEST_ASSERT_EQ(1, http_is_textual_content_type("application/javascript"), "application/javascript is textual"); TEST_ASSERT_EQ(1, http_is_textual_content_type("application/xml"), "application/xml is textual"); TEST_ASSERT_EQ(1, http_is_textual_content_type("application/xhtml+xml"), "application/xhtml+xml is textual"); TEST_ASSERT_EQ(0, http_is_textual_content_type("image/png"), "image/png is not textual"); TEST_ASSERT_EQ(0, http_is_textual_content_type("image/jpeg"), "image/jpeg is not textual"); TEST_ASSERT_EQ(0, http_is_textual_content_type("application/octet-stream"), "octet-stream is not textual"); TEST_ASSERT_EQ(0, http_is_textual_content_type("video/mp4"), "video/mp4 is not textual"); TEST_ASSERT_EQ(0, http_is_textual_content_type("audio/mpeg"), "audio/mpeg is not textual"); TEST_ASSERT_EQ(1, http_is_textual_content_type("text/html; charset=utf-8"), "text/html with charset is textual"); TEST_ASSERT_EQ(1, http_is_textual_content_type("application/json; charset=utf-8"), "json with charset is textual"); TEST_ASSERT_EQ(0, http_is_textual_content_type(NULL), "NULL is not textual"); TEST_SUITE_END(); } void test_http_detect_binary_content(void) { TEST_SUITE_BEGIN("HTTP Binary Content Detection"); const char *text_data = "Hello, World! This is plain text content."; TEST_ASSERT_EQ(0, http_detect_binary_content(text_data, strlen(text_data)), "Plain text is not binary"); const char *html_data = "

Hello

"; TEST_ASSERT_EQ(0, http_detect_binary_content(html_data, strlen(html_data)), "HTML is not binary"); const char *json_data = "{\"key\": \"value\", \"number\": 123}"; TEST_ASSERT_EQ(0, http_detect_binary_content(json_data, strlen(json_data)), "JSON is not binary"); const unsigned char binary_data[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; TEST_ASSERT_EQ(1, http_detect_binary_content((const char*)binary_data, sizeof(binary_data)), "PNG header is binary"); const unsigned char null_bytes[] = {'H', 'e', 'l', 'l', 'o', 0x00, 'W', 'o', 'r', 'l', 'd'}; TEST_ASSERT_EQ(1, http_detect_binary_content((const char*)null_bytes, sizeof(null_bytes)), "Data with null bytes is binary"); TEST_ASSERT_EQ(0, http_detect_binary_content(NULL, 0), "NULL data returns 0"); TEST_ASSERT_EQ(0, http_detect_binary_content("", 0), "Empty data returns 0"); TEST_SUITE_END(); } void test_http_get_content_length(void) { TEST_SUITE_BEGIN("HTTP Get Content-Length"); const char *headers1 = "HTTP/1.1 200 OK\r\nContent-Length: 1234\r\nContent-Type: text/html\r\n\r\n"; TEST_ASSERT_EQ(1234, http_get_content_length(headers1, strlen(headers1)), "Content-Length 1234 parsed"); const char *headers2 = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 0\r\n\r\n"; TEST_ASSERT_EQ(0, http_get_content_length(headers2, strlen(headers2)), "Content-Length 0 parsed"); const char *headers3 = "HTTP/1.1 200 OK\r\nContent-Length: 9999999\r\n\r\n"; TEST_ASSERT_EQ(9999999, http_get_content_length(headers3, strlen(headers3)), "Large Content-Length parsed"); const char *headers4 = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; TEST_ASSERT_EQ(-1, http_get_content_length(headers4, strlen(headers4)), "Missing Content-Length returns -1"); const char *headers5 = "HTTP/1.1 200 OK\r\ncontent-length: 500\r\n\r\n"; long len5 = http_get_content_length(headers5, strlen(headers5)); TEST_ASSERT(len5 == 500 || len5 == -1, "Lowercase content-length handled"); TEST_SUITE_END(); } void test_http_find_headers_end(void) { TEST_SUITE_BEGIN("HTTP Find Headers End"); const char *request1 = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\nBody content here"; size_t end1; int found1 = http_find_headers_end(request1, strlen(request1), &end1); TEST_ASSERT_EQ(1, found1, "Headers end found in complete request"); TEST_ASSERT(end1 > 0 && end1 < strlen(request1), "Headers end position is valid"); const char *request2 = "GET / HTTP/1.1\r\nHost: example.com\r\n"; size_t end2; int found2 = http_find_headers_end(request2, strlen(request2), &end2); TEST_ASSERT_EQ(0, found2, "Incomplete headers not found"); const char *request3 = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"; size_t end3; int found3 = http_find_headers_end(request3, strlen(request3), &end3); TEST_ASSERT_EQ(1, found3, "Headers end found with no body"); TEST_ASSERT_EQ(strlen(request3), end3, "Headers end at string end for no body"); TEST_SUITE_END(); } void test_http_rewrite_content_length(void) { TEST_SUITE_BEGIN("HTTP Rewrite Content-Length"); char headers1[512] = "HTTP/1.1 200 OK\r\nContent-Length: 100\r\nContent-Type: text/html\r\n\r\n"; size_t len1 = strlen(headers1); int result1 = http_rewrite_content_length(headers1, &len1, sizeof(headers1), 200); TEST_ASSERT_EQ(1, result1, "Content-Length rewrite succeeded"); TEST_ASSERT(strstr(headers1, "200") != NULL, "New length present in headers"); char headers2[512] = "HTTP/1.1 200 OK\r\nContent-Length: 99999\r\n\r\n"; size_t len2 = strlen(headers2); int result2 = http_rewrite_content_length(headers2, &len2, sizeof(headers2), 50); TEST_ASSERT_EQ(1, result2, "Content-Length rewrite to smaller succeeded"); char headers3[512] = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; size_t len3 = strlen(headers3); int result3 = http_rewrite_content_length(headers3, &len3, sizeof(headers3), 100); TEST_ASSERT_EQ(0, result3, "Rewrite fails when no Content-Length present"); TEST_SUITE_END(); } void test_http_find_header_line_bounds_edge_cases(void) { TEST_SUITE_BEGIN("HTTP Header Line Bounds Edge Cases"); const char *request1 = "GET / HTTP/1.1\r\nHost: example.com\r\nX-Test:no-space\r\n\r\n"; const char *start1, *end1; int found1 = http_find_header_line_bounds(request1, strlen(request1), "X-Test", &start1, &end1); TEST_ASSERT_EQ(1, found1, "Header without space after colon found"); const char *request2 = "GET / HTTP/1.1\r\nHost: lots-of-spaces \r\n\r\n"; const char *start2, *end2; int found2 = http_find_header_line_bounds(request2, strlen(request2), "Host", &start2, &end2); TEST_ASSERT_EQ(1, found2, "Header with extra spaces found"); const char *request3 = "GET / HTTP/1.1\r\nhost: lowercase.com\r\n\r\n"; const char *start3, *end3; int found3 = http_find_header_line_bounds(request3, strlen(request3), "Host", &start3, &end3); TEST_ASSERT_EQ(1, found3, "Lowercase header name found"); const char *request4 = "GET / HTTP/1.1\r\nHOST: UPPERCASE.COM\r\n\r\n"; const char *start4, *end4; int found4 = http_find_header_line_bounds(request4, strlen(request4), "host", &start4, &end4); TEST_ASSERT_EQ(1, found4, "Uppercase header with lowercase search found"); const char *request5 = "GET / HTTP/1.1\r\n\r\n"; const char *start5, *end5; int found5 = http_find_header_line_bounds(request5, strlen(request5), "Host", &start5, &end5); TEST_ASSERT_EQ(0, found5, "Header not found in request with no headers"); TEST_SUITE_END(); } void run_http_helper_tests(void) { test_http_find_header_value(); test_http_is_textual_content_type(); test_http_detect_binary_content(); test_http_get_content_length(); test_http_find_headers_end(); test_http_rewrite_content_length(); test_http_find_header_line_bounds_edge_cases(); }