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"
9 #include "mozilla/StaticPrefs_network.h"
10 #include "mozilla/Telemetry.h"
11 #include "mozilla/Unused.h"
12 #include "nsSocketTransportService2.h"
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"
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 |
44 // | Fingerprinting | III |
45 // ----------------------------------------------------
46 // ====================================================
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 // ====================================================
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
);
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
:
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
:
102 case TrackingClassification::eContent
:
105 case TrackingClassification::eFingerprinting
:
109 MOZ_ASSERT(false, "incorrect classification");
110 return HttpTrafficCategory::eInvalid
;
113 switch (aClassOfService
) {
114 case ClassOfService::eLeader
:
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")));
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
:
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")));
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
:
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")));
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
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) {
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"));
238 MOZ_ASSERT(gKeyName
[24].Equals(kInvalidCategory
),
239 "category definition isn't consistent");
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
);
269 } // namespace mozilla