Bug 1955948 - Add classes for url classifier exception list. r=timhuang

Differential Revision: https://phabricator.services.mozilla.com/D243197
This commit is contained in:
Emma Zuehlcke
2025-04-02 11:25:26 +00:00
parent c444f31a9e
commit d65a75cae3
8 changed files with 446 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
/* -*- 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 "UrlClassifierExceptionList.h"
#include "nsIUrlClassifierExceptionListEntry.h"
#include "nsIURI.h"
#include "mozilla/net/UrlClassifierCommon.h"
namespace mozilla::net {
NS_IMPL_ISUPPORTS(UrlClassifierExceptionList, nsIUrlClassifierExceptionList)
NS_IMETHODIMP
UrlClassifierExceptionList::Init(const nsACString& aFeature) {
mFeature = aFeature;
return NS_OK;
}
NS_IMETHODIMP
UrlClassifierExceptionList::AddEntry(
nsIUrlClassifierExceptionListEntry* aEntry) {
if (!aEntry) {
return NS_ERROR_INVALID_ARG;
}
mEntries.AppendElement(aEntry);
return NS_OK;
}
NS_IMETHODIMP
UrlClassifierExceptionList::Matches(nsIURI* aURI, nsIURI* aTopLevelURI,
bool aIsPrivateBrowsing, bool* aResult) {
NS_ENSURE_ARG_POINTER(aURI);
NS_ENSURE_ARG_POINTER(aResult);
*aResult = false;
UC_LOG_DEBUG(
("UrlClassifierExceptionList::%s - aURI: %s, aTopLevelURI: %s, "
"aIsPrivateBrowsing: %d",
__FUNCTION__, aURI->GetSpecOrDefault().get(),
aTopLevelURI ? aTopLevelURI->GetSpecOrDefault().get() : "null",
aIsPrivateBrowsing));
for (auto& entry : mEntries) {
nsresult rv =
entry->Matches(aURI, aTopLevelURI, aIsPrivateBrowsing, aResult);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
if (*aResult) {
// Match found, return immediately.
if (MOZ_LOG_TEST(UrlClassifierCommon::sLog, LogLevel::Debug)) {
nsAutoCString entryString;
Unused << entry->Describe(entryString);
UC_LOG_DEBUG(
("UrlClassifierExceptionList::%s - Exception list match found. "
"entry: %s",
__FUNCTION__, entryString.get()));
}
return NS_OK;
}
}
// No match found, return false.
UC_LOG_DEBUG(("%s - No match found", __FUNCTION__));
return NS_OK;
}
} // namespace mozilla::net

View File

@@ -0,0 +1,36 @@
/* -*- 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/. */
#ifndef mozilla_UrlClassifierExceptionList_h
#define mozilla_UrlClassifierExceptionList_h
#include "nsIUrlClassifierExceptionList.h"
#include "nsISupports.h"
#include "nsTArray.h"
#include "nsString.h"
namespace mozilla::net {
/**
* @see nsIUrlClassifierExceptionList
*/
class UrlClassifierExceptionList final : public nsIUrlClassifierExceptionList {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIURLCLASSIFIEREXCEPTIONLIST
UrlClassifierExceptionList() = default;
private:
~UrlClassifierExceptionList() = default;
nsCString mFeature;
nsTArray<RefPtr<nsIUrlClassifierExceptionListEntry>> mEntries;
};
} // namespace mozilla::net
#endif

View File

@@ -0,0 +1,152 @@
/* -*- 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 "UrlClassifierExceptionListEntry.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Preferences.h"
namespace mozilla::net {
NS_IMPL_ISUPPORTS(UrlClassifierExceptionListEntry,
nsIUrlClassifierExceptionListEntry)
NS_IMETHODIMP
UrlClassifierExceptionListEntry::Init(
const nsACString& aUrlPattern, const nsACString& aTopLevelUrlPattern,
bool aIsPrivateBrowsingOnly,
const nsTArray<nsCString>& aFilterContentBlockingCategories,
const nsTArray<nsCString>& aClassifierFeatures) {
mUrlPattern = aUrlPattern;
mTopLevelUrlPattern = aTopLevelUrlPattern;
mIsPrivateBrowsingOnly = aIsPrivateBrowsingOnly;
mFilterContentBlockingCategories = aFilterContentBlockingCategories.Clone();
mClassifierFeatures = aClassifierFeatures.Clone();
// Create pattern from urlPattern and topLevelUrlPattern strings.
ErrorResult error;
mMatcher = new extensions::MatchPatternCore(
NS_ConvertUTF8toUTF16(mUrlPattern), false, false, error);
RETURN_NSRESULT_ON_FAILURE(error);
if (!mTopLevelUrlPattern.IsEmpty()) {
mTopLevelMatcher = new extensions::MatchPatternCore(
NS_ConvertUTF8toUTF16(mTopLevelUrlPattern), false, false, error);
RETURN_NSRESULT_ON_FAILURE(error);
}
return NS_OK;
}
NS_IMETHODIMP
UrlClassifierExceptionListEntry::Matches(nsIURI* aURI, nsIURI* aTopLevelURI,
bool aIsPrivateBrowsing,
bool* aResult) {
NS_ENSURE_ARG_POINTER(aURI);
NS_ENSURE_ARG_POINTER(aResult);
*aResult = false;
// Do the private browsing check first, because it's cheap.
if (!aIsPrivateBrowsing && mIsPrivateBrowsingOnly) {
return NS_OK;
}
// Next, check if the current content blocking category pref matches the
// allowed content blocking categories for this exception entry.
if (!mFilterContentBlockingCategories.IsEmpty()) {
nsCString prefValue;
// TODO: Bug 1956620: This is a desktop-only pref. We also need to check
// Fenix.
nsresult rv =
Preferences::GetCString("browser.contentblocking.category", prefValue);
// If the pref is not set this check is skipped.
if (NS_SUCCEEDED(rv) && !prefValue.IsEmpty()) {
if (!mFilterContentBlockingCategories.Contains(prefValue)) {
return NS_OK;
}
}
}
// Check if the load URI matches the urlPattern.
if (!mMatcher->Matches(aURI)) {
return NS_OK;
}
// If this entry filters for top level site, check if the top level URI
// matches the topLevelUrlPattern. If the entry filters for top level site,
// but the caller does not provide one, we will not match.
if (mTopLevelMatcher &&
(!aTopLevelURI || !mTopLevelMatcher->Matches(aTopLevelURI))) {
return NS_OK;
}
*aResult = true;
return NS_OK;
}
NS_IMETHODIMP
UrlClassifierExceptionListEntry::GetUrlPattern(nsACString& aUrlPattern) {
aUrlPattern = mUrlPattern;
return NS_OK;
}
NS_IMETHODIMP
UrlClassifierExceptionListEntry::GetTopLevelUrlPattern(
nsACString& aTopLevelUrlPattern) {
aTopLevelUrlPattern = mTopLevelUrlPattern;
return NS_OK;
}
NS_IMETHODIMP
UrlClassifierExceptionListEntry::GetIsPrivateBrowsingOnly(
bool* aIsPrivateBrowsingOnly) {
*aIsPrivateBrowsingOnly = mIsPrivateBrowsingOnly;
return NS_OK;
}
NS_IMETHODIMP
UrlClassifierExceptionListEntry::GetFilterContentBlockingCategories(
nsTArray<nsCString>& aFilterContentBlockingCategories) {
aFilterContentBlockingCategories = mFilterContentBlockingCategories.Clone();
return NS_OK;
}
NS_IMETHODIMP
UrlClassifierExceptionListEntry::GetClassifierFeatures(
nsTArray<nsCString>& aClassifierFeatures) {
aClassifierFeatures = mClassifierFeatures.Clone();
return NS_OK;
}
NS_IMETHODIMP
UrlClassifierExceptionListEntry::Describe(nsACString& aDescription) {
nsAutoCString categories;
for (const auto& category : mFilterContentBlockingCategories) {
if (!categories.IsEmpty()) {
categories.AppendLiteral(", ");
}
categories.Append(category);
}
nsAutoCString classifierFeatures;
for (const auto& feature : mClassifierFeatures) {
if (!classifierFeatures.IsEmpty()) {
classifierFeatures.AppendLiteral(", ");
}
classifierFeatures.Append(feature);
}
aDescription.AppendPrintf(
"UrlClassifierExceptionListEntry(urlPattern='%s', "
"topLevelUrlPattern='%s', isPrivateBrowsingOnly=%s, "
"filterContentBlockingCategories=[%s], classifierFeatures=[%s])",
mUrlPattern.get(), mTopLevelUrlPattern.get(),
mIsPrivateBrowsingOnly ? "true" : "false", categories.get(),
classifierFeatures.get());
return NS_OK;
}
} // namespace mozilla::net

View File

@@ -0,0 +1,53 @@
/* -*- 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/. */
#ifndef mozilla_UrlClassifierExceptionListEntry_h
#define mozilla_UrlClassifierExceptionListEntry_h
#include "mozilla/extensions/MatchPattern.h"
#include "nsIUrlClassifierExceptionListEntry.h"
#include "nsString.h"
#include "nsISupports.h"
namespace mozilla::net {
/**
* @see nsIUrlClassifierExceptionListEntry
*/
class UrlClassifierExceptionListEntry final
: public nsIUrlClassifierExceptionListEntry {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIURLCLASSIFIEREXCEPTIONLISTENTRY
UrlClassifierExceptionListEntry() = default;
UrlClassifierExceptionListEntry(
const nsACString& aUrlPattern, const nsACString& aTopLevelUrlPattern,
bool aIsPrivateBrowsingOnly,
const nsTArray<nsCString>& aClassifierFeatures)
: mUrlPattern(aUrlPattern),
mTopLevelUrlPattern(aTopLevelUrlPattern),
mIsPrivateBrowsingOnly(aIsPrivateBrowsingOnly) {
mClassifierFeatures = aClassifierFeatures.Clone();
}
private:
~UrlClassifierExceptionListEntry() = default;
nsCString mUrlPattern;
nsCString mTopLevelUrlPattern;
bool mIsPrivateBrowsingOnly{};
nsTArray<nsCString> mFilterContentBlockingCategories;
nsTArray<nsCString> mClassifierFeatures;
RefPtr<extensions::MatchPatternCore> mMatcher;
RefPtr<extensions::MatchPatternCore> mTopLevelMatcher;
};
} // namespace mozilla::net
#endif

View File

@@ -19,4 +19,18 @@ Classes = [
'esModule': 'resource://gre/modules/UrlClassifierExceptionListService.sys.mjs', 'esModule': 'resource://gre/modules/UrlClassifierExceptionListService.sys.mjs',
'constructor': 'UrlClassifierExceptionListService', 'constructor': 'UrlClassifierExceptionListService',
}, },
{
'cid': '{8753A413-3ED6-4A61-A1DC-B31A7E69B796}',
'interfaces': ['nsIUrlClassifierExceptionListEntry'],
'headers': ['mozilla/net/UrlClassifierExceptionListEntry.h'],
'type': 'mozilla::net::UrlClassifierExceptionListEntry',
'contract_ids': ['@mozilla.org/url-classifier/exception-list-entry;1'],
},
{
'cid': '{807535BF-018E-4300-B8D3-4A6405FB9F65}',
'interfaces': ['nsIUrlClassifierExceptionList'],
'headers': ['mozilla/net/UrlClassifierExceptionList.h'],
'type': 'mozilla::net::UrlClassifierExceptionList',
'contract_ids': ['@mozilla.org/url-classifier/exception-list;1'],
},
] ]

View File

@@ -10,6 +10,8 @@ with Files("**"):
XPIDL_SOURCES += [ XPIDL_SOURCES += [
"nsIChannelClassifierService.idl", "nsIChannelClassifierService.idl",
"nsIURIClassifier.idl", "nsIURIClassifier.idl",
"nsIUrlClassifierExceptionList.idl",
"nsIUrlClassifierExceptionListEntry.idl",
"nsIUrlClassifierExceptionListService.idl", "nsIUrlClassifierExceptionListService.idl",
"nsIUrlClassifierFeature.idl", "nsIUrlClassifierFeature.idl",
] ]
@@ -32,6 +34,8 @@ UNIFIED_SOURCES += [
"ChannelClassifierService.cpp", "ChannelClassifierService.cpp",
"nsChannelClassifier.cpp", "nsChannelClassifier.cpp",
"UrlClassifierCommon.cpp", "UrlClassifierCommon.cpp",
"UrlClassifierExceptionList.cpp",
"UrlClassifierExceptionListEntry.cpp",
"UrlClassifierFeatureBase.cpp", "UrlClassifierFeatureBase.cpp",
"UrlClassifierFeatureConsentManagerAnnotation.cpp", "UrlClassifierFeatureConsentManagerAnnotation.cpp",
"UrlClassifierFeatureCryptominingAnnotation.cpp", "UrlClassifierFeatureCryptominingAnnotation.cpp",
@@ -54,6 +58,8 @@ EXPORTS.mozilla.net += [
"AsyncUrlChannelClassifier.h", "AsyncUrlChannelClassifier.h",
"ChannelClassifierService.h", "ChannelClassifierService.h",
"UrlClassifierCommon.h", "UrlClassifierCommon.h",
"UrlClassifierExceptionList.h",
"UrlClassifierExceptionListEntry.h",
"UrlClassifierFeatureFactory.h", "UrlClassifierFeatureFactory.h",
"UrlClassifierFeatureResult.h", "UrlClassifierFeatureResult.h",
] ]

View File

@@ -0,0 +1,37 @@
/* 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 "nsISupports.idl"
#include "nsIURI.idl"
#include "nsIUrlClassifierExceptionListEntry.idl"
/**
* Interface for managing URL classifier exception lists.
*
* @see nsIUrlClassifierExceptionListEntry
*/
[scriptable, uuid(807535BF-018E-4300-B8D3-4A6405FB9F65)]
interface nsIUrlClassifierExceptionList : nsISupports
{
/**
* Initialize the exception list for a specific feature.
* @param aFeature The feature to initialize the exception list for
*/
void init(in ACString aFeature);
/**
* Add a new exception list entry to the list.
* @param aEntry The exception list entry to add
*/
void addEntry(in nsIUrlClassifierExceptionListEntry aEntry);
/**
* Check if the exception list matches the given URI.
* @param aURI The URI to check
* @param aTopLevelURI The top-level URI to check
* @param aIsPrivateBrowsing Whether the load is in private browsing mode
* @return True if the exception list matches, false otherwise
*/
boolean matches(in nsIURI aURI, in nsIURI aTopLevelURI, in boolean aIsPrivateBrowsing);
};

View File

@@ -0,0 +1,75 @@
/* 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 "nsISupports.idl"
#include "nsIURI.idl"
/**
* Represents a single exception list entry for the url classifier exception list.
* Needs to be initialized with init() before use.
*
* @see nsIUrlClassifierExceptionList
*/
[scriptable, uuid(8753A413-3ED6-4A61-A1DC-B31A7E69B796)]
interface nsIUrlClassifierExceptionListEntry : nsISupports
{
/**
* Initialize all fields of the exception list entry.
* @param aUrlPattern - The urlPattern for the url to be loaded. See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns for more info.
* @param aTopLevelUrlPattern - Optional top-level url pattern to filter for this exception. If not set the exception applies to all top level sites.
* @param aIsPrivateBrowsingOnly - Whether this applies only to private browsing
* @param aFilterContentBlockingCategories - The content blocking categories to filter for this exception.
* @param aClassifierFeatures - The list of url classifier features to apply this exception to.
*/
void init(in ACString aUrlPattern,
in ACString aTopLevelUrlPattern,
in boolean aIsPrivateBrowsingOnly,
in Array<ACString> aFilterContentBlockingCategories,
in Array<ACString> aClassifierFeatures);
/**
* Check if the exception list entry matches the given load.
* @param aURI The URI to check
* @param aTopLevelURI The top-level URI to check
* @param aIsPrivateBrowsing Whether the load is in private browsing mode
* @return True if the exception list entry matches the given load and it
* should be skipped from classification, false otherwise
*/
boolean matches(in nsIURI aURI, in nsIURI aTopLevelURI, in boolean aIsPrivateBrowsing);
/**
* The urlPattern name for this exception entry.
*/
readonly attribute ACString urlPattern;
/**
* Optional top-level url pattern to filter for this exception. If not set
* the exception applies to all top level sites.
*/
readonly attribute ACString topLevelUrlPattern;
/**
* Whether this exception only applies in private browsing mode.
*/
readonly attribute boolean isPrivateBrowsingOnly;
/**
* Optional array of content blocking categories to filter for this
* exception. If not set the exception applies to all content blocking
* categories.
*/
readonly attribute Array<ACString> filterContentBlockingCategories;
/**
* The list of url classifier features to apply this exception to.
*/
readonly attribute Array<ACString> classifierFeatures;
/**
* Returns a string containing all attributes of this exception list entry.
* This is intended for logging purposes only.
* @return A string containing all attributes
*/
[noscript] ACString describe();
};