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