|
| 1 | +/** |
| 2 | + * Tempesta FW |
| 3 | + * |
| 4 | + * Test for proper cache key calculation when using vhosts and HTTP chains. |
| 5 | + * |
| 6 | + * Copyright (C) 2023-2025 Tempesta Technologies, Inc. |
| 7 | + * |
| 8 | + * This program is free software; you can redistribute it and/or modify it |
| 9 | + * under the terms of the GNU General Public License as published by |
| 10 | + * the Free Software Foundation; either version 2 of the License, |
| 11 | + * or (at your option) any later version. |
| 12 | + * |
| 13 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 14 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 15 | + * FITNESS FOR A PARTICULAR PURPOSE. |
| 16 | + * See the GNU General Public License for more details. |
| 17 | + * |
| 18 | + * You should have received a copy of the GNU General Public License along with |
| 19 | + * this program; if not, write to the Free Software Foundation, Inc., 59 |
| 20 | + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 21 | + */ |
| 22 | + |
| 23 | +#include "helpers.h" |
| 24 | +#include "http.h" |
| 25 | +#include "test.h" |
| 26 | +#include "vhost.h" |
| 27 | + |
| 28 | +/** |
| 29 | + * Test that cache key calculation correctly uses vhost name instead of host header. |
| 30 | + */ |
| 31 | +TEST(http_cache_key, uses_vhost_not_host) |
| 32 | +{ |
| 33 | + TfwHttpReq *req; |
| 34 | + unsigned long key1, key2; |
| 35 | + TfwVhost vhost1, vhost2; |
| 36 | + BasicStr vhost1_name = { .data = "app1.example.com", .len = 15 }; |
| 37 | + BasicStr vhost2_name = { .data = "app2.example.com", .len = 15 }; |
| 38 | + |
| 39 | + /* Create request with Host header */ |
| 40 | + req = test_req_alloc(1); |
| 41 | + EXPECT_NOT_NULL(req); |
| 42 | + if (!req) |
| 43 | + return; |
| 44 | + |
| 45 | + /* Initialize test vhosts */ |
| 46 | + memset(&vhost1, 0, sizeof(vhost1)); |
| 47 | + memset(&vhost2, 0, sizeof(vhost2)); |
| 48 | + vhost1.name = vhost1_name; |
| 49 | + vhost2.name = vhost2_name; |
| 50 | + |
| 51 | + /* Set the Host header to a specific value */ |
| 52 | + TfwStr host = { |
| 53 | + .data = (void *)"same.host.example.com", |
| 54 | + .len = 19 |
| 55 | + }; |
| 56 | + req->host = host; |
| 57 | + |
| 58 | + /* Set a URI path */ |
| 59 | + TfwStr uri_path = { |
| 60 | + .data = (void *)"/test/path", |
| 61 | + .len = 10 |
| 62 | + }; |
| 63 | + req->uri_path = uri_path; |
| 64 | + |
| 65 | + /* Calculate cache key with first vhost */ |
| 66 | + req->vhost = &vhost1; |
| 67 | + req->hash = 0; /* Clear cached hash */ |
| 68 | + key1 = tfw_http_req_key_calc(req); |
| 69 | + |
| 70 | + /* Now change to second vhost, same Host header */ |
| 71 | + req->vhost = &vhost2; |
| 72 | + req->hash = 0; /* Clear cached hash */ |
| 73 | + key2 = tfw_http_req_key_calc(req); |
| 74 | + |
| 75 | + /* Keys should be different because vhost names are different */ |
| 76 | + EXPECT_NE(key1, key2); |
| 77 | + |
| 78 | + //test_req_free(req); // TODO: kernel stuck here, why? |
| 79 | +} |
| 80 | + |
| 81 | +/** |
| 82 | + * Test that the cache key is the same even if the Host header changes |
| 83 | + * but the vhost remains the same (which is what happens with HTTP chains) |
| 84 | + */ |
| 85 | +TEST(http_cache_key, stable_with_http_chains) |
| 86 | +{ |
| 87 | + TfwHttpReq *req; |
| 88 | + unsigned long key1, key2; |
| 89 | + TfwVhost vhost; |
| 90 | + BasicStr vhost_name = { .data = "app2.example.com", .len = 15 }; |
| 91 | + |
| 92 | + /* Create request with Host header */ |
| 93 | + req = test_req_alloc(1); |
| 94 | + EXPECT_NOT_NULL(req); |
| 95 | + if (!req) |
| 96 | + return; |
| 97 | + |
| 98 | + /* Initialize test vhost */ |
| 99 | + memset(&vhost, 0, sizeof(vhost)); |
| 100 | + vhost.name = vhost_name; |
| 101 | + |
| 102 | + /* Set a URI path */ |
| 103 | + TfwStr uri_path = { |
| 104 | + .data = (void *)"/test/path", |
| 105 | + .len = 10 |
| 106 | + }; |
| 107 | + req->uri_path = uri_path; |
| 108 | + |
| 109 | + /* Set the first Host header */ |
| 110 | + TfwStr host1 = { |
| 111 | + .data = (void *)"app1.example.com", |
| 112 | + .len = 15 |
| 113 | + }; |
| 114 | + req->host = host1; |
| 115 | + |
| 116 | + /* Set vhost to "app2" (as would happen with HTTP chains) */ |
| 117 | + req->vhost = &vhost; |
| 118 | + req->hash = 0; /* Clear cached hash */ |
| 119 | + key1 = tfw_http_req_key_calc(req); |
| 120 | + |
| 121 | + /* Change Host header but keep same vhost */ |
| 122 | + TfwStr host2 = { |
| 123 | + .data = (void *)"app3.example.com", |
| 124 | + .len = 15 |
| 125 | + }; |
| 126 | + req->host = host2; |
| 127 | + req->hash = 0; /* Clear cached hash */ |
| 128 | + key2 = tfw_http_req_key_calc(req); |
| 129 | + |
| 130 | + /* Keys should be the same because vhost name is the same */ |
| 131 | + EXPECT_EQ(key1, key2); |
| 132 | + |
| 133 | + //test_req_free(req); // TODO: kernel stuck here, why? |
| 134 | +} |
| 135 | + |
| 136 | +/** |
| 137 | + * Test fallback to host header when vhost is NULL |
| 138 | + */ |
| 139 | +TEST(http_cache_key, fallback_to_host) |
| 140 | +{ |
| 141 | + TfwHttpReq *req; |
| 142 | + unsigned long key1, key2; |
| 143 | + |
| 144 | + /* Create request with Host header */ |
| 145 | + req = test_req_alloc(1); |
| 146 | + EXPECT_NOT_NULL(req); |
| 147 | + if (!req) |
| 148 | + return; |
| 149 | + |
| 150 | + /* Set a URI path */ |
| 151 | + TfwStr uri_path = { |
| 152 | + .data = (void *)"/test/path", |
| 153 | + .len = 10 |
| 154 | + }; |
| 155 | + req->uri_path = uri_path; |
| 156 | + |
| 157 | + /* Set the first Host header */ |
| 158 | + TfwStr host1 = { |
| 159 | + .data = (void *)"app1.example.com", |
| 160 | + .len = 15 |
| 161 | + }; |
| 162 | + req->host = host1; |
| 163 | + |
| 164 | + /* No vhost */ |
| 165 | + req->vhost = NULL; |
| 166 | + req->hash = 0; /* Clear cached hash */ |
| 167 | + key1 = tfw_http_req_key_calc(req); |
| 168 | + |
| 169 | + /* Change Host header, still no vhost */ |
| 170 | + TfwStr host2 = { |
| 171 | + .data = (void *)"app2.example.com", |
| 172 | + .len = 15 |
| 173 | + }; |
| 174 | + req->host = host2; |
| 175 | + req->hash = 0; /* Clear cached hash */ |
| 176 | + key2 = tfw_http_req_key_calc(req); |
| 177 | + |
| 178 | + /* Keys should be different because host headers are different */ |
| 179 | + EXPECT_NE(key1, key2); |
| 180 | + |
| 181 | + //test_req_free(req); // TODO: kernel stuck here, why? |
| 182 | +} |
| 183 | + |
| 184 | +/** |
| 185 | + * Test health monitoring requests are handled correctly |
| 186 | + */ |
| 187 | +TEST(http_cache_key, health_monitor) |
| 188 | +{ |
| 189 | + TfwHttpReq *req; |
| 190 | + unsigned long key1, key2; |
| 191 | + TfwVhost vhost; |
| 192 | + BasicStr vhost_name = { .data = "app2.example.com", .len = 15 }; |
| 193 | + |
| 194 | + /* Create request with Host header */ |
| 195 | + req = test_req_alloc(1); |
| 196 | + EXPECT_NOT_NULL(req); |
| 197 | + if (!req) |
| 198 | + return; |
| 199 | + |
| 200 | + /* Initialize test vhost */ |
| 201 | + memset(&vhost, 0, sizeof(vhost)); |
| 202 | + vhost.name = vhost_name; |
| 203 | + |
| 204 | + /* Set the Host header and URI */ |
| 205 | + TfwStr host = { |
| 206 | + .data = (void *)"app1.example.com", |
| 207 | + .len = 15 |
| 208 | + }; |
| 209 | + req->host = host; |
| 210 | + |
| 211 | + TfwStr uri_path = { |
| 212 | + .data = (void *)"/health", |
| 213 | + .len = 7 |
| 214 | + }; |
| 215 | + req->uri_path = uri_path; |
| 216 | + |
| 217 | + /* Set health monitor flag */ |
| 218 | + __set_bit(TFW_HTTP_B_HMONITOR, req->flags); |
| 219 | + |
| 220 | + /* Compute key with vhost */ |
| 221 | + req->vhost = &vhost; |
| 222 | + req->hash = 0; |
| 223 | + key1 = tfw_http_req_key_calc(req); |
| 224 | + |
| 225 | + /* Compute key without vhost */ |
| 226 | + req->vhost = NULL; |
| 227 | + req->hash = 0; |
| 228 | + key2 = tfw_http_req_key_calc(req); |
| 229 | + |
| 230 | + /* Keys should be the same since only uri_path is used for HM requests */ |
| 231 | + EXPECT_EQ(key1, key2); |
| 232 | + |
| 233 | + //test_req_free(req); // TODO: kernel stuck here, why? |
| 234 | +} |
| 235 | + |
| 236 | +TEST_SUITE(http_cache_key) |
| 237 | +{ |
| 238 | + printk(KERN_INFO "TEST_DEBUG: Starting http_cache_key test suite\n"); |
| 239 | + TEST_RUN(http_cache_key, uses_vhost_not_host); |
| 240 | + TEST_RUN(http_cache_key, stable_with_http_chains); |
| 241 | + TEST_RUN(http_cache_key, fallback_to_host); |
| 242 | + TEST_RUN(http_cache_key, health_monitor); |
| 243 | + printk(KERN_INFO "TEST_DEBUG: http_cache_key test suite completed\n"); |
| 244 | +} |
0 commit comments