aboutsummaryrefslogtreecommitdiff
path: root/zenserver/cache/structuredcache.cpp
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2022-05-16 15:55:07 +0200
committerDan Engelbrecht <[email protected]>2022-05-16 15:55:07 +0200
commitc442837aff6212c711e959a44fba7c070bcdcaf1 (patch)
tree15e133a9f256ce9b9d92096acdb1d999954c0908 /zenserver/cache/structuredcache.cpp
parentuse ns_ prefix on disk only (diff)
downloadzen-c442837aff6212c711e959a44fba7c070bcdcaf1.tar.xz
zen-c442837aff6212c711e959a44fba7c070bcdcaf1.zip
drop api/v2 prefix for non-legacy requests
Diffstat (limited to 'zenserver/cache/structuredcache.cpp')
-rw-r--r--zenserver/cache/structuredcache.cpp284
1 files changed, 172 insertions, 112 deletions
diff --git a/zenserver/cache/structuredcache.cpp b/zenserver/cache/structuredcache.cpp
index 6d3211c0b..b6b5b218e 100644
--- a/zenserver/cache/structuredcache.cpp
+++ b/zenserver/cache/structuredcache.cpp
@@ -87,127 +87,188 @@ namespace {
std::optional<IoHash> ValueContentId;
};
- bool IsValidNamespaceName(std::string_view Name)
+ const char* ValidNameCharacters = "abcdefghijklmnopqrstuvwxyz0123456789-_.ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ std::optional<std::string> GetValidNamespaceName(std::string_view Name)
{
- if (Name == ZenCacheStore::DefaultNamespace)
- {
- return true;
- }
if (Name.empty())
{
- return false;
+ return {};
}
if (Name.length() > 64)
{
- return false;
+ return {};
}
- return Name.find_first_not_of("abcdefghijklmnopqrstuvwxyz0123456789-_.") == std::string::npos;
- }
- bool IsValidBucketName(std::string_view Name)
- {
- if (Name.empty())
+ if (Name.find_first_not_of(ValidNameCharacters) != std::string::npos)
{
- return false;
+ return {};
}
- return std::all_of(begin(Name), end(Name), [](const char c) { return std::isalnum(c); });
+ return ToLower(Name);
}
- bool HttpRequestParseRelativeUri(std::string_view Key, HttpRequestData& Data)
+ std::optional<std::string> GetValidBucketName(std::string_view Name)
{
- if (Key.starts_with(HttpZCacheAPIV2Prefix))
+ if (Name.empty())
{
- Key = Key.substr(HttpZCacheAPIV2Prefix.length());
- // Namespace reference
- std::string_view::size_type NamespaceSplitOffset = Key.find_first_of('/');
-
- std::string Namespace = ToLower(Key.substr(0, NamespaceSplitOffset));
- if (!IsValidNamespaceName(Namespace))
- {
- return false;
- }
-
- Data.Namespace = Namespace;
-
- if (NamespaceSplitOffset == std::string_view::npos)
- {
- return true;
- }
- Key = Key.substr(NamespaceSplitOffset + 1);
+ return {};
}
- else
+ if (Name.find_first_not_of(ValidNameCharacters) != std::string::npos)
{
- Data.Namespace = ZenCacheStore::DefaultNamespace;
+ return {};
}
+ return ToLower(Name);
+ }
- std::string_view::size_type BucketSplitOffset = Key.find_first_of('/');
- std::string Bucket = ToLower(Key.substr(0, BucketSplitOffset));
- if (!IsValidBucketName(Bucket))
+ std::optional<IoHash> GetValidIoHash(std::string_view Hash)
+ {
+ if (Hash.length() != IoHash::StringLength)
{
- return false;
+ return {};
}
- Data.Bucket = Bucket;
- if (BucketSplitOffset == std::string_view::npos)
+ IoHash KeyHash;
+ if (!ParseHexBytes(Hash.data(), Hash.size(), KeyHash.Hash))
{
- // Bucket reference
- return true;
+ return {};
}
+ return KeyHash;
+ }
- std::string_view HashSegment;
- std::string_view ValueSegment;
+ bool HttpRequestParseRelativeUri(std::string_view Key, HttpRequestData& Data)
+ {
+ std::vector<std::string_view> Tokens;
+ uint32_t TokenCount = zen::ForEachStrTok(Key, '/', [&](const std::string_view& Token) {
+ Tokens.push_back(Token);
+ return true;
+ });
- std::string_view::size_type ValueSplitOffset = Key.find_last_of('/');
- if (ValueSplitOffset == BucketSplitOffset)
- {
- // Basic cache record lookup
- HashSegment = Key.substr(BucketSplitOffset + 1);
- }
- else
+ switch (TokenCount)
{
- // Cache record + valueid lookup
- HashSegment = Key.substr(BucketSplitOffset + 1, ValueSplitOffset - BucketSplitOffset - 1);
- ValueSegment = Key.substr(ValueSplitOffset + 1);
- }
+ case 1:
+ Data.Namespace = GetValidNamespaceName(Tokens[0]);
+ return Data.Namespace.has_value();
+ case 2:
+ {
+ std::optional<IoHash> PossibleHashKey = GetValidIoHash(Tokens[1]);
+ if (PossibleHashKey.has_value())
+ {
+ // Legacy bucket/key request
+ Data.Bucket = GetValidBucketName(Tokens[0]);
+ if (!Data.Bucket.has_value())
+ {
+ return false;
+ }
+ Data.HashKey = PossibleHashKey;
+ Data.Namespace = ZenCacheStore::DefaultNamespace;
+ return true;
+ }
+ Data.Namespace = GetValidNamespaceName(Tokens[0]);
+ if (!Data.Namespace.has_value())
+ {
+ return false;
+ }
+ Data.Bucket = GetValidBucketName(Tokens[1]);
+ if (!Data.Bucket.has_value())
+ {
+ return false;
+ }
+ return true;
+ }
+ case 3:
+ {
+ std::optional<IoHash> PossibleHashKey = GetValidIoHash(Tokens[1]);
+ if (PossibleHashKey.has_value())
+ {
+ // Legacy bucket/key/valueid request
+ Data.Bucket = GetValidBucketName(Tokens[0]);
+ if (!Data.Bucket.has_value())
+ {
+ return false;
+ }
+ Data.HashKey = PossibleHashKey;
+ Data.ValueContentId = GetValidIoHash(Tokens[2]);
+ if (!Data.ValueContentId.has_value())
+ {
+ return false;
+ }
+ Data.Namespace = ZenCacheStore::DefaultNamespace;
+ return true;
+ }
+ Data.Namespace = GetValidNamespaceName(Tokens[0]);
+ if (!Data.Namespace.has_value())
+ {
+ return false;
+ }
+ Data.Bucket = GetValidBucketName(Tokens[1]);
+ if (!Data.Bucket.has_value())
+ {
+ return false;
+ }
+ Data.HashKey = GetValidIoHash(Tokens[2]);
+ if (!Data.HashKey)
+ {
+ return false;
+ }
+ return true;
+ }
+ case 4:
+ {
+ Data.Namespace = GetValidNamespaceName(Tokens[0]);
+ if (!Data.Namespace.has_value())
+ {
+ return false;
+ }
- if (HashSegment.size() != IoHash::StringLength)
- {
- return false;
- }
+ Data.Bucket = GetValidBucketName(Tokens[1]);
+ if (!Data.Bucket.has_value())
+ {
+ return false;
+ }
- IoHash KeyHash;
- if (!ParseHexBytes(HashSegment.data(), HashSegment.size(), KeyHash.Hash))
- {
- return false;
- }
+ Data.HashKey = GetValidIoHash(Tokens[2]);
+ if (!Data.HashKey.has_value())
+ {
+ return false;
+ }
- Data.HashKey = KeyHash;
+ Data.ValueContentId = GetValidIoHash(Tokens[3]);
+ if (!Data.ValueContentId.has_value())
+ {
+ return false;
+ }
+ return true;
+ }
+ default:
+ return false;
+ }
+ }
- if (ValueSegment.empty())
+ bool GetRpcRequestCacheKey(const CbObjectView& KeyView, CacheKey& Key)
+ {
+ CbFieldView NamespaceField = KeyView["Namespace"sv];
+ std::optional<std::string> Namespace;
+ if (!NamespaceField)
{
- return true;
+ Namespace = ZenCacheStore::DefaultNamespace;
}
-
- if (ValueSegment.size() != IoHash::StringLength)
+ else
{
- return false;
+ if (NamespaceField.HasError())
+ {
+ return false;
+ }
+ if (!NamespaceField.IsString())
+ {
+ return false;
+ }
+ Namespace = GetValidNamespaceName(NamespaceField.AsString());
}
-
- IoHash ValueHash;
- if (!ParseHexBytes(ValueSegment.data(), ValueSegment.size(), ValueHash.Hash))
+ if (!Namespace.has_value())
{
return false;
}
- Data.ValueContentId = ValueHash;
-
- return true;
- }
-
- bool GetRpcRequestCacheKey(const CbObjectView& KeyView, CacheKey& Key)
- {
- CbFieldView NamespaceField = KeyView["Namespace"sv];
- std::string_view Namespace = NamespaceField.AsString(ZenCacheStore::DefaultNamespace);
- CbFieldView BucketField = KeyView["Bucket"sv];
+ CbFieldView BucketField = KeyView["Bucket"sv];
if (BucketField.HasError())
{
return false;
@@ -216,8 +277,8 @@ namespace {
{
return false;
}
- std::string_view Bucket = BucketField.AsString();
- if (!IsValidBucketName(Bucket))
+ std::optional<std::string> Bucket = GetValidBucketName(BucketField.AsString());
+ if (!Bucket.has_value())
{
return false;
}
@@ -231,7 +292,7 @@ namespace {
return false;
}
IoHash Hash = HashField.AsHash();
- Key = CacheKey::Create(Namespace, Bucket, Hash);
+ Key = CacheKey::Create(*Namespace, *Bucket, Hash);
return true;
}
@@ -2325,12 +2386,12 @@ HttpStructuredCacheService::HandleStatusRequest(zen::HttpServerRequest& Request)
TEST_CASE("z$service.parse.relative.Uri")
{
- HttpRequestData LegacyBucketRequest;
- CHECK(HttpRequestParseRelativeUri("test", LegacyBucketRequest));
- CHECK(LegacyBucketRequest.Namespace == ZenCacheStore::DefaultNamespace);
- CHECK(LegacyBucketRequest.Bucket == "test"sv);
- CHECK(!LegacyBucketRequest.HashKey.has_value());
- CHECK(!LegacyBucketRequest.ValueContentId.has_value());
+ HttpRequestData LegacyBucketRequestBecomesNamespaceRequest;
+ CHECK(HttpRequestParseRelativeUri("test", LegacyBucketRequestBecomesNamespaceRequest));
+ CHECK(LegacyBucketRequestBecomesNamespaceRequest.Namespace == "test"sv);
+ CHECK(!LegacyBucketRequestBecomesNamespaceRequest.Bucket.has_value());
+ CHECK(!LegacyBucketRequestBecomesNamespaceRequest.HashKey.has_value());
+ CHECK(!LegacyBucketRequestBecomesNamespaceRequest.ValueContentId.has_value());
HttpRequestData LegacyHashKeyRequest;
CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234", LegacyHashKeyRequest));
@@ -2348,61 +2409,60 @@ TEST_CASE("z$service.parse.relative.Uri")
CHECK(LegacyValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789"sv));
HttpRequestData V2DefaultNamespaceRequest;
- CHECK(HttpRequestParseRelativeUri("api/v2/default", V2DefaultNamespaceRequest));
+ CHECK(HttpRequestParseRelativeUri("default", V2DefaultNamespaceRequest));
CHECK(V2DefaultNamespaceRequest.Namespace == ZenCacheStore::DefaultNamespace);
CHECK(!V2DefaultNamespaceRequest.Bucket.has_value());
CHECK(!V2DefaultNamespaceRequest.HashKey.has_value());
CHECK(!V2DefaultNamespaceRequest.ValueContentId.has_value());
HttpRequestData V2NamespaceRequest;
- CHECK(HttpRequestParseRelativeUri("api/v2/nicenamespace", V2NamespaceRequest));
+ CHECK(HttpRequestParseRelativeUri("nicenamespace", V2NamespaceRequest));
CHECK(V2NamespaceRequest.Namespace == "nicenamespace"sv);
CHECK(!V2NamespaceRequest.Bucket.has_value());
CHECK(!V2NamespaceRequest.HashKey.has_value());
CHECK(!V2NamespaceRequest.ValueContentId.has_value());
HttpRequestData V2BucketRequestWithDefaultNamespace;
- CHECK(HttpRequestParseRelativeUri("api/v2/default/test", V2BucketRequestWithDefaultNamespace));
+ CHECK(HttpRequestParseRelativeUri("default/test", V2BucketRequestWithDefaultNamespace));
CHECK(V2BucketRequestWithDefaultNamespace.Namespace == ZenCacheStore::DefaultNamespace);
CHECK(V2BucketRequestWithDefaultNamespace.Bucket == "test"sv);
CHECK(!V2BucketRequestWithDefaultNamespace.HashKey.has_value());
CHECK(!V2BucketRequestWithDefaultNamespace.ValueContentId.has_value());
HttpRequestData V2BucketRequestWithNamespace;
- CHECK(HttpRequestParseRelativeUri("api/v2/nicenamespace/test", V2BucketRequestWithNamespace));
+ CHECK(HttpRequestParseRelativeUri("nicenamespace/test", V2BucketRequestWithNamespace));
CHECK(V2BucketRequestWithNamespace.Namespace == "nicenamespace"sv);
CHECK(V2BucketRequestWithNamespace.Bucket == "test"sv);
CHECK(!V2BucketRequestWithNamespace.HashKey.has_value());
CHECK(!V2BucketRequestWithNamespace.ValueContentId.has_value());
HttpRequestData V2HashKeyRequest;
- CHECK(HttpRequestParseRelativeUri("api/v2/default/test/0123456789abcdef12340123456789abcdef1234", V2HashKeyRequest));
+ CHECK(HttpRequestParseRelativeUri("default/test/0123456789abcdef12340123456789abcdef1234", V2HashKeyRequest));
CHECK(V2HashKeyRequest.Namespace == ZenCacheStore::DefaultNamespace);
CHECK(V2HashKeyRequest.Bucket == "test");
CHECK(V2HashKeyRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv));
CHECK(!V2HashKeyRequest.ValueContentId.has_value());
HttpRequestData V2ValueContentIdRequest;
- CHECK(HttpRequestParseRelativeUri(
- "api/v2/nicenamespace/test/0123456789abcdef12340123456789abcdef1234/56789abcdef12345678956789abcdef123456789",
- V2ValueContentIdRequest));
+ CHECK(
+ HttpRequestParseRelativeUri("nicenamespace/test/0123456789abcdef12340123456789abcdef1234/56789abcdef12345678956789abcdef123456789",
+ V2ValueContentIdRequest));
CHECK(V2ValueContentIdRequest.Namespace == "nicenamespace"sv);
CHECK(V2ValueContentIdRequest.Bucket == "test"sv);
CHECK(V2ValueContentIdRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv));
CHECK(V2ValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789"sv));
HttpRequestData Invalid;
- CHECK(!HttpRequestParseRelativeUri("api/v2/", Invalid));
- CHECK(!HttpRequestParseRelativeUri("api/v2//", Invalid));
- CHECK(!HttpRequestParseRelativeUri("api/v2/bad\2_namespace", Invalid));
- CHECK(!HttpRequestParseRelativeUri("api/v2/nice/\2\1bucket", Invalid));
- CHECK(!HttpRequestParseRelativeUri("api/v2/namespace/bucket/0123456789a", Invalid));
- CHECK(!HttpRequestParseRelativeUri("api/v2/namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcdef1234", Invalid));
- CHECK(!HttpRequestParseRelativeUri("api/v2/namespace/bucket/pppppppp89abcdef12340123456789abcdef1234", Invalid));
- CHECK(!HttpRequestParseRelativeUri("api/v2/namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcd", Invalid));
- CHECK(!HttpRequestParseRelativeUri(
- "api/v2/namespace/bucket/0123456789abcdef12340123456789abcdef1234/ppppppppdef12345678956789abcdef123456789",
- Invalid));
+ CHECK(!HttpRequestParseRelativeUri("", Invalid));
+ CHECK(!HttpRequestParseRelativeUri("/", Invalid));
+ CHECK(!HttpRequestParseRelativeUri("bad\2_namespace", Invalid));
+ CHECK(!HttpRequestParseRelativeUri("nice/\2\1bucket", Invalid));
+ CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789a", Invalid));
+ CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcdef1234", Invalid));
+ CHECK(!HttpRequestParseRelativeUri("namespace/bucket/pppppppp89abcdef12340123456789abcdef1234", Invalid));
+ CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcd", Invalid));
+ CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/ppppppppdef12345678956789abcdef123456789",
+ Invalid));
}
#endif