summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/HttpTrafficAnalyzer.cpp
blob: 4fdabef14ac10213307cb6f764abf3f8fd71a588 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
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