tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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