1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <string_view>
20 
21 #include <folly/FBString.h>
22 #include <folly/Range.h>
23 #include <folly/lang/Exception.h>
24 #include <thrift/lib/cpp2/type/UniversalHashAlgorithm.h>
25 
26 namespace apache::thrift::type {
27 using hash_size_t = int8_t;
28 inline constexpr hash_size_t kDisableUniversalHash = 0;
29 
30 // Validates that uri is a valid universal name uri of the form:
31 // {domain}/{path}. For example: facebook.com/thrift/Value.
32 //
33 // The scheme "fbthrift://"" is implied and not included in the uri.
34 //
35 // Throws std::invalid_argument on failure.
36 void validateUniversalName(std::string_view uri);
37 
38 // Validates that the given type hash meets the size requirements.
39 //
40 // Throws std::invalid_argument on failure.
41 void validateUniversalHash(
42     UniversalHashAlgorithm alg,
43     folly::StringPiece universalHash,
44     hash_size_t minHashBytes);
45 
46 // Validates that the given type hash bytes size meets size requirements.
47 //
48 // Throws std::invalid_argument on failure.
49 void validateUniversalHashBytes(
50     hash_size_t hashBytes, hash_size_t minHashBytes);
51 
52 // The number of bytes returned by the given type hash algorithm.
53 hash_size_t getUniversalHashSize(UniversalHashAlgorithm alg);
54 
55 // Returns the hash for the given universal name uri.
56 //
57 // The hash includes the implied scheme, "fbthrift://".
58 folly::fbstring getUniversalHash(
59     UniversalHashAlgorithm alg, std::string_view uri);
60 
61 // Shrinks the universalHash to fit in the given number of bytes.
62 folly::StringPiece getUniversalHashPrefix(
63     folly::StringPiece universalHash, hash_size_t hashBytes);
64 
65 // Returns the type hash prefix iff smaller than the uri.
66 folly::fbstring maybeGetUniversalHashPrefix(
67     UniversalHashAlgorithm alg, std::string_view uri, hash_size_t hashBytes);
68 
69 // Returns true iff prefix was derived from universalHash.
70 bool matchesUniversalHash(
71     folly::StringPiece universalHash, folly::StringPiece prefix);
72 
73 // Returns true, if the given sorted map contains an entry that matches the
74 // given type hash prefix.
75 template <typename C, typename K>
containsUniversalHash(C & sortedMap,const K & universalHashPrefix)76 bool containsUniversalHash(C& sortedMap, const K& universalHashPrefix) {
77   auto itr = sortedMap.lower_bound(universalHashPrefix);
78   return itr != sortedMap.end() &&
79       matchesUniversalHash(itr->first, universalHashPrefix);
80 }
81 
82 // Finds a matching hash within the given sorted map.
83 //
84 // Raises a std::runtime_error if the result is ambiguous.
85 template <typename C, typename K>
findByUniversalHash(C & sortedMap,const K & universalHashPrefix)86 auto findByUniversalHash(C& sortedMap, const K& universalHashPrefix) {
87   auto itr = sortedMap.lower_bound(universalHashPrefix);
88   if (itr == sortedMap.end() ||
89       !matchesUniversalHash(itr->first, universalHashPrefix)) {
90     return sortedMap.end();
91   }
92   auto next = itr;
93   if (++next != sortedMap.end() &&
94       matchesUniversalHash(next->first, universalHashPrefix)) {
95     folly::throw_exception<std::runtime_error>("type hash look up ambiguous");
96   }
97   return itr;
98 }
99 
100 } // namespace apache::thrift::type
101