/* * test_header_handling.c - Unit tests for header handling (truncation and limits) */ #include #include #include #include #include #include #include #include /* Mock header truncation function */ static char *truncate_header_value(apr_pool_t *pool, const char *value, int max_len) { if (value == NULL) { return NULL; } size_t len = strlen(value); if ((int)len > max_len) { return apr_pstrmemdup(pool, value, max_len); } return apr_pstrdup(pool, value); } /* Mock header matching function */ static int header_name_matches(const char *configured, const char *actual) { return strcasecmp(configured, actual) == 0; } /* Test: Header value within limit */ static void test_header_truncation_within_limit(void **state) { apr_pool_t *pool; apr_pool_create(&pool, NULL); const char *value = "short value"; char *result = truncate_header_value(pool, value, 256); assert_string_equal(result, "short value"); apr_pool_destroy(pool); } /* Test: Header value exactly at limit */ static void test_header_truncation_exact_limit(void **state) { apr_pool_t *pool; apr_pool_create(&pool, NULL); const char *value = "exactly10c"; char *result = truncate_header_value(pool, value, 10); assert_string_equal(result, "exactly10c"); apr_pool_destroy(pool); } /* Test: Header value exceeds limit */ static void test_header_truncation_exceeds_limit(void **state) { apr_pool_t *pool; apr_pool_create(&pool, NULL); const char *value = "this is a very long header value that should be truncated"; char *result = truncate_header_value(pool, value, 15); assert_string_equal(result, "this is a very "); assert_int_equal(strlen(result), 15); apr_pool_destroy(pool); } /* Test: Header value with limit of 1 */ static void test_header_truncation_limit_one(void **state) { apr_pool_t *pool; apr_pool_create(&pool, NULL); const char *value = "abc"; char *result = truncate_header_value(pool, value, 1); assert_string_equal(result, "a"); apr_pool_destroy(pool); } /* Test: NULL header value */ static void test_header_truncation_null(void **state) { apr_pool_t *pool; apr_pool_create(&pool, NULL); char *result = truncate_header_value(pool, NULL, 256); assert_null(result); apr_pool_destroy(pool); } /* Test: Empty header value */ static void test_header_truncation_empty(void **state) { apr_pool_t *pool; apr_pool_create(&pool, NULL); const char *value = ""; char *result = truncate_header_value(pool, value, 256); assert_string_equal(result, ""); apr_pool_destroy(pool); } /* Test: Header name matching (case-insensitive) */ static void test_header_name_matching_case_insensitive(void **state) { assert_true(header_name_matches("X-Request-Id", "x-request-id")); assert_true(header_name_matches("user-agent", "User-Agent")); assert_true(header_name_matches("HOST", "host")); } /* Test: Header name matching (different headers) */ static void test_header_name_matching_different(void **state) { assert_false(header_name_matches("X-Request-Id", "X-Trace-Id")); assert_false(header_name_matches("Host", "User-Agent")); } /* Test: Multiple headers with limit */ static void test_header_count_limit(void **state) { apr_pool_t *pool; apr_pool_create(&pool, NULL); /* Simulate configured headers */ const char *configured[] = {"X-Request-Id", "X-Trace-Id", "User-Agent", "Referer"}; int configured_count = 4; int max_headers = 2; /* Simulate present headers */ const char *present[] = {"X-Request-Id", "User-Agent", "Referer"}; int present_count = 3; int logged_count = 0; for (int i = 0; i < configured_count && logged_count < max_headers; i++) { for (int j = 0; j < present_count; j++) { if (header_name_matches(configured[i], present[j])) { logged_count++; break; } } } assert_int_equal(logged_count, 2); apr_pool_destroy(pool); } /* Test: Header value with special JSON characters */ static void test_header_value_json_special(void **state) { apr_pool_t *pool; apr_pool_create(&pool, NULL); const char *value = "test\"value\\with\tspecial"; char *truncated = truncate_header_value(pool, value, 256); /* Truncation should preserve the value */ assert_string_equal(truncated, "test\"value\\with\tspecial"); apr_pool_destroy(pool); } /* Test: Unicode in header value (UTF-8) */ static void test_header_value_unicode(void **state) { apr_pool_t *pool; apr_pool_create(&pool, NULL); const char *value = "Mozilla/5.0 (compatible; 日本語)"; char *result = truncate_header_value(pool, value, 50); /* Should be truncated but valid */ assert_non_null(result); assert_true(strlen(result) <= 50); apr_pool_destroy(pool); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_header_truncation_within_limit), cmocka_unit_test(test_header_truncation_exact_limit), cmocka_unit_test(test_header_truncation_exceeds_limit), cmocka_unit_test(test_header_truncation_limit_one), cmocka_unit_test(test_header_truncation_null), cmocka_unit_test(test_header_truncation_empty), cmocka_unit_test(test_header_name_matching_case_insensitive), cmocka_unit_test(test_header_name_matching_different), cmocka_unit_test(test_header_count_limit), cmocka_unit_test(test_header_value_json_special), cmocka_unit_test(test_header_value_unicode), }; return cmocka_run_group_tests(tests, NULL, NULL); }