Backed out changeset 44635c073692 (bug 1345058) on suspicion of causing intermittent xpcshell failures in toolkit/components/url-classifier/tests/unit/test_bug1274685_unowned_list.js on OS X. r=backout

This commit is contained in:
Sebastian Hengst 2017-05-19 13:13:18 +02:00
parent 8f7f5942b2
commit e07a98a1b3
3 changed files with 78 additions and 385 deletions

View File

@ -269,7 +269,6 @@
#endif // MOZ_WEBRTC
#include "nsIURIClassifier.h"
#include "mozilla/ClearOnShutdown.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -310,65 +309,6 @@ GetHttpChannelHelper(nsIChannel* aChannel, nsIHttpChannel** aHttpChannel)
return NS_OK;
}
////////////////////////////////////////////////////////////////////
// PrincipalFlashClassifier
// Classify the flash based on the document principal.
// The usage of this class is as follows:
//
// 1) Call AsyncClassify() as early as possible to asynchronously do
// classification against all the flash blocking related tables
// via nsIURIClassifier.asyncClassifyLocalWithTables.
//
// 2) At any time you need the classification result, call Result()
// and it is guaranteed to give you the result. Note that you have
// to specify "aIsThirdParty" to the function so please make sure
// you can already corretly decide if the document is third-party.
//
// Behind the scenes, the sync classification API
// (nsIURIClassifier.classifyLocalWithTable) may be called as a fallback to
// synchronously get the result if the asyncClassifyLocalWithTables hasn't
// been done yet.
//
// 3) You can call Result() as many times as you want and only the first time
// may it unfortunately call the blocking sync API. The subsequent call
// will just return the result we came out in the first time.
//
class PrincipalFlashClassifier final : public nsIURIClassifierCallback
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIURICLASSIFIERCALLBACK
explicit PrincipalFlashClassifier();
// Fire async classification based on the given principal.
void AsyncClassify(nsIPrincipal* aPrincipal);
// Would block if the result hasn't come out.
mozilla::dom::FlashClassification Result(nsIPrincipal* aPrincipal,
bool aIsThirdParty);
private:
~PrincipalFlashClassifier() = default;
void Reset();
bool EnsureUriClassifier();
mozilla::dom::FlashClassification CheckIfClassifyNeeded(nsIPrincipal* aPrincipal);
mozilla::dom::FlashClassification Resolve(bool aIsThirdParty);
mozilla::dom::FlashClassification AsyncClassifyInternal(nsIPrincipal* aPrincipal);
nsCString GetClassificationTables(bool aIsThirdParty);
// For the fallback sync classification.
nsCOMPtr<nsIURI> mClassificationURI;
nsCOMPtr<nsIURIClassifier> mUriClassifier;
bool mAsyncClassified;
nsTArray<nsCString> mMatchedTables;
mozilla::dom::FlashClassification mResult;
};
#define NAME_NOT_VALID ((nsSimpleContentList*)1)
nsIdentifierMapEntry::~nsIdentifierMapEntry()
@ -1496,10 +1436,6 @@ nsDocument::nsDocument(const char* aContentType)
// void state used to differentiate an empty source from an unselected source
mPreloadPictureFoundSource.SetIsVoid(true);
// For determining if this is a flash document which should be
// blocked based on its principal.
mPrincipalFlashClassifier = new PrincipalFlashClassifier();
}
void
@ -2648,11 +2584,6 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
NS_ENSURE_SUCCESS(rv, rv);
}
// Perform a async flash classification based on the doc principal
// in an early stage to reduce the blocking time.
mFlashClassification = FlashClassification::Unclassified;
mPrincipalFlashClassifier->AsyncClassify(GetPrincipal());
return NS_OK;
}
@ -13252,21 +13183,6 @@ nsIDocument::UpdateStyleBackendType()
#endif
}
/**
* Retrieves the classification of the Flash plugins in the document based on
* the classification lists. We perform AsyncInitFlashClassification on
* StartDocumentLoad() and the result may not be initialized when this function
* gets called. In that case, We can only unfortunately have a blocking wait.
*
* For more information, see
* toolkit/components/url-classifier/flash-block-lists.rst
*/
FlashClassification
nsDocument::PrincipalFlashClassification()
{
return mPrincipalFlashClassifier->Result(GetPrincipal(), IsThirdParty());
}
/**
* Helper function for |nsDocument::PrincipalFlashClassification|
*
@ -13307,268 +13223,27 @@ ArrayContainsTable(const nsTArray<nsCString>& aTableArray,
return false;
}
namespace {
// An object to store all preferences we need for flash blocking feature.
struct PrefStore
{
PrefStore()
{
Preferences::AddBoolVarCache(&mFlashBlockEnabled,
"plugins.flashBlock.enabled");
Preferences::AddBoolVarCache(&mPluginsHttpOnly,
"plugins.http_https_only");
// We only need to register string-typed preferences.
Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashAllowTable", this);
Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashAllowExceptTable", this);
Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashTable", this);
Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashExceptTable", this);
Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashSubDocTable", this);
Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashSubDocExceptTable", this);
UpdateStringPrefs();
}
~PrefStore()
{
Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashAllowTable", this);
Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashAllowExceptTable", this);
Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashTable", this);
Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashExceptTable", this);
Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashSubDocTable", this);
Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashSubDocExceptTable", this);
}
void UpdateStringPrefs()
{
Preferences::GetCString("urlclassifier.flashAllowTable", &mAllowTables);
Preferences::GetCString("urlclassifier.flashAllowExceptTable", &mAllowExceptionsTables);
Preferences::GetCString("urlclassifier.flashTable", &mDenyTables);
Preferences::GetCString("urlclassifier.flashExceptTable", &mDenyExceptionsTables);
Preferences::GetCString("urlclassifier.flashSubDocTable", &mSubDocDenyTables);
Preferences::GetCString("urlclassifier.flashSubDocExceptTable", &mSubDocDenyExceptionsTables);
}
static void UpdateStringPrefs(const char*, void* aClosure)
{
static_cast<PrefStore*>(aClosure)->UpdateStringPrefs();
}
bool mFlashBlockEnabled;
bool mPluginsHttpOnly;
nsCString mAllowTables;
nsCString mAllowExceptionsTables;
nsCString mDenyTables;
nsCString mDenyExceptionsTables;
nsCString mSubDocDenyTables;
nsCString mSubDocDenyExceptionsTables;
};
static const
PrefStore& GetPrefStore()
{
static UniquePtr<PrefStore> sPrefStore;
if (!sPrefStore) {
sPrefStore.reset(new PrefStore());
ClearOnShutdown(&sPrefStore);
}
return *sPrefStore;
}
} // end of unnamed namespace.
////////////////////////////////////////////////////////////////////
// PrincipalFlashClassifier implementation.
NS_IMPL_ISUPPORTS(PrincipalFlashClassifier, nsIURIClassifierCallback)
PrincipalFlashClassifier::PrincipalFlashClassifier()
{
Reset();
}
void
PrincipalFlashClassifier::Reset()
{
mAsyncClassified = false;
mMatchedTables.Clear();
mResult = FlashClassification::Unclassified;
}
nsCString
PrincipalFlashClassifier::GetClassificationTables(bool aIsThirdParty)
{
nsAutoCString tables;
auto& prefs = GetPrefStore();
MaybeAddTableToTableList(prefs.mAllowTables, tables);
MaybeAddTableToTableList(prefs.mAllowExceptionsTables, tables);
MaybeAddTableToTableList(prefs.mDenyTables, tables);
MaybeAddTableToTableList(prefs.mDenyExceptionsTables, tables);
if (aIsThirdParty) {
MaybeAddTableToTableList(prefs.mSubDocDenyTables, tables);
MaybeAddTableToTableList(prefs.mSubDocDenyExceptionsTables, tables);
}
return tables;
}
bool
PrincipalFlashClassifier::EnsureUriClassifier()
{
if (mUriClassifier) {
return true;
}
mUriClassifier = do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
return !!mUriClassifier;
}
/**
* Retrieves the classification of the Flash plugins in the document based on
* the classification lists.
*
* For more information, see
* toolkit/components/url-classifier/flash-block-lists.rst
*/
FlashClassification
PrincipalFlashClassifier::Result(nsIPrincipal* aPrincipal, bool aIsThirdParty)
{
if (FlashClassification::Unclassified != mResult) {
// We already have the result. Just return it.
return mResult;
}
// TODO: Bug 1342333 - Entirely remove the use of the sync API
// (ClassifyLocalWithTables).
if (!mAsyncClassified) {
//
// We may
// 1) have called AsyncClassifyLocalWithTables but OnClassifyComplete
// hasn't been called.
// 2) haven't even called AsyncClassifyLocalWithTables.
//
// In both cases we need to do the synchronous classification as the fallback.
//
if (!EnsureUriClassifier()) {
return FlashClassification::Denied;
}
mResult = CheckIfClassifyNeeded(aPrincipal);
if (FlashClassification::Unclassified != mResult) {
return mResult;
}
nsCString classificationTables = GetClassificationTables(aIsThirdParty);
nsresult rv = mUriClassifier->ClassifyLocalWithTables(mClassificationURI,
classificationTables,
mMatchedTables);
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_MALFORMED_URI) {
// This means that the URI had no hostname (ex: file://doc.html). In this
// case, we allow the default (Unknown plugin) behavior.
mResult = FlashClassification::Unknown;
} else {
mResult = FlashClassification::Denied;
}
return mResult;
}
}
// Resolve the result based on mMatchedTables and aIsThirdParty.
mResult = Resolve(aIsThirdParty);
MOZ_ASSERT(FlashClassification::Unclassified != mResult);
// The subsequent call of Result() will return the resolved result
// and never reach here until Reset() is called.
return mResult;
}
/*virtual*/ nsresult
PrincipalFlashClassifier::OnClassifyComplete(nsresult /*aErrorCode*/,
const nsACString& aLists, // Only this matters.
const nsACString& /*aProvider*/,
const nsACString& /*aPrefix*/)
{
mAsyncClassified = true;
if (FlashClassification::Unclassified != mResult) {
// Result() has been called prior to this callback.
return NS_OK;
}
// TODO: Bug 1364804 - We should use a callback type which notifies
// the result as a string array rather than a formatted string.
// We only populate the matched list without resolving the classification
// result because we are not sure if the parent doc has been properly set.
// We also parse the comma-separated tables to array. (the code is copied
// from Classifier::SplitTables.)
nsACString::const_iterator begin, iter, end;
aLists.BeginReading(begin);
aLists.EndReading(end);
while (begin != end) {
iter = begin;
FindCharInReadable(',', iter, end);
nsDependentCSubstring table = Substring(begin,iter);
if (!table.IsEmpty()) {
mMatchedTables.AppendElement(Substring(begin, iter));
}
begin = iter;
if (begin != end) {
begin++;
}
}
return NS_OK;
}
// We resolve the classification result based on aIsThirdParty
// and the matched tables we got ealier on (via either sync or async API).
FlashClassification
PrincipalFlashClassifier::Resolve(bool aIsThirdParty)
{
MOZ_ASSERT(FlashClassification::Unclassified == mResult,
"We already have resolved classification result.");
if (mMatchedTables.IsEmpty()) {
return FlashClassification::Unknown;
}
auto& prefs = GetPrefStore();
if (ArrayContainsTable(mMatchedTables, prefs.mDenyTables) &&
!ArrayContainsTable(mMatchedTables, prefs.mDenyExceptionsTables)) {
return FlashClassification::Denied;
} else if (ArrayContainsTable(mMatchedTables, prefs.mAllowTables) &&
!ArrayContainsTable(mMatchedTables, prefs.mAllowExceptionsTables)) {
return FlashClassification::Allowed;
}
if (aIsThirdParty && ArrayContainsTable(mMatchedTables, prefs.mSubDocDenyTables) &&
!ArrayContainsTable(mMatchedTables, prefs.mSubDocDenyExceptionsTables)) {
return FlashClassification::Denied;
}
return FlashClassification::Unknown;
}
void
PrincipalFlashClassifier::AsyncClassify(nsIPrincipal* aPrincipal)
{
MOZ_ASSERT(FlashClassification::Unclassified == mResult,
"The old classification result should be reset first.");
Reset();
mResult = AsyncClassifyInternal(aPrincipal);
}
FlashClassification
PrincipalFlashClassifier::CheckIfClassifyNeeded(nsIPrincipal* aPrincipal)
nsDocument::PrincipalFlashClassification()
{
nsresult rv;
auto& prefs = GetPrefStore();
bool httpOnly = Preferences::GetBool("plugins.http_https_only", true);
bool flashBlock = Preferences::GetBool("plugins.flashBlock.enabled", false);
// If neither pref is on, skip the null-principal and principal URI checks.
if (prefs.mPluginsHttpOnly && !prefs.mFlashBlockEnabled) {
if (!httpOnly && !flashBlock) {
return FlashClassification::Unknown;
}
nsCOMPtr<nsIPrincipal> principal = aPrincipal;
nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
if (principal->GetIsNullPrincipal()) {
return FlashClassification::Denied;
}
@ -13579,7 +13254,7 @@ PrincipalFlashClassifier::CheckIfClassifyNeeded(nsIPrincipal* aPrincipal)
return FlashClassification::Denied;
}
if (prefs.mPluginsHttpOnly) {
if (httpOnly) {
// Only allow plugins for documents from an HTTP/HTTPS origin. This should
// allow dependent data: URIs to load plugins, but not:
// * chrome documents
@ -13595,47 +13270,49 @@ PrincipalFlashClassifier::CheckIfClassifyNeeded(nsIPrincipal* aPrincipal)
// If flash blocking is disabled, it is equivalent to all sites being
// on neither list.
if (!prefs.mFlashBlockEnabled) {
if (!flashBlock) {
return FlashClassification::Unknown;
}
return FlashClassification::Unclassified;
}
nsAutoCString allowTables, allowExceptionsTables,
denyTables, denyExceptionsTables,
subDocDenyTables, subDocDenyExceptionsTables,
tables;
Preferences::GetCString("urlclassifier.flashAllowTable", &allowTables);
MaybeAddTableToTableList(allowTables, tables);
Preferences::GetCString("urlclassifier.flashAllowExceptTable",
&allowExceptionsTables);
MaybeAddTableToTableList(allowExceptionsTables, tables);
Preferences::GetCString("urlclassifier.flashTable", &denyTables);
MaybeAddTableToTableList(denyTables, tables);
Preferences::GetCString("urlclassifier.flashExceptTable",
&denyExceptionsTables);
MaybeAddTableToTableList(denyExceptionsTables, tables);
// Using nsIURIClassifier.asyncClassifyLocalWithTables to do classification
// against the flash related tables based on the given principal.
FlashClassification
PrincipalFlashClassifier::AsyncClassifyInternal(nsIPrincipal* aPrincipal)
{
auto result = CheckIfClassifyNeeded(aPrincipal);
if (FlashClassification::Unclassified != result) {
return result;
bool isThirdPartyDoc = IsThirdParty();
if (isThirdPartyDoc) {
Preferences::GetCString("urlclassifier.flashSubDocTable",
&subDocDenyTables);
MaybeAddTableToTableList(subDocDenyTables, tables);
Preferences::GetCString("urlclassifier.flashSubDocExceptTable",
&subDocDenyExceptionsTables);
MaybeAddTableToTableList(subDocDenyExceptionsTables, tables);
}
// We haven't been able to decide if it's a third party document
// since determining if a document is third-party may depend on its
// parent document. At the time we call AsyncClassifyInternal
// (i.e. StartDocumentLoad) the parent document may not have been
// set. As a result, we wait until Resolve() to be called to
// take "is third party" into account. At this point, we just assume
// it's third-party to include every list.
nsCString tables = GetClassificationTables(true);
if (tables.IsEmpty()) {
return FlashClassification::Unknown;
}
if (!EnsureUriClassifier()) {
nsCOMPtr<nsIURIClassifier> uriClassifier =
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
return FlashClassification::Denied;
}
nsresult rv = aPrincipal->GetURI(getter_AddRefs(mClassificationURI));
if (NS_FAILED(rv) || !mClassificationURI) {
return FlashClassification::Denied;
}
rv = mUriClassifier->AsyncClassifyLocalWithTables(mClassificationURI,
tables,
this);
nsTArray<nsCString> results;
rv = uriClassifier->ClassifyLocalWithTables(classificationURI,
tables,
results);
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_MALFORMED_URI) {
// This means that the URI had no hostname (ex: file://doc.html). In this
@ -13646,7 +13323,24 @@ PrincipalFlashClassifier::AsyncClassifyInternal(nsIPrincipal* aPrincipal)
}
}
return FlashClassification::Unclassified;
if (results.IsEmpty()) {
return FlashClassification::Unknown;
}
if (ArrayContainsTable(results, denyTables) &&
!ArrayContainsTable(results, denyExceptionsTables)) {
return FlashClassification::Denied;
} else if (ArrayContainsTable(results, allowTables) &&
!ArrayContainsTable(results, allowExceptionsTables)) {
return FlashClassification::Allowed;
}
if (isThirdPartyDoc && ArrayContainsTable(results, subDocDenyTables) &&
!ArrayContainsTable(results, subDocDenyExceptionsTables)) {
return FlashClassification::Denied;
}
return FlashClassification::Unknown;
}
FlashClassification

View File

@ -71,7 +71,6 @@
#include "CustomElementRegistry.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/Maybe.h"
#include "nsIURIClassifier.h"
#define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0)
#define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1)
@ -556,9 +555,6 @@ protected:
bool mHaveShutDown;
};
// For classifying a flash document based on its principal.
class PrincipalFlashClassifier;
// Base class for our document implementations.
class nsDocument : public nsIDocument,
public nsIDOMDocument,
@ -1459,7 +1455,6 @@ protected:
// non-null when this document is in fullscreen mode.
nsWeakPtr mFullscreenRoot;
RefPtr<PrincipalFlashClassifier> mPrincipalFlashClassifier;
mozilla::dom::FlashClassification mFlashClassification;
// Do not use this value directly. Call the |IsThirdParty()| method, which
// caches its result here.

View File

@ -1649,6 +1649,12 @@ nsUrlClassifierDBService::Init()
ReadTablesFromPrefs();
nsresult rv;
{
// Force PSM loading on main thread
nsCOMPtr<nsICryptoHash> dummy = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
{
// Force nsIUrlClassifierUtils loading on main thread.
nsCOMPtr<nsIUrlClassifierUtils> dummy =
@ -1815,18 +1821,6 @@ nsUrlClassifierDBService::AsyncClassifyLocalWithTables(nsIURI *aURI,
MOZ_ASSERT(NS_IsMainThread(), "AsyncClassifyLocalWithTables must be called "
"on main thread");
// We do this check no matter what process we are in to return
// error as early as possible.
nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
nsAutoCString key;
// Canonicalize the url
nsCOMPtr<nsIUrlClassifierUtils> utilsService =
do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID);
nsresult rv = utilsService->GetKeyForURI(uri, key);
NS_ENSURE_SUCCESS(rv, rv);
if (XRE_IsContentProcess()) {
using namespace mozilla::dom;
using namespace mozilla::ipc;
@ -1859,6 +1853,16 @@ nsUrlClassifierDBService::AsyncClassifyLocalWithTables(nsIURI *aURI,
using namespace mozilla::Telemetry;
auto startTime = TimeStamp::Now(); // For telemetry.
nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
nsAutoCString key;
// Canonicalize the url
nsCOMPtr<nsIUrlClassifierUtils> utilsService =
do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID);
nsresult rv = utilsService->GetKeyForURI(uri, key);
NS_ENSURE_SUCCESS(rv, rv);
auto worker = mWorker;
nsCString tables(aTables);