Bug 1814798 - pt 2. Add a PHCManager component to control PHC r=glandium,emilio
[gecko.git] / netwerk / protocol / http / HttpTrafficAnalyzer.cpp
blob5b8f3bbb219d159132924a45ccee18798bc3c58d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "HttpTrafficAnalyzer.h"
7 #include "HttpLog.h"
9 #include "mozilla/StaticPrefs_network.h"
10 #include "mozilla/Telemetry.h"
11 #include "mozilla/Unused.h"
12 #include "nsSocketTransportService2.h"
14 namespace mozilla {
15 namespace net {
17 constexpr auto kInvalidCategory = "INVALID_CATEGORY"_ns;
19 #define DEFINE_CATEGORY(_name, _idx) nsLiteralCString("Y" #_idx "_" #_name),
20 static constexpr nsLiteralCString gKeyName[] = {
21 #include "HttpTrafficAnalyzer.inc"
22 kInvalidCategory,
24 #undef DEFINE_CATEGORY
26 #define DEFINE_CATEGORY(_name, _idx) \
27 Telemetry::LABELS_HTTP_TRAFFIC_ANALYSIS_3::Y##_idx##_##_name,
28 static const Telemetry::LABELS_HTTP_TRAFFIC_ANALYSIS_3 gTelemetryLabel[] = {
29 #include "HttpTrafficAnalyzer.inc"
31 #undef DEFINE_CATEGORY
33 // ----------------------------------------------------
34 // | Flags | Load Type |
35 // ----------------------------------------------------
36 // | nsIClassOfService::Leader | A |
37 // | w/o nsIRequest::LOAD_BACKGROUND | B |
38 // | w/ nsIRequest::LOAD_BACKGROUND | C |
39 // ----------------------------------------------------
40 // | Category | List Category |
41 // ----------------------------------------------------
42 // | Basic Disconnected List | I |
43 // | Content | II |
44 // | Fingerprinting | III |
45 // ----------------------------------------------------
46 // ====================================================
47 // | Normal Mode |
48 // ----------------------------------------------------
49 // | Y = 0 for system principals |
50 // | Y = 1 for first party |
51 // | Y = 2 for non-listed third party type |
52 // ----------------------------------------------------
53 // | \Y\ | Type A | Type B | Type C |
54 // ----------------------------------------------------
55 // | Category I | 3 | 4 | 5 |
56 // | Category II | 6 | 7 | 8 |
57 // | Category III | 9 | 10 | 11 |
58 // ====================================================
59 // | Private Mode |
60 // ----------------------------------------------------
61 // | Y = 12 for system principals |
62 // | Y = 13 for first party |
63 // | Y = 14 for non-listed third party type |
64 // ----------------------------------------------------
65 // | \Y\ | Type A | Type B | Type C |
66 // ----------------------------------------------------
67 // | Category I | 15 | 16 | 17 |
68 // | Category II | 18 | 19 | 20 |
69 // | Category III | 21 | 22 | 23 |
70 // ====================================================
72 HttpTrafficCategory HttpTrafficAnalyzer::CreateTrafficCategory(
73 bool aIsPrivateMode, bool aIsSystemPrincipal, bool aIsThirdParty,
74 ClassOfService aClassOfService, TrackingClassification aClassification) {
75 uint8_t category = aIsPrivateMode ? 12 : 0;
76 if (aIsSystemPrincipal) {
77 MOZ_ASSERT_IF(!aIsPrivateMode,
78 gKeyName[category].EqualsLiteral("Y0_N1Sys"));
79 MOZ_ASSERT_IF(aIsPrivateMode,
80 gKeyName[category].EqualsLiteral("Y12_P1Sys"));
81 return static_cast<HttpTrafficCategory>(category);
83 ++category;
85 if (!aIsThirdParty) {
86 MOZ_ASSERT_IF(!aIsPrivateMode, gKeyName[category].EqualsLiteral("Y1_N1"));
87 MOZ_ASSERT_IF(aIsPrivateMode, gKeyName[category].EqualsLiteral("Y13_P1"));
88 return static_cast<HttpTrafficCategory>(category);
91 switch (aClassification) {
92 case TrackingClassification::eNone:
93 ++category;
94 MOZ_ASSERT_IF(!aIsPrivateMode,
95 gKeyName[category].EqualsLiteral("Y2_N3Oth"));
96 MOZ_ASSERT_IF(aIsPrivateMode,
97 gKeyName[category].EqualsLiteral("Y14_P3Oth"));
98 return static_cast<HttpTrafficCategory>(category);
99 case TrackingClassification::eBasic:
100 category += 2;
101 break;
102 case TrackingClassification::eContent:
103 category += 5;
104 break;
105 case TrackingClassification::eFingerprinting:
106 category += 8;
107 break;
108 default:
109 MOZ_ASSERT(false, "incorrect classification");
110 return HttpTrafficCategory::eInvalid;
113 switch (aClassOfService) {
114 case ClassOfService::eLeader:
115 MOZ_ASSERT_IF(
116 !aIsPrivateMode,
117 (aClassification == TrackingClassification::eBasic &&
118 gKeyName[category].EqualsLiteral("Y3_N3BasicLead")) ||
119 (aClassification == TrackingClassification::eContent &&
120 gKeyName[category].EqualsLiteral("Y6_N3ContentLead")) ||
121 (aClassification == TrackingClassification::eFingerprinting &&
122 gKeyName[category].EqualsLiteral("Y9_N3FpLead")));
123 MOZ_ASSERT_IF(
124 aIsPrivateMode,
125 (aClassification == TrackingClassification::eBasic &&
126 gKeyName[category].EqualsLiteral("Y15_P3BasicLead")) ||
127 (aClassification == TrackingClassification::eContent &&
128 gKeyName[category].EqualsLiteral("Y18_P3ContentLead")) ||
129 (aClassification == TrackingClassification::eFingerprinting &&
130 gKeyName[category].EqualsLiteral("Y21_P3FpLead")));
131 return static_cast<HttpTrafficCategory>(category);
132 case ClassOfService::eBackground:
133 ++category;
135 MOZ_ASSERT_IF(
136 !aIsPrivateMode,
137 (aClassification == TrackingClassification::eBasic &&
138 gKeyName[category].EqualsLiteral("Y4_N3BasicBg")) ||
139 (aClassification == TrackingClassification::eContent &&
140 gKeyName[category].EqualsLiteral("Y7_N3ContentBg")) ||
141 (aClassification == TrackingClassification::eFingerprinting &&
142 gKeyName[category].EqualsLiteral("Y10_N3FpBg")));
143 MOZ_ASSERT_IF(
144 aIsPrivateMode,
145 (aClassification == TrackingClassification::eBasic &&
146 gKeyName[category].EqualsLiteral("Y16_P3BasicBg")) ||
147 (aClassification == TrackingClassification::eContent &&
148 gKeyName[category].EqualsLiteral("Y19_P3ContentBg")) ||
149 (aClassification == TrackingClassification::eFingerprinting &&
150 gKeyName[category].EqualsLiteral("Y22_P3FpBg")));
152 return static_cast<HttpTrafficCategory>(category);
153 case ClassOfService::eOther:
154 category += 2;
156 MOZ_ASSERT_IF(
157 !aIsPrivateMode,
158 (aClassification == TrackingClassification::eBasic &&
159 gKeyName[category].EqualsLiteral("Y5_N3BasicOth")) ||
160 (aClassification == TrackingClassification::eContent &&
161 gKeyName[category].EqualsLiteral("Y8_N3ContentOth")) ||
162 (aClassification == TrackingClassification::eFingerprinting &&
163 gKeyName[category].EqualsLiteral("Y11_N3FpOth")));
164 MOZ_ASSERT_IF(
165 aIsPrivateMode,
166 (aClassification == TrackingClassification::eBasic &&
167 gKeyName[category].EqualsLiteral("Y17_P3BasicOth")) ||
168 (aClassification == TrackingClassification::eContent &&
169 gKeyName[category].EqualsLiteral("Y20_P3ContentOth")) ||
170 (aClassification == TrackingClassification::eFingerprinting &&
171 gKeyName[category].EqualsLiteral("Y23_P3FpOth")));
173 return static_cast<HttpTrafficCategory>(category);
176 MOZ_ASSERT(false, "incorrect class of service");
177 return HttpTrafficCategory::eInvalid;
180 void HttpTrafficAnalyzer::IncrementHttpTransaction(
181 HttpTrafficCategory aCategory) {
182 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
183 MOZ_ASSERT(StaticPrefs::network_traffic_analyzer_enabled());
184 MOZ_ASSERT(aCategory != HttpTrafficCategory::eInvalid, "invalid category");
186 LOG(("HttpTrafficAnalyzer::IncrementHttpTransaction [%s] [this=%p]\n",
187 gKeyName[aCategory].get(), this));
189 Telemetry::AccumulateCategoricalKeyed("Transaction"_ns,
190 gTelemetryLabel[aCategory]);
193 void HttpTrafficAnalyzer::IncrementHttpConnection(
194 HttpTrafficCategory aCategory) {
195 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
196 MOZ_ASSERT(StaticPrefs::network_traffic_analyzer_enabled());
197 MOZ_ASSERT(aCategory != HttpTrafficCategory::eInvalid, "invalid category");
199 LOG(("HttpTrafficAnalyzer::IncrementHttpConnection [%s] [this=%p]\n",
200 gKeyName[aCategory].get(), this));
202 Telemetry::AccumulateCategoricalKeyed("Connection"_ns,
203 gTelemetryLabel[aCategory]);
206 void HttpTrafficAnalyzer::IncrementHttpConnection(
207 nsTArray<HttpTrafficCategory>&& aCategories) {
208 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
209 MOZ_ASSERT(StaticPrefs::network_traffic_analyzer_enabled());
210 MOZ_ASSERT(!aCategories.IsEmpty(), "empty category");
212 nsTArray<HttpTrafficCategory> categories(std::move(aCategories));
214 LOG(("HttpTrafficAnalyzer::IncrementHttpConnection size=%" PRIuPTR
215 " [this=%p]\n",
216 categories.Length(), this));
218 // divide categories into 4 parts:
219 // 1) normal 1st-party (Y in {0, 1})
220 // 2) normal 3rd-party (1 < Y < 12)
221 // 3) private 1st-party (Y in {12, 13})
222 // 4) private 3rd-party (13 < Y < 24)
223 // Normal and private transaction should not share the same connection,
224 // and we choose 3rd-party prior than 1st-party.
225 HttpTrafficCategory best = categories[0];
226 for (auto category : categories) {
227 MOZ_ASSERT(category != HttpTrafficCategory::eInvalid, "invalid category");
229 if (category == 0 || category == 1 || category == 12 || category == 13) {
230 // first party
231 MOZ_ASSERT(gKeyName[category].EqualsLiteral("Y0_N1Sys") ||
232 gKeyName[category].EqualsLiteral("Y1_N1") ||
233 gKeyName[category].EqualsLiteral("Y12_P1Sys") ||
234 gKeyName[category].EqualsLiteral("Y13_P1"));
235 continue;
237 // third party
238 MOZ_ASSERT(gKeyName[24].Equals(kInvalidCategory),
239 "category definition isn't consistent");
240 best = category;
241 break;
244 IncrementHttpConnection(best);
247 #define CLAMP_U32(num) \
248 Clamp<uint32_t>(num, 0, std::numeric_limits<uint32_t>::max())
250 void HttpTrafficAnalyzer::AccumulateHttpTransferredSize(
251 HttpTrafficCategory aCategory, uint64_t aBytesRead, uint64_t aBytesSent) {
252 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
253 MOZ_ASSERT(StaticPrefs::network_traffic_analyzer_enabled());
254 MOZ_ASSERT(aCategory != HttpTrafficCategory::eInvalid, "invalid category");
256 LOG(("HttpTrafficAnalyzer::AccumulateHttpTransferredSize [%s] rb=%" PRIu64 " "
257 "sb=%" PRIu64 " [this=%p]\n",
258 gKeyName[aCategory].get(), aBytesRead, aBytesSent, this));
260 // Telemetry supports uint32_t only, and we send KB here.
261 auto total = CLAMP_U32((aBytesRead >> 10) + (aBytesSent >> 10));
262 if (aBytesRead || aBytesSent) {
263 Telemetry::ScalarAdd(Telemetry::ScalarID::NETWORKING_DATA_TRANSFERRED_V3_KB,
264 NS_ConvertUTF8toUTF16(gKeyName[aCategory]), total);
268 } // namespace net
269 } // namespace mozilla