From c442837aff6212c711e959a44fba7c070bcdcaf1 Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Mon, 16 May 2022 15:55:07 +0200 Subject: drop api/v2 prefix for non-legacy requests --- zenserver/cache/structuredcache.cpp | 284 ++++++++++++++++++++++-------------- 1 file changed, 172 insertions(+), 112 deletions(-) (limited to 'zenserver/cache/structuredcache.cpp') 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 ValueContentId; }; - bool IsValidNamespaceName(std::string_view Name) + const char* ValidNameCharacters = "abcdefghijklmnopqrstuvwxyz0123456789-_.ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + std::optional 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 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 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 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 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 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 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 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 -- cgit v1.2.3