summaryrefslogtreecommitdiffstats
path: root/netwerk/url-classifier/ChannelClassifierService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/url-classifier/ChannelClassifierService.cpp')
-rw-r--r--netwerk/url-classifier/ChannelClassifierService.cpp271
1 files changed, 271 insertions, 0 deletions
diff --git a/netwerk/url-classifier/ChannelClassifierService.cpp b/netwerk/url-classifier/ChannelClassifierService.cpp
new file mode 100644
index 0000000000..4b1145ba00
--- /dev/null
+++ b/netwerk/url-classifier/ChannelClassifierService.cpp
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "ChannelClassifierService.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/dom/BrowserParent.h"
+#include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/CanonicalBrowsingContext.h"
+#include "mozilla/dom/WindowGlobalParent.h"
+#include "mozilla/net/UrlClassifierCommon.h"
+
+#include "UrlClassifierFeatureCryptominingProtection.h"
+#include "UrlClassifierFeatureFingerprintingProtection.h"
+#include "UrlClassifierFeatureSocialTrackingProtection.h"
+#include "UrlClassifierFeatureTrackingProtection.h"
+
+#include "mozilla/StaticPtr.h"
+#include "nsIChannel.h"
+
+namespace mozilla {
+namespace net {
+
+static StaticRefPtr<ChannelClassifierService> gChannelClassifierService;
+
+NS_IMPL_ISUPPORTS(UrlClassifierBlockedChannel, nsIUrlClassifierBlockedChannel)
+
+UrlClassifierBlockedChannel::UrlClassifierBlockedChannel(nsIChannel* aChannel)
+ : mChannel(aChannel),
+ mDecision(ChannelBlockDecision::Blocked),
+ mReason(TRACKING_PROTECTION) {
+ MOZ_ASSERT(aChannel);
+}
+
+NS_IMETHODIMP
+UrlClassifierBlockedChannel::GetReason(uint8_t* aReason) {
+ NS_ENSURE_ARG_POINTER(aReason);
+
+ *aReason = mReason;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierBlockedChannel::GetUrl(nsAString& aUrl) {
+ nsCOMPtr<nsIURI> uri;
+ mChannel->GetURI(getter_AddRefs(uri));
+ if (uri) {
+ CopyUTF8toUTF16(uri->GetSpecOrDefault(), aUrl);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierBlockedChannel::GetTabId(uint64_t* aTabId) {
+ NS_ENSURE_ARG_POINTER(aTabId);
+
+ *aTabId = 0;
+
+ nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
+ MOZ_ASSERT(loadInfo);
+
+ RefPtr<dom::BrowsingContext> browsingContext;
+ nsresult rv =
+ loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
+ if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // Get top-level browsing context to ensure window global parent is ready
+ // to use, tabId is the same anyway.
+ dom::CanonicalBrowsingContext* top = browsingContext->Canonical()->Top();
+ dom::WindowGlobalParent* wgp = top->GetCurrentWindowGlobal();
+ if (!wgp) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<dom::BrowserParent> browserParent = wgp->GetBrowserParent();
+ if (!browserParent) {
+ return NS_ERROR_FAILURE;
+ }
+
+ *aTabId = browserParent->GetTabId();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierBlockedChannel::GetChannelId(uint64_t* aChannelId) {
+ NS_ENSURE_ARG_POINTER(aChannelId);
+
+ nsCOMPtr<nsIIdentChannel> channel(do_QueryInterface(mChannel));
+ *aChannelId = channel ? channel->ChannelId() : 0;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierBlockedChannel::GetTopLevelUrl(nsAString& aTopLevelUrl) {
+ nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
+ MOZ_ASSERT(loadInfo);
+
+ RefPtr<dom::BrowsingContext> browsingContext;
+ nsresult rv =
+ loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
+ if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // Get top-level browsing context to ensure window global parent is ready
+ // to use, tabId is the same anyway.
+ dom::CanonicalBrowsingContext* top = browsingContext->Canonical()->Top();
+ dom::WindowGlobalParent* wgp = top->GetCurrentWindowGlobal();
+ if (!wgp) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<nsIURI> uri = wgp->GetDocumentURI();
+ if (!uri) {
+ return NS_ERROR_FAILURE;
+ }
+
+ CopyUTF8toUTF16(uri->GetSpecOrDefault(), aTopLevelUrl);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierBlockedChannel::GetTables(nsACString& aTables) {
+ aTables.Assign(mTables);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierBlockedChannel::GetIsPrivateBrowsing(bool* aIsPrivateBrowsing) {
+ NS_ENSURE_ARG_POINTER(aIsPrivateBrowsing);
+
+ *aIsPrivateBrowsing = NS_UsePrivateBrowsing(mChannel);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierBlockedChannel::Allow() {
+ UC_LOG(("ChannelClassifierService: allow loading the channel %p",
+ mChannel.get()));
+
+ mDecision = ChannelBlockDecision::Allowed;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierBlockedChannel::Replace() {
+ UC_LOG(("ChannelClassifierService: replace channel %p", mChannel.get()));
+
+ mDecision = ChannelBlockDecision::Replaced;
+ return NS_OK;
+}
+
+void UrlClassifierBlockedChannel::SetReason(const nsACString& aFeatureName,
+ const nsACString& aTableName) {
+ mTables = aTableName;
+
+ nsCOMPtr<nsIUrlClassifierFeature> feature;
+ feature =
+ UrlClassifierFeatureTrackingProtection::GetIfNameMatches(aFeatureName);
+ if (feature) {
+ mReason = TRACKING_PROTECTION;
+ return;
+ }
+
+ feature = UrlClassifierFeatureSocialTrackingProtection::GetIfNameMatches(
+ aFeatureName);
+ if (feature) {
+ mReason = SOCIAL_TRACKING_PROTECTION;
+ return;
+ }
+
+ feature = UrlClassifierFeatureFingerprintingProtection::GetIfNameMatches(
+ aFeatureName);
+ if (feature) {
+ mReason = FINGERPRINTING_PROTECTION;
+ return;
+ }
+
+ feature = UrlClassifierFeatureCryptominingProtection::GetIfNameMatches(
+ aFeatureName);
+ if (feature) {
+ mReason = CRYPTOMINING_PROTECTION;
+ return;
+ }
+}
+
+NS_IMPL_ISUPPORTS(ChannelClassifierService, nsIChannelClassifierService)
+
+// static
+already_AddRefed<nsIChannelClassifierService>
+ChannelClassifierService::GetSingleton() {
+ if (gChannelClassifierService) {
+ return do_AddRef(gChannelClassifierService);
+ }
+
+ gChannelClassifierService = new ChannelClassifierService();
+ ClearOnShutdown(&gChannelClassifierService);
+ return do_AddRef(gChannelClassifierService);
+}
+
+ChannelClassifierService::ChannelClassifierService() { mListeners.Clear(); }
+
+NS_IMETHODIMP
+ChannelClassifierService::AddListener(nsIObserver* aObserver) {
+ MOZ_ASSERT(aObserver);
+ MOZ_ASSERT(!mListeners.Contains(aObserver));
+
+ mListeners.AppendElement(aObserver);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ChannelClassifierService::RemoveListener(nsIObserver* aObserver) {
+ MOZ_ASSERT(aObserver);
+ MOZ_ASSERT(mListeners.Contains(aObserver));
+
+ mListeners.RemoveElement(aObserver);
+ return NS_OK;
+}
+
+/* static */
+ChannelBlockDecision ChannelClassifierService::OnBeforeBlockChannel(
+ nsIChannel* aChannel, const nsACString& aFeatureName,
+ const nsACString& aTableName) {
+ MOZ_ASSERT(aChannel);
+
+ // Don't bother continuing if no one has ever registered listener
+ if (!gChannelClassifierService || !gChannelClassifierService->HasListener()) {
+ return ChannelBlockDecision::Blocked;
+ }
+
+ ChannelBlockDecision decision;
+ nsresult rv = gChannelClassifierService->OnBeforeBlockChannel(
+ aChannel, aFeatureName, aTableName, decision);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return ChannelBlockDecision::Blocked;
+ }
+
+ return decision;
+}
+
+nsresult ChannelClassifierService::OnBeforeBlockChannel(
+ nsIChannel* aChannel, const nsACString& aFeatureName,
+ const nsACString& aTableName, ChannelBlockDecision& aDecision) {
+ MOZ_ASSERT(aChannel);
+
+ aDecision = ChannelBlockDecision::Blocked;
+
+ RefPtr<UrlClassifierBlockedChannel> channel =
+ new UrlClassifierBlockedChannel(aChannel);
+ channel->SetReason(aFeatureName, aTableName);
+
+ for (const auto& listener : mListeners) {
+ listener->Observe(
+ NS_ISUPPORTS_CAST(nsIUrlClassifierBlockedChannel*, channel),
+ "urlclassifier-before-block-channel", nullptr);
+
+ aDecision = channel->GetDecision();
+ }
+
+ return NS_OK;
+}
+
+} // namespace net
+} // namespace mozilla