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