123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697 |
- /* -*- Mode: C++; tab-width: 8; 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 "nsChannelClassifier.h"
- #include "mozIThirdPartyUtil.h"
- #include "nsCharSeparatedTokenizer.h"
- #include "nsContentUtils.h"
- #include "nsICacheEntry.h"
- #include "nsICachingChannel.h"
- #include "nsIChannel.h"
- #include "nsIDocShell.h"
- #include "nsIDocument.h"
- #include "nsIDOMDocument.h"
- #include "nsIHttpChannelInternal.h"
- #include "nsIIOService.h"
- #include "nsILoadContext.h"
- #include "nsIParentChannel.h"
- #include "nsIPermissionManager.h"
- #include "nsIPrivateBrowsingTrackingProtectionWhitelist.h"
- #include "nsIProtocolHandler.h"
- #include "nsIScriptError.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsISecureBrowserUI.h"
- #include "nsISecurityEventSink.h"
- #include "nsIURL.h"
- #include "nsIWebProgressListener.h"
- #include "nsNetUtil.h"
- #include "nsPIDOMWindow.h"
- #include "nsXULAppAPI.h"
- #include "mozilla/ErrorNames.h"
- #include "mozilla/Logging.h"
- #include "mozilla/Preferences.h"
- namespace mozilla {
- namespace net {
- //
- // MOZ_LOG=nsChannelClassifier:5
- //
- static LazyLogModule gChannelClassifierLog("nsChannelClassifier");
- #undef LOG
- #define LOG(args) MOZ_LOG(gChannelClassifierLog, LogLevel::Debug, args)
- #define LOG_ENABLED() MOZ_LOG_TEST(gChannelClassifierLog, LogLevel::Debug)
- NS_IMPL_ISUPPORTS(nsChannelClassifier,
- nsIURIClassifierCallback)
- nsChannelClassifier::nsChannelClassifier()
- : mIsAllowListed(false),
- mSuspendedChannel(false)
- {
- }
- nsresult
- nsChannelClassifier::ShouldEnableTrackingProtection(nsIChannel *aChannel,
- bool *result)
- {
- // Should only be called in the parent process.
- MOZ_ASSERT(XRE_IsParentProcess());
- NS_ENSURE_ARG(result);
- *result = false;
- nsCOMPtr<nsILoadContext> loadContext;
- NS_QueryNotificationCallbacks(aChannel, loadContext);
- if (!loadContext || !(loadContext->UseTrackingProtection())) {
- return NS_OK;
- }
- nsresult rv;
- nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
- do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIHttpChannelInternal> chan = do_QueryInterface(aChannel, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIURI> topWinURI;
- rv = chan->GetTopWindowURI(getter_AddRefs(topWinURI));
- NS_ENSURE_SUCCESS(rv, rv);
- if (!topWinURI) {
- LOG(("nsChannelClassifier[%p]: No window URI\n", this));
- }
- nsCOMPtr<nsIURI> chanURI;
- rv = aChannel->GetURI(getter_AddRefs(chanURI));
- NS_ENSURE_SUCCESS(rv, rv);
- // Third party checks don't work for chrome:// URIs in mochitests, so just
- // default to isThirdParty = true. We check isThirdPartyWindow to expand
- // the list of domains that are considered first party (e.g., if
- // facebook.com includes an iframe from fatratgames.com, all subsources
- // included in that iframe are considered third-party with
- // isThirdPartyChannel, even if they are not third-party w.r.t.
- // facebook.com), and isThirdPartyChannel to prevent top-level navigations
- // from being detected as third-party.
- bool isThirdPartyChannel = true;
- bool isThirdPartyWindow = true;
- thirdPartyUtil->IsThirdPartyURI(chanURI, topWinURI, &isThirdPartyWindow);
- thirdPartyUtil->IsThirdPartyChannel(aChannel, nullptr, &isThirdPartyChannel);
- if (!isThirdPartyWindow || !isThirdPartyChannel) {
- *result = false;
- if (LOG_ENABLED()) {
- LOG(("nsChannelClassifier[%p]: Skipping tracking protection checks "
- "for first party or top-level load channel[%p] with uri %s",
- this, aChannel, chanURI->GetSpecOrDefault().get()));
- }
- return NS_OK;
- }
- nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- const char ALLOWLIST_EXAMPLE_PREF[] = "channelclassifier.allowlist_example";
- if (!topWinURI && Preferences::GetBool(ALLOWLIST_EXAMPLE_PREF, false)) {
- LOG(("nsChannelClassifier[%p]: Allowlisting test domain\n", this));
- rv = ios->NewURI(NS_LITERAL_CSTRING("http://allowlisted.example.com"),
- nullptr, nullptr, getter_AddRefs(topWinURI));
- NS_ENSURE_SUCCESS(rv, rv);
- }
- // Take the host/port portion so we can allowlist by site. Also ignore the
- // scheme, since users who put sites on the allowlist probably don't expect
- // allowlisting to depend on scheme.
- nsCOMPtr<nsIURL> url = do_QueryInterface(topWinURI, &rv);
- if (NS_FAILED(rv)) {
- return rv; // normal for some loads, no need to print a warning
- }
- nsCString escaped(NS_LITERAL_CSTRING("https://"));
- nsAutoCString temp;
- rv = url->GetHostPort(temp);
- NS_ENSURE_SUCCESS(rv, rv);
- escaped.Append(temp);
- // Stuff the whole thing back into a URI for the permission manager.
- rv = ios->NewURI(escaped, nullptr, nullptr, getter_AddRefs(topWinURI));
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIPermissionManager> permMgr =
- do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- uint32_t permissions = nsIPermissionManager::UNKNOWN_ACTION;
- rv = permMgr->TestPermission(topWinURI, "trackingprotection", &permissions);
- NS_ENSURE_SUCCESS(rv, rv);
- if (permissions == nsIPermissionManager::ALLOW_ACTION) {
- LOG(("nsChannelClassifier[%p]: Allowlisting channel[%p] for %s", this,
- aChannel, escaped.get()));
- mIsAllowListed = true;
- *result = false;
- } else {
- *result = true;
- }
- // In Private Browsing Mode we also check against an in-memory list.
- if (NS_UsePrivateBrowsing(aChannel)) {
- nsCOMPtr<nsIPrivateBrowsingTrackingProtectionWhitelist> pbmtpWhitelist =
- do_GetService(NS_PBTRACKINGPROTECTIONWHITELIST_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- bool exists = false;
- rv = pbmtpWhitelist->ExistsInAllowList(topWinURI, &exists);
- NS_ENSURE_SUCCESS(rv, rv);
- if (exists) {
- mIsAllowListed = true;
- LOG(("nsChannelClassifier[%p]: Allowlisting channel[%p] in PBM for %s",
- this, aChannel, escaped.get()));
- }
- *result = !exists;
- }
- // Tracking protection will be enabled so return without updating
- // the security state. If any channels are subsequently cancelled
- // (page elements blocked) the state will be then updated.
- if (*result) {
- if (LOG_ENABLED()) {
- LOG(("nsChannelClassifier[%p]: Enabling tracking protection checks on "
- "channel[%p] with uri %s for toplevel window %s", this, aChannel,
- chanURI->GetSpecOrDefault().get(),
- topWinURI->GetSpecOrDefault().get()));
- }
- return NS_OK;
- }
- // Tracking protection will be disabled so update the security state
- // of the document and fire a secure change event. If we can't get the
- // window for the channel, then the shield won't show up so we can't send
- // an event to the securityUI anyway.
- return NotifyTrackingProtectionDisabled(aChannel);
- }
- // static
- nsresult
- nsChannelClassifier::NotifyTrackingProtectionDisabled(nsIChannel *aChannel)
- {
- // Can be called in EITHER the parent or child process.
- nsCOMPtr<nsIParentChannel> parentChannel;
- NS_QueryNotificationCallbacks(aChannel, parentChannel);
- if (parentChannel) {
- // This channel is a parent-process proxy for a child process request.
- // Tell the child process channel to do this instead.
- parentChannel->NotifyTrackingProtectionDisabled();
- return NS_OK;
- }
- nsresult rv;
- nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
- do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<mozIDOMWindowProxy> win;
- rv = thirdPartyUtil->GetTopWindowForChannel(aChannel, getter_AddRefs(win));
- NS_ENSURE_SUCCESS(rv, rv);
- auto* pwin = nsPIDOMWindowOuter::From(win);
- nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
- if (!docShell) {
- return NS_OK;
- }
- nsCOMPtr<nsIDocument> doc = docShell->GetDocument();
- NS_ENSURE_TRUE(doc, NS_OK);
- // Notify nsIWebProgressListeners of this security event.
- // Can be used to change the UI state.
- nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell, &rv);
- NS_ENSURE_SUCCESS(rv, NS_OK);
- uint32_t state = 0;
- nsCOMPtr<nsISecureBrowserUI> securityUI;
- docShell->GetSecurityUI(getter_AddRefs(securityUI));
- if (!securityUI) {
- return NS_OK;
- }
- doc->SetHasTrackingContentLoaded(true);
- securityUI->GetState(&state);
- state |= nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT;
- eventSink->OnSecurityChange(nullptr, state);
- return NS_OK;
- }
- void
- nsChannelClassifier::Start(nsIChannel *aChannel)
- {
- mChannel = aChannel;
- nsresult rv = StartInternal();
- if (NS_FAILED(rv)) {
- // If we aren't getting a callback for any reason, assume a good verdict and
- // make sure we resume the channel if necessary.
- OnClassifyComplete(NS_OK);
- }
- }
- nsresult
- nsChannelClassifier::StartInternal()
- {
- // Should only be called in the parent process.
- MOZ_ASSERT(XRE_IsParentProcess());
- // Don't bother to run the classifier on a load that has already failed.
- // (this might happen after a redirect)
- nsresult status;
- mChannel->GetStatus(&status);
- if (NS_FAILED(status))
- return status;
- // Don't bother to run the classifier on a cached load that was
- // previously classified as good.
- if (HasBeenClassified(mChannel)) {
- return NS_ERROR_UNEXPECTED;
- }
- nsCOMPtr<nsIURI> uri;
- nsresult rv = mChannel->GetURI(getter_AddRefs(uri));
- NS_ENSURE_SUCCESS(rv, rv);
- // Don't bother checking certain types of URIs.
- bool hasFlags;
- rv = NS_URIChainHasFlags(uri,
- nsIProtocolHandler::URI_DANGEROUS_TO_LOAD,
- &hasFlags);
- NS_ENSURE_SUCCESS(rv, rv);
- if (hasFlags) return NS_ERROR_UNEXPECTED;
- rv = NS_URIChainHasFlags(uri,
- nsIProtocolHandler::URI_IS_LOCAL_FILE,
- &hasFlags);
- NS_ENSURE_SUCCESS(rv, rv);
- if (hasFlags) return NS_ERROR_UNEXPECTED;
- rv = NS_URIChainHasFlags(uri,
- nsIProtocolHandler::URI_IS_UI_RESOURCE,
- &hasFlags);
- NS_ENSURE_SUCCESS(rv, rv);
- if (hasFlags) return NS_ERROR_UNEXPECTED;
- rv = NS_URIChainHasFlags(uri,
- nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
- &hasFlags);
- NS_ENSURE_SUCCESS(rv, rv);
- if (hasFlags) return NS_ERROR_UNEXPECTED;
- // Skip whitelisted hostnames.
- nsAutoCString whitelisted;
- Preferences::GetCString("urlclassifier.skipHostnames", &whitelisted);
- if (!whitelisted.IsEmpty()) {
- ToLowerCase(whitelisted);
- LOG(("nsChannelClassifier[%p]:StartInternal whitelisted hostnames = %s",
- this, whitelisted.get()));
- if (IsHostnameWhitelisted(uri, whitelisted)) {
- return NS_ERROR_UNEXPECTED;
- }
- }
- nsCOMPtr<nsIURIClassifier> uriClassifier =
- do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
- if (rv == NS_ERROR_FACTORY_NOT_REGISTERED ||
- rv == NS_ERROR_NOT_AVAILABLE) {
- // no URI classifier, ignore this failure.
- return NS_ERROR_NOT_AVAILABLE;
- }
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIScriptSecurityManager> securityManager =
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIPrincipal> principal;
- rv = securityManager->GetChannelURIPrincipal(mChannel, getter_AddRefs(principal));
- NS_ENSURE_SUCCESS(rv, rv);
- bool expectCallback;
- bool trackingProtectionEnabled = false;
- (void)ShouldEnableTrackingProtection(mChannel, &trackingProtectionEnabled);
- if (LOG_ENABLED()) {
- nsCOMPtr<nsIURI> principalURI;
- principal->GetURI(getter_AddRefs(principalURI));
- LOG(("nsChannelClassifier[%p]: Classifying principal %s on channel with "
- "uri %s", this, principalURI->GetSpecOrDefault().get(),
- uri->GetSpecOrDefault().get()));
- }
- rv = uriClassifier->Classify(principal, trackingProtectionEnabled, this,
- &expectCallback);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (expectCallback) {
- // Suspend the channel, it will be resumed when we get the classifier
- // callback.
- rv = mChannel->Suspend();
- if (NS_FAILED(rv)) {
- // Some channels (including nsJSChannel) fail on Suspend. This
- // shouldn't be fatal, but will prevent malware from being
- // blocked on these channels.
- LOG(("nsChannelClassifier[%p]: Couldn't suspend channel", this));
- return rv;
- }
- mSuspendedChannel = true;
- LOG(("nsChannelClassifier[%p]: suspended channel %p",
- this, mChannel.get()));
- } else {
- LOG(("nsChannelClassifier[%p]: not expecting callback", this));
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
- }
- bool
- nsChannelClassifier::IsHostnameWhitelisted(nsIURI *aUri,
- const nsACString &aWhitelisted)
- {
- nsAutoCString host;
- nsresult rv = aUri->GetHost(host);
- if (NS_FAILED(rv) || host.IsEmpty()) {
- return false;
- }
- ToLowerCase(host);
- nsCCharSeparatedTokenizer tokenizer(aWhitelisted, ',');
- while (tokenizer.hasMoreTokens()) {
- const nsCSubstring& token = tokenizer.nextToken();
- if (token.Equals(host)) {
- LOG(("nsChannelClassifier[%p]:StartInternal skipping %s (whitelisted)",
- this, host.get()));
- return true;
- }
- }
- return false;
- }
- // Note in the cache entry that this URL was classified, so that future
- // cached loads don't need to be checked.
- void
- nsChannelClassifier::MarkEntryClassified(nsresult status)
- {
- // Should only be called in the parent process.
- MOZ_ASSERT(XRE_IsParentProcess());
- // Don't cache tracking classifications because we support allowlisting.
- if (status == NS_ERROR_TRACKING_URI || mIsAllowListed) {
- return;
- }
- if (LOG_ENABLED()) {
- nsAutoCString errorName;
- GetErrorName(status, errorName);
- nsCOMPtr<nsIURI> uri;
- mChannel->GetURI(getter_AddRefs(uri));
- nsAutoCString spec;
- uri->GetAsciiSpec(spec);
- LOG(("nsChannelClassifier::MarkEntryClassified[%s] %s",
- errorName.get(), spec.get()));
- }
- nsCOMPtr<nsICachingChannel> cachingChannel = do_QueryInterface(mChannel);
- if (!cachingChannel) {
- return;
- }
- nsCOMPtr<nsISupports> cacheToken;
- cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
- if (!cacheToken) {
- return;
- }
- nsCOMPtr<nsICacheEntry> cacheEntry =
- do_QueryInterface(cacheToken);
- if (!cacheEntry) {
- return;
- }
- cacheEntry->SetMetaDataElement("necko:classified",
- NS_SUCCEEDED(status) ? "1" : nullptr);
- }
- bool
- nsChannelClassifier::HasBeenClassified(nsIChannel *aChannel)
- {
- // Should only be called in the parent process.
- MOZ_ASSERT(XRE_IsParentProcess());
- nsCOMPtr<nsICachingChannel> cachingChannel =
- do_QueryInterface(aChannel);
- if (!cachingChannel) {
- return false;
- }
- // Only check the tag if we are loading from the cache without
- // validation.
- bool fromCache;
- if (NS_FAILED(cachingChannel->IsFromCache(&fromCache)) || !fromCache) {
- return false;
- }
- nsCOMPtr<nsISupports> cacheToken;
- cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
- if (!cacheToken) {
- return false;
- }
- nsCOMPtr<nsICacheEntry> cacheEntry =
- do_QueryInterface(cacheToken);
- if (!cacheEntry) {
- return false;
- }
- nsXPIDLCString tag;
- cacheEntry->GetMetaDataElement("necko:classified", getter_Copies(tag));
- return tag.EqualsLiteral("1");
- }
- //static
- bool
- nsChannelClassifier::SameLoadingURI(nsIDocument *aDoc, nsIChannel *aChannel)
- {
- nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
- nsCOMPtr<nsILoadInfo> channelLoadInfo = aChannel->GetLoadInfo();
- if (!channelLoadInfo || !docURI) {
- return false;
- }
- nsCOMPtr<nsIPrincipal> channelLoadingPrincipal = channelLoadInfo->LoadingPrincipal();
- if (!channelLoadingPrincipal) {
- // TYPE_DOCUMENT loads will not have a channelLoadingPrincipal. But top level
- // loads should not be blocked by Tracking Protection, so we will return
- // false
- return false;
- }
- nsCOMPtr<nsIURI> channelLoadingURI;
- channelLoadingPrincipal->GetURI(getter_AddRefs(channelLoadingURI));
- if (!channelLoadingURI) {
- return false;
- }
- bool equals = false;
- nsresult rv = docURI->EqualsExceptRef(channelLoadingURI, &equals);
- return NS_SUCCEEDED(rv) && equals;
- }
- // static
- nsresult
- nsChannelClassifier::SetBlockedTrackingContent(nsIChannel *channel)
- {
- // Can be called in EITHER the parent or child process.
- nsCOMPtr<nsIParentChannel> parentChannel;
- NS_QueryNotificationCallbacks(channel, parentChannel);
- if (parentChannel) {
- // This channel is a parent-process proxy for a child process request. The
- // actual channel will be notified via the status passed to
- // nsIRequest::Cancel and do this for us.
- return NS_OK;
- }
- nsresult rv;
- nsCOMPtr<mozIDOMWindowProxy> win;
- nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
- do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, NS_OK);
- rv = thirdPartyUtil->GetTopWindowForChannel(channel, getter_AddRefs(win));
- NS_ENSURE_SUCCESS(rv, NS_OK);
- auto* pwin = nsPIDOMWindowOuter::From(win);
- nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
- if (!docShell) {
- return NS_OK;
- }
- nsCOMPtr<nsIDocument> doc = docShell->GetDocument();
- NS_ENSURE_TRUE(doc, NS_OK);
- // This event might come after the user has navigated to another page.
- // To prevent showing the TrackingProtection UI on the wrong page, we need to
- // check that the loading URI for the channel is the same as the URI currently
- // loaded in the document.
- if (!SameLoadingURI(doc, channel)) {
- return NS_OK;
- }
- // Notify nsIWebProgressListeners of this security event.
- // Can be used to change the UI state.
- nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell, &rv);
- NS_ENSURE_SUCCESS(rv, NS_OK);
- uint32_t state = 0;
- nsCOMPtr<nsISecureBrowserUI> securityUI;
- docShell->GetSecurityUI(getter_AddRefs(securityUI));
- if (!securityUI) {
- return NS_OK;
- }
- doc->SetHasTrackingContentBlocked(true);
- securityUI->GetState(&state);
- state |= nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT;
- eventSink->OnSecurityChange(nullptr, state);
- // Log a warning to the web console.
- nsCOMPtr<nsIURI> uri;
- channel->GetURI(getter_AddRefs(uri));
- NS_ConvertUTF8toUTF16 spec(uri->GetSpecOrDefault());
- const char16_t* params[] = { spec.get() };
- nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
- NS_LITERAL_CSTRING("Tracking Protection"),
- doc,
- nsContentUtils::eNECKO_PROPERTIES,
- "TrackingUriBlocked",
- params, ArrayLength(params));
- return NS_OK;
- }
- nsresult
- nsChannelClassifier::IsTrackerWhitelisted()
- {
- nsresult rv;
- nsCOMPtr<nsIURIClassifier> uriClassifier =
- do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- nsAutoCString tables;
- Preferences::GetCString("urlclassifier.trackingWhitelistTable", &tables);
- if (tables.IsEmpty()) {
- LOG(("nsChannelClassifier[%p]:IsTrackerWhitelisted whitelist disabled",
- this));
- return NS_ERROR_TRACKING_URI;
- }
- nsCOMPtr<nsIHttpChannelInternal> chan = do_QueryInterface(mChannel, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIURI> topWinURI;
- rv = chan->GetTopWindowURI(getter_AddRefs(topWinURI));
- NS_ENSURE_SUCCESS(rv, rv);
- if (!topWinURI) {
- LOG(("nsChannelClassifier[%p]: No window URI", this));
- return NS_ERROR_TRACKING_URI;
- }
- nsCOMPtr<nsIScriptSecurityManager> securityManager =
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIPrincipal> chanPrincipal;
- rv = securityManager->GetChannelURIPrincipal(mChannel,
- getter_AddRefs(chanPrincipal));
- NS_ENSURE_SUCCESS(rv, rv);
- // Craft a whitelist URL like "toplevel.page/?resource=third.party.domain"
- nsAutoCString pageHostname, resourceDomain;
- rv = topWinURI->GetHost(pageHostname);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = chanPrincipal->GetBaseDomain(resourceDomain);
- NS_ENSURE_SUCCESS(rv, rv);
- nsAutoCString whitelistEntry = NS_LITERAL_CSTRING("http://") +
- pageHostname + NS_LITERAL_CSTRING("/?resource=") + resourceDomain;
- LOG(("nsChannelClassifier[%p]: Looking for %s in the whitelist",
- this, whitelistEntry.get()));
- nsCOMPtr<nsIURI> whitelistURI;
- rv = NS_NewURI(getter_AddRefs(whitelistURI), whitelistEntry);
- NS_ENSURE_SUCCESS(rv, rv);
- // Check whether or not the tracker is in the entity whitelist
- nsAutoCString results;
- rv = uriClassifier->ClassifyLocalWithTables(whitelistURI, tables, results);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!results.IsEmpty()) {
- return NS_OK; // found it on the whitelist, must not be blocked
- }
- LOG(("nsChannelClassifier[%p]: %s is not in the whitelist",
- this, whitelistEntry.get()));
- return NS_ERROR_TRACKING_URI;
- }
- NS_IMETHODIMP
- nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode)
- {
- // Should only be called in the parent process.
- MOZ_ASSERT(XRE_IsParentProcess());
- if (aErrorCode == NS_ERROR_TRACKING_URI &&
- NS_SUCCEEDED(IsTrackerWhitelisted())) {
- LOG(("nsChannelClassifier[%p]:OnClassifyComplete tracker found "
- "in whitelist so we won't block it", this));
- aErrorCode = NS_OK;
- }
- if (mSuspendedChannel) {
- nsAutoCString errorName;
- if (LOG_ENABLED()) {
- GetErrorName(aErrorCode, errorName);
- LOG(("nsChannelClassifier[%p]:OnClassifyComplete %s (suspended channel)",
- this, errorName.get()));
- }
- MarkEntryClassified(aErrorCode);
- if (NS_FAILED(aErrorCode)) {
- if (LOG_ENABLED()) {
- nsCOMPtr<nsIURI> uri;
- mChannel->GetURI(getter_AddRefs(uri));
- LOG(("nsChannelClassifier[%p]: cancelling channel %p for %s "
- "with error code %s", this, mChannel.get(),
- uri->GetSpecOrDefault().get(), errorName.get()));
- }
- // Channel will be cancelled (page element blocked) due to tracking.
- // Do update the security state of the document and fire a security
- // change event.
- if (aErrorCode == NS_ERROR_TRACKING_URI) {
- SetBlockedTrackingContent(mChannel);
- }
- mChannel->Cancel(aErrorCode);
- }
- LOG(("nsChannelClassifier[%p]: resuming channel %p from "
- "OnClassifyComplete", this, mChannel.get()));
- mChannel->Resume();
- }
- mChannel = nullptr;
- return NS_OK;
- }
- } // namespace net
- } // namespace mozilla
|