Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/netwerk/url-classifier/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 26 kB image not shown  

Quelle  AsyncUrlChannelClassifier.cpp   Sprache: C

 
/* -*- 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/. */


#include "Classifier.h"
#include "mozilla/Components.h"
#include "mozilla/ErrorNames.h"
#include "mozilla/net/AsyncUrlChannelClassifier.h"
#include "mozilla/net/UrlClassifierCommon.h"
#include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "mozilla/net/UrlClassifierFeatureResult.h"
#include "nsContentUtils.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsPrintfCString.h"
#include "nsProxyRelease.h"
#include "nsServiceManagerUtils.h"
#include "nsUrlClassifierDBService.h"
#include "nsUrlClassifierUtils.h"

namespace mozilla {
namespace net {

namespace {

// 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.

// URIData
// -----------------------------------------------------------------------------

// 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);

  static nsresult Create(nsIURI* aURI, nsIURI* aInnermostURI,
                         nsIUrlClassifierFeature::URIType aURIType,
                         URIData** aData);

  bool IsEqual(nsIURI* aURI) const;

  const nsTArray<nsCString>& Fragments();

  nsIURI* URI() const;

 private:
  URIData();
  ~URIData() = default;

  nsCOMPtr<nsIURI> mURI;
  nsCString mURISpec;
  nsTArray<nsCString> mFragments;
  nsIUrlClassifierFeature::URIType mURIType;
};

/* static */
nsresult URIData::Create(nsIURI* aURI, nsIURI* aInnermostURI,
                         nsIUrlClassifierFeature::URIType aURIType,
                         URIData** aData) {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aURI);
  MOZ_ASSERT(aInnermostURI);

  RefPtr<URIData> data = new URIData();
  data->mURI = aURI;
  data->mURIType = aURIType;

  nsUrlClassifierUtils* utilsService = nsUrlClassifierUtils::GetInstance();
  if (NS_WARN_IF(!utilsService)) {
    return NS_ERROR_FAILURE;
  }

  nsresult rv = utilsService->GetKeyForURI(aInnermostURI, data->mURISpec);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::URIData::Create new URIData created for spec "
       "%s [this=%p]",
       data->mURISpec.get(), data.get()));

  data.forget(aData);
  return NS_OK;
}

URIData::URIData() { MOZ_ASSERT(NS_IsMainThread()); }

bool URIData::IsEqual(nsIURI* aURI) const {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aURI);

  bool isEqual = false;
  nsresult rv = mURI->Equals(aURI, &isEqual);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return false;
  }

  return isEqual;
}

const nsTArray<nsCString>& URIData::Fragments() {
  MOZ_ASSERT(!NS_IsMainThread());

  if (mFragments.IsEmpty()) {
    nsresult rv;

    if (mURIType == nsIUrlClassifierFeature::pairwiseEntitylistURI) {
      rv = LookupCache::GetLookupEntitylistFragments(mURISpec, &mFragments);
    } else {
      rv = LookupCache::GetLookupFragments(mURISpec, &mFragments);
    }

    Unused << NS_WARN_IF(NS_FAILED(rv));
  }

  return mFragments;
}

nsIURI* URIData::URI() const {
  MOZ_ASSERT(NS_IsMainThread());
  return mURI;
}

// TableData
// ----------------------------------------------------------------------------

// In order to avoid multiple lookups on the same table + URI, we have this
// class.
class TableData {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TableData);

  enum State {
    eUnclassified,
    eNoMatch,
    eMatch,
  };

  TableData(URIData* aURIData, const nsACString& aTable);

  nsIURI* URI() const;

  const nsACString& Table() const;

  const LookupResultArray& Result() const;

  State MatchState() const;

  bool IsEqual(URIData* aURIData, const nsACString& aTable) const;

  // Returns true if the table classifies the URI. This method must be called
  // on hte classifier worker thread.
  bool DoLookup(nsUrlClassifierDBServiceWorker* aWorkerClassifier);

 private:
  ~TableData();

  RefPtr<URIData> mURIData;
  State mState;

  nsCString mTable;
  LookupResultArray mResults;
};

TableData::TableData(URIData* aURIData, const nsACString& aTable)
    : mURIData(aURIData), mState(eUnclassified), mTable(aTable) {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aURIData);

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::TableData CTOR - new TableData created %s "
       "[this=%p]",
       aTable.BeginReading(), this));
}

TableData::~TableData() = default;

nsIURI* TableData::URI() const {
  MOZ_ASSERT(NS_IsMainThread());
  return mURIData->URI();
}

const nsACString& TableData::Table() const {
  MOZ_ASSERT(NS_IsMainThread());
  return mTable;
}

const LookupResultArray& TableData::Result() const {
  MOZ_ASSERT(NS_IsMainThread());
  return mResults;
}

TableData::State TableData::MatchState() const {
  MOZ_ASSERT(NS_IsMainThread());
  return mState;
}

bool TableData::IsEqual(URIData* aURIData, const nsACString& aTable) const {
  MOZ_ASSERT(NS_IsMainThread());
  return mURIData == aURIData && mTable == aTable;
}

bool TableData::DoLookup(nsUrlClassifierDBServiceWorker* aWorkerClassifier) {
  MOZ_ASSERT(!NS_IsMainThread());
  MOZ_ASSERT(aWorkerClassifier);

  if (mState == TableData::eUnclassified) {
    UC_LOG_LEAK(
        ("AsyncChannelClassifier::TableData::DoLookup - starting lookup "
         "[this=%p]",
         this));

    const nsTArray<nsCString>& fragments = mURIData->Fragments();
    nsresult rv = aWorkerClassifier->DoSingleLocalLookupWithURIFragments(
        fragments, mTable, mResults);
    Unused << NS_WARN_IF(NS_FAILED(rv));

    mState = mResults.IsEmpty() ? TableData::eNoMatch : TableData::eMatch;

    UC_LOG_LEAK(
        ("AsyncChannelClassifier::TableData::DoLookup - lookup completed. "
         "Matches: %d [this=%p]",
         (int)mResults.Length(), this));
  }

  return !mResults.IsEmpty();
}

// FeatureData
// ----------------------------------------------------------------------------

class FeatureTask;

// This is class contains all the Feature data.
class FeatureData {
  enum State {
    eUnclassified,
    eNoMatch,
    eMatchBlocklist,
    eMatchEntitylist,
  };

 public:
  FeatureData() = default;
  ~FeatureData();

  nsresult Initialize(FeatureTask* aTask, nsIChannel* aChannel,
                      nsIUrlClassifierFeature* aFeature);

  void DoLookup(nsUrlClassifierDBServiceWorker* aWorkerClassifier);

  // Returns true if the next feature should be processed.
  bool MaybeCompleteClassification(nsIChannel* aChannel);

 private:
  nsresult InitializeList(FeatureTask* aTask, nsIChannel* aChannel,
                          nsIUrlClassifierFeature::listType aListType,
                          nsTArray<RefPtr<TableData>>& aList);

  State mState{eUnclassified};
  nsCOMPtr<nsIUrlClassifierFeature> mFeature;
  nsCOMPtr<nsIChannel> mChannel;

  nsTArray<RefPtr<TableData>> mBlocklistTables;
  nsTArray<RefPtr<TableData>> mEntitylistTables;

  // blocklist + entitylist.
  nsCString mHostInPrefTables[2];
};

FeatureData::~FeatureData() {
  NS_ReleaseOnMainThread("FeatureData:mFeature", mFeature.forget());
}

nsresult FeatureData::Initialize(FeatureTask* aTask, nsIChannel* aChannel,
                                 nsIUrlClassifierFeature* aFeature) {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aTask);
  MOZ_ASSERT(aChannel);
  MOZ_ASSERT(aFeature);

  if (UC_LOG_ENABLED()) {
    nsAutoCString name;
    aFeature->GetName(name);
    UC_LOG_LEAK(
        ("AsyncChannelClassifier::FeatureData::Initialize - Feature %s "
         "[this=%p, channel=%p]",
         name.get(), this, aChannel));
  }

  mFeature = aFeature;
  mChannel = aChannel;

  nsresult rv = InitializeList(
      aTask, aChannel, nsIUrlClassifierFeature::blocklist, mBlocklistTables);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  rv = InitializeList(aTask, aChannel, nsIUrlClassifierFeature::entitylist,
                      mEntitylistTables);
  if (NS_FAILED(rv)) {
    return rv;
  }

  return NS_OK;
}

void FeatureData::DoLookup(nsUrlClassifierDBServiceWorker* aWorkerClassifier) {
  MOZ_ASSERT(!NS_IsMainThread());
  MOZ_ASSERT(aWorkerClassifier);
  MOZ_ASSERT(mState == eUnclassified);

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureData::DoLookup - lookup starting "
       "[this=%p]",
       this));

  // 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.

  bool isBlocklisted =
      !mHostInPrefTables[nsIUrlClassifierFeature::blocklist].IsEmpty();

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureData::DoLookup - blocklisted by pref: "
       "%d [this=%p]",
       isBlocklisted, this));

  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;
      }
    }
  }

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureData::DoLookup - blocklisted before "
       "entitylisting: %d [this=%p]",
       isBlocklisted, this));

  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;
    }
  }

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureData::DoLookup - blocklisted [this=%p]",
       this));
  mState = eMatchBlocklist;
}

bool FeatureData::MaybeCompleteClassification(nsIChannel* aChannel) {
  MOZ_ASSERT(NS_IsMainThread());

  nsAutoCString name;
  mFeature->GetName(name);

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureData::MaybeCompleteClassification - "
       "completing "
       "classification [this=%p channel=%p]",
       this, aChannel));

  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));
      return true;

    case eMatchEntitylist:
      UC_LOG(
          ("AsyncChannelClassifier::FeatureData::MayebeCompleteClassification "
           "- entitylisted by feature %s. Let's "
           "move on [this=%p channel=%p]",
           name.get(), this, aChannel));
      return true;

    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));
    return true;
  }

  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));
    return true;
  }

  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 (const auto& r : tableData->Result()) {
        hashes.AppendElement(r->hash.complete.ToString());
      }
    }
  }

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureData::MaybeCompleteClassification - "
       "process channel [this=%p channel=%p]",
       this, aChannel));

  bool shouldContinue = false;
  rv = mFeature->ProcessChannel(aChannel, list, hashes, &shouldContinue);
  Unused << NS_WARN_IF(NS_FAILED(rv));

  return shouldContinue;
}

// CallbackHolder
// ----------------------------------------------------------------------------

// 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);

  explicit CallbackHolder(std::function<void()>&& aCallback)
      : mCallback(std::move(aCallback)) {}

  void Exec() const { mCallback(); }

 private:
  ~CallbackHolder() = default;

  std::function<void()> mCallback;
};

// FeatureTask
// ----------------------------------------------------------------------------

// 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);

  static nsresult Create(nsIChannel* aChannel,
                         std::function<void()>&& aCallback,
                         FeatureTask** aTask);

  // Called on the classifier thread.
  void DoLookup(nsUrlClassifierDBServiceWorker* aWorkerClassifier);

  // Called on the main-thread to process the channel.
  void CompleteClassification();

  nsresult GetOrCreateURIData(nsIURI* aURI, nsIURI* aInnermostURI,
                              nsIUrlClassifierFeature::URIType aURIType,
                              URIData** aData);

  nsresult GetOrCreateTableData(URIData* aURIData, const nsACString& aTable,
                                TableData** aData);

 private:
  FeatureTask(nsIChannel* aChannel, std::function<void()>&& aCallback);
  ~FeatureTask();

  nsCOMPtr<nsIChannel> mChannel;
  RefPtr<CallbackHolder> mCallbackHolder;

  nsTArray<FeatureData> mFeatures;
  nsTArray<RefPtr<URIData>> mURIs;
  nsTArray<RefPtr<TableData>> mTables;
};

// 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));

  UC_LOG(
      ("AsyncChannelClassifier::FeatureTask::Create - FeatureTask %p created "
       "for channel %p",
       task.get(), aChannel));

  for (nsIUrlClassifierFeature* feature : features) {
    FeatureData* featureData = task->mFeatures.AppendElement();
    nsresult rv = featureData->Initialize(task, aChannel, feature);
    if (NS_FAILED(rv)) {
      return rv;
    }
  }

  task.forget(aTask);
  return NS_OK;
}

FeatureTask::FeatureTask(nsIChannel* aChannel,
                         std::function<void()>&& aCallback)
    : mChannel(aChannel) {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(mChannel);

  std::function<void()> callback = std::move(aCallback);
  mCallbackHolder = new CallbackHolder(std::move(callback));
}

FeatureTask::~FeatureTask() {
  NS_ReleaseOnMainThread("FeatureTask::mChannel", mChannel.forget());
  NS_ReleaseOnMainThread("FeatureTask::mCallbackHolder",
                         mCallbackHolder.forget());
}

nsresult FeatureTask::GetOrCreateURIData(
    nsIURI* aURI, nsIURI* aInnermostURI,
    nsIUrlClassifierFeature::URIType aURIType, URIData** aData) {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aURI);
  MOZ_ASSERT(aInnermostURI);
  MOZ_ASSERT(aData);

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureTask::GetOrCreateURIData - checking if "
       "a URIData must be "
       "created [this=%p]",
       this));

  for (URIData* data : mURIs) {
    if (data->IsEqual(aURI)) {
      UC_LOG_LEAK(
          ("AsyncChannelClassifier::FeatureTask::GetOrCreateURIData - reuse "
           "existing URIData %p [this=%p]",
           data, this));

      RefPtr<URIData> uriData = data;
      uriData.forget(aData);
      return NS_OK;
    }
  }

  RefPtr<URIData> data;
  nsresult rv =
      URIData::Create(aURI, aInnermostURI, aURIType, getter_AddRefs(data));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  mURIs.AppendElement(data);

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureTask::GetOrCreateURIData - create new "
       "URIData %p [this=%p]",
       data.get(), this));

  data.forget(aData);
  return NS_OK;
}

nsresult FeatureTask::GetOrCreateTableData(URIData* aURIData,
                                           const nsACString& aTable,
                                           TableData** aData) {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aURIData);
  MOZ_ASSERT(aData);

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureTask::GetOrCreateTableData - checking "
       "if TableData must be "
       "created [this=%p]",
       this));

  for (TableData* data : mTables) {
    if (data->IsEqual(aURIData, aTable)) {
      UC_LOG_LEAK(
          ("FeatureTask::GetOrCreateTableData - reuse existing TableData %p "
           "[this=%p]",
           data, this));

      RefPtr<TableData> tableData = data;
      tableData.forget(aData);
      return NS_OK;
    }
  }

  RefPtr<TableData> data = new TableData(aURIData, aTable);
  mTables.AppendElement(data);

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureTask::GetOrCreateTableData - create new "
       "TableData %p [this=%p]",
       data.get(), this));

  data.forget(aData);
  return NS_OK;
}

void FeatureTask::DoLookup(nsUrlClassifierDBServiceWorker* aWorkerClassifier) {
  MOZ_ASSERT(!NS_IsMainThread());
  MOZ_ASSERT(aWorkerClassifier);

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureTask::DoLookup - starting lookup "
       "[this=%p]",
       this));

  for (FeatureData& feature : mFeatures) {
    feature.DoLookup(aWorkerClassifier);
  }

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureTask::DoLookup - lookup completed "
       "[this=%p]",
       this));
}

void FeatureTask::CompleteClassification() {
  MOZ_ASSERT(NS_IsMainThread());

  for (FeatureData& feature : mFeatures) {
    if (!feature.MaybeCompleteClassification(mChannel)) {
      break;
    }
  }

  UC_LOG(
      ("AsyncChannelClassifier::FeatureTask::CompleteClassification - complete "
       "classification for "
       "channel %p [this=%p]",
       mChannel.get(), this));

  mCallbackHolder->Exec();
}

nsresult FeatureData::InitializeList(
    FeatureTask* aTask, nsIChannel* aChannel,
    nsIUrlClassifierFeature::listType aListType,
    nsTArray<RefPtr<TableData>>& aList) {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aTask);
  MOZ_ASSERT(aChannel);

  UC_LOG_LEAK(
      ("AsyncChannelClassifier::FeatureData::InitializeList - initialize list "
       "%d for channel %p [this=%p]",
       aListType, aChannel, this));

  nsCOMPtr<nsIURI> uri;
  nsIUrlClassifierFeature::URIType URIType;
  nsresult rv = mFeature->GetURIByListType(aChannel, aListType, &URIType,
                                           getter_AddRefs(uri));
  if (NS_FAILED(rv)) {
    if (UC_LOG_ENABLED()) {
      nsAutoCString errorName;
      GetErrorName(rv, errorName);
      UC_LOG_LEAK(
          ("AsyncChannelClassifier::FeatureData::InitializeList - Got an "
           "unexpected error (rv=%s) [this=%p]",
           errorName.get(), this));
    }
    return rv;
  }

  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;
  }

  nsAutoCString host;
  rv = innermostURI->GetHost(host);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  bool found = false;
  nsAutoCString tableName;
  rv = mFeature->HasHostInPreferences(host, aListType, tableName, &found);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  if (found) {
    mHostInPrefTables[aListType] = tableName;
  }

  RefPtr<URIData> uriData;
  rv = aTask->GetOrCreateURIData(uri, innermostURI, URIType,
                                 getter_AddRefs(uriData));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  MOZ_ASSERT(uriData);

  nsTArray<nsCString> tables;
  rv = mFeature->GetTables(aListType, tables);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  for (const nsCString& table : tables) {
    RefPtr<TableData> data;
    rv = aTask->GetOrCreateTableData(uriData, table, getter_AddRefs(data));
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }

    MOZ_ASSERT(data);
    aList.AppendElement(data);
  }

  return NS_OK;
}

}  // namespace

/* static */
nsresult AsyncUrlChannelClassifier::CheckChannel(
    nsIChannel* aChannel, std::function<void()>&& aCallback) {
  MOZ_ASSERT(XRE_IsParentProcess());
  MOZ_ASSERT(aChannel);

  if (!aCallback) {
    return NS_ERROR_INVALID_ARG;
  }

  if (UC_LOG_ENABLED()) {
    nsCOMPtr<nsIURI> chanURI;
    if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(chanURI)))) {
      nsCString chanSpec = chanURI->GetSpecOrDefault();
      chanSpec.Truncate(
          std::min(chanSpec.Length(), UrlClassifierCommon::sMaxSpecLength));

      nsCOMPtr<nsIURI> topWinURI;
      Unused << UrlClassifierCommon::GetTopWindowURI(aChannel,
                                                     getter_AddRefs(topWinURI));
      nsCString topWinSpec =
          topWinURI ? topWinURI->GetSpecOrDefault() : "(null)"_ns;

      topWinSpec.Truncate(
          std::min(topWinSpec.Length(), UrlClassifierCommon::sMaxSpecLength));

      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));
    }
  }

  RefPtr<FeatureTask> task;
  nsresult rv =
      FeatureTask::Create(aChannel, std::move(aCallback), getter_AddRefs(task));
  if (NS_FAILED(rv)) {
    return rv;
  }

  if (!task) {
    // No task is needed for this channel, return an error so the caller won't
    // wait for a callback.
    return NS_ERROR_FAILURE;
  }

  RefPtr<nsUrlClassifierDBServiceWorker> workerClassifier =
      nsUrlClassifierDBService::GetWorker();
  if (NS_WARN_IF(!workerClassifier)) {
    return NS_ERROR_FAILURE;
  }

  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
      "AsyncUrlChannelClassifier::CheckChannel",
      [task, workerClassifier]() -> void {
        MOZ_ASSERT(!NS_IsMainThread());
        task->DoLookup(workerClassifier);

        nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
            "AsyncUrlChannelClassifier::CheckChannel - return",
            [task]() -> void { task->CompleteClassification(); });

        NS_DispatchToMainThread(r);
      });

  return nsUrlClassifierDBService::BackgroundThread()->Dispatch(
      r, NS_DISPATCH_NORMAL);
}

}  // namespace net
}  // namespace mozilla

92%


¤ Dauer der Verarbeitung: 0.63 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.