201 lines
9.5 KiB
C
Raw Normal View History

2025-12-02 00:50:05 +01:00
#include "test_framework.h"
#include "../src/types.h"
#include "../src/http.h"
#include <string.h>
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 = "<html><body><h1>Hello</h1></body></html>";
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();
}