Skip to content

Commit 50f3f95

Browse files
fix(router): harden policy store file handling
1 parent aba47b8 commit 50f3f95

3 files changed

Lines changed: 25 additions & 1 deletion

File tree

src/cpp/include/lemon/routing_policy_store.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class RoutingPolicyStore {
4343
ClassifierServices services_;
4444
RoutingPolicyParseOptions parse_options_;
4545
std::unique_ptr<DirectoryWatcher> watcher_;
46+
// TODO(C++20): replace std::atomic_load/store free functions with a
47+
// std::atomic<std::shared_ptr<const Snapshot>> member (deprecated in C++20).
4648
std::shared_ptr<const Snapshot> snapshot_;
4749
};
4850

src/cpp/server/routing_policy_store.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
#include "lemon/model_types.h"
44
#include "lemon/utils/aixlog.hpp"
55

6+
#include <algorithm>
67
#include <atomic>
8+
#include <cctype>
79
#include <filesystem>
810
#include <fstream>
911
#include <set>
@@ -16,7 +18,10 @@ namespace fs = std::filesystem;
1618
namespace {
1719

1820
bool is_json_file(const fs::path& path) {
19-
return path.has_extension() && path.extension() == ".json";
21+
std::string extension = path.extension().string();
22+
std::transform(extension.begin(), extension.end(), extension.begin(),
23+
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
24+
return extension == ".json";
2025
}
2126

2227
json load_json_file(const fs::path& path) {

test/cpp/test_routing_policy_store.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,22 @@ static void test_invalid_policy_reports_error() {
141141
fs::remove_all(dir);
142142
}
143143

144+
static void test_uppercase_json_extension_loads_policy() {
145+
fs::path dir = make_temp_dir();
146+
fs::path policy_path = dir / "router.JSON";
147+
json doc = load_fixture("l1_keywords.json");
148+
write_json(policy_path, doc);
149+
150+
lemon::testing::FakeClassifierServices fake;
151+
RoutingPolicyStore store(dir.string(), fake.make());
152+
auto snapshot = store.reload();
153+
154+
check("uppercase .JSON policy file extension is accepted",
155+
snapshot->engines.count("user.Router-Keywords") == 1);
156+
157+
fs::remove_all(dir);
158+
}
159+
144160
static void test_duplicate_policy_model_names_report_errors() {
145161
fs::path dir = make_temp_dir();
146162
json doc = load_fixture("l1_keywords.json");
@@ -165,6 +181,7 @@ int main() {
165181
test_reload_swaps_snapshot();
166182
test_directory_watcher_reload();
167183
test_invalid_policy_reports_error();
184+
test_uppercase_json_extension_loads_policy();
168185
test_duplicate_policy_model_names_report_errors();
169186

170187
if (g_failures == 0) {

0 commit comments

Comments
 (0)