Skip to content

Commit 9408b37

Browse files
committed
Address review comments from bryancall
- CacheHosting.cc: restrict suffix skip loops to uppercase KMGT to match ink_atoi64's uppercase-only handling - RemapConfig.cc: use swoc::TextView to validate @Volume= segments (rejects empty, zero, out-of-range, trailing comma) - ReverseProxy.h/cc, HttpSM.cc: use std::atomic<UrlRewrite*> for rewrite_table to make atomic access explicit - cache_volume_features.replay.yaml: remove misleading @Volume=99 remap entry and its corresponding session test
1 parent a586613 commit 9408b37

7 files changed

Lines changed: 42 additions & 55 deletions

File tree

include/proxy/ReverseProxy.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
#pragma once
3434

35+
#include <atomic>
36+
3537
#include "records/RecProcess.h"
3638

3739
#include "tscore/ink_defs.h"
@@ -45,7 +47,7 @@
4547
class url_mapping;
4648
struct host_hdr_info;
4749

48-
extern UrlRewrite *rewrite_table;
50+
extern std::atomic<UrlRewrite *> rewrite_table;
4951

5052
// API Functions
5153
int init_reverse_proxy();

src/iocore/cache/CacheHosting.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ ConfigVolumes::BuildListFromString(char *config_file_path, char *file_buf)
754754
err = "Invalid avg_obj_size value (must be >= 0)";
755755
break;
756756
}
757-
while (*tmp && (ParseRules::is_digit(*tmp) || strchr("kmgtKMGT", *tmp))) {
757+
while (*tmp && (ParseRules::is_digit(*tmp) || strchr("KMGT", *tmp))) {
758758
tmp++;
759759
}
760760
} else if (strcasecmp(tmp, "fragment_size") == 0) { // match fragment_size
@@ -769,7 +769,7 @@ ConfigVolumes::BuildListFromString(char *config_file_path, char *file_buf)
769769
err = "Invalid fragment_size value (must be >= 0)";
770770
break;
771771
}
772-
while (*tmp && (ParseRules::is_digit(*tmp) || strchr("kmgtKMGT", *tmp))) {
772+
while (*tmp && (ParseRules::is_digit(*tmp) || strchr("KMGT", *tmp))) {
773773
tmp++;
774774
}
775775
} else if (strcasecmp(tmp, "ramcache") == 0) { // match ramcache
@@ -797,7 +797,7 @@ ConfigVolumes::BuildListFromString(char *config_file_path, char *file_buf)
797797
break;
798798
}
799799
// Note: ram_cache_size=0 disables RAM cache for this volume, same as ramcache=false
800-
while (*tmp && (ParseRules::is_digit(*tmp) || strchr("kmgtKMGT", *tmp))) {
800+
while (*tmp && (ParseRules::is_digit(*tmp) || strchr("KMGT", *tmp))) {
801801
tmp++;
802802
}
803803
} else if (strcasecmp(tmp, "ram_cache_cutoff") == 0) { // match ram_cache_cutoff
@@ -812,7 +812,7 @@ ConfigVolumes::BuildListFromString(char *config_file_path, char *file_buf)
812812
err = "Invalid ram_cache_cutoff value (must be >= 0)";
813813
break;
814814
}
815-
while (*tmp && (ParseRules::is_digit(*tmp) || strchr("kmgtKMGT", *tmp))) {
815+
while (*tmp && (ParseRules::is_digit(*tmp) || strchr("KMGT", *tmp))) {
816816
tmp++;
817817
}
818818
}

src/proxy/ReverseProxy.cc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ DbgCtl dbg_ctl_url_rewrite{"url_rewrite"};
5050
} // end anonymous namespace
5151

5252
// Global Ptrs
53-
UrlRewrite *rewrite_table = nullptr;
53+
std::atomic<UrlRewrite *> rewrite_table = nullptr;
5454
thread_local PluginThreadContext *pluginThreadContext = nullptr;
5555

5656
// Tokens for the Callback function
@@ -67,13 +67,13 @@ thread_local PluginThreadContext *pluginThreadContext = nullptr;
6767
int
6868
init_reverse_proxy()
6969
{
70-
ink_assert(rewrite_table == nullptr);
70+
ink_assert(rewrite_table.load() == nullptr);
7171
reconfig_mutex = new_ProxyMutex();
72-
rewrite_table = new UrlRewrite();
72+
rewrite_table.store(new UrlRewrite());
7373

74-
rewrite_table->acquire();
74+
rewrite_table.load()->acquire();
7575
Note("%s loading ...", ts::filename::REMAP);
76-
if (!rewrite_table->load()) {
76+
if (!rewrite_table.load()->load()) {
7777
Emergency("%s failed to load", ts::filename::REMAP);
7878
} else {
7979
Note("%s finished loading", ts::filename::REMAP);
@@ -147,7 +147,7 @@ reloadUrlRewrite()
147147
newTable->acquire();
148148

149149
// Swap configurations
150-
oldTable = ink_atomic_swap(&rewrite_table, newTable);
150+
oldTable = rewrite_table.exchange(newTable);
151151

152152
ink_assert(oldTable != nullptr);
153153

@@ -206,7 +206,7 @@ init_store_volume_host_records(UrlRewrite::MappingsStore &store)
206206
void
207207
init_remap_volume_host_records()
208208
{
209-
UrlRewrite *table = rewrite_table;
209+
UrlRewrite *table = rewrite_table.load(std::memory_order_acquire);
210210

211211
if (!table) {
212212
return;
@@ -233,7 +233,7 @@ url_rewrite_CB(const char * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNU
233233

234234
switch (my_token) {
235235
case REVERSE_CHANGED:
236-
rewrite_table->SetReverseFlag(data.rec_int);
236+
rewrite_table.load()->SetReverseFlag(data.rec_int);
237237
break;
238238

239239
case TSNAME_CHANGED:

src/proxy/http/HttpSM.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ HttpSM::init(bool from_early_data)
332332

333333
t_state.http_config_param = HttpConfig::acquire();
334334
// Acquire a lease on the global remap / rewrite table (stupid global name ...)
335-
m_remap = rewrite_table->acquire();
335+
m_remap = rewrite_table.load()->acquire();
336336

337337
// Simply point to the global config for the time being, no need to copy this
338338
// entire struct if nothing is going to change it.

src/proxy/http/remap/RemapConfig.cc

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,12 +1228,31 @@ remap_parse_config_bti(const char *path, BUILD_TABLE_INFO *bti)
12281228
goto MAP_ERROR;
12291229
}
12301230

1231-
for (const char *p = volume_str; *p; p++) {
1232-
if (*p != ',' && (*p < '0' || *p > '9')) {
1233-
snprintf(errStrBuf, sizeof(errStrBuf), "Invalid character '%c' in @volume=%s at line %d", *p, volume_str, cln + 1);
1231+
{
1232+
swoc::TextView vol_list{volume_str};
1233+
1234+
if (vol_list.back() == ',') {
1235+
snprintf(errStrBuf, sizeof(errStrBuf), "Invalid @volume=%s at line %d (trailing comma)", volume_str, cln + 1);
12341236
errStr = errStrBuf;
12351237
goto MAP_ERROR;
12361238
}
1239+
while (!vol_list.empty()) {
1240+
swoc::TextView span;
1241+
swoc::TextView token{vol_list.take_prefix_at(',')};
1242+
auto n = swoc::svtoi(token, &span);
1243+
1244+
if (span.size() != token.size() || token.empty()) {
1245+
snprintf(errStrBuf, sizeof(errStrBuf), "Invalid @volume=%s at line %d (expected comma-separated numbers 1-255)",
1246+
volume_str, cln + 1);
1247+
errStr = errStrBuf;
1248+
goto MAP_ERROR;
1249+
} else if (n < 1 || n > 255) {
1250+
snprintf(errStrBuf, sizeof(errStrBuf), "Volume number %jd out of range (1-255) in @volume=%s at line %d", n,
1251+
volume_str, cln + 1);
1252+
errStr = errStrBuf;
1253+
goto MAP_ERROR;
1254+
}
1255+
}
12371256
}
12381257

12391258
// Check if cache is ready (will be true during config reload, possibly false during initial startup)

tests/gold_tests/cache/cache_volume_features.replay.yaml

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,6 @@ autest:
7878
options:
7979
- "@volume=2"
8080

81-
# Invalid volume selection (should fallback)
82-
- from: "http://invalid.example.com/"
83-
to: "http://backend.ex:{SERVER_HTTP_PORT}/"
84-
options:
85-
- "@volume=99"
86-
8781
# Proxy verifier test sessions
8882
sessions:
8983
# Test 1: Volume selection via @volume=1
@@ -144,36 +138,7 @@ sessions:
144138
fields:
145139
- [X-Volume-Test, { value: "2", as: equal }]
146140

147-
# Test 3: Invalid volume selection (should fallback to default)
148-
- transactions:
149-
- client-request:
150-
method: "GET"
151-
version: "1.1"
152-
url: "/test_invalid"
153-
headers:
154-
fields:
155-
- [Host, invalid.example.com]
156-
- [X-Test-ID, "invalid-volume-test"]
157-
- [uuid, 3]
158-
159-
server-response:
160-
status: 200
161-
reason: OK
162-
headers:
163-
fields:
164-
- [Content-Type, "text/plain"]
165-
- [Cache-Control, "max-age=3600"]
166-
- [X-Volume-Test, "fallback"]
167-
content:
168-
data: "Content for invalid volume (fallback)"
169-
170-
proxy-response:
171-
status: 200
172-
headers:
173-
fields:
174-
- [X-Volume-Test, { value: "fallback", as: equal }]
175-
176-
# Test 4: Default volume selection (no @volume=)
141+
# Test 3: Default volume selection (no @volume=)
177142
- transactions:
178143
- client-request:
179144
method: "GET"
@@ -202,7 +167,7 @@ sessions:
202167
fields:
203168
- [X-Volume-Test, { value: "default", as: equal }]
204169

205-
# Test 5: Cache hit test (verify caching works)
170+
# Test 4: Cache hit test (verify caching works)
206171
- transactions:
207172
- client-request:
208173
method: "GET"
@@ -231,7 +196,7 @@ sessions:
231196
fields:
232197
- [X-Origin-Response, { value: "yes", as: equal }]
233198

234-
# Test 6: Second request for cached content (should be cache hit)
199+
# Test 5: Second request for cached content (should be cache hit)
235200
- transactions:
236201
- client-request:
237202
method: "GET"

tests/gold_tests/cache/cache_volume_features.test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@
2020
- @volume= directive in remap.config for volume selection
2121
- Integration between both features
2222
'''
23+
# TODO: hosting.config + @volume= priority interaction test requires ats_replay.test.ext to support volume_config/hosting_config.
2324

2425
Test.ATSReplayTest(replay_file="cache_volume_features.replay.yaml")

0 commit comments

Comments
 (0)