/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set expandtab ts=4 sw=2 sts=2 cin: */ /* 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/. */
// Big picture comment // ----------------------------------------------------------------------------- // nsUrlClassifierDBService::channelClassify() classifies a channel using a set // of URL-Classifier features. This method minimizes the number of lookups and // URI parsing and this is done using the classes here described. // // The first class is 'FeatureTask' which is able to retrieve the list of // features for this channel using the feature-factory. See // UrlClassifierFeatureFactory. // For each feature, it creates a FeatureData object, which contains the // entitylist and blocklist prefs and tables. The reason why we create // FeatureData is because: // - features are not thread-safe. // - we want to store the state of the classification in the FeatureData // object. // // It can happen that multiple features share the same tables. In order to do // the lookup just once, we have TableData class. When multiple features // contain the same table, they have references to the same couple TableData + // URIData objects. // // During the classification, the channel's URIs are fragmented. In order to // create these fragments just once, we use the URIData class, which is pointed // by TableData classes. // // The creation of these classes happens on the main-thread. The classification // happens on the worker thread.
// In order to avoid multiple URI parsing, we have this class which contains // nsIURI and its fragments. class URIData { public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URIData);
// In order to avoid multiple lookups on the same table + URI, we have this // class. class TableData { public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TableData);
// Returns true if the table classifies the URI. This method must be called // on hte classifier worker thread. bool DoLookup(nsUrlClassifierDBServiceWorker* aWorkerClassifier);
// This is wrong, but it's fast: we don't want to check if the host is in the // blocklist table if we know that it's going to be entitylisted by pref. // So, also if maybe it's not blocklisted, let's consider it 'entitylisted'. if (!mHostInPrefTables[nsIUrlClassifierFeature::entitylist].IsEmpty()) {
UC_LOG_LEAK(
("AsyncChannelClassifier::FeatureData::DoLookup - entitylisted by pref " "[this=%p]", this));
mState = eMatchEntitylist; return;
}
// Let's check if this feature blocklists the URI.
if (!isBlocklisted) { // If one of the blocklist table matches the URI, we don't need to continue // with the others: the feature is blocklisted (but maybe also // entitylisted). for (TableData* tableData : mBlocklistTables) { if (tableData->DoLookup(aWorkerClassifier)) {
isBlocklisted = true; break;
}
}
}
if (!isBlocklisted) {
mState = eNoMatch; return;
}
// Now, let's check if we need to entitylist the same URI.
for (TableData* tableData : mEntitylistTables) { // If one of the entitylist table matches the URI, we don't need to continue // with the others: the feature is entitylisted. if (tableData->DoLookup(aWorkerClassifier)) {
UC_LOG_LEAK(
("AsyncChannelClassifier::FeatureData::DoLookup - entitylisted by " "table [this=%p]", this));
mState = eMatchEntitylist; return;
}
}
switch (mState) { case eNoMatch:
UC_LOG(
("AsyncChannelClassifier::FeatureData::MaybeCompleteClassification - " "no match for feature %s. Let's " "move on [this=%p channel=%p]",
name.get(), this, aChannel)); returntrue;
case eMatchEntitylist:
UC_LOG(
("AsyncChannelClassifier::FeatureData::MayebeCompleteClassification " "- entitylisted by feature %s. Let's " "move on [this=%p channel=%p]",
name.get(), this, aChannel)); returntrue;
case eMatchBlocklist:
UC_LOG(
("AsyncChannelClassifier::FeatureData::MaybeCompleteClassification - " "blocklisted by feature %s [this=%p channel=%p]",
name.get(), this, aChannel)); break;
case eUnclassified:
MOZ_CRASH("We should not be here!"); break;
}
MOZ_ASSERT(mState == eMatchBlocklist);
// Maybe we have to ignore this host
nsAutoCString exceptionList;
nsresult rv = mFeature->GetExceptionHostList(exceptionList); if (NS_WARN_IF(NS_FAILED(rv))) {
UC_LOG_WARN(
("AsyncChannelClassifier::FeatureData::MayebeCompleteClassification - " "error. Let's move on [this=%p channel=%p]", this, aChannel)); returntrue;
}
if (!mBlocklistTables.IsEmpty() &&
nsContentUtils::IsURIInList(mBlocklistTables[0]->URI(), exceptionList)) {
nsCString spec = mBlocklistTables[0]->URI()->GetSpecOrDefault();
spec.Truncate(std::min(spec.Length(), UrlClassifierCommon::sMaxSpecLength));
UC_LOG(
("AsyncChannelClassifier::FeatureData::MaybeCompleteClassification - " "uri %s found in " "exceptionlist of feature %s [this=%p channel=%p]",
spec.get(), name.get(), this, aChannel)); returntrue;
}
nsTArray<nsCString> list;
nsTArray<nsCString> hashes; if (!mHostInPrefTables[nsIUrlClassifierFeature::blocklist].IsEmpty()) {
list.AppendElement(mHostInPrefTables[nsIUrlClassifierFeature::blocklist]);
// Telemetry expects every tracking channel has hash, create it for test // entry
Completion complete;
complete.FromPlaintext(
mHostInPrefTables[nsIUrlClassifierFeature::blocklist]);
hashes.AppendElement(complete.ToString());
}
for (TableData* tableData : mBlocklistTables) { if (tableData->MatchState() == TableData::eMatch) {
list.AppendElement(tableData->Table());
for (constauto& r : tableData->Result()) {
hashes.AppendElement(r->hash.complete.ToString());
}
}
}
// This class keeps the callback alive and makes sure that we release it on the // correct thread. class CallbackHolder final { public:
NS_INLINE_DECL_REFCOUNTING(CallbackHolder);
// A FeatureTask is a class that is able to classify a channel using a set of // features. The features are grouped by: // - URIs - to avoid extra URI parsing. // - Tables - to avoid multiple lookup on the same table. class FeatureTask { public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FeatureTask);
// Features are able to classify particular URIs from a channel. For instance, // tracking-annotation feature uses the top-level URI to entitylist the current // channel's URI. Because of // this, this function aggregates feature per URI and tables. /* static */
nsresult FeatureTask::Create(nsIChannel* aChannel,
std::function<void()>&& aCallback,
FeatureTask** aTask) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aChannel);
MOZ_ASSERT(aTask);
// We need to obtain the list of nsIUrlClassifierFeature objects able to // classify this channel. If the list is empty, we do an early return.
nsTArray<nsCOMPtr<nsIUrlClassifierFeature>> features;
UrlClassifierFeatureFactory::GetFeaturesFromChannel(aChannel, features); if (features.IsEmpty()) {
UC_LOG(
("AsyncChannelClassifier::FeatureTask::Create - no task is needed for " "channel %p",
aChannel)); return NS_OK;
}
RefPtr<FeatureTask> task = new FeatureTask(aChannel, std::move(aCallback));
if (!uri) { // Return success when the URI is empty to conitnue to do the lookup.
UC_LOG_LEAK(
("AsyncChannelClassifier::FeatureData::InitializeList - got an empty " "URL [this=%p]", this)); return NS_OK;
}
nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(uri); if (NS_WARN_IF(!innermostURI)) { return NS_ERROR_FAILURE;
}
UC_LOG(
("AsyncUrlChannelClassifier::CheckChannel - starting the " "classification on channel %p",
aChannel));
UC_LOG((" uri is %s [channel=%p]", chanSpec.get(), aChannel));
UC_LOG(
(" top-level uri is %s [channel=%p]", topWinSpec.get(), aChannel));
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.