| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef NET_TRAFFIC_ANNOTATION_NETWORK_TRAFFIC_ANNOTATION_H_ |
| #define NET_TRAFFIC_ANNOTATION_NETWORK_TRAFFIC_ANNOTATION_H_ |
| |
| #include "base/logging.h" |
| #include "build/build_config.h" |
| |
| namespace { |
| |
| // Recursively compute hash code of the given string as a constant expression. |
| template <int N> |
| constexpr uint32_t recursive_hash(const char* str) { |
| return static_cast<uint32_t>((recursive_hash<N - 1>(str) * 31 + str[N - 1]) % |
| 138003713); |
| } |
| |
| // Recursion stopper for the above function. Note that string of size 0 will |
| // result in compile error. |
| template <> |
| constexpr uint32_t recursive_hash<1>(const char* str) { |
| return static_cast<uint32_t>(*str); |
| } |
| |
| // Entry point to function that computes hash as constant expression. |
| #define COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(S) \ |
| static_cast<int32_t>(recursive_hash<sizeof(S) - 1>(S)) |
| |
| constexpr int TRAFFIC_ANNOTATION_UNINITIALIZED = -1; |
| |
| } // namespace |
| |
| namespace net { |
| |
| // Defined types for network traffic annotation tags. |
| struct NetworkTrafficAnnotationTag { |
| const int32_t unique_id_hash_code; |
| |
| bool operator==(const NetworkTrafficAnnotationTag& other) const { |
| return unique_id_hash_code == other.unique_id_hash_code; |
| } |
| |
| static NetworkTrafficAnnotationTag NotReached() { |
| NOTREACHED(); |
| return net::NetworkTrafficAnnotationTag({TRAFFIC_ANNOTATION_UNINITIALIZED}); |
| } |
| }; |
| struct PartialNetworkTrafficAnnotationTag { |
| const int32_t unique_id_hash_code; |
| |
| #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) |
| // |completing_id_hash_code| holds a reference to the hash coded unique id |
| // of a network traffic annotation (or group id of several network traffic |
| // annotations) that complete a partial network annotation. Please refer to |
| // the description of DefinePartialNetworkTrafficAnnotation function for more |
| // details. |
| // This value is used by the clang tools to find linkage between partial |
| // annotations and their completing parts, and is used in debug mode to check |
| // if an intended completing part is added to a partial network annotation. |
| const int32_t completing_id_hash_code; |
| #endif |
| }; |
| |
| // Function to convert a network traffic annotation's unique id and protobuf |
| // text into a NetworkTrafficAnnotationTag. |
| // |
| // This function serves as a tag that can be discovered and extracted via |
| // clang tools. This allows reviewing all network traffic that is generated |
| // and annotated by Chrome. |
| // |
| // |unique_id| should be a string that uniquely identifies this annotation |
| // across all of Chromium source code. |unique_id| should be kept unchanged |
| // as long as possible as its hashed value will be used for differnt logging, |
| // debugging, or auditing tasks. Unique ids should include only alphanumeric |
| // characters and underline. |
| // |proto| is a text-encoded NetworkTrafficAnnotation protobuf (see |
| // tools/traffic_annotation/traffic_annotation.proto) |
| // |
| // An empty and a sample template for the text-encoded protobuf can be found in |
| // tools/traffic_annotation/sample_traffic_annotation.cc. |
| // TODO(crbug.com/690323): Add tools to check annotation text's format during |
| // presubmit checks. |
| template <size_t N1, size_t N2> |
| constexpr NetworkTrafficAnnotationTag DefineNetworkTrafficAnnotation( |
| const char (&unique_id)[N1], |
| const char (&)[N2]) { |
| return NetworkTrafficAnnotationTag( |
| {COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id)}); |
| } |
| |
| // There are cases where the network traffic annotation cannot be fully |
| // specified in one place. For example, in one place we know the trigger of a |
| // network request and in another place we know the data that will be sent. In |
| // these cases, we prefer that both parts of the annotation appear in context so |
| // that they are updated if code changes. The following functions help splitting |
| // the network traffic annotation into two pieces. Please refer to |
| // tools/traffic_annotation/sample_traffic_annotation.cc for usage samples. |
| |
| // This function can be used to define a partial annotation that will be |
| // completed later. The completing annotation can be defined with either of |
| // 'CompleteNetworkTrafficAnnotation' or |
| // 'BranchedCompleteNetworkTrafficAnnotation' functions. In case of |
| // CompleteNetworkTrafficAnnotation, |completing_id| is the unique id of the |
| // annotation that will complete it. In the case of |
| // BranchedCompleteNetworkTrafficAnnotation, |completing_id| is the group id |
| // of the completing annotations. |
| template <size_t N1, size_t N2, size_t N3> |
| constexpr PartialNetworkTrafficAnnotationTag |
| DefinePartialNetworkTrafficAnnotation(const char (&unique_id)[N1], |
| const char (&completing_id)[N2], |
| const char (&)[N3]) { |
| #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) |
| return PartialNetworkTrafficAnnotationTag( |
| {COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id), |
| COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(completing_id)}); |
| #else |
| return PartialNetworkTrafficAnnotationTag( |
| {COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id)}); |
| #endif |
| } |
| |
| // This function can be used to define a completing partial annotation. This |
| // annotation adds details to another annotation that is defined before. |
| // |partial_annotation| is the PartialNetworkTrafficAnnotationTag returned |
| // by a call to DefinePartialNetworkTrafficAnnotation(). |
| template <size_t N1, size_t N2> |
| NetworkTrafficAnnotationTag CompleteNetworkTrafficAnnotation( |
| const char (&unique_id)[N1], |
| const PartialNetworkTrafficAnnotationTag& partial_annotation, |
| const char (&)[N2]) { |
| #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) |
| DCHECK(partial_annotation.completing_id_hash_code == |
| COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id) || |
| partial_annotation.unique_id_hash_code == |
| COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("test_partial") || |
| partial_annotation.unique_id_hash_code == |
| COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("undefined")); |
| #endif |
| return NetworkTrafficAnnotationTag({partial_annotation.unique_id_hash_code}); |
| } |
| |
| // This function can be used to define a completing partial annotation that is |
| // branched into several annotations. In this case, |group_id| is a common id |
| // that is used by all members of the branch and referenced by partial |
| // annotation that is completed by them. |
| template <size_t N1, size_t N2, size_t N3> |
| NetworkTrafficAnnotationTag BranchedCompleteNetworkTrafficAnnotation( |
| const char (&unique_id)[N1], |
| const char (&)[N2], |
| const PartialNetworkTrafficAnnotationTag& partial_annotation, |
| const char (&)[N3]) { |
| #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) |
| DCHECK(partial_annotation.completing_id_hash_code == |
| COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id) || |
| partial_annotation.unique_id_hash_code == |
| COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("test_partial") || |
| partial_annotation.unique_id_hash_code == |
| COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("undefined")); |
| #endif |
| return NetworkTrafficAnnotationTag( |
| {COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id)}); |
| } |
| |
| // Example for joining N x 1 partial annotations: |
| // N functions foo1(), ..., fooN() call one function bar(). Each |
| // foo...() function defines part of a network traffic annotation. |
| // These N partial annotations are combined with a second part in |
| // bar(). |
| // |
| // void foo1() { |
| // auto tag = DefinePartialNetworkTrafficAnnotation( |
| // "call_by_foo1", "completion_by_bar", [partial_proto]); |
| // bar(tag); |
| // } |
| // void foo2() { |
| // auto tag = DefinePartialNetworkTrafficAnnotation( |
| // "call_by_foo2", "completion_by_bar", [partial_proto]); |
| // bar(tag); |
| // } |
| // void bar(PartialNetworkTrafficAnnotationTag tag) { |
| // auto final_tag = CompleteNetworkTrafficAnnotation( |
| // "completion_by_bar", tag, [rest_of_proto]); |
| // // final_tag matches the value of tag (which is hash code of |
| // // "call_by_fooX" where X can be 1 or 2). |
| // net::URLFetcher::Create(..., final_tag); |
| // } |
| |
| // Example for joining 1 x N partial annotations: |
| // A function foo() calls a function bar(bool param), that sends |
| // different network requests depending on param. Both functions |
| // define parts of the network traffic annotation. |
| // |
| // void foo(bool param) { |
| // auto tag = DefinePartialNetworkTrafficAnnotation( |
| // "call_by_foo1", "completion_by_bar", [partial_proto]); |
| // bar(param, tag); |
| // } |
| // void bar(bool param, PartialNetworkTrafficAnnotationTag tag) { |
| // if (param) { |
| // auto final_tag = BranchedCompleteNetworkTrafficAnnotation( |
| // "call_bool_branch_1", "completion_by_bar", tag, [rest_of_proto]); |
| // // final_tag is hash code of "call_bool_branch_1". |
| // net::URLFetcher::Create(url1, ..., final_tag); |
| // } else { |
| // auto final_tag = BranchedCompleteNetworkTrafficAnnotation( |
| // "call_bool_branch_2", "completion_by_bar", tag, [rest_of_proto]); |
| // // final_tag is hash code of "call_bool_branch_2". |
| // net::URLFetcher::Create(url2, ..., final_tag); |
| // } |
| // } |
| |
| // Please do not use this unless uninitialized annotations are required. |
| // Mojo interfaces for this class and the next one are defined in |
| // '/services/network/public/mojom'. |
| struct MutableNetworkTrafficAnnotationTag { |
| MutableNetworkTrafficAnnotationTag() |
| : unique_id_hash_code(TRAFFIC_ANNOTATION_UNINITIALIZED) {} |
| explicit MutableNetworkTrafficAnnotationTag( |
| const NetworkTrafficAnnotationTag& traffic_annotation) |
| : unique_id_hash_code(traffic_annotation.unique_id_hash_code) {} |
| |
| int32_t unique_id_hash_code; |
| |
| bool operator==(const MutableNetworkTrafficAnnotationTag& other) const { |
| return unique_id_hash_code == other.unique_id_hash_code; |
| } |
| |
| explicit operator NetworkTrafficAnnotationTag() const { |
| DCHECK(is_valid()); |
| return NetworkTrafficAnnotationTag({unique_id_hash_code}); |
| } |
| |
| bool is_valid() const { |
| return unique_id_hash_code != TRAFFIC_ANNOTATION_UNINITIALIZED; |
| } |
| |
| void reset() { unique_id_hash_code = TRAFFIC_ANNOTATION_UNINITIALIZED; } |
| }; |
| |
| struct MutablePartialNetworkTrafficAnnotationTag { |
| #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) |
| MutablePartialNetworkTrafficAnnotationTag() |
| : unique_id_hash_code(TRAFFIC_ANNOTATION_UNINITIALIZED), |
| completing_id_hash_code(TRAFFIC_ANNOTATION_UNINITIALIZED) {} |
| explicit MutablePartialNetworkTrafficAnnotationTag( |
| const PartialNetworkTrafficAnnotationTag& partial_traffic_annotation) |
| : unique_id_hash_code(partial_traffic_annotation.unique_id_hash_code), |
| completing_id_hash_code( |
| partial_traffic_annotation.completing_id_hash_code) {} |
| |
| int32_t unique_id_hash_code; |
| int32_t completing_id_hash_code; |
| |
| explicit operator PartialNetworkTrafficAnnotationTag() const { |
| DCHECK(is_valid()); |
| return PartialNetworkTrafficAnnotationTag( |
| {unique_id_hash_code, completing_id_hash_code}); |
| } |
| |
| bool is_valid() const { |
| return unique_id_hash_code != TRAFFIC_ANNOTATION_UNINITIALIZED && |
| completing_id_hash_code != TRAFFIC_ANNOTATION_UNINITIALIZED; |
| } |
| |
| void reset() { |
| unique_id_hash_code = TRAFFIC_ANNOTATION_UNINITIALIZED; |
| completing_id_hash_code = TRAFFIC_ANNOTATION_UNINITIALIZED; |
| } |
| #else |
| MutablePartialNetworkTrafficAnnotationTag() |
| : unique_id_hash_code(TRAFFIC_ANNOTATION_UNINITIALIZED) {} |
| explicit MutablePartialNetworkTrafficAnnotationTag( |
| const PartialNetworkTrafficAnnotationTag& partial_traffic_annotation) |
| : unique_id_hash_code(partial_traffic_annotation.unique_id_hash_code) {} |
| |
| int32_t unique_id_hash_code; |
| |
| explicit operator PartialNetworkTrafficAnnotationTag() const { |
| return PartialNetworkTrafficAnnotationTag({unique_id_hash_code}); |
| } |
| |
| bool is_valid() const { |
| return unique_id_hash_code != TRAFFIC_ANNOTATION_UNINITIALIZED; |
| } |
| |
| void reset() { unique_id_hash_code = TRAFFIC_ANNOTATION_UNINITIALIZED; } |
| #endif // !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) |
| }; |
| |
| } // namespace net |
| |
| // Placeholder for unannotated usages. |
| #if !defined(OS_WIN) && !defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| #define TRAFFIC_ANNOTATION_WITHOUT_PROTO(ANNOTATION_ID) \ |
| net::DefineNetworkTrafficAnnotation(ANNOTATION_ID, "No proto yet.") |
| #endif |
| |
| #define NO_TRAFFIC_ANNOTATION_YET \ |
| net::DefineNetworkTrafficAnnotation("undefined", "Nothing here yet.") |
| |
| #define NO_PARTIAL_TRAFFIC_ANNOTATION_YET \ |
| net::DefinePartialNetworkTrafficAnnotation("undefined", "undefined", \ |
| "Nothing here yet.") |
| |
| #define MISSING_TRAFFIC_ANNOTATION \ |
| net::DefineNetworkTrafficAnnotation( \ |
| "missing", "Function called without traffic annotation.") |
| |
| #endif // NET_TRAFFIC_ANNOTATION_NETWORK_TRAFFIC_ANNOTATION_H_ |