From c8e03e3c3dcab7d61cb388b45518e00856b5ce06 Mon Sep 17 00:00:00 2001 From: retoor Date: Wed, 5 Nov 2025 11:08:18 +0100 Subject: [PATCH] feat: add http implementation test suite --- CHANGELOG.md | 8 ++ http.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 http.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 035fc62..1420462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ + +## Version 0.2.0 - 2025-11-05 + +Updated documentation files. This includes changes to the project's release notes and a header file. + +**Changes:** 2 files, 103 lines +**Languages:** C (93 lines), Markdown (10 lines) + ## Version 0.1.0 - 2025-11-05 Automated versioning and changelog updates are now available when you commit code. This simplifies release management and ensures accurate changelog entries. diff --git a/http.c b/http.c new file mode 100644 index 0000000..31e6137 --- /dev/null +++ b/http.c @@ -0,0 +1,286 @@ +// HTTP Implementation Test Suite +// Copyright (c) 2023 retoor +// Licensed under MIT License + +#include +#include +#include +#include +#include +#include "http.h" + +double get_current_time_in_milliseconds() { + struct timeval time_value; + gettimeofday(&time_value, NULL); + return (time_value.tv_sec * 1000.0) + (time_value.tv_usec / 1000.0); +} + +void print_response_preview(const char *response, size_t maximum_length) { + if (!response) { + printf("Response: NULL\n"); + return; + } + + size_t response_length = strlen(response); + printf("Response length: %zu bytes\n", response_length); + printf("First %zu chars: %.100s%s\n", + maximum_length, response, response_length > maximum_length ? "..." : ""); +} + +void test_https_get() { + printf("\n=== Testing HTTPS GET ===\n"); + + const char * const test_urls[] = { + "https://httpbin.org/get", + "https://jsonplaceholder.typicode.com/posts/1", + "https://api.github.com/repos/torvalds/linux", + "https://www.example.com/", + "https://httpbin.org/bytes/1024" + }; + + size_t number_of_tests = sizeof(test_urls) / sizeof(test_urls[0]); + + for (size_t index = 0; index < number_of_tests; index++) { + printf("\nTest %zu: GET %s\n", index + 1, test_urls[index]); + + double start_time = get_current_time_in_milliseconds(); + char *response = https_get((char *)test_urls[index]); + double end_time = get_current_time_in_milliseconds(); + + printf("Time taken: %.2f ms\n", end_time - start_time); + print_response_preview(response, 100); + + if (response) { + free(response); + printf("Status: SUCCESS\n"); + } else { + printf("Status: FAILED\n"); + } + } +} + +void test_https_post() { + printf("\n=== Testing HTTPS POST ===\n"); + + const char * const test_urls[] = { + "https://httpbin.org/post", + "https://jsonplaceholder.typicode.com/posts", + "https://httpbin.org/anything" + }; + + const char * const test_payloads[] = { + "{\"test\": \"data\", \"number\": 123}", + "{\"title\": \"foo\", \"body\": \"bar\", \"userId\": 1}", + "{\"key1\": \"value1\", \"key2\": [1, 2, 3], \"key3\": {\"nested\": true}}" + }; + + size_t number_of_tests = sizeof(test_urls) / sizeof(test_urls[0]); + + for (size_t index = 0; index < number_of_tests; index++) { + printf("\nTest %zu: POST %s\n", index + 1, test_urls[index]); + printf("Payload: %s\n", test_payloads[index]); + + double start_time = get_current_time_in_milliseconds(); + char *response = https_post((char *)test_urls[index], (char *)test_payloads[index]); + double end_time = get_current_time_in_milliseconds(); + + printf("Time taken: %.2f ms\n", end_time - start_time); + print_response_preview(response, 100); + + if (response) { + free(response); + printf("Status: SUCCESS\n"); + } else { + printf("Status: FAILED\n"); + } + } +} + +void test_http_get() { + printf("\n=== Testing HTTP GET ===\n"); + + const char * const test_urls[] = { + "http://httpbin.org/get", + "http://httpbin.org/headers", + "http://httpbin.org/user-agent" + }; + + size_t number_of_tests = sizeof(test_urls) / sizeof(test_urls[0]); + + for (size_t index = 0; index < number_of_tests; index++) { + printf("\nTest %zu: GET %s\n", index + 1, test_urls[index]); + + double start_time = get_current_time_in_milliseconds(); + char *response = http_get((char *)test_urls[index]); + double end_time = get_current_time_in_milliseconds(); + + printf("Time taken: %.2f ms\n", end_time - start_time); + print_response_preview(response, 100); + + if (response) { + free(response); + printf("Status: SUCCESS\n"); + } else { + printf("Status: FAILED\n"); + } + } +} + +void test_http_post() { + printf("\n=== Testing HTTP POST ===\n"); + + const char * const test_urls[] = { + "http://httpbin.org/post", + "http://httpbin.org/anything" + }; + + const char * const test_payloads[] = { + "{\"message\": \"Hello World\"}", + "{\"test\": true, \"count\": 42}" + }; + + size_t number_of_tests = sizeof(test_urls) / sizeof(test_urls[0]); + + for (size_t index = 0; index < number_of_tests; index++) { + printf("\nTest %zu: POST %s\n", index + 1, test_urls[index]); + printf("Payload: %s\n", test_payloads[index]); + + double start_time = get_current_time_in_milliseconds(); + char *response = http_post((char *)test_urls[index], (char *)test_payloads[index]); + double end_time = get_current_time_in_milliseconds(); + + printf("Time taken: %.2f ms\n", end_time - start_time); + print_response_preview(response, 100); + + if (response) { + free(response); + printf("Status: SUCCESS\n"); + } else { + printf("Status: FAILED\n"); + } + } +} + +void test_chunked_response() { + printf("\n=== Testing Chunked Transfer Encoding ===\n"); + + const char * const test_urls[] = { + "https://httpbin.org/stream/5", + "https://httpbin.org/drip?duration=2&numbytes=10&code=200", + "http://httpbin.org/stream-bytes/1024" + }; + + size_t number_of_tests = sizeof(test_urls) / sizeof(test_urls[0]); + + for (size_t index = 0; index < number_of_tests; index++) { + printf("\nTest %zu: GET %s\n", index + 1, test_urls[index]); + + double start_time = get_current_time_in_milliseconds(); + char *response = NULL; + + if (strncmp(test_urls[index], "https://", 8) == 0) { + response = https_get((char *)test_urls[index]); + } else { + response = http_get((char *)test_urls[index]); + } + + double end_time = get_current_time_in_milliseconds(); + + printf("Time taken: %.2f ms\n", end_time - start_time); + print_response_preview(response, 100); + + if (response) { + free(response); + printf("Status: SUCCESS\n"); + } else { + printf("Status: FAILED\n"); + } + } +} + +void benchmark_requests() { + printf("\n=== Benchmarking Performance ===\n"); + + const char * const benchmark_url = "https://httpbin.org/get"; + size_t number_of_requests = 10; + double total_time = 0.0; + size_t successful_requests = 0; + + printf("Benchmarking %zu requests to %s\n", number_of_requests, benchmark_url); + + for (size_t index = 0; index < number_of_requests; index++) { + double start_time = get_current_time_in_milliseconds(); + char *response = https_get((char *)benchmark_url); + double end_time = get_current_time_in_milliseconds(); + + double request_time = end_time - start_time; + total_time += request_time; + + if (response) { + successful_requests++; + free(response); + printf("Request %2zu: %.2f ms\n", index + 1, request_time); + } else { + printf("Request %2zu: FAILED\n", index + 1); + } + } + + printf("\nBenchmark Results:\n"); + printf("Total requests: %zu\n", number_of_requests); + printf("Successful: %zu\n", successful_requests); + printf("Failed: %zu\n", number_of_requests - successful_requests); + printf("Total time: %.2f ms\n", total_time); + printf("Average time per request: %.2f ms\n", total_time / number_of_requests); + printf("Success rate: %.1f%%\n", (successful_requests * 100.0) / number_of_requests); +} + +void test_large_response() { + printf("\n=== Testing Large Response Handling ===\n"); + + const char * const test_urls[] = { + "https://httpbin.org/bytes/10240", // 10 KB + "https://httpbin.org/bytes/102400", // 100 KB + "https://httpbin.org/base64/SFRUUEJJTiBpcyBhd2Vzb21l" // Base64 response + }; + + const char * const size_descriptions[] = {"10 KB", "100 KB", "Base64"}; + + size_t number_of_tests = sizeof(test_urls) / sizeof(test_urls[0]); + + for (size_t index = 0; index < number_of_tests; index++) { + printf("\nTest %zu: Large response (%s) from %s\n", index + 1, size_descriptions[index], test_urls[index]); + + double start_time = get_current_time_in_milliseconds(); + char *response = https_get((char *)test_urls[index]); + double end_time = get_current_time_in_milliseconds(); + + if (response) { + size_t response_length = strlen(response); + printf("Response size: %zu bytes\n", response_length); + printf("Time taken: %.2f ms\n", end_time - start_time); + printf("Transfer rate: %.2f KB/s\n", (response_length / 1024.0) / ((end_time - start_time) / 1000.0)); + free(response); + printf("Status: SUCCESS\n"); + } else { + printf("Status: FAILED\n"); + } + } +} + +int main(int argument_count, char *argument_values[]) { + printf("HTTP Implementation Test Suite\n"); + printf("==============================\n"); + + test_https_get(); + test_https_post(); + test_http_get(); + test_http_post(); + test_chunked_response(); + test_large_response(); + benchmark_requests(); + + printf("\n\nAll tests completed!\n"); + + return 0; +} +