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