1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 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/. */
7 #include "ChannelClassifierService.h"
9 #include "mozilla/ClearOnShutdown.h"
10 #include "mozilla/dom/BrowserParent.h"
11 #include "mozilla/dom/BrowsingContext.h"
12 #include "mozilla/dom/CanonicalBrowsingContext.h"
13 #include "mozilla/dom/WindowGlobalParent.h"
14 #include "mozilla/net/UrlClassifierCommon.h"
16 #include "UrlClassifierFeatureCryptominingProtection.h"
17 #include "UrlClassifierFeatureFingerprintingProtection.h"
18 #include "UrlClassifierFeatureSocialTrackingProtection.h"
19 #include "UrlClassifierFeatureTrackingProtection.h"
21 #include "mozilla/StaticPtr.h"
22 #include "nsIChannel.h"
27 static StaticRefPtr
<ChannelClassifierService
> gChannelClassifierService
;
29 NS_IMPL_ISUPPORTS(UrlClassifierBlockedChannel
, nsIUrlClassifierBlockedChannel
)
31 UrlClassifierBlockedChannel::UrlClassifierBlockedChannel(nsIChannel
* aChannel
)
33 mDecision(ChannelBlockDecision::Blocked
),
34 mReason(TRACKING_PROTECTION
) {
39 UrlClassifierBlockedChannel::GetReason(uint8_t* aReason
) {
40 NS_ENSURE_ARG_POINTER(aReason
);
47 UrlClassifierBlockedChannel::GetUrl(nsAString
& aUrl
) {
49 mChannel
->GetURI(getter_AddRefs(uri
));
51 CopyUTF8toUTF16(uri
->GetSpecOrDefault(), aUrl
);
57 UrlClassifierBlockedChannel::GetTabId(uint64_t* aTabId
) {
58 NS_ENSURE_ARG_POINTER(aTabId
);
62 nsCOMPtr
<nsILoadInfo
> loadInfo
= mChannel
->LoadInfo();
65 RefPtr
<dom::BrowsingContext
> browsingContext
;
67 loadInfo
->GetTargetBrowsingContext(getter_AddRefs(browsingContext
));
68 if (NS_WARN_IF(NS_FAILED(rv
)) || !browsingContext
) {
69 return NS_ERROR_FAILURE
;
72 // Get top-level browsing context to ensure window global parent is ready
73 // to use, tabId is the same anyway.
74 dom::CanonicalBrowsingContext
* top
= browsingContext
->Canonical()->Top();
75 dom::WindowGlobalParent
* wgp
= top
->GetCurrentWindowGlobal();
77 return NS_ERROR_FAILURE
;
80 RefPtr
<dom::BrowserParent
> browserParent
= wgp
->GetBrowserParent();
82 return NS_ERROR_FAILURE
;
85 *aTabId
= browserParent
->GetTabId();
90 UrlClassifierBlockedChannel::GetChannelId(uint64_t* aChannelId
) {
91 NS_ENSURE_ARG_POINTER(aChannelId
);
93 nsCOMPtr
<nsIIdentChannel
> channel(do_QueryInterface(mChannel
));
94 *aChannelId
= channel
? channel
->ChannelId() : 0;
100 UrlClassifierBlockedChannel::GetTopLevelUrl(nsAString
& aTopLevelUrl
) {
101 nsCOMPtr
<nsILoadInfo
> loadInfo
= mChannel
->LoadInfo();
102 MOZ_ASSERT(loadInfo
);
104 RefPtr
<dom::BrowsingContext
> browsingContext
;
106 loadInfo
->GetTargetBrowsingContext(getter_AddRefs(browsingContext
));
107 if (NS_WARN_IF(NS_FAILED(rv
)) || !browsingContext
) {
108 return NS_ERROR_FAILURE
;
111 // Get top-level browsing context to ensure window global parent is ready
112 // to use, tabId is the same anyway.
113 dom::CanonicalBrowsingContext
* top
= browsingContext
->Canonical()->Top();
114 dom::WindowGlobalParent
* wgp
= top
->GetCurrentWindowGlobal();
116 return NS_ERROR_FAILURE
;
119 RefPtr
<nsIURI
> uri
= wgp
->GetDocumentURI();
121 return NS_ERROR_FAILURE
;
124 CopyUTF8toUTF16(uri
->GetSpecOrDefault(), aTopLevelUrl
);
129 UrlClassifierBlockedChannel::GetTables(nsACString
& aTables
) {
130 aTables
.Assign(mTables
);
135 UrlClassifierBlockedChannel::GetIsPrivateBrowsing(bool* aIsPrivateBrowsing
) {
136 NS_ENSURE_ARG_POINTER(aIsPrivateBrowsing
);
138 *aIsPrivateBrowsing
= NS_UsePrivateBrowsing(mChannel
);
143 UrlClassifierBlockedChannel::Allow() {
144 UC_LOG(("ChannelClassifierService: allow loading the channel %p",
147 mDecision
= ChannelBlockDecision::Allowed
;
152 UrlClassifierBlockedChannel::Replace() {
153 UC_LOG(("ChannelClassifierService: replace channel %p", mChannel
.get()));
155 mDecision
= ChannelBlockDecision::Replaced
;
159 void UrlClassifierBlockedChannel::SetReason(const nsACString
& aFeatureName
,
160 const nsACString
& aTableName
) {
161 mTables
= aTableName
;
163 nsCOMPtr
<nsIUrlClassifierFeature
> feature
;
165 UrlClassifierFeatureTrackingProtection::GetIfNameMatches(aFeatureName
);
167 mReason
= TRACKING_PROTECTION
;
171 feature
= UrlClassifierFeatureSocialTrackingProtection::GetIfNameMatches(
174 mReason
= SOCIAL_TRACKING_PROTECTION
;
178 feature
= UrlClassifierFeatureFingerprintingProtection::GetIfNameMatches(
181 mReason
= FINGERPRINTING_PROTECTION
;
185 feature
= UrlClassifierFeatureCryptominingProtection::GetIfNameMatches(
188 mReason
= CRYPTOMINING_PROTECTION
;
193 NS_IMPL_ISUPPORTS(ChannelClassifierService
, nsIChannelClassifierService
)
196 already_AddRefed
<nsIChannelClassifierService
>
197 ChannelClassifierService::GetSingleton() {
198 if (gChannelClassifierService
) {
199 return do_AddRef(gChannelClassifierService
);
202 gChannelClassifierService
= new ChannelClassifierService();
203 ClearOnShutdown(&gChannelClassifierService
);
204 return do_AddRef(gChannelClassifierService
);
207 ChannelClassifierService::ChannelClassifierService() { mListeners
.Clear(); }
210 ChannelClassifierService::AddListener(nsIObserver
* aObserver
) {
211 MOZ_ASSERT(aObserver
);
212 MOZ_ASSERT(!mListeners
.Contains(aObserver
));
214 mListeners
.AppendElement(aObserver
);
219 ChannelClassifierService::RemoveListener(nsIObserver
* aObserver
) {
220 MOZ_ASSERT(aObserver
);
221 MOZ_ASSERT(mListeners
.Contains(aObserver
));
223 mListeners
.RemoveElement(aObserver
);
228 ChannelBlockDecision
ChannelClassifierService::OnBeforeBlockChannel(
229 nsIChannel
* aChannel
, const nsACString
& aFeatureName
,
230 const nsACString
& aTableName
) {
231 MOZ_ASSERT(aChannel
);
233 // Don't bother continuing if no one has ever registered listener
234 if (!gChannelClassifierService
|| !gChannelClassifierService
->HasListener()) {
235 return ChannelBlockDecision::Blocked
;
238 ChannelBlockDecision decision
;
239 nsresult rv
= gChannelClassifierService
->OnBeforeBlockChannel(
240 aChannel
, aFeatureName
, aTableName
, decision
);
241 if (NS_WARN_IF(NS_FAILED(rv
))) {
242 return ChannelBlockDecision::Blocked
;
248 nsresult
ChannelClassifierService::OnBeforeBlockChannel(
249 nsIChannel
* aChannel
, const nsACString
& aFeatureName
,
250 const nsACString
& aTableName
, ChannelBlockDecision
& aDecision
) {
251 MOZ_ASSERT(aChannel
);
253 aDecision
= ChannelBlockDecision::Blocked
;
255 RefPtr
<UrlClassifierBlockedChannel
> channel
=
256 new UrlClassifierBlockedChannel(aChannel
);
257 channel
->SetReason(aFeatureName
, aTableName
);
259 for (const auto& listener
: mListeners
) {
261 NS_ISUPPORTS_CAST(nsIUrlClassifierBlockedChannel
*, channel
),
262 "urlclassifier-before-block-channel", nullptr);
264 aDecision
= channel
->GetDecision();
271 } // namespace mozilla