summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/HttpTrafficAnalyzer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/protocol/http/HttpTrafficAnalyzer.cpp')
-rw-r--r--netwerk/protocol/http/HttpTrafficAnalyzer.cpp269
1 files changed, 269 insertions, 0 deletions
diff --git a/netwerk/protocol/http/HttpTrafficAnalyzer.cpp b/netwerk/protocol/http/HttpTrafficAnalyzer.cpp
new file mode 100644
index 0000000000..4fdabef14a
--- /dev/null
+++ b/netwerk/protocol/http/HttpTrafficAnalyzer.cpp
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "HttpTrafficAnalyzer.h"
+#include "HttpLog.h"
+
+#include "mozilla/StaticPrefs_network.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/Unused.h"
+#include "nsSocketTransportService2.h"
+
+namespace mozilla {
+namespace net {
+
+constexpr auto kInvalidCategory = "INVALID_CATEGORY"_ns;
+
+#define DEFINE_CATEGORY(_name, _idx) nsLiteralCString("Y" #_idx "_" #_name),
+static const nsCString gKeyName[] = {
+#include "HttpTrafficAnalyzer.inc"
+ kInvalidCategory,
+};
+#undef DEFINE_CATEGORY
+
+#define DEFINE_CATEGORY(_name, _idx) \
+ Telemetry::LABELS_HTTP_TRAFFIC_ANALYSIS_3::Y##_idx##_##_name,
+static const Telemetry::LABELS_HTTP_TRAFFIC_ANALYSIS_3 gTelemetryLabel[] = {
+#include "HttpTrafficAnalyzer.inc"
+};
+#undef DEFINE_CATEGORY
+
+// ----------------------------------------------------
+// | Flags | Load Type |
+// ----------------------------------------------------
+// | nsIClassOfService::Leader | A |
+// | w/o nsIRequest::LOAD_BACKGROUND | B |
+// | w/ nsIRequest::LOAD_BACKGROUND | C |
+// ----------------------------------------------------
+// | Category | List Category |
+// ----------------------------------------------------
+// | Basic Disconnected List | I |
+// | Content | II |
+// | Fingerprinting | III |
+// ----------------------------------------------------
+// ====================================================
+// | Normal Mode |
+// ----------------------------------------------------
+// | Y = 0 for system principals |
+// | Y = 1 for first party |
+// | Y = 2 for non-listed third party type |
+// ----------------------------------------------------
+// | \Y\ | Type A | Type B | Type C |
+// ----------------------------------------------------
+// | Category I | 3 | 4 | 5 |
+// | Category II | 6 | 7 | 8 |
+// | Category III | 9 | 10 | 11 |
+// ====================================================
+// | Private Mode |
+// ----------------------------------------------------
+// | Y = 12 for system principals |
+// | Y = 13 for first party |
+// | Y = 14 for non-listed third party type |
+// ----------------------------------------------------
+// | \Y\ | Type A | Type B | Type C |
+// ----------------------------------------------------
+// | Category I | 15 | 16 | 17 |
+// | Category II | 18 | 19 | 20 |
+// | Category III | 21 | 22 | 23 |
+// ====================================================
+
+HttpTrafficCategory HttpTrafficAnalyzer::CreateTrafficCategory(
+ bool aIsPrivateMode, bool aIsSystemPrincipal, bool aIsThirdParty,
+ ClassOfService aClassOfService, TrackingClassification aClassification) {
+ uint8_t category = aIsPrivateMode ? 12 : 0;
+ if (aIsSystemPrincipal) {
+ MOZ_ASSERT_IF(!aIsPrivateMode,
+ gKeyName[category].EqualsLiteral("Y0_N1Sys"));
+ MOZ_ASSERT_IF(aIsPrivateMode,
+ gKeyName[category].EqualsLiteral("Y12_P1Sys"));
+ return static_cast<HttpTrafficCategory>(category);
+ }
+ ++category;
+
+ if (!aIsThirdParty) {
+ MOZ_ASSERT_IF(!aIsPrivateMode, gKeyName[category].EqualsLiteral("Y1_N1"));
+ MOZ_ASSERT_IF(aIsPrivateMode, gKeyName[category].EqualsLiteral("Y13_P1"));
+ return static_cast<HttpTrafficCategory>(category);
+ }
+
+ switch (aClassification) {
+ case TrackingClassification::eNone:
+ ++category;
+ MOZ_ASSERT_IF(!aIsPrivateMode,
+ gKeyName[category].EqualsLiteral("Y2_N3Oth"));
+ MOZ_ASSERT_IF(aIsPrivateMode,
+ gKeyName[category].EqualsLiteral("Y14_P3Oth"));
+ return static_cast<HttpTrafficCategory>(category);
+ case TrackingClassification::eBasic:
+ category += 2;
+ break;
+ case TrackingClassification::eContent:
+ category += 5;
+ break;
+ case TrackingClassification::eFingerprinting:
+ category += 8;
+ break;
+ default:
+ MOZ_ASSERT(false, "incorrect classification");
+ return HttpTrafficCategory::eInvalid;
+ }
+
+ switch (aClassOfService) {
+ case ClassOfService::eLeader:
+ MOZ_ASSERT_IF(
+ !aIsPrivateMode,
+ (aClassification == TrackingClassification::eBasic &&
+ gKeyName[category].EqualsLiteral("Y3_N3BasicLead")) ||
+ (aClassification == TrackingClassification::eContent &&
+ gKeyName[category].EqualsLiteral("Y6_N3ContentLead")) ||
+ (aClassification == TrackingClassification::eFingerprinting &&
+ gKeyName[category].EqualsLiteral("Y9_N3FpLead")));
+ MOZ_ASSERT_IF(
+ aIsPrivateMode,
+ (aClassification == TrackingClassification::eBasic &&
+ gKeyName[category].EqualsLiteral("Y15_P3BasicLead")) ||
+ (aClassification == TrackingClassification::eContent &&
+ gKeyName[category].EqualsLiteral("Y18_P3ContentLead")) ||
+ (aClassification == TrackingClassification::eFingerprinting &&
+ gKeyName[category].EqualsLiteral("Y21_P3FpLead")));
+ return static_cast<HttpTrafficCategory>(category);
+ case ClassOfService::eBackground:
+ ++category;
+
+ MOZ_ASSERT_IF(
+ !aIsPrivateMode,
+ (aClassification == TrackingClassification::eBasic &&
+ gKeyName[category].EqualsLiteral("Y4_N3BasicBg")) ||
+ (aClassification == TrackingClassification::eContent &&
+ gKeyName[category].EqualsLiteral("Y7_N3ContentBg")) ||
+ (aClassification == TrackingClassification::eFingerprinting &&
+ gKeyName[category].EqualsLiteral("Y10_N3FpBg")));
+ MOZ_ASSERT_IF(
+ aIsPrivateMode,
+ (aClassification == TrackingClassification::eBasic &&
+ gKeyName[category].EqualsLiteral("Y16_P3BasicBg")) ||
+ (aClassification == TrackingClassification::eContent &&
+ gKeyName[category].EqualsLiteral("Y19_P3ContentBg")) ||
+ (aClassification == TrackingClassification::eFingerprinting &&
+ gKeyName[category].EqualsLiteral("Y22_P3FpBg")));
+
+ return static_cast<HttpTrafficCategory>(category);
+ case ClassOfService::eOther:
+ category += 2;
+
+ MOZ_ASSERT_IF(
+ !aIsPrivateMode,
+ (aClassification == TrackingClassification::eBasic &&
+ gKeyName[category].EqualsLiteral("Y5_N3BasicOth")) ||
+ (aClassification == TrackingClassification::eContent &&
+ gKeyName[category].EqualsLiteral("Y8_N3ContentOth")) ||
+ (aClassification == TrackingClassification::eFingerprinting &&
+ gKeyName[category].EqualsLiteral("Y11_N3FpOth")));
+ MOZ_ASSERT_IF(
+ aIsPrivateMode,
+ (aClassification == TrackingClassification::eBasic &&
+ gKeyName[category].EqualsLiteral("Y17_P3BasicOth")) ||
+ (aClassification == TrackingClassification::eContent &&
+ gKeyName[category].EqualsLiteral("Y20_P3ContentOth")) ||
+ (aClassification == TrackingClassification::eFingerprinting &&
+ gKeyName[category].EqualsLiteral("Y23_P3FpOth")));
+
+ return static_cast<HttpTrafficCategory>(category);
+ }
+
+ MOZ_ASSERT(false, "incorrect class of service");
+ return HttpTrafficCategory::eInvalid;
+}
+
+void HttpTrafficAnalyzer::IncrementHttpTransaction(
+ HttpTrafficCategory aCategory) {
+ MOZ_ASSERT(OnSocketThread(), "not on socket thread");
+ MOZ_ASSERT(StaticPrefs::network_traffic_analyzer_enabled());
+ MOZ_ASSERT(aCategory != HttpTrafficCategory::eInvalid, "invalid category");
+
+ LOG(("HttpTrafficAnalyzer::IncrementHttpTransaction [%s] [this=%p]\n",
+ gKeyName[aCategory].get(), this));
+
+ Telemetry::AccumulateCategoricalKeyed("Transaction"_ns,
+ gTelemetryLabel[aCategory]);
+}
+
+void HttpTrafficAnalyzer::IncrementHttpConnection(
+ HttpTrafficCategory aCategory) {
+ MOZ_ASSERT(OnSocketThread(), "not on socket thread");
+ MOZ_ASSERT(StaticPrefs::network_traffic_analyzer_enabled());
+ MOZ_ASSERT(aCategory != HttpTrafficCategory::eInvalid, "invalid category");
+
+ LOG(("HttpTrafficAnalyzer::IncrementHttpConnection [%s] [this=%p]\n",
+ gKeyName[aCategory].get(), this));
+
+ Telemetry::AccumulateCategoricalKeyed("Connection"_ns,
+ gTelemetryLabel[aCategory]);
+}
+
+void HttpTrafficAnalyzer::IncrementHttpConnection(
+ nsTArray<HttpTrafficCategory>&& aCategories) {
+ MOZ_ASSERT(OnSocketThread(), "not on socket thread");
+ MOZ_ASSERT(StaticPrefs::network_traffic_analyzer_enabled());
+ MOZ_ASSERT(!aCategories.IsEmpty(), "empty category");
+
+ nsTArray<HttpTrafficCategory> categories(std::move(aCategories));
+
+ LOG(("HttpTrafficAnalyzer::IncrementHttpConnection size=%" PRIuPTR
+ " [this=%p]\n",
+ categories.Length(), this));
+
+ // divide categories into 4 parts:
+ // 1) normal 1st-party (Y in {0, 1})
+ // 2) normal 3rd-party (1 < Y < 12)
+ // 3) private 1st-party (Y in {12, 13})
+ // 4) private 3rd-party (13 < Y < 24)
+ // Normal and private transaction should not share the same connection,
+ // and we choose 3rd-party prior than 1st-party.
+ HttpTrafficCategory best = categories[0];
+ for (auto category : categories) {
+ MOZ_ASSERT(category != HttpTrafficCategory::eInvalid, "invalid category");
+
+ if (category == 0 || category == 1 || category == 12 || category == 13) {
+ // first party
+ MOZ_ASSERT(gKeyName[category].EqualsLiteral("Y0_N1Sys") ||
+ gKeyName[category].EqualsLiteral("Y1_N1") ||
+ gKeyName[category].EqualsLiteral("Y12_P1Sys") ||
+ gKeyName[category].EqualsLiteral("Y13_P1"));
+ continue;
+ }
+ // third party
+ MOZ_ASSERT(gKeyName[24].Equals(kInvalidCategory),
+ "category definition isn't consistent");
+ best = category;
+ break;
+ }
+
+ IncrementHttpConnection(best);
+}
+
+#define CLAMP_U32(num) \
+ Clamp<uint32_t>(num, 0, std::numeric_limits<uint32_t>::max())
+
+void HttpTrafficAnalyzer::AccumulateHttpTransferredSize(
+ HttpTrafficCategory aCategory, uint64_t aBytesRead, uint64_t aBytesSent) {
+ MOZ_ASSERT(OnSocketThread(), "not on socket thread");
+ MOZ_ASSERT(StaticPrefs::network_traffic_analyzer_enabled());
+ MOZ_ASSERT(aCategory != HttpTrafficCategory::eInvalid, "invalid category");
+
+ LOG(("HttpTrafficAnalyzer::AccumulateHttpTransferredSize [%s] rb=%" PRIu64 " "
+ "sb=%" PRIu64 " [this=%p]\n",
+ gKeyName[aCategory].get(), aBytesRead, aBytesSent, this));
+
+ // Telemetry supports uint32_t only, and we send KB here.
+ auto total = CLAMP_U32((aBytesRead >> 10) + (aBytesSent >> 10));
+ if (aBytesRead || aBytesSent) {
+ Telemetry::ScalarAdd(Telemetry::ScalarID::NETWORKING_DATA_TRANSFERRED_V3_KB,
+ NS_ConvertUTF8toUTF16(gKeyName[aCategory]), total);
+ }
+}
+
+} // namespace net
+} // namespace mozilla