#include static bool bytes_equal(const char* a, const char* b, int len) { for (int i = 0; i < len; ++i) if (a[i] != b[i]) return false; return true; } static int test_content_length() { char raw[] = "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain\r\n" "Content-Length: 5\r\n\r\n" "helloignored"; http::Response response = {}; if (http::parse_response(raw, sizeof(raw) - 1, &response) != 200) return 1; if (response.error != http::Error::NONE || response.body_len != 5) return 2; if (!bytes_equal(response.body, "hello", 5)) return 3; char type[32]; if (!http::get_header(&response, "content-type", type, sizeof(type))) return 4; if (!bytes_equal(type, "text/plain", 10) || type[10] != '\0') return 5; return 0; } static int test_chunked() { char raw[] = "HTTP/1.1 200 OK\r\n" "Transfer-Encoding: Chunked\r\n\r\n" "4\r\nWiki\r\n5;extension=yes\r\npedia\r\n0\r\nX-Trailer: yes\r\n\r\n"; http::Response response = {}; if (http::parse_response(raw, sizeof(raw) - 1, &response) != 200) return 1; if (response.error != http::Error::NONE || response.body_len != 9) return 2; if (!bytes_equal(response.body, "Wikipedia", 9)) return 3; return 0; } static int test_informational() { char raw[] = "HTTP/1.1 100 Continue\r\nHeader: value\r\n\r\n" "HTTP/1.1 201 Created\r\nContent-Length: 2\r\n\r\nok"; http::Response response = {}; if (http::parse_response(raw, sizeof(raw) - 1, &response) != 201) return 1; if (response.status != 201 || response.body_len != 2) return 2; if (!bytes_equal(response.body, "ok", 2)) return 3; return 0; } static int test_rejections() { char truncated[] = "HTTP/1.1 200 OK\r\nContent-Length: 8\r\n\r\nshort"; http::Response response = {}; if (http::parse_response(truncated, sizeof(truncated) - 1, &response) != 200) return 1; if (response.error != http::Error::TRUNCATED_RESPONSE) return 2; char malformed[] = "not http\r\n\r\n"; response = {}; if (http::parse_response(malformed, sizeof(malformed) - 1, &response) >= 0) return 3; if (response.error != http::Error::INVALID_RESPONSE) return 4; char request[128]; if (http::build_request(request, sizeof(request), "GET", "safe\r\nInjected: yes", "/", nullptr, nullptr, 0, nullptr) >= 0) return 5; if (http::build_request(request, 16, "GET", "example.com", "/", nullptr, nullptr, 0, nullptr) >= 0) return 6; char bad_chunk[] = "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n"; response = {}; http::parse_response(bad_chunk, sizeof(bad_chunk) - 1, &response); if (response.error != http::Error::TRUNCATED_RESPONSE) return 7; if (http::build_request(request, sizeof(request), "GET", "example.com", "/", nullptr, nullptr, 0, "Safe: yes\r\n\r\nGET /evil") >= 0) return 8; return 0; } int main() { int result = test_content_length(); if (result) return 10 + result; result = test_chunked(); if (result) return 20 + result; result = test_informational(); if (result) return 30 + result; result = test_rejections(); if (result) return 40 + result; return 0; }