• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #ifndef NET_TRAFFIC_ANNOTATION_NETWORK_TRAFFIC_ANNOTATION_H_
11 #define NET_TRAFFIC_ANNOTATION_NETWORK_TRAFFIC_ANNOTATION_H_
12 
13 #include <cstdint>
14 
15 #include "base/check.h"
16 #include "base/notreached.h"
17 #include "build/build_config.h"
18 #include "build/chromeos_buildflags.h"
19 
20 #if BUILDFLAG(IS_ANDROID)
21 #include "base/android/scoped_java_ref.h"
22 #endif
23 
24 namespace {
25 
26 // Recursively compute hash code of the given string as a constant expression.
27 template <int N>
recursive_hash(const char * str)28 constexpr uint32_t recursive_hash(const char* str) {
29   return (recursive_hash<N - 1>(str) * 31u +
30           static_cast<uint32_t>(str[N - 1])) %
31          138003713u;
32 }
33 
34 // Recursion stopper for the above function. Note that string of size 0 will
35 // result in compile error.
36 template <>
37 constexpr uint32_t recursive_hash<1>(const char* str) {
38   return static_cast<uint32_t>(*str);
39 }
40 
41 // Entry point to function that computes hash as constant expression.
42 #define COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(S) \
43   static_cast<int32_t>(recursive_hash<sizeof(S) - 1>(S))
44 
45 constexpr int TRAFFIC_ANNOTATION_UNINITIALIZED = -1;
46 
47 }  // namespace
48 
49 namespace net {
50 
51 struct PartialNetworkTrafficAnnotationTag;
52 
53 // Defined types for network traffic annotation tags.
54 struct NetworkTrafficAnnotationTag {
55   const int32_t unique_id_hash_code;
56 
57   bool operator==(const NetworkTrafficAnnotationTag& other) const {
58     return unique_id_hash_code == other.unique_id_hash_code;
59   }
60 
NotReachedNetworkTrafficAnnotationTag61   static NetworkTrafficAnnotationTag NotReached() { NOTREACHED(); }
62 
63   // These functions are wrappers around the (private) constructor, so we can
64   // easily find the constructor's call-sites with a script.
65   template <size_t N1, size_t N2>
66   friend constexpr NetworkTrafficAnnotationTag DefineNetworkTrafficAnnotation(
67       const char (&unique_id)[N1],
68       const char (&proto)[N2]);
69 
70   template <size_t N1, size_t N2>
71   friend NetworkTrafficAnnotationTag CompleteNetworkTrafficAnnotation(
72       const char (&unique_id)[N1],
73       const PartialNetworkTrafficAnnotationTag& partial_annotation,
74       const char (&proto)[N2]);
75 
76   template <size_t N1, size_t N2, size_t N3>
77   friend NetworkTrafficAnnotationTag BranchedCompleteNetworkTrafficAnnotation(
78       const char (&unique_id)[N1],
79       const char (&group_id)[N2],
80       const PartialNetworkTrafficAnnotationTag& partial_annotation,
81       const char (&proto)[N3]);
82 
83 #if BUILDFLAG(IS_ANDROID)
84   // Allows C++ methods to receive a Java NetworkTrafficAnnotationTag via JNI,
85   // and convert it to the C++ version.
86   static NetworkTrafficAnnotationTag FromJavaAnnotation(
87       int32_t unique_id_hash_code);
88 #endif
89 
90   friend struct MutableNetworkTrafficAnnotationTag;
91 
92  private:
NetworkTrafficAnnotationTagNetworkTrafficAnnotationTag93   constexpr explicit NetworkTrafficAnnotationTag(int32_t unique_id_hash_code_)
94       : unique_id_hash_code(unique_id_hash_code_) {}
95 };
96 
97 struct PartialNetworkTrafficAnnotationTag {
98   const int32_t unique_id_hash_code;
99 
100 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
101   // |completing_id_hash_code| holds a reference to the hash coded unique id
102   // of a network traffic annotation (or group id of several network traffic
103   // annotations) that complete a partial network annotation. Please refer to
104   // the description of DefinePartialNetworkTrafficAnnotation function for more
105   // details.
106   // This value is used by the clang tools to find linkage between partial
107   // annotations and their completing parts, and is used in debug mode to check
108   // if an intended completing part is added to a partial network annotation.
109   const int32_t completing_id_hash_code;
110 #endif
111 
112   // This function is a wrapper around the (private) constructor, so we can
113   // easily find the constructor's call-sites with a script.
114   template <size_t N1, size_t N2, size_t N3>
115   friend constexpr PartialNetworkTrafficAnnotationTag
116   DefinePartialNetworkTrafficAnnotation(const char (&unique_id)[N1],
117                                         const char (&completing_id)[N2],
118                                         const char (&proto)[N3]);
119 
120   friend struct MutablePartialNetworkTrafficAnnotationTag;
121 
122  private:
123 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
PartialNetworkTrafficAnnotationTagPartialNetworkTrafficAnnotationTag124   constexpr PartialNetworkTrafficAnnotationTag(int32_t unique_id_hash_code_,
125                                                int32_t completing_id_hash_code_)
126       : unique_id_hash_code(unique_id_hash_code_),
127         completing_id_hash_code(completing_id_hash_code_) {}
128 #else
129   constexpr explicit PartialNetworkTrafficAnnotationTag(
130       int32_t unique_id_hash_code_)
131       : unique_id_hash_code(unique_id_hash_code_) {}
132 #endif
133 };
134 
135 // Function to convert a network traffic annotation's unique id and protobuf
136 // text into a NetworkTrafficAnnotationTag.
137 //
138 // This function serves as a tag that can be discovered and extracted via
139 // clang tools. This allows reviewing all network traffic that is generated
140 // and annotated by Chrome.
141 //
142 // |unique_id| should be a string that uniquely identifies this annotation
143 // across all of Chromium source code. |unique_id| should be kept unchanged
144 // as long as possible as its hashed value will be used for differnt logging,
145 // debugging, or auditing tasks. Unique ids should include only alphanumeric
146 // characters and underline.
147 // |proto| is a text-encoded NetworkTrafficAnnotation protobuf (see
148 // chrome/browser/privacy/traffic_annotation.proto)
149 //
150 // An empty and a sample template for the text-encoded protobuf can be found in
151 // tools/traffic_annotation/sample_traffic_annotation.cc.
152 // TODO(crbug.com/40505662): Add tools to check annotation text's format during
153 // presubmit checks.
154 template <size_t N1, size_t N2>
DefineNetworkTrafficAnnotation(const char (& unique_id)[N1],const char (& proto)[N2])155 constexpr NetworkTrafficAnnotationTag DefineNetworkTrafficAnnotation(
156     const char (&unique_id)[N1],
157     const char (&proto)[N2]) {
158   return NetworkTrafficAnnotationTag(
159       COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id));
160 }
161 
162 // There are cases where the network traffic annotation cannot be fully
163 // specified in one place. For example, in one place we know the trigger of a
164 // network request and in another place we know the data that will be sent. In
165 // these cases, we prefer that both parts of the annotation appear in context so
166 // that they are updated if code changes. The following functions help splitting
167 // the network traffic annotation into two pieces. Please refer to
168 // tools/traffic_annotation/sample_traffic_annotation.cc for usage samples.
169 
170 // This function can be used to define a partial annotation that will be
171 // completed later. The completing annotation can be defined with either of
172 // 'CompleteNetworkTrafficAnnotation' or
173 // 'BranchedCompleteNetworkTrafficAnnotation' functions. In case of
174 // CompleteNetworkTrafficAnnotation, |completing_id| is the unique id of the
175 // annotation that will complete it. In the case of
176 // BranchedCompleteNetworkTrafficAnnotation, |completing_id| is the group id
177 // of the completing annotations.
178 template <size_t N1, size_t N2, size_t N3>
179 constexpr PartialNetworkTrafficAnnotationTag
DefinePartialNetworkTrafficAnnotation(const char (& unique_id)[N1],const char (& completing_id)[N2],const char (& proto)[N3])180 DefinePartialNetworkTrafficAnnotation(const char (&unique_id)[N1],
181                                       const char (&completing_id)[N2],
182                                       const char (&proto)[N3]) {
183 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
184   return PartialNetworkTrafficAnnotationTag(
185       COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id),
186       COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(completing_id));
187 #else
188   return PartialNetworkTrafficAnnotationTag(
189       COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id));
190 #endif
191 }
192 
193 // This function can be used to define a completing partial annotation. This
194 // annotation adds details to another annotation that is defined before.
195 // |partial_annotation| is the PartialNetworkTrafficAnnotationTag returned
196 // by a call to DefinePartialNetworkTrafficAnnotation().
197 template <size_t N1, size_t N2>
CompleteNetworkTrafficAnnotation(const char (& unique_id)[N1],const PartialNetworkTrafficAnnotationTag & partial_annotation,const char (& proto)[N2])198 NetworkTrafficAnnotationTag CompleteNetworkTrafficAnnotation(
199     const char (&unique_id)[N1],
200     const PartialNetworkTrafficAnnotationTag& partial_annotation,
201     const char (&proto)[N2]) {
202 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
203   DCHECK(partial_annotation.completing_id_hash_code ==
204              COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id) ||
205          partial_annotation.unique_id_hash_code ==
206              COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("test_partial") ||
207          partial_annotation.unique_id_hash_code ==
208              COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("undefined"));
209 #endif
210   return NetworkTrafficAnnotationTag(partial_annotation.unique_id_hash_code);
211 }
212 
213 // This function can be used to define a completing partial annotation that is
214 // branched into several annotations. In this case, |group_id| is a common id
215 // that is used by all members of the branch and referenced by partial
216 // annotation that is completed by them.
217 template <size_t N1, size_t N2, size_t N3>
BranchedCompleteNetworkTrafficAnnotation(const char (& unique_id)[N1],const char (& group_id)[N2],const PartialNetworkTrafficAnnotationTag & partial_annotation,const char (& proto)[N3])218 NetworkTrafficAnnotationTag BranchedCompleteNetworkTrafficAnnotation(
219     const char (&unique_id)[N1],
220     const char (&group_id)[N2],
221     const PartialNetworkTrafficAnnotationTag& partial_annotation,
222     const char (&proto)[N3]) {
223 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
224   DCHECK(partial_annotation.completing_id_hash_code ==
225              COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(group_id) ||
226          partial_annotation.unique_id_hash_code ==
227              COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("test_partial") ||
228          partial_annotation.unique_id_hash_code ==
229              COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("undefined"));
230 #endif
231   return NetworkTrafficAnnotationTag(
232       COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id));
233 }
234 
235 // Example for joining N x 1 partial annotations:
236 // N functions foo1(), ..., fooN() call one function bar(). Each
237 // foo...() function defines part of a network traffic annotation.
238 // These N partial annotations are combined with a second part in
239 // bar().
240 //
241 // void foo1() {
242 //   auto tag = DefinePartialNetworkTrafficAnnotation(
243 //       "call_by_foo1", "completion_by_bar", [partial_proto]);
244 //   bar(tag);
245 // }
246 // void foo2() {
247 //   auto tag = DefinePartialNetworkTrafficAnnotation(
248 //       "call_by_foo2", "completion_by_bar", [partial_proto]);
249 //   bar(tag);
250 // }
251 // void bar(PartialNetworkTrafficAnnotationTag tag) {
252 //   auto final_tag = CompleteNetworkTrafficAnnotation(
253 //     "completion_by_bar", tag, [rest_of_proto]);
254 //   // final_tag matches the value of tag (which is hash code of
255 //   // "call_by_fooX" where X can be 1 or 2).
256 //   net::URLFetcher::Create(..., final_tag);
257 // }
258 
259 // Example for joining 1 x N partial annotations:
260 // A function foo() calls a function bar(bool param), that sends
261 // different network requests depending on param. Both functions
262 // define parts of the network traffic annotation.
263 //
264 // void foo(bool param) {
265 //   auto tag = DefinePartialNetworkTrafficAnnotation(
266 //       "call_by_foo1", "completion_by_bar", [partial_proto]);
267 //   bar(param, tag);
268 // }
269 // void bar(bool param, PartialNetworkTrafficAnnotationTag tag) {
270 //   if (param) {
271 //     auto final_tag = BranchedCompleteNetworkTrafficAnnotation(
272 //       "call_bool_branch_1", "completion_by_bar", tag, [rest_of_proto]);
273 //     // final_tag is hash code of "call_bool_branch_1".
274 //     net::URLFetcher::Create(url1, ..., final_tag);
275 //   } else {
276 //     auto final_tag = BranchedCompleteNetworkTrafficAnnotation(
277 //       "call_bool_branch_2", "completion_by_bar", tag, [rest_of_proto]);
278 //     // final_tag is hash code of "call_bool_branch_2".
279 //     net::URLFetcher::Create(url2, ..., final_tag);
280 //   }
281 // }
282 
283 // Please do not use this unless uninitialized annotations are required.
284 // Mojo interfaces for this class and the next one are defined in
285 // '/services/network/public/mojom'.
286 struct MutableNetworkTrafficAnnotationTag {
MutableNetworkTrafficAnnotationTagMutableNetworkTrafficAnnotationTag287   MutableNetworkTrafficAnnotationTag()
288       : unique_id_hash_code(TRAFFIC_ANNOTATION_UNINITIALIZED) {}
MutableNetworkTrafficAnnotationTagMutableNetworkTrafficAnnotationTag289   explicit MutableNetworkTrafficAnnotationTag(
290       const NetworkTrafficAnnotationTag& traffic_annotation)
291       : unique_id_hash_code(traffic_annotation.unique_id_hash_code) {}
292 
293   int32_t unique_id_hash_code;
294 
295   bool operator==(const MutableNetworkTrafficAnnotationTag& other) const {
296     return unique_id_hash_code == other.unique_id_hash_code;
297   }
298 
NetworkTrafficAnnotationTagMutableNetworkTrafficAnnotationTag299   explicit operator NetworkTrafficAnnotationTag() const {
300     DCHECK(is_valid());
301     return NetworkTrafficAnnotationTag(unique_id_hash_code);
302   }
303 
is_validMutableNetworkTrafficAnnotationTag304   bool is_valid() const {
305     return unique_id_hash_code != TRAFFIC_ANNOTATION_UNINITIALIZED;
306   }
307 
resetMutableNetworkTrafficAnnotationTag308   void reset() { unique_id_hash_code = TRAFFIC_ANNOTATION_UNINITIALIZED; }
309 
310   // This function is a wrapper around the private constructor, so we can easily
311   // find the constructor's call-sites with a script.
312   friend MutableNetworkTrafficAnnotationTag
313   CreateMutableNetworkTrafficAnnotationTag(int32_t unique_id_hash_code);
314 
315  private:
MutableNetworkTrafficAnnotationTagMutableNetworkTrafficAnnotationTag316   explicit MutableNetworkTrafficAnnotationTag(int32_t unique_id_hash_code_)
317       : unique_id_hash_code(unique_id_hash_code_) {}
318 };
319 
320 inline MutableNetworkTrafficAnnotationTag
CreateMutableNetworkTrafficAnnotationTag(int32_t unique_id_hash_code)321 CreateMutableNetworkTrafficAnnotationTag(int32_t unique_id_hash_code) {
322   return MutableNetworkTrafficAnnotationTag(unique_id_hash_code);
323 }
324 
325 struct MutablePartialNetworkTrafficAnnotationTag {
326 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
MutablePartialNetworkTrafficAnnotationTagMutablePartialNetworkTrafficAnnotationTag327   MutablePartialNetworkTrafficAnnotationTag()
328       : unique_id_hash_code(TRAFFIC_ANNOTATION_UNINITIALIZED),
329         completing_id_hash_code(TRAFFIC_ANNOTATION_UNINITIALIZED) {}
MutablePartialNetworkTrafficAnnotationTagMutablePartialNetworkTrafficAnnotationTag330   explicit MutablePartialNetworkTrafficAnnotationTag(
331       const PartialNetworkTrafficAnnotationTag& partial_traffic_annotation)
332       : unique_id_hash_code(partial_traffic_annotation.unique_id_hash_code),
333         completing_id_hash_code(
334             partial_traffic_annotation.completing_id_hash_code) {}
335 
336   int32_t unique_id_hash_code;
337   int32_t completing_id_hash_code;
338 
PartialNetworkTrafficAnnotationTagMutablePartialNetworkTrafficAnnotationTag339   explicit operator PartialNetworkTrafficAnnotationTag() const {
340     DCHECK(is_valid());
341     return PartialNetworkTrafficAnnotationTag(unique_id_hash_code,
342                                               completing_id_hash_code);
343   }
344 
is_validMutablePartialNetworkTrafficAnnotationTag345   bool is_valid() const {
346     return unique_id_hash_code != TRAFFIC_ANNOTATION_UNINITIALIZED &&
347            completing_id_hash_code != TRAFFIC_ANNOTATION_UNINITIALIZED;
348   }
349 
resetMutablePartialNetworkTrafficAnnotationTag350   void reset() {
351     unique_id_hash_code = TRAFFIC_ANNOTATION_UNINITIALIZED;
352     completing_id_hash_code = TRAFFIC_ANNOTATION_UNINITIALIZED;
353   }
354 #else
355   MutablePartialNetworkTrafficAnnotationTag()
356       : unique_id_hash_code(TRAFFIC_ANNOTATION_UNINITIALIZED) {}
357   explicit MutablePartialNetworkTrafficAnnotationTag(
358       const PartialNetworkTrafficAnnotationTag& partial_traffic_annotation)
359       : unique_id_hash_code(partial_traffic_annotation.unique_id_hash_code) {}
360 
361   int32_t unique_id_hash_code;
362 
363   explicit operator PartialNetworkTrafficAnnotationTag() const {
364     return PartialNetworkTrafficAnnotationTag(unique_id_hash_code);
365   }
366 
367   bool is_valid() const {
368     return unique_id_hash_code != TRAFFIC_ANNOTATION_UNINITIALIZED;
369   }
370 
371   void reset() { unique_id_hash_code = TRAFFIC_ANNOTATION_UNINITIALIZED; }
372 #endif  // !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
373 };
374 
375 }  // namespace net
376 
377 // Placeholder for unannotated usages.
378 #if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
379 #define TRAFFIC_ANNOTATION_WITHOUT_PROTO(ANNOTATION_ID) \
380   net::DefineNetworkTrafficAnnotation(ANNOTATION_ID, "No proto yet.")
381 #endif
382 
383 // These annotations are unavailable on desktop Linux + Windows. They are
384 // available on other platforms, since we only audit network annotations on
385 // Linux & Windows.
386 //
387 // On Linux and Windows, use MISSING_TRAFFIC_ANNOTATION or
388 // TRAFFIC_ANNOTATION_FOR_TESTS.
389 // TODO(crbug.com/40118868): Revisit once build flag switch of lacros-chrome is
390 // complete.
391 #if !BUILDFLAG(IS_WIN) && \
392     !(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
393 
394 #define NO_TRAFFIC_ANNOTATION_YET \
395   net::DefineNetworkTrafficAnnotation("undefined", "Nothing here yet.")
396 
397 #endif
398 
399 #define MISSING_TRAFFIC_ANNOTATION     \
400   net::DefineNetworkTrafficAnnotation( \
401       "missing", "Function called without traffic annotation.")
402 
403 #endif  // NET_TRAFFIC_ANNOTATION_NETWORK_TRAFFIC_ANNOTATION_H_
404