|
// HTTP Implementation Test Suite
|
|
// Copyright (c) 2023 retoor
|
|
// Licensed under MIT License
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#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;
|
|
}
|
|
|