Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/base/nsChannelClassifier.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set sw=2 sts=2 ts=8 et tw=80 : */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsChannelClassifier.h"
8
9
#include "mozIThirdPartyUtil.h"
10
#include "nsCharSeparatedTokenizer.h"
11
#include "nsContentUtils.h"
12
#include "nsIAddonPolicyService.h"
13
#include "nsICacheEntry.h"
14
#include "nsICachingChannel.h"
15
#include "nsICookieService.h"
16
#include "nsIChannel.h"
17
#include "nsIClassOfService.h"
18
#include "nsIDocShell.h"
19
#include "nsIDocument.h"
20
#include "nsIHttpChannel.h"
21
#include "nsIHttpChannelInternal.h"
22
#include "nsIIOService.h"
23
#include "nsIParentChannel.h"
24
#include "nsIPermissionManager.h"
25
#include "nsIProtocolHandler.h"
26
#include "nsIScriptError.h"
27
#include "nsIScriptSecurityManager.h"
28
#include "nsISecureBrowserUI.h"
29
#include "nsISecurityEventSink.h"
30
#include "nsISupportsPriority.h"
31
#include "nsIURL.h"
32
#include "nsIWebProgressListener.h"
33
#include "nsNetUtil.h"
34
#include "nsPIDOMWindow.h"
35
#include "nsXULAppAPI.h"
36
#include "nsQueryObject.h"
37
#include "nsIUrlClassifierDBService.h"
38
#include "nsIURLFormatter.h"
39
40
#include "mozilla/AntiTrackingCommon.h"
41
#include "mozilla/ErrorNames.h"
42
#include "mozilla/Logging.h"
43
#include "mozilla/Preferences.h"
44
#include "mozilla/net/HttpBaseChannel.h"
45
#include "mozilla/ClearOnShutdown.h"
46
#include "mozilla/Services.h"
47
#include "mozilla/StaticPrefs.h"
48
#include "mozilla/Unused.h"
49
50
namespace mozilla {
51
namespace net {
52
53
//
54
// MOZ_LOG=nsChannelClassifier:5
55
//
56
static LazyLogModule gChannelClassifierLog("nsChannelClassifier");
57
58
59
#undef LOG
60
0
#define LOG(args) MOZ_LOG(gChannelClassifierLog, LogLevel::Info, args)
61
0
#define LOG_DEBUG(args) MOZ_LOG(gChannelClassifierLog, LogLevel::Debug, args)
62
0
#define LOG_WARN(args) MOZ_LOG(gChannelClassifierLog, LogLevel::Warning, args)
63
0
#define LOG_ENABLED() MOZ_LOG_TEST(gChannelClassifierLog, LogLevel::Info)
64
65
0
#define URLCLASSIFIER_SKIP_HOSTNAMES       "urlclassifier.skipHostnames"
66
0
#define URLCLASSIFIER_ANNOTATION_TABLE     "urlclassifier.trackingAnnotationTable"
67
0
#define URLCLASSIFIER_ANNOTATION_TABLE_TEST_ENTRIES "urlclassifier.trackingAnnotationTable.testEntries"
68
0
#define URLCLASSIFIER_ANNOTATION_WHITELIST "urlclassifier.trackingAnnotationWhitelistTable"
69
0
#define URLCLASSIFIER_ANNOTATION_WHITELIST_TEST_ENTRIES "urlclassifier.trackingAnnotationWhitelistTable.testEntries"
70
0
#define URLCLASSIFIER_TRACKING_TABLE       "urlclassifier.trackingTable"
71
0
#define URLCLASSIFIER_TRACKING_TABLE_TEST_ENTRIES "urlclassifier.trackingTable.testEntries"
72
0
#define URLCLASSIFIER_TRACKING_WHITELIST   "urlclassifier.trackingWhitelistTable"
73
0
#define URLCLASSIFIER_TRACKING_WHITELIST_TEST_ENTRIES "urlclassifier.trackingWhitelistTable.testEntries"
74
75
0
#define TABLE_TRACKING_BLACKLIST_PREF "tracking-blacklist-pref"
76
0
#define TABLE_TRACKING_WHITELIST_PREF "tracking-whitelist-pref"
77
0
#define TABLE_ANNOTATION_BLACKLIST_PREF "annotation-blacklist-pref"
78
0
#define TABLE_ANNOTATION_WHITELIST_PREF "annotation-whitelist-pref"
79
80
static const nsCString::size_type sMaxSpecLength = 128;
81
82
// Put CachedPrefs in anonymous namespace to avoid any collision from outside of
83
// this file.
84
namespace {
85
86
/**
87
 * It is not recommended to read from Preference everytime a channel is
88
 * connected.
89
 * That is not fast and we should cache preference values and reuse them
90
 */
91
class CachedPrefs final
92
{
93
public:
94
  static CachedPrefs* GetInstance();
95
96
  void Init();
97
0
  bool IsAllowListExample() { return sAllowListExample;}
98
0
  bool IsLowerNetworkPriority() { return sLowerNetworkPriority;}
99
0
  bool IsAnnotateChannelEnabled() { return sAnnotateChannelEnabled;}
100
101
0
  nsCString GetSkipHostnames() const { return mSkipHostnames; }
102
0
  nsCString GetAnnotationBlackList() const { return mAnnotationBlacklist; }
103
0
  nsCString GetAnnotationBlackListExtraEntries() const { return mAnnotationBlacklistExtraEntries; }
104
0
  nsCString GetAnnotationWhiteList() const { return mAnnotationWhitelist; }
105
0
  nsCString GetAnnotationWhiteListExtraEntries() const { return mAnnotationWhitelistExtraEntries; }
106
0
  nsCString GetTrackingBlackList() const { return mTrackingBlacklist; }
107
0
  nsCString GetTrackingBlackListExtraEntries() { return mTrackingBlacklistExtraEntries; }
108
0
  nsCString GetTrackingWhiteList() const { return mTrackingWhitelist; }
109
0
  nsCString GetTrackingWhiteListExtraEntries() { return mTrackingWhitelistExtraEntries; }
110
111
0
  void SetSkipHostnames(const nsACString& aHostnames) { mSkipHostnames = aHostnames; }
112
0
  void SetAnnotationBlackList(const nsACString& aList) { mAnnotationBlacklist = aList; }
113
0
  void SetAnnotationBlackListExtraEntries(const nsACString& aList) { mAnnotationBlacklistExtraEntries = aList; }
114
0
  void SetAnnotationWhiteList(const nsACString& aList) { mAnnotationWhitelist = aList; }
115
0
  void SetAnnotationWhiteListExtraEntries(const nsACString& aList) { mAnnotationWhitelistExtraEntries = aList; }
116
0
  void SetTrackingBlackList(const nsACString& aList) { mTrackingBlacklist = aList; }
117
0
  void SetTrackingBlackListExtraEntries(const nsACString& aList) { mTrackingBlacklistExtraEntries = aList; }
118
0
  void SetTrackingWhiteList(const nsACString& aList) { mTrackingWhitelist = aList; }
119
0
  void SetTrackingWhiteListExtraEntries(const nsACString& aList) { mTrackingWhitelistExtraEntries = aList; }
120
121
private:
122
  friend class StaticAutoPtr<CachedPrefs>;
123
  CachedPrefs();
124
  ~CachedPrefs();
125
126
  static void OnPrefsChange(const char* aPrefName, CachedPrefs*);
127
128
  // Whether channels should be annotated as being on the tracking protection
129
  // list.
130
  static bool sAnnotateChannelEnabled;
131
  // Whether the priority of the channels annotated as being on the tracking
132
  // protection list should be lowered.
133
  static bool sLowerNetworkPriority;
134
  static bool sAllowListExample;
135
136
  nsCString mSkipHostnames;
137
  nsCString mAnnotationBlacklist;
138
  nsCString mAnnotationBlacklistExtraEntries;
139
  nsCString mAnnotationWhitelist;
140
  nsCString mAnnotationWhitelistExtraEntries;
141
  nsCString mTrackingBlacklist;
142
  nsCString mTrackingBlacklistExtraEntries;
143
  nsCString mTrackingWhitelist;
144
  nsCString mTrackingWhitelistExtraEntries;
145
146
  static StaticAutoPtr<CachedPrefs> sInstance;
147
};
148
149
bool CachedPrefs::sAllowListExample = false;
150
bool CachedPrefs::sLowerNetworkPriority = false;
151
bool CachedPrefs::sAnnotateChannelEnabled = false;
152
153
StaticAutoPtr<CachedPrefs> CachedPrefs::sInstance;
154
155
// static
156
void
157
CachedPrefs::OnPrefsChange(const char* aPref, CachedPrefs* aPrefs)
158
0
{
159
0
  if (!strcmp(aPref, URLCLASSIFIER_SKIP_HOSTNAMES)) {
160
0
    nsCString skipHostnames;
161
0
    Preferences::GetCString(URLCLASSIFIER_SKIP_HOSTNAMES, skipHostnames);
162
0
    ToLowerCase(skipHostnames);
163
0
    aPrefs->SetSkipHostnames(skipHostnames);
164
0
  } else if (!strcmp(aPref, URLCLASSIFIER_ANNOTATION_TABLE)) {
165
0
    nsAutoCString annotationBlacklist;
166
0
    Preferences::GetCString(URLCLASSIFIER_ANNOTATION_TABLE,
167
0
                            annotationBlacklist);
168
0
    aPrefs->SetAnnotationBlackList(annotationBlacklist);
169
0
  } else if (!strcmp(aPref, URLCLASSIFIER_ANNOTATION_TABLE_TEST_ENTRIES)) {
170
0
    nsAutoCString annotationBlacklistExtraEntries;
171
0
    Preferences::GetCString(URLCLASSIFIER_ANNOTATION_TABLE_TEST_ENTRIES,
172
0
                            annotationBlacklistExtraEntries);
173
0
    aPrefs->SetAnnotationBlackListExtraEntries(annotationBlacklistExtraEntries);
174
0
  } else if (!strcmp(aPref, URLCLASSIFIER_ANNOTATION_WHITELIST)) {
175
0
    nsAutoCString annotationWhitelist;
176
0
    Preferences::GetCString(URLCLASSIFIER_ANNOTATION_WHITELIST,
177
0
                            annotationWhitelist);
178
0
    aPrefs->SetAnnotationWhiteList(annotationWhitelist);
179
0
  } else if (!strcmp(aPref, URLCLASSIFIER_ANNOTATION_WHITELIST_TEST_ENTRIES)) {
180
0
    nsAutoCString annotationWhitelistExtraEntries;
181
0
    Preferences::GetCString(URLCLASSIFIER_ANNOTATION_WHITELIST_TEST_ENTRIES,
182
0
                            annotationWhitelistExtraEntries);
183
0
    aPrefs->SetAnnotationWhiteListExtraEntries(annotationWhitelistExtraEntries);
184
0
  } else if (!strcmp(aPref, URLCLASSIFIER_TRACKING_WHITELIST)) {
185
0
    nsCString trackingWhitelist;
186
0
    Preferences::GetCString(URLCLASSIFIER_TRACKING_WHITELIST,
187
0
                            trackingWhitelist);
188
0
    aPrefs->SetTrackingWhiteList(trackingWhitelist);
189
0
  } else if (!strcmp(aPref, URLCLASSIFIER_TRACKING_WHITELIST_TEST_ENTRIES)) {
190
0
    nsCString trackingWhitelistExtraEntries;
191
0
    Preferences::GetCString(URLCLASSIFIER_TRACKING_WHITELIST_TEST_ENTRIES,
192
0
                            trackingWhitelistExtraEntries);
193
0
    aPrefs->SetTrackingWhiteListExtraEntries(trackingWhitelistExtraEntries);
194
0
  } else if (!strcmp(aPref, URLCLASSIFIER_TRACKING_TABLE)) {
195
0
    nsCString trackingBlacklist;
196
0
    Preferences::GetCString(URLCLASSIFIER_TRACKING_TABLE, trackingBlacklist);
197
0
    aPrefs->SetTrackingBlackList(trackingBlacklist);
198
0
  } else if (!strcmp(aPref, URLCLASSIFIER_TRACKING_TABLE_TEST_ENTRIES)) {
199
0
    nsCString trackingBlacklistExtraEntries;
200
0
    Preferences::GetCString(URLCLASSIFIER_TRACKING_TABLE_TEST_ENTRIES, trackingBlacklistExtraEntries);
201
0
    aPrefs->SetTrackingBlackListExtraEntries(trackingBlacklistExtraEntries);
202
0
  }
203
0
}
204
205
void
206
CachedPrefs::Init()
207
0
{
208
0
  Preferences::AddBoolVarCache(&sAnnotateChannelEnabled,
209
0
                               "privacy.trackingprotection.annotate_channels");
210
0
  Preferences::AddBoolVarCache(&sLowerNetworkPriority,
211
0
                               "privacy.trackingprotection.lower_network_priority");
212
0
  Preferences::AddBoolVarCache(&sAllowListExample,
213
0
                               "channelclassifier.allowlist_example");
214
0
  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
215
0
                                       URLCLASSIFIER_SKIP_HOSTNAMES, this);
216
0
  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
217
0
                                       URLCLASSIFIER_ANNOTATION_TABLE, this);
218
0
  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
219
0
                                       URLCLASSIFIER_ANNOTATION_TABLE_TEST_ENTRIES, this);
220
0
  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
221
0
                                       URLCLASSIFIER_ANNOTATION_WHITELIST, this);
222
0
  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
223
0
                                       URLCLASSIFIER_ANNOTATION_WHITELIST_TEST_ENTRIES, this);
224
0
  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
225
0
                                       URLCLASSIFIER_TRACKING_WHITELIST, this);
226
0
  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
227
0
                                       URLCLASSIFIER_TRACKING_WHITELIST_TEST_ENTRIES, this);
228
0
  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
229
0
                                       URLCLASSIFIER_TRACKING_TABLE, this);
230
0
  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
231
0
                                       URLCLASSIFIER_TRACKING_TABLE_TEST_ENTRIES, this);
232
0
}
233
234
// static
235
CachedPrefs*
236
CachedPrefs::GetInstance()
237
0
{
238
0
  if (!sInstance) {
239
0
    sInstance = new CachedPrefs();
240
0
    sInstance->Init();
241
0
    ClearOnShutdown(&sInstance);
242
0
  }
243
0
  MOZ_ASSERT(sInstance);
244
0
  return sInstance;
245
0
}
246
247
CachedPrefs::CachedPrefs()
248
0
{
249
0
  MOZ_COUNT_CTOR(CachedPrefs);
250
0
}
251
252
CachedPrefs::~CachedPrefs()
253
0
{
254
0
  MOZ_COUNT_DTOR(CachedPrefs);
255
0
256
0
  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_SKIP_HOSTNAMES, this);
257
0
  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_ANNOTATION_TABLE, this);
258
0
  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_ANNOTATION_TABLE_TEST_ENTRIES, this);
259
0
  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_ANNOTATION_WHITELIST, this);
260
0
  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_ANNOTATION_WHITELIST_TEST_ENTRIES, this);
261
0
  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_TRACKING_WHITELIST, this);
262
0
  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_TRACKING_WHITELIST_TEST_ENTRIES, this);
263
0
  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_TRACKING_TABLE, this);
264
0
  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_TRACKING_TABLE_TEST_ENTRIES, this);
265
0
}
266
} // anonymous namespace
267
268
static nsresult
269
IsThirdParty(nsIChannel* aChannel, bool* aResult)
270
0
{
271
0
  NS_ENSURE_ARG(aResult);
272
0
  *aResult = false;
273
0
274
0
  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil();
275
0
  if (NS_WARN_IF(!thirdPartyUtil)) {
276
0
    return NS_ERROR_FAILURE;
277
0
  }
278
0
279
0
  nsresult rv;
280
0
  nsCOMPtr<nsIHttpChannelInternal> chan = do_QueryInterface(aChannel, &rv);
281
0
  if (NS_FAILED(rv) || !chan) {
282
0
    LOG(("nsChannelClassifier: Not an HTTP channel"));
283
0
    return NS_OK;
284
0
  }
285
0
  nsCOMPtr<nsIURI> chanURI;
286
0
  rv = aChannel->GetURI(getter_AddRefs(chanURI));
287
0
  NS_ENSURE_SUCCESS(rv, rv);
288
0
289
0
  nsCOMPtr<nsIURI> topWinURI;
290
0
  rv = chan->GetTopWindowURI(getter_AddRefs(topWinURI));
291
0
  if (NS_FAILED(rv)) {
292
0
    return rv;
293
0
  }
294
0
  if (!topWinURI) {
295
0
    LOG(("nsChannelClassifier: No window URI\n"));
296
0
  }
297
0
298
0
  // Third party checks don't work for chrome:// URIs in mochitests, so just
299
0
  // default to isThirdParty = true. We check isThirdPartyWindow to expand
300
0
  // the list of domains that are considered first party (e.g., if
301
0
  // facebook.com includes an iframe from fatratgames.com, all subsources
302
0
  // included in that iframe are considered third-party with
303
0
  // isThirdPartyChannel, even if they are not third-party w.r.t.
304
0
  // facebook.com), and isThirdPartyChannel to prevent top-level navigations
305
0
  // from being detected as third-party.
306
0
  bool isThirdPartyChannel = true;
307
0
  bool isThirdPartyWindow = true;
308
0
  thirdPartyUtil->IsThirdPartyURI(chanURI, topWinURI, &isThirdPartyWindow);
309
0
  thirdPartyUtil->IsThirdPartyChannel(aChannel, nullptr, &isThirdPartyChannel);
310
0
311
0
  *aResult = isThirdPartyWindow && isThirdPartyChannel;
312
0
  return NS_OK;
313
0
}
314
315
static void
316
SetIsTrackingResourceHelper(nsIChannel* aChannel, bool aIsThirdParty)
317
0
{
318
0
  MOZ_ASSERT(aChannel);
319
0
320
0
  nsCOMPtr<nsIParentChannel> parentChannel;
321
0
  NS_QueryNotificationCallbacks(aChannel, parentChannel);
322
0
  if (parentChannel) {
323
0
    // This channel is a parent-process proxy for a child process
324
0
    // request. We should notify the child process as well.
325
0
    parentChannel->NotifyTrackingResource(aIsThirdParty);
326
0
  }
327
0
328
0
  RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(aChannel);
329
0
  if (httpChannel) {
330
0
    httpChannel->SetIsTrackingResource(aIsThirdParty);
331
0
  }
332
0
}
333
334
static void
335
LowerPriorityHelper(nsIChannel* aChannel)
336
0
{
337
0
  MOZ_ASSERT(aChannel);
338
0
339
0
  bool isBlockingResource = false;
340
0
341
0
  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(aChannel));
342
0
  if (cos) {
343
0
    if (nsContentUtils::IsTailingEnabled()) {
344
0
      uint32_t cosFlags = 0;
345
0
      cos->GetClassFlags(&cosFlags);
346
0
      isBlockingResource = cosFlags & (nsIClassOfService::UrgentStart |
347
0
                                       nsIClassOfService::Leader |
348
0
                                       nsIClassOfService::Unblocked);
349
0
350
0
      // Requests not allowed to be tailed are usually those with higher
351
0
      // prioritization.  That overweights being a tracker: don't throttle
352
0
      // them when not in background.
353
0
      if (!(cosFlags & nsIClassOfService::TailForbidden)) {
354
0
        cos->AddClassFlags(nsIClassOfService::Throttleable);
355
0
      }
356
0
    } else {
357
0
      // Yes, we even don't want to evaluate the isBlockingResource when tailing is off
358
0
      // see bug 1395525.
359
0
360
0
      cos->AddClassFlags(nsIClassOfService::Throttleable);
361
0
    }
362
0
  }
363
0
364
0
  if (!isBlockingResource) {
365
0
    nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(aChannel);
366
0
    if (p) {
367
0
      if (LOG_ENABLED()) {
368
0
        nsCOMPtr<nsIURI> uri;
369
0
        aChannel->GetURI(getter_AddRefs(uri));
370
0
        nsAutoCString spec;
371
0
        uri->GetAsciiSpec(spec);
372
0
        spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
373
0
        LOG(("Setting PRIORITY_LOWEST for channel[%p] (%s)",
374
0
             aChannel, spec.get()));
375
0
      }
376
0
      p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
377
0
    }
378
0
  }
379
0
}
380
381
NS_IMPL_ISUPPORTS(nsChannelClassifier,
382
                  nsIURIClassifierCallback,
383
                  nsIObserver)
384
385
nsChannelClassifier::nsChannelClassifier(nsIChannel *aChannel)
386
  : mIsAllowListed(false),
387
    mSuspendedChannel(false),
388
    mChannel(aChannel),
389
    mTrackingProtectionEnabled(Nothing()),
390
    mTrackingAnnotationEnabled(Nothing())
391
0
{
392
0
  LOG_DEBUG(("nsChannelClassifier::nsChannelClassifier %p", this));
393
0
  MOZ_ASSERT(mChannel);
394
0
}
395
396
nsChannelClassifier::~nsChannelClassifier()
397
0
{
398
0
  LOG_DEBUG(("nsChannelClassifier::~nsChannelClassifier %p", this));
399
0
}
400
401
bool
402
nsChannelClassifier::ShouldEnableTrackingProtection()
403
0
{
404
0
  if (mTrackingProtectionEnabled) {
405
0
    return mTrackingProtectionEnabled.value();
406
0
  }
407
0
408
0
  mTrackingProtectionEnabled = Some(false);
409
0
410
0
  nsCOMPtr<nsILoadContext> loadContext;
411
0
  NS_QueryNotificationCallbacks(mChannel, loadContext);
412
0
  if (loadContext && loadContext->UseTrackingProtection()) {
413
0
    Unused << ShouldEnableTrackingProtectionInternal(
414
0
      mChannel, false, mTrackingProtectionEnabled.ptr());
415
0
  }
416
0
417
0
  return mTrackingProtectionEnabled.value();
418
0
}
419
420
bool
421
nsChannelClassifier::ShouldEnableTrackingAnnotation()
422
0
{
423
0
  if (mTrackingAnnotationEnabled) {
424
0
    return mTrackingAnnotationEnabled.value();
425
0
  }
426
0
427
0
  mTrackingAnnotationEnabled = Some(false);
428
0
429
0
  if (!CachedPrefs::GetInstance()->IsAnnotateChannelEnabled()) {
430
0
    return mTrackingAnnotationEnabled.value();
431
0
  }
432
0
433
0
  // If tracking protection is enabled, no need to do channel annotation.
434
0
  if (ShouldEnableTrackingProtection()) {
435
0
    return mTrackingAnnotationEnabled.value();
436
0
  }
437
0
438
0
  // To prevent calling ShouldEnableTrackingProtectionInternal() again,
439
0
  // check loadContext->UseTrackingProtection() here.
440
0
  // If loadContext->UseTrackingProtection() is true, here it means
441
0
  // ShouldEnableTrackingProtectionInternal() has been called before in
442
0
  // ShouldEnableTrackingProtection() above and the result is false.
443
0
  // So, we can just return false.
444
0
  nsCOMPtr<nsILoadContext> loadContext;
445
0
  NS_QueryNotificationCallbacks(mChannel, loadContext);
446
0
  if (loadContext && loadContext->UseTrackingProtection()) {
447
0
    return mTrackingAnnotationEnabled.value();
448
0
  }
449
0
450
0
  Unused << ShouldEnableTrackingProtectionInternal(
451
0
      mChannel, true, mTrackingAnnotationEnabled.ptr());
452
0
453
0
  return mTrackingAnnotationEnabled.value();
454
0
}
455
456
nsresult
457
nsChannelClassifier::ShouldEnableTrackingProtectionInternal(
458
                                                         nsIChannel *aChannel,
459
                                                         bool aAnnotationsOnly,
460
                                                         bool *result)
461
0
{
462
0
    // Should only be called in the parent process.
463
0
    MOZ_ASSERT(XRE_IsParentProcess());
464
0
465
0
    NS_ENSURE_ARG(result);
466
0
    *result = false;
467
0
468
0
    nsresult rv;
469
0
    nsCOMPtr<nsIHttpChannelInternal> chan = do_QueryInterface(aChannel, &rv);
470
0
    if (NS_FAILED(rv) || !chan) {
471
0
      LOG(("nsChannelClassifier[%p]: Not an HTTP channel", this));
472
0
      return NS_OK;
473
0
    }
474
0
475
0
    nsCOMPtr<nsIURI> chanURI;
476
0
    rv = aChannel->GetURI(getter_AddRefs(chanURI));
477
0
    NS_ENSURE_SUCCESS(rv, rv);
478
0
479
0
    // Only perform third-party checks for tracking protection
480
0
    if (!aAnnotationsOnly) {
481
0
      bool isThirdParty = false;
482
0
      rv = IsThirdParty(aChannel, &isThirdParty);
483
0
      if (NS_WARN_IF(NS_FAILED(rv))) {
484
0
        LOG(("nsChannelClassifier[%p]: IsThirdParty() failed", this));
485
0
        return NS_OK;
486
0
      }
487
0
      if (!isThirdParty) {
488
0
        *result = false;
489
0
        if (LOG_ENABLED()) {
490
0
          nsCString spec = chanURI->GetSpecOrDefault();
491
0
          spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
492
0
          LOG(("nsChannelClassifier[%p]: Skipping tracking protection checks "
493
0
               "for first party or top-level load channel[%p] with uri %s",
494
0
               this, aChannel, spec.get()));
495
0
        }
496
0
        return NS_OK;
497
0
      }
498
0
    }
499
0
500
0
    if (AddonMayLoad(aChannel, chanURI)) {
501
0
        return NS_OK;
502
0
    }
503
0
504
0
    nsCOMPtr<nsIIOService> ios = services::GetIOService();
505
0
    NS_ENSURE_TRUE(ios, NS_ERROR_FAILURE);
506
0
507
0
    nsCOMPtr<nsIURI> topWinURI;
508
0
    rv = chan->GetTopWindowURI(getter_AddRefs(topWinURI));
509
0
    if (NS_FAILED(rv)) {
510
0
      return rv;
511
0
    }
512
0
513
0
    if (!topWinURI && CachedPrefs::GetInstance()->IsAllowListExample()) {
514
0
      LOG(("nsChannelClassifier[%p]: Allowlisting test domain\n", this));
515
0
      rv = ios->NewURI(NS_LITERAL_CSTRING("http://allowlisted.example.com"),
516
0
                       nullptr, nullptr, getter_AddRefs(topWinURI));
517
0
      NS_ENSURE_SUCCESS(rv, rv);
518
0
    }
519
0
520
0
    rv = AntiTrackingCommon::IsOnContentBlockingAllowList(topWinURI,
521
0
                                                          aAnnotationsOnly ?
522
0
                                                            AntiTrackingCommon::eTrackingAnnotations :
523
0
                                                            AntiTrackingCommon::eTrackingProtection,
524
0
                                                          mIsAllowListed);
525
0
    if (NS_FAILED(rv)) {
526
0
      return rv; // normal for some loads, no need to print a warning
527
0
    }
528
0
529
0
    if (mIsAllowListed) {
530
0
      *result = false;
531
0
      if (LOG_ENABLED()) {
532
0
        nsCString chanSpec = chanURI->GetSpecOrDefault();
533
0
        chanSpec.Truncate(std::min(chanSpec.Length(), sMaxSpecLength));
534
0
        LOG(("nsChannelClassifier[%p]: User override on channel[%p] (%s)",
535
0
             this, aChannel, chanSpec.get()));
536
0
      }
537
0
    } else {
538
0
      *result = true;
539
0
    }
540
0
541
0
    // Tracking protection will be enabled so return without updating
542
0
    // the security state. If any channels are subsequently cancelled
543
0
    // (page elements blocked) the state will be then updated.
544
0
    if (*result) {
545
0
      if (LOG_ENABLED()) {
546
0
        nsCString chanSpec = chanURI->GetSpecOrDefault();
547
0
        chanSpec.Truncate(std::min(chanSpec.Length(), sMaxSpecLength));
548
0
        nsCString topWinSpec = topWinURI->GetSpecOrDefault();
549
0
        topWinSpec.Truncate(std::min(topWinSpec.Length(), sMaxSpecLength));
550
0
        LOG(("nsChannelClassifier[%p]: Enabling tracking protection checks on "
551
0
             "channel[%p] with uri %s for toplevel window uri %s", this,
552
0
             aChannel, chanSpec.get(), topWinSpec.get()));
553
0
      }
554
0
      return NS_OK;
555
0
    }
556
0
557
0
    // Tracking protection will be disabled so update the security state
558
0
    // of the document and fire a secure change event. If we can't get the
559
0
    // window for the channel, then the shield won't show up so we can't send
560
0
    // an event to the securityUI anyway.
561
0
    return NotifyTrackingProtectionDisabled(aChannel);
562
0
}
563
564
bool
565
nsChannelClassifier::AddonMayLoad(nsIChannel *aChannel, nsIURI *aUri)
566
0
{
567
0
    nsCOMPtr<nsILoadInfo> channelLoadInfo = aChannel->GetLoadInfo();
568
0
    if (!channelLoadInfo)
569
0
        return false;
570
0
571
0
    // loadingPrincipal is used here to ensure we are loading into an
572
0
    // addon principal.  This allows an addon, with explicit permission, to
573
0
    // call out to API endpoints that may otherwise get blocked.
574
0
    nsIPrincipal* loadingPrincipal = channelLoadInfo->LoadingPrincipal();
575
0
    if (!loadingPrincipal)
576
0
        return false;
577
0
578
0
    return BasePrincipal::Cast(loadingPrincipal)->AddonAllowsLoad(aUri, true);
579
0
}
580
581
// static
582
nsresult
583
nsChannelClassifier::NotifyTrackingProtectionDisabled(nsIChannel *aChannel)
584
0
{
585
0
    // Can be called in EITHER the parent or child process.
586
0
    nsCOMPtr<nsIParentChannel> parentChannel;
587
0
    NS_QueryNotificationCallbacks(aChannel, parentChannel);
588
0
    if (parentChannel) {
589
0
      // This channel is a parent-process proxy for a child process request.
590
0
      // Tell the child process channel to do this instead.
591
0
      parentChannel->NotifyTrackingProtectionDisabled();
592
0
      return NS_OK;
593
0
    }
594
0
595
0
    nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
596
0
      services::GetThirdPartyUtil();
597
0
    if (NS_WARN_IF(!thirdPartyUtil)) {
598
0
      return NS_ERROR_FAILURE;
599
0
    }
600
0
601
0
    nsresult rv;
602
0
    nsCOMPtr<mozIDOMWindowProxy> win;
603
0
    rv = thirdPartyUtil->GetTopWindowForChannel(aChannel, getter_AddRefs(win));
604
0
    NS_ENSURE_SUCCESS(rv, rv);
605
0
606
0
    auto* pwin = nsPIDOMWindowOuter::From(win);
607
0
    nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
608
0
    if (!docShell) {
609
0
      return NS_OK;
610
0
    }
611
0
    nsCOMPtr<nsIDocument> doc = docShell->GetDocument();
612
0
    NS_ENSURE_TRUE(doc, NS_OK);
613
0
614
0
    // Notify nsIWebProgressListeners of this security event.
615
0
    // Can be used to change the UI state.
616
0
    nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell, &rv);
617
0
    NS_ENSURE_SUCCESS(rv, NS_OK);
618
0
    uint32_t state = 0;
619
0
    nsCOMPtr<nsISecureBrowserUI> securityUI;
620
0
    docShell->GetSecurityUI(getter_AddRefs(securityUI));
621
0
    if (!securityUI) {
622
0
      return NS_OK;
623
0
    }
624
0
    doc->SetHasTrackingContentLoaded(true);
625
0
    securityUI->GetState(&state);
626
0
    state |= nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT;
627
0
    eventSink->OnSecurityChange(nullptr, state);
628
0
629
0
    return NS_OK;
630
0
}
631
632
void
633
nsChannelClassifier::Start()
634
0
{
635
0
  nsresult rv = StartInternal();
636
0
  if (NS_FAILED(rv)) {
637
0
    // If we aren't getting a callback for any reason, assume a good verdict and
638
0
    // make sure we resume the channel if necessary.
639
0
    OnClassifyComplete(NS_OK, NS_LITERAL_CSTRING(""),NS_LITERAL_CSTRING(""),
640
0
                       NS_LITERAL_CSTRING(""));
641
0
  }
642
0
}
643
644
nsresult
645
nsChannelClassifier::StartInternal()
646
0
{
647
0
    // Should only be called in the parent process.
648
0
    MOZ_ASSERT(XRE_IsParentProcess());
649
0
650
0
    // Don't bother to run the classifier on a load that has already failed.
651
0
    // (this might happen after a redirect)
652
0
    nsresult status;
653
0
    mChannel->GetStatus(&status);
654
0
    if (NS_FAILED(status))
655
0
        return status;
656
0
657
0
    // Don't bother to run the classifier on a cached load that was
658
0
    // previously classified as good.
659
0
    if (HasBeenClassified(mChannel)) {
660
0
        return NS_ERROR_UNEXPECTED;
661
0
    }
662
0
663
0
    nsCOMPtr<nsIURI> uri;
664
0
    nsresult rv = mChannel->GetURI(getter_AddRefs(uri));
665
0
    NS_ENSURE_SUCCESS(rv, rv);
666
0
667
0
    // Don't bother checking certain types of URIs.
668
0
    bool isAbout = false;
669
0
    rv = uri->SchemeIs("about", &isAbout);
670
0
    NS_ENSURE_SUCCESS(rv, rv);
671
0
    if (isAbout) return NS_ERROR_UNEXPECTED;
672
0
673
0
    bool hasFlags;
674
0
    rv = NS_URIChainHasFlags(uri,
675
0
                             nsIProtocolHandler::URI_DANGEROUS_TO_LOAD,
676
0
                             &hasFlags);
677
0
    NS_ENSURE_SUCCESS(rv, rv);
678
0
    if (hasFlags) return NS_ERROR_UNEXPECTED;
679
0
680
0
    rv = NS_URIChainHasFlags(uri,
681
0
                             nsIProtocolHandler::URI_IS_LOCAL_FILE,
682
0
                             &hasFlags);
683
0
    NS_ENSURE_SUCCESS(rv, rv);
684
0
    if (hasFlags) return NS_ERROR_UNEXPECTED;
685
0
686
0
    rv = NS_URIChainHasFlags(uri,
687
0
                             nsIProtocolHandler::URI_IS_UI_RESOURCE,
688
0
                             &hasFlags);
689
0
    NS_ENSURE_SUCCESS(rv, rv);
690
0
    if (hasFlags) return NS_ERROR_UNEXPECTED;
691
0
692
0
    rv = NS_URIChainHasFlags(uri,
693
0
                             nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
694
0
                             &hasFlags);
695
0
    NS_ENSURE_SUCCESS(rv, rv);
696
0
    if (hasFlags) return NS_ERROR_UNEXPECTED;
697
0
698
0
    nsCString skipHostnames = CachedPrefs::GetInstance()->GetSkipHostnames();
699
0
    if (!skipHostnames.IsEmpty()) {
700
0
      LOG(("nsChannelClassifier[%p]:StartInternal whitelisted hostnames = %s",
701
0
           this, skipHostnames.get()));
702
0
      if (IsHostnameWhitelisted(uri, skipHostnames)) {
703
0
        return NS_ERROR_UNEXPECTED;
704
0
      }
705
0
    }
706
0
707
0
    nsCOMPtr<nsIURIClassifier> uriClassifier =
708
0
        do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
709
0
    if (rv == NS_ERROR_FACTORY_NOT_REGISTERED ||
710
0
        rv == NS_ERROR_NOT_AVAILABLE) {
711
0
        // no URI classifier, ignore this failure.
712
0
        return NS_ERROR_NOT_AVAILABLE;
713
0
    }
714
0
    NS_ENSURE_SUCCESS(rv, rv);
715
0
716
0
    nsCOMPtr<nsIScriptSecurityManager> securityManager =
717
0
        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
718
0
    NS_ENSURE_SUCCESS(rv, rv);
719
0
720
0
    nsCOMPtr<nsIPrincipal> principal;
721
0
    rv = securityManager->GetChannelURIPrincipal(mChannel, getter_AddRefs(principal));
722
0
    NS_ENSURE_SUCCESS(rv, rv);
723
0
724
0
    bool expectCallback;
725
0
    if (LOG_ENABLED()) {
726
0
      nsCOMPtr<nsIURI> principalURI;
727
0
      principal->GetURI(getter_AddRefs(principalURI));
728
0
      nsCString spec = principalURI->GetSpecOrDefault();
729
0
      spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
730
0
      LOG(("nsChannelClassifier[%p]: Classifying principal %s on channel[%p]",
731
0
           this, spec.get(), mChannel.get()));
732
0
    }
733
0
    // The classify is running in parent process, no need to give a valid event
734
0
    // target
735
0
    rv = uriClassifier->Classify(principal, nullptr,
736
0
                                 false,
737
0
                                 this, &expectCallback);
738
0
    if (NS_FAILED(rv)) {
739
0
        return rv;
740
0
    }
741
0
742
0
    if (expectCallback) {
743
0
        // Suspend the channel, it will be resumed when we get the classifier
744
0
        // callback.
745
0
        rv = mChannel->Suspend();
746
0
        if (NS_FAILED(rv)) {
747
0
            // Some channels (including nsJSChannel) fail on Suspend.  This
748
0
            // shouldn't be fatal, but will prevent malware from being
749
0
            // blocked on these channels.
750
0
            LOG_WARN(("nsChannelClassifier[%p]: Couldn't suspend channel", this));
751
0
            return rv;
752
0
        }
753
0
754
0
        mSuspendedChannel = true;
755
0
        LOG_DEBUG(("nsChannelClassifier[%p]: suspended channel %p",
756
0
             this, mChannel.get()));
757
0
    } else {
758
0
        LOG(("nsChannelClassifier[%p]: not expecting callback", this));
759
0
        return NS_ERROR_FAILURE;
760
0
    }
761
0
762
0
    // Add an observer for shutdown
763
0
    AddShutdownObserver();
764
0
    return NS_OK;
765
0
}
766
767
bool
768
nsChannelClassifier::IsHostnameWhitelisted(nsIURI *aUri,
769
                                           const nsACString &aWhitelisted)
770
0
{
771
0
  nsAutoCString host;
772
0
  nsresult rv = aUri->GetHost(host);
773
0
  if (NS_FAILED(rv) || host.IsEmpty()) {
774
0
    return false;
775
0
  }
776
0
  ToLowerCase(host);
777
0
778
0
  nsCCharSeparatedTokenizer tokenizer(aWhitelisted, ',');
779
0
  while (tokenizer.hasMoreTokens()) {
780
0
    const nsACString& token = tokenizer.nextToken();
781
0
    if (token.Equals(host)) {
782
0
      LOG(("nsChannelClassifier[%p]:StartInternal skipping %s (whitelisted)",
783
0
           this, host.get()));
784
0
      return true;
785
0
    }
786
0
  }
787
0
788
0
  return false;
789
0
}
790
791
// Note in the cache entry that this URL was classified, so that future
792
// cached loads don't need to be checked.
793
void
794
nsChannelClassifier::MarkEntryClassified(nsresult status)
795
0
{
796
0
    // Should only be called in the parent process.
797
0
    MOZ_ASSERT(XRE_IsParentProcess());
798
0
799
0
    // Don't cache tracking classifications because we support allowlisting.
800
0
    if (status == NS_ERROR_TRACKING_URI || mIsAllowListed) {
801
0
        return;
802
0
    }
803
0
804
0
    if (LOG_ENABLED()) {
805
0
      nsAutoCString errorName;
806
0
      GetErrorName(status, errorName);
807
0
      nsCOMPtr<nsIURI> uri;
808
0
      mChannel->GetURI(getter_AddRefs(uri));
809
0
      nsAutoCString spec;
810
0
      uri->GetAsciiSpec(spec);
811
0
      spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
812
0
      LOG(("nsChannelClassifier::MarkEntryClassified[%s] %s",
813
0
           errorName.get(), spec.get()));
814
0
    }
815
0
816
0
    nsCOMPtr<nsICachingChannel> cachingChannel = do_QueryInterface(mChannel);
817
0
    if (!cachingChannel) {
818
0
        return;
819
0
    }
820
0
821
0
    nsCOMPtr<nsISupports> cacheToken;
822
0
    cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
823
0
    if (!cacheToken) {
824
0
        return;
825
0
    }
826
0
827
0
    nsCOMPtr<nsICacheEntry> cacheEntry =
828
0
        do_QueryInterface(cacheToken);
829
0
    if (!cacheEntry) {
830
0
        return;
831
0
    }
832
0
833
0
    cacheEntry->SetMetaDataElement("necko:classified",
834
0
                                   NS_SUCCEEDED(status) ? "1" : nullptr);
835
0
}
836
837
bool
838
nsChannelClassifier::HasBeenClassified(nsIChannel *aChannel)
839
0
{
840
0
    // Should only be called in the parent process.
841
0
    MOZ_ASSERT(XRE_IsParentProcess());
842
0
843
0
    nsCOMPtr<nsICachingChannel> cachingChannel =
844
0
        do_QueryInterface(aChannel);
845
0
    if (!cachingChannel) {
846
0
        return false;
847
0
    }
848
0
849
0
    // Only check the tag if we are loading from the cache without
850
0
    // validation.
851
0
    bool fromCache;
852
0
    if (NS_FAILED(cachingChannel->IsFromCache(&fromCache)) || !fromCache) {
853
0
        return false;
854
0
    }
855
0
856
0
    nsCOMPtr<nsISupports> cacheToken;
857
0
    cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
858
0
    if (!cacheToken) {
859
0
        return false;
860
0
    }
861
0
862
0
    nsCOMPtr<nsICacheEntry> cacheEntry =
863
0
        do_QueryInterface(cacheToken);
864
0
    if (!cacheEntry) {
865
0
        return false;
866
0
    }
867
0
868
0
    nsCString tag;
869
0
    cacheEntry->GetMetaDataElement("necko:classified", getter_Copies(tag));
870
0
    return tag.EqualsLiteral("1");
871
0
}
872
873
// static
874
nsresult
875
nsChannelClassifier::SetBlockedContent(nsIChannel *channel,
876
                                       nsresult aErrorCode,
877
                                       const nsACString& aList,
878
                                       const nsACString& aProvider,
879
                                       const nsACString& aFullHash)
880
0
{
881
0
  NS_ENSURE_ARG(!aList.IsEmpty());
882
0
883
0
  // Can be called in EITHER the parent or child process.
884
0
  nsCOMPtr<nsIParentChannel> parentChannel;
885
0
  NS_QueryNotificationCallbacks(channel, parentChannel);
886
0
  if (parentChannel) {
887
0
    // This channel is a parent-process proxy for a child process request.
888
0
    // Tell the child process channel to do this instead.
889
0
    parentChannel->SetClassifierMatchedInfo(aList, aProvider, aFullHash);
890
0
    return NS_OK;
891
0
  }
892
0
893
0
  nsresult rv;
894
0
  nsCOMPtr<nsIClassifiedChannel> classifiedChannel = do_QueryInterface(channel, &rv);
895
0
  NS_ENSURE_SUCCESS(rv, rv);
896
0
897
0
  if (classifiedChannel) {
898
0
    classifiedChannel->SetMatchedInfo(aList, aProvider, aFullHash);
899
0
  }
900
0
901
0
  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
902
0
    services::GetThirdPartyUtil();
903
0
  if (NS_WARN_IF(!thirdPartyUtil)) {
904
0
    return NS_OK;
905
0
  }
906
0
907
0
  nsCOMPtr<mozIDOMWindowProxy> win;
908
0
  rv = thirdPartyUtil->GetTopWindowForChannel(channel, getter_AddRefs(win));
909
0
  NS_ENSURE_SUCCESS(rv, NS_OK);
910
0
  auto* pwin = nsPIDOMWindowOuter::From(win);
911
0
  nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
912
0
  if (!docShell) {
913
0
    return NS_OK;
914
0
  }
915
0
  nsCOMPtr<nsIDocument> doc = docShell->GetDocument();
916
0
  NS_ENSURE_TRUE(doc, NS_OK);
917
0
918
0
  unsigned state;
919
0
  if (aErrorCode == NS_ERROR_TRACKING_URI) {
920
0
    state = nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT;
921
0
  } else {
922
0
    state = nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT;
923
0
  }
924
0
  pwin->NotifyContentBlockingState(state, channel);
925
0
926
0
  // Log a warning to the web console.
927
0
  nsCOMPtr<nsIURI> uri;
928
0
  channel->GetURI(getter_AddRefs(uri));
929
0
  NS_ConvertUTF8toUTF16 spec(uri->GetSpecOrDefault());
930
0
  const char16_t* params[] = { spec.get() };
931
0
  const char* message = (aErrorCode == NS_ERROR_TRACKING_URI) ?
932
0
    "TrackerUriBlocked" : "UnsafeUriBlocked";
933
0
  nsCString category = (aErrorCode == NS_ERROR_TRACKING_URI) ?
934
0
    NS_LITERAL_CSTRING("Tracking Protection") :
935
0
    NS_LITERAL_CSTRING("Safe Browsing");
936
0
937
0
  nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
938
0
                                  category,
939
0
                                  doc,
940
0
                                  nsContentUtils::eNECKO_PROPERTIES,
941
0
                                  message,
942
0
                                  params, ArrayLength(params));
943
0
944
0
  return NS_OK;
945
0
}
946
947
namespace {
948
949
// This class is designed to get the results of checking blacklist and whitelist.
950
// |mExpect*WhitelistResult| are used to indicate that |OnClassifyComplete| is called
951
// for the result of blacklist or whitelist check.
952
class TrackingURICallback final : public nsIURIClassifierCallback {
953
public:
954
  NS_DECL_THREADSAFE_ISUPPORTS
955
  NS_DECL_NSIURICLASSIFIERCALLBACK
956
957
  explicit TrackingURICallback(nsChannelClassifier* aChannelClassifier,
958
                               std::function<void()>&& aCallback)
959
    : mChannelClassifier(aChannelClassifier)
960
    , mChannelCallback(std::move(aCallback))
961
    , mExpectAnnotationWhitelistResult(false)
962
    , mExpectTrackingWhitelistResult(false)
963
0
  {
964
0
    MOZ_ASSERT(mChannelClassifier);
965
0
  }
966
967
private:
968
0
  ~TrackingURICallback() = default;
969
  nsresult OnBlacklistResult(nsresult aErrorCode, bool aInTrackingTable,
970
                             bool aInAnnotationTable);
971
  nsresult OnWhitelistResult(nsresult aErrorCode);
972
  void OnTrackerFound(nsresult aErrorCode);
973
974
  RefPtr<nsChannelClassifier> mChannelClassifier;
975
  std::function<void()> mChannelCallback;
976
  bool mExpectAnnotationWhitelistResult;
977
  bool mExpectTrackingWhitelistResult;
978
979
  nsCString mList;
980
  nsCString mProvider;
981
  nsCString mFullHash;
982
};
983
984
NS_IMPL_ISUPPORTS(TrackingURICallback, nsIURIClassifierCallback)
985
986
// This function gets called whenever we receive the results (match or
987
// no match) from an asynchronous list (blacklist or whitelist) lookup.
988
/*virtual*/ nsresult
989
TrackingURICallback::OnClassifyComplete(nsresult aErrorCode,
990
                                        const nsACString& aLists,
991
                                        const nsACString& aProvider,
992
                                        const nsACString& aFullHash)
993
0
{
994
0
  MOZ_ASSERT(aErrorCode == NS_OK);
995
0
996
0
  const bool shouldEnableTrackingProtection =
997
0
    mChannelClassifier->ShouldEnableTrackingProtection();
998
0
  const bool shouldEnableTrackingAnnotation =
999
0
    mChannelClassifier->ShouldEnableTrackingAnnotation();
1000
0
  MOZ_ASSERT(shouldEnableTrackingProtection || shouldEnableTrackingAnnotation);
1001
0
1002
0
  LOG(("TrackingURICallback[%p]:OnClassifyComplete "
1003
0
       "shouldEnableTrackingProtection=%d, shouldEnableTrackingAnnnotation=%d",
1004
0
       mChannelClassifier.get(), shouldEnableTrackingProtection,
1005
0
       shouldEnableTrackingAnnotation));
1006
0
1007
0
  // Figure out whether we are receiving the results of a blacklist or
1008
0
  // a whitelist lookup
1009
0
1010
0
  if (!mExpectAnnotationWhitelistResult && !mExpectTrackingWhitelistResult) {
1011
0
    // Blacklist lookup results
1012
0
1013
0
    mList = aLists;
1014
0
    mProvider = aProvider;
1015
0
    mFullHash = aFullHash;
1016
0
1017
0
    if (aLists.IsEmpty()) {
1018
0
      return OnBlacklistResult(NS_OK, false, false); // not a tracker
1019
0
    }
1020
0
1021
0
    // Figure out which of the blacklist(s) matched
1022
0
1023
0
    const nsCString annotationTable =
1024
0
      CachedPrefs::GetInstance()->GetAnnotationBlackList();
1025
0
    const nsCString trackingTable =
1026
0
      CachedPrefs::GetInstance()->GetTrackingBlackList();
1027
0
1028
0
    bool inTrackingTable = false;
1029
0
    bool inAnnotationTable = false;
1030
0
1031
0
1032
0
    nsCCharSeparatedTokenizer tokenizer(aLists, ',');
1033
0
    while (tokenizer.hasMoreTokens()) {
1034
0
      const nsACString& list = tokenizer.nextToken();
1035
0
      if (shouldEnableTrackingProtection && !inTrackingTable &&
1036
0
          (list == TABLE_TRACKING_BLACKLIST_PREF ||
1037
0
           FindInReadable(list, trackingTable))) {
1038
0
        inTrackingTable = true;
1039
0
      }
1040
0
      if (shouldEnableTrackingAnnotation && !inAnnotationTable &&
1041
0
          (list == TABLE_ANNOTATION_BLACKLIST_PREF ||
1042
0
           FindInReadable(list, annotationTable))) {
1043
0
        inAnnotationTable = true;
1044
0
      }
1045
0
    }
1046
0
1047
0
    MOZ_ASSERT(shouldEnableTrackingProtection || !inTrackingTable);
1048
0
    MOZ_ASSERT(shouldEnableTrackingAnnotation || !inAnnotationTable);
1049
0
1050
0
    if ((shouldEnableTrackingProtection && inTrackingTable) ||
1051
0
        (shouldEnableTrackingAnnotation && inAnnotationTable)) {
1052
0
      // Valid blacklist result, need to check the whitelist(s) next
1053
0
      return OnBlacklistResult(NS_ERROR_MAYBE_TRACKING_URI, inTrackingTable,
1054
0
                               inAnnotationTable);
1055
0
    }
1056
0
1057
0
    if (NS_WARN_IF(!inTrackingTable && !inAnnotationTable)) {
1058
0
      MOZ_ASSERT(false, "The matching lists should be tracking-related.");
1059
0
    }
1060
0
1061
0
    // Nothing to annotate or block
1062
0
    return OnBlacklistResult(NS_OK, inTrackingTable, inAnnotationTable);
1063
0
  }
1064
0
1065
0
  // Whitelist lookup results
1066
0
1067
0
  MOZ_ASSERT(shouldEnableTrackingProtection || !mExpectTrackingWhitelistResult);
1068
0
  MOZ_ASSERT(shouldEnableTrackingAnnotation || !mExpectAnnotationWhitelistResult);
1069
0
1070
0
  bool isTracker = mExpectTrackingWhitelistResult;
1071
0
  bool isAnnotation = mExpectAnnotationWhitelistResult;
1072
0
  MOZ_ASSERT(isTracker || isAnnotation);
1073
0
1074
0
  if (!aLists.IsEmpty()) {
1075
0
    // Figure out which of the whitelist(s) matched
1076
0
1077
0
    const nsCString annotationWhitelistTable =
1078
0
      CachedPrefs::GetInstance()->GetAnnotationWhiteList();
1079
0
    const nsCString trackingWhitelistTable =
1080
0
      CachedPrefs::GetInstance()->GetTrackingWhiteList();
1081
0
1082
0
    nsCCharSeparatedTokenizer tokenizer(aLists, ',');
1083
0
    while (tokenizer.hasMoreTokens() && (isTracker || isAnnotation)) {
1084
0
      const nsACString& list = tokenizer.nextToken();
1085
0
      if (isTracker &&
1086
0
          (list == TABLE_TRACKING_WHITELIST_PREF ||
1087
0
           FindInReadable(list, trackingWhitelistTable))) {
1088
0
        isTracker = false;
1089
0
      }
1090
0
      if (isAnnotation &&
1091
0
          (list == TABLE_ANNOTATION_WHITELIST_PREF ||
1092
0
           FindInReadable(list, annotationWhitelistTable))) {
1093
0
        isAnnotation = false;
1094
0
      }
1095
0
    }
1096
0
  }
1097
0
1098
0
  MOZ_ASSERT(shouldEnableTrackingProtection || !isTracker);
1099
0
  MOZ_ASSERT(shouldEnableTrackingAnnotation || !isAnnotation);
1100
0
1101
0
  if (!isTracker && !isAnnotation) {
1102
0
    return OnWhitelistResult(NS_OK); // fully whitelisted
1103
0
  }
1104
0
1105
0
  // The lookup failed to match at least one of the active whitelists
1106
0
  // (tracking protection takes precedence over tracking annotations)
1107
0
  return OnWhitelistResult(isTracker ? NS_ERROR_TRACKING_URI :
1108
0
                           NS_ERROR_TRACKING_ANNOTATION_URI);
1109
0
}
1110
1111
nsresult
1112
TrackingURICallback::OnBlacklistResult(nsresult aErrorCode,
1113
                                       bool aInTrackingTable,
1114
                                       bool aInAnnotationTable)
1115
0
{
1116
0
  LOG_DEBUG(("TrackingURICallback[%p]::OnBlacklistResult aErrorCode=0x%" PRIx32,
1117
0
             mChannelClassifier.get(), static_cast<uint32_t>(aErrorCode)));
1118
0
1119
0
  if (NS_SUCCEEDED(aErrorCode)) {
1120
0
    if (LOG_ENABLED()) {
1121
0
      nsCOMPtr<nsIChannel> channel = mChannelClassifier->GetChannel();
1122
0
      nsCOMPtr<nsIURI> uri;
1123
0
      channel->GetURI(getter_AddRefs(uri));
1124
0
      nsCString spec = uri->GetSpecOrDefault();
1125
0
      spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
1126
0
      LOG(("TrackingURICallback[%p]::OnBlacklistResult uri %s not found "
1127
0
           "in blacklist", mChannelClassifier.get(), spec.get()));
1128
0
    }
1129
0
    mChannelCallback();
1130
0
    return NS_OK;
1131
0
  }
1132
0
  MOZ_ASSERT(aErrorCode == NS_ERROR_MAYBE_TRACKING_URI);
1133
0
1134
0
  if (LOG_ENABLED()) {
1135
0
    nsCOMPtr<nsIChannel> channel = mChannelClassifier->GetChannel();
1136
0
    nsCOMPtr<nsIURI> uri;
1137
0
    channel->GetURI(getter_AddRefs(uri));
1138
0
    nsCString spec = uri->GetSpecOrDefault();
1139
0
    spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
1140
0
    LOG(("TrackingURICallback[%p]::OnBlacklistResult channel[%p] "
1141
0
         "uri=%s, is in blacklist. Start checking whitelist.",
1142
0
         mChannelClassifier.get(), channel.get(), spec.get()));
1143
0
  }
1144
0
1145
0
  nsCOMPtr<nsIURI> whitelistURI;
1146
0
  nsresult rv = mChannelClassifier->CreateWhiteListURI(getter_AddRefs(whitelistURI));
1147
0
  if (NS_FAILED(rv)) {
1148
0
    nsAutoCString errorName;
1149
0
    GetErrorName(rv, errorName);
1150
0
    NS_WARNING(nsPrintfCString("TrackingURICallback[%p]:OnBlacklistResult got "
1151
0
                               "an unexpected error (rv=%s) while trying to "
1152
0
                               "create a whitelist URI. Allowing tracker.",
1153
0
                               mChannelClassifier.get(), errorName.get()).get());
1154
0
    mChannelCallback();
1155
0
    return NS_OK; // let the tracker through
1156
0
  }
1157
0
1158
0
  if (!whitelistURI) {
1159
0
    LOG(("TrackingURICallback[%p]:OnBlacklistResult could not create a "
1160
0
         "whitelist URI. Ignoring whitelist.", mChannelClassifier.get()));
1161
0
    OnTrackerFound(aInTrackingTable ? NS_ERROR_TRACKING_URI :
1162
0
                   NS_ERROR_TRACKING_ANNOTATION_URI);
1163
0
    mChannelCallback();
1164
0
    return NS_OK;
1165
0
  }
1166
0
1167
0
  rv = mChannelClassifier->IsTrackerWhitelisted(whitelistURI,
1168
0
                                                aInTrackingTable,
1169
0
                                                aInAnnotationTable,
1170
0
                                                this);
1171
0
  if (NS_FAILED(rv)) {
1172
0
    if (LOG_ENABLED()) {
1173
0
      nsAutoCString errorName;
1174
0
      GetErrorName(rv, errorName);
1175
0
      LOG(("TrackingURICallback[%p]:OnBlacklistResult "
1176
0
           "IsTrackerWhitelisted has failed with rv=%s.",
1177
0
           mChannelClassifier.get(), errorName.get()));
1178
0
    }
1179
0
1180
0
    if (rv == NS_ERROR_TRACKING_URI ||
1181
0
        rv == NS_ERROR_TRACKING_ANNOTATION_URI) {
1182
0
      // whitelist disabled, blocking tracker
1183
0
      OnTrackerFound(rv);
1184
0
    } else {
1185
0
      // ignore other failures and let the tracker through
1186
0
      nsAutoCString errorName;
1187
0
      GetErrorName(rv, errorName);
1188
0
      NS_WARNING(nsPrintfCString("Unexpected error (%s) received from "
1189
0
                                 "TrackingURICallback::IsTrackerWhitelisted()",
1190
0
                                 errorName.get()).get());
1191
0
    }
1192
0
    mChannelCallback();
1193
0
    return NS_OK;
1194
0
  }
1195
0
1196
0
  // We'll have to wait for OnWhitelistResult() to get called.
1197
0
  MOZ_ASSERT(aInTrackingTable || aInAnnotationTable);
1198
0
  mExpectTrackingWhitelistResult = aInTrackingTable;
1199
0
  mExpectAnnotationWhitelistResult = aInAnnotationTable;
1200
0
  return NS_OK;
1201
0
}
1202
1203
nsresult
1204
TrackingURICallback::OnWhitelistResult(nsresult aErrorCode)
1205
0
{
1206
0
  LOG_DEBUG(("TrackingURICallback[%p]::OnWhitelistResult aErrorCode=0x%" PRIx32,
1207
0
             mChannelClassifier.get(), static_cast<uint32_t>(aErrorCode)));
1208
0
1209
0
  if (NS_SUCCEEDED(aErrorCode)) {
1210
0
    if (LOG_ENABLED()) {
1211
0
      nsCOMPtr<nsIChannel> channel = mChannelClassifier->GetChannel();
1212
0
      nsCOMPtr<nsIURI> uri;
1213
0
      channel->GetURI(getter_AddRefs(uri));
1214
0
      nsCString spec = uri->GetSpecOrDefault();
1215
0
      spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
1216
0
      LOG(("TrackingURICallback[%p]::OnWhitelistResult uri %s found "
1217
0
           "in whitelist so we won't block it", mChannelClassifier.get(),
1218
0
           spec.get()));
1219
0
    }
1220
0
    mChannelCallback();
1221
0
    return NS_OK;
1222
0
  }
1223
0
1224
0
  if (LOG_ENABLED()) {
1225
0
    nsCOMPtr<nsIChannel> channel = mChannelClassifier->GetChannel();
1226
0
    nsCOMPtr<nsIURI> uri;
1227
0
    channel->GetURI(getter_AddRefs(uri));
1228
0
    nsCString spec = uri->GetSpecOrDefault();
1229
0
    spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
1230
0
    LOG(("TrackingURICallback[%p]::OnWhitelistResult "
1231
0
         "channel[%p] uri=%s, should not be whitelisted",
1232
0
         mChannelClassifier.get(), channel.get(), spec.get()));
1233
0
  }
1234
0
1235
0
  OnTrackerFound(aErrorCode);
1236
0
  mChannelCallback();
1237
0
  return NS_OK;
1238
0
}
1239
1240
void
1241
TrackingURICallback::OnTrackerFound(nsresult aErrorCode)
1242
0
{
1243
0
  nsCOMPtr<nsIChannel> channel = mChannelClassifier->GetChannel();
1244
0
  MOZ_ASSERT(channel);
1245
0
  if (aErrorCode == NS_ERROR_TRACKING_URI &&
1246
0
      mChannelClassifier->ShouldEnableTrackingProtection()) {
1247
0
    mChannelClassifier->SetBlockedContent(channel, aErrorCode,
1248
0
                                          mList, mProvider, mFullHash);
1249
0
    LOG(("TrackingURICallback[%p]::OnTrackerFound, cancelling channel[%p]",
1250
0
         mChannelClassifier.get(), channel.get()));
1251
0
    nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(channel);
1252
0
    if (httpChannel) {
1253
0
      Unused << httpChannel->CancelForTrackingProtection();
1254
0
    } else {
1255
0
      Unused << channel->Cancel(aErrorCode);
1256
0
    }
1257
0
  } else {
1258
0
    MOZ_ASSERT(aErrorCode == NS_ERROR_TRACKING_ANNOTATION_URI);
1259
0
    MOZ_ASSERT(mChannelClassifier->ShouldEnableTrackingAnnotation());
1260
0
1261
0
    bool isThirdPartyWithTopLevelWinURI = false;
1262
0
    nsresult rv = IsThirdParty(channel, &isThirdPartyWithTopLevelWinURI);
1263
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
1264
0
      LOG(("TrackingURICallback[%p]::OnTrackerFound IsThirdParty() failed",
1265
0
           mChannelClassifier.get()));
1266
0
      return; // we'll assume the channel is NOT third-party
1267
0
    }
1268
0
1269
0
    LOG(("TrackingURICallback[%p]::OnTrackerFound, annotating channel[%p]",
1270
0
         mChannelClassifier.get(), channel.get()));
1271
0
1272
0
    SetIsTrackingResourceHelper(channel, isThirdPartyWithTopLevelWinURI);
1273
0
1274
0
    if (isThirdPartyWithTopLevelWinURI) {
1275
0
      // Even with TP disabled, we still want to show the user that there
1276
0
      // are unblocked trackers on the site, so notify the UI that we loaded
1277
0
      // tracking content. UI code can treat this notification differently
1278
0
      // depending on whether TP is enabled or disabled.
1279
0
      mChannelClassifier->NotifyTrackingProtectionDisabled(channel);
1280
0
1281
0
      if (CachedPrefs::GetInstance()->IsLowerNetworkPriority()) {
1282
0
        LowerPriorityHelper(channel);
1283
0
      }
1284
0
    }
1285
0
  }
1286
0
}
1287
1288
} // end of unnamed namespace/
1289
1290
nsresult
1291
nsChannelClassifier::CreateWhiteListURI(nsIURI** aURI) const
1292
0
{
1293
0
  nsresult rv;
1294
0
  nsCOMPtr<nsIHttpChannelInternal> chan = do_QueryInterface(mChannel, &rv);
1295
0
  NS_ENSURE_SUCCESS(rv, rv);
1296
0
  if (!chan) {
1297
0
    return NS_ERROR_FAILURE;
1298
0
  }
1299
0
1300
0
  nsCOMPtr<nsIURI> topWinURI;
1301
0
  rv = chan->GetTopWindowURI(getter_AddRefs(topWinURI));
1302
0
  NS_ENSURE_SUCCESS(rv, rv);
1303
0
  if (!topWinURI) {
1304
0
    if (LOG_ENABLED()) {
1305
0
      nsresult rv;
1306
0
      nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(mChannel, &rv);
1307
0
      nsCOMPtr<nsIURI> uri;
1308
0
      rv = httpChan->GetURI(getter_AddRefs(uri));
1309
0
      nsAutoCString spec;
1310
0
      uri->GetAsciiSpec(spec);
1311
0
      spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
1312
0
      LOG(("nsChannelClassifier[%p]: No window URI associated with %s",
1313
0
           this, spec.get()));
1314
0
    }
1315
0
    return NS_OK;
1316
0
  }
1317
0
1318
0
  nsCOMPtr<nsIScriptSecurityManager> securityManager =
1319
0
    do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
1320
0
  NS_ENSURE_SUCCESS(rv, rv);
1321
0
  nsCOMPtr<nsIPrincipal> chanPrincipal;
1322
0
  rv = securityManager->GetChannelURIPrincipal(mChannel,
1323
0
                                               getter_AddRefs(chanPrincipal));
1324
0
  NS_ENSURE_SUCCESS(rv, rv);
1325
0
1326
0
  // Craft a whitelist URL like "toplevel.page/?resource=third.party.domain"
1327
0
  nsAutoCString pageHostname, resourceDomain;
1328
0
  rv = topWinURI->GetHost(pageHostname);
1329
0
  NS_ENSURE_SUCCESS(rv, rv);
1330
0
  rv = chanPrincipal->GetBaseDomain(resourceDomain);
1331
0
  NS_ENSURE_SUCCESS(rv, rv);
1332
0
  nsAutoCString whitelistEntry = NS_LITERAL_CSTRING("http://") +
1333
0
    pageHostname + NS_LITERAL_CSTRING("/?resource=") + resourceDomain;
1334
0
  LOG(("nsChannelClassifier[%p]: Looking for %s in the whitelist (channel=%p)",
1335
0
       this, whitelistEntry.get(), mChannel.get()));
1336
0
1337
0
  nsCOMPtr<nsIURI> whitelistURI;
1338
0
  rv = NS_NewURI(getter_AddRefs(whitelistURI), whitelistEntry);
1339
0
  NS_ENSURE_SUCCESS(rv, rv);
1340
0
1341
0
  whitelistURI.forget(aURI);
1342
0
  return NS_OK;
1343
0
}
1344
1345
nsresult
1346
nsChannelClassifier::IsTrackerWhitelisted(nsIURI* aWhiteListURI,
1347
                                          bool aUseTrackingTable,
1348
                                          bool aUseAnnotationTable,
1349
                                          nsIURIClassifierCallback *aCallback)
1350
0
{
1351
0
  MOZ_ASSERT(aUseTrackingTable || aUseAnnotationTable);
1352
0
  MOZ_ASSERT(aWhiteListURI);
1353
0
  if (!aCallback) {
1354
0
    return NS_ERROR_INVALID_ARG;
1355
0
  }
1356
0
1357
0
  nsresult rv;
1358
0
  nsCOMPtr<nsIURIClassifier> uriClassifier =
1359
0
    do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
1360
0
  NS_ENSURE_SUCCESS(rv, rv);
1361
0
1362
0
  nsAutoCString whitelist;
1363
0
  nsTArray<nsCString> whitelistExtraTables;
1364
0
  nsTArray<nsCString> whitelistExtraEntries;
1365
0
  if (aUseAnnotationTable) {
1366
0
    whitelist += CachedPrefs::GetInstance()->GetAnnotationWhiteList();
1367
0
    whitelist += NS_LITERAL_CSTRING(",");
1368
0
    whitelistExtraTables.AppendElement(TABLE_ANNOTATION_WHITELIST_PREF);
1369
0
    whitelistExtraEntries.AppendElement(CachedPrefs::GetInstance()->GetAnnotationWhiteListExtraEntries());
1370
0
  }
1371
0
  if (aUseTrackingTable) {
1372
0
    whitelist += CachedPrefs::GetInstance()->GetTrackingWhiteList();
1373
0
    whitelistExtraTables.AppendElement(TABLE_TRACKING_WHITELIST_PREF);
1374
0
    whitelistExtraEntries.AppendElement(CachedPrefs::GetInstance()->GetTrackingWhiteListExtraEntries());
1375
0
  }
1376
0
1377
0
  if (whitelist.IsEmpty()) {
1378
0
    LOG(("nsChannelClassifier[%p]:IsTrackerWhitelisted whitelist disabled",
1379
0
         this));
1380
0
    return aUseTrackingTable ? NS_ERROR_TRACKING_URI :
1381
0
      NS_ERROR_TRACKING_ANNOTATION_URI;
1382
0
  }
1383
0
1384
0
  return uriClassifier->AsyncClassifyLocalWithTables(aWhiteListURI, whitelist,
1385
0
                                                     whitelistExtraTables,
1386
0
                                                     whitelistExtraEntries,
1387
0
                                                     aCallback);
1388
0
}
1389
1390
/* static */
1391
nsresult
1392
nsChannelClassifier::SendThreatHitReport(nsIChannel *aChannel,
1393
                                         const nsACString& aProvider,
1394
                                         const nsACString& aList,
1395
                                         const nsACString& aFullHash)
1396
0
{
1397
0
  NS_ENSURE_ARG_POINTER(aChannel);
1398
0
1399
0
  nsAutoCString provider(aProvider);
1400
0
  nsPrintfCString reportEnablePref("browser.safebrowsing.provider.%s.dataSharing.enabled",
1401
0
                                   provider.get());
1402
0
  if (!Preferences::GetBool(reportEnablePref.get(), false)) {
1403
0
    LOG(("nsChannelClassifier::SendThreatHitReport data sharing disabled for %s",
1404
0
         provider.get()));
1405
0
    return NS_OK;
1406
0
  }
1407
0
1408
0
  nsCOMPtr<nsIURIClassifier> uriClassifier =
1409
0
    do_GetService(NS_URLCLASSIFIERDBSERVICE_CONTRACTID);
1410
0
  if (!uriClassifier) {
1411
0
    return NS_ERROR_UNEXPECTED;
1412
0
  }
1413
0
1414
0
  nsresult rv = uriClassifier->SendThreatHitReport(aChannel, aProvider, aList,
1415
0
                                                   aFullHash);
1416
0
  NS_ENSURE_SUCCESS(rv, rv);
1417
0
1418
0
  return NS_OK;
1419
0
}
1420
1421
NS_IMETHODIMP
1422
nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode,
1423
                                        const nsACString& aList,
1424
                                        const nsACString& aProvider,
1425
                                        const nsACString& aFullHash)
1426
0
{
1427
0
  // Should only be called in the parent process.
1428
0
  MOZ_ASSERT(XRE_IsParentProcess());
1429
0
  MOZ_ASSERT(aErrorCode != NS_ERROR_TRACKING_URI);
1430
0
1431
0
  if (mSuspendedChannel) {
1432
0
    nsAutoCString errorName;
1433
0
    if (LOG_ENABLED() && NS_FAILED(aErrorCode)) {
1434
0
      GetErrorName(aErrorCode, errorName);
1435
0
      LOG(("nsChannelClassifier[%p]:OnClassifyComplete %s (suspended channel)",
1436
0
           this, errorName.get()));
1437
0
    }
1438
0
    MarkEntryClassified(aErrorCode);
1439
0
1440
0
    if (NS_FAILED(aErrorCode)) {
1441
0
      if (LOG_ENABLED()) {
1442
0
        nsCOMPtr<nsIURI> uri;
1443
0
        mChannel->GetURI(getter_AddRefs(uri));
1444
0
        nsCString spec = uri->GetSpecOrDefault();
1445
0
        spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
1446
0
        LOG(("nsChannelClassifier[%p]: cancelling channel %p for %s "
1447
0
             "with error code %s", this, mChannel.get(),
1448
0
              spec.get(), errorName.get()));
1449
0
      }
1450
0
1451
0
      // Channel will be cancelled (page element blocked) due to Safe Browsing.
1452
0
      // Do update the security state of the document and fire a security
1453
0
      // change event.
1454
0
      SetBlockedContent(mChannel, aErrorCode, aList, aProvider, aFullHash);
1455
0
1456
0
      if (aErrorCode == NS_ERROR_MALWARE_URI ||
1457
0
          aErrorCode == NS_ERROR_PHISHING_URI ||
1458
0
          aErrorCode == NS_ERROR_UNWANTED_URI ||
1459
0
          aErrorCode == NS_ERROR_HARMFUL_URI) {
1460
0
        SendThreatHitReport(mChannel, aProvider, aList, aFullHash);
1461
0
      }
1462
0
1463
0
      mChannel->Cancel(aErrorCode);
1464
0
    }
1465
0
    LOG_DEBUG(("nsChannelClassifier[%p]: resuming channel[%p] from "
1466
0
               "OnClassifyComplete", this, mChannel.get()));
1467
0
    mChannel->Resume();
1468
0
  }
1469
0
1470
0
  mChannel = nullptr;
1471
0
  RemoveShutdownObserver();
1472
0
1473
0
  return NS_OK;
1474
0
}
1475
1476
nsresult
1477
nsChannelClassifier::CheckIsTrackerWithLocalTable(std::function<void()>&& aCallback)
1478
0
{
1479
0
  nsresult rv;
1480
0
1481
0
  if (!aCallback) {
1482
0
    return NS_ERROR_INVALID_ARG;
1483
0
  }
1484
0
1485
0
  nsCOMPtr<nsIURIClassifier> uriClassifier =
1486
0
    do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
1487
0
  if (NS_FAILED(rv)) {
1488
0
    return rv;
1489
0
  }
1490
0
1491
0
  const bool shouldEnableTrackingProtection = ShouldEnableTrackingProtection();
1492
0
  const bool shouldEnableTrackingAnnotation = ShouldEnableTrackingAnnotation();
1493
0
  if (!shouldEnableTrackingProtection && !shouldEnableTrackingAnnotation) {
1494
0
    return NS_ERROR_FAILURE;
1495
0
  }
1496
0
1497
0
  nsCOMPtr<nsIURI> uri;
1498
0
  rv = mChannel->GetURI(getter_AddRefs(uri));
1499
0
  if (NS_FAILED(rv) || !uri) {
1500
0
    return rv;
1501
0
  }
1502
0
1503
0
  nsAutoCString blacklist;
1504
0
  nsTArray<nsCString> blacklistExtraTables;
1505
0
  nsTArray<nsCString> blacklistExtraEntries;
1506
0
  if (shouldEnableTrackingAnnotation) {
1507
0
    blacklist += CachedPrefs::GetInstance()->GetAnnotationBlackList();
1508
0
    blacklist += NS_LITERAL_CSTRING(",");
1509
0
    blacklistExtraTables.AppendElement(TABLE_ANNOTATION_BLACKLIST_PREF);
1510
0
    blacklistExtraEntries.AppendElement(CachedPrefs::GetInstance()->GetAnnotationBlackListExtraEntries());
1511
0
  }
1512
0
  if (shouldEnableTrackingProtection) {
1513
0
    blacklist += CachedPrefs::GetInstance()->GetTrackingBlackList();
1514
0
    blacklistExtraTables.AppendElement(TABLE_TRACKING_BLACKLIST_PREF);
1515
0
    blacklistExtraEntries.AppendElement(CachedPrefs::GetInstance()->GetTrackingBlackListExtraEntries());
1516
0
  }
1517
0
  if (blacklist.IsEmpty()) {
1518
0
    LOG_WARN(("nsChannelClassifier[%p]:CheckIsTrackerWithLocalTable blacklist is empty",
1519
0
              this));
1520
0
    return NS_ERROR_FAILURE;
1521
0
  }
1522
0
  // Note: duplicate lists will be removed in Classifier::SplitTables().
1523
0
1524
0
  nsCOMPtr<nsIURIClassifierCallback> callback =
1525
0
    new TrackingURICallback(this, std::move(aCallback));
1526
0
1527
0
  if (LOG_ENABLED()) {
1528
0
    nsCString spec = uri->GetSpecOrDefault();
1529
0
    spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
1530
0
    LOG(("nsChannelClassifier[%p]: Checking blacklist for uri=%s\n",
1531
0
         this, spec.get()));
1532
0
  }
1533
0
  return uriClassifier->AsyncClassifyLocalWithTables(uri, blacklist,
1534
0
                                                     blacklistExtraTables,
1535
0
                                                     blacklistExtraEntries,
1536
0
                                                     callback);
1537
0
}
1538
1539
already_AddRefed<nsIChannel>
1540
nsChannelClassifier::GetChannel()
1541
0
{
1542
0
  nsCOMPtr<nsIChannel> channel = mChannel;
1543
0
  return channel.forget();
1544
0
}
1545
1546
void
1547
nsChannelClassifier::AddShutdownObserver()
1548
0
{
1549
0
  nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
1550
0
  if (observerService) {
1551
0
    observerService->AddObserver(this, "profile-change-net-teardown", false);
1552
0
  }
1553
0
}
1554
1555
void
1556
nsChannelClassifier::RemoveShutdownObserver()
1557
0
{
1558
0
  nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
1559
0
  if (observerService) {
1560
0
    observerService->RemoveObserver(this, "profile-change-net-teardown");
1561
0
  }
1562
0
}
1563
1564
///////////////////////////////////////////////////////////////////////////////
1565
// nsIObserver implementation
1566
NS_IMETHODIMP
1567
nsChannelClassifier::Observe(nsISupports *aSubject, const char *aTopic,
1568
                             const char16_t *aData)
1569
0
{
1570
0
  if (!strcmp(aTopic, "profile-change-net-teardown")) {
1571
0
    // If we aren't getting a callback for any reason, make sure
1572
0
    // we resume the channel.
1573
0
1574
0
    if (mChannel && mSuspendedChannel) {
1575
0
      mSuspendedChannel = false;
1576
0
      mChannel->Cancel(NS_ERROR_ABORT);
1577
0
      mChannel->Resume();
1578
0
      mChannel = nullptr;
1579
0
    }
1580
0
1581
0
    RemoveShutdownObserver();
1582
0
  }
1583
0
1584
0
  return NS_OK;
1585
0
}
1586
1587
#undef LOG_ENABLED
1588
1589
} // namespace net
1590
} // namespace mozilla