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