Bug 1341506 - Part 2.1: Refined IPC.
MozReview-Commit-ID: KYwB5v7J7QR
--- a/dom/ipc/PURLClassifier.ipdl
+++ b/dom/ipc/PURLClassifier.ipdl
@@ -21,25 +21,29 @@ union MaybeInfo {
};
sync protocol PURLClassifier
{
manager PContent;
parent:
// Moved from PContent.ipdl.
- sync Classify(Principal principal, bool useTrackingProtection)
+ sync Classify(Principal principal, bool useTrackingProtection, uint32_t callbackId)
returns (bool success);
// Moved from PContent.ipdl.
// TODO: Remove and relpace with the async version.
// See Bug 1342333.
sync ClassifyLocal(URIParams uri, nsCString tables)
returns (nsresult rv, nsCString[] results);
- async AsyncClassifyLocal(URIParams uri, nsCString tables);
+ async AsyncClassifyLocal(URIParams uri, nsCString tables, uint32_t callbackId);
+
+ async __delete__();
child:
- async __delete__(MaybeInfo info, nsresult errorCode);
+ async OnClassifyComplete(MaybeInfo info, nsresult errorCode, uint32_t callbackId);
+
+
};
} // namespace dom
} // namespace mozilla
--- a/dom/ipc/URLClassifierChild.cpp
+++ b/dom/ipc/URLClassifierChild.cpp
@@ -5,20 +5,75 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "URLClassifierChild.h"
#include "nsComponentManagerUtils.h"
#include "nsIURI.h"
using namespace mozilla::dom;
+URLClassifierChild::~URLClassifierChild()
+{
+ if (mIPCOpen) {
+ Send__delete__(this);
+ }
+}
+
mozilla::ipc::IPCResult
-URLClassifierChild::Recv__delete__(const MaybeInfo& aInfo,
- const nsresult& aResult)
+URLClassifierChild::RecvOnClassifyComplete(const MaybeInfo& aInfo,
+ const nsresult& aResult,
+ const uint32_t& aCallbackId)
{
- MOZ_ASSERT(mCallback);
- if (aInfo.type() == MaybeInfo::TClassifierInfo) {
- mCallback->OnClassifyComplete(aResult, aInfo.get_ClassifierInfo().list(),
- aInfo.get_ClassifierInfo().provider(),
- aInfo.get_ClassifierInfo().prefix());
+ // Look up the actual callback by the given callback id.
+ RefPtr<nsIURIClassifierCallback> callback = mCallbacks.Get(aCallbackId);
+ if (!callback) {
+ // Junk callback id is given.
+ return IPC_OK();
}
+ mCallbacks.Remove(aCallbackId);
+
+ callback->OnClassifyComplete(aResult,
+ aInfo.get_ClassifierInfo().list(),
+ aInfo.get_ClassifierInfo().provider(),
+ aInfo.get_ClassifierInfo().prefix());
+
return IPC_OK();
}
+
+bool
+URLClassifierChild::Classify(const Principal& principal,
+ const bool& useTrackingProtection,
+ nsIURIClassifierCallback* callback,
+ bool* success)
+{
+ if (!mIPCOpen) {
+ return false;
+ }
+ uint32_t callbackId = GenNextCallbackId(callback);
+ if (!SendClassify(principal, useTrackingProtection, callbackId, success)) {
+ mCallbacks.Remove(callbackId);
+ return false;
+ }
+ return true;
+}
+
+bool
+URLClassifierChild::AsyncClassifyLocal(const URIParams& uri,
+ const nsCString& tables,
+ nsIURIClassifierCallback* callback)
+{
+ if (!mIPCOpen) {
+ return false;
+ }
+ uint32_t callbackId = GenNextCallbackId(callback);
+ if (!SendAsyncClassifyLocal(uri, tables, callbackId)) {
+ return false;
+ }
+ return true;
+}
+
+uint32_t
+URLClassifierChild::GenNextCallbackId(nsIURIClassifierCallback* aCallback)
+{
+ uint32_t callbackId = mCurCallbackId++;
+ mCallbacks.Put(callbackId, aCallback);
+ return callbackId;
+}
\ No newline at end of file
--- a/dom/ipc/URLClassifierChild.h
+++ b/dom/ipc/URLClassifierChild.h
@@ -4,34 +4,51 @@
* 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_dom_URLClassifierChild_h
#define mozilla_dom_URLClassifierChild_h
#include "mozilla/dom/PURLClassifierChild.h"
#include "nsIURIClassifier.h"
+#include "nsDataHashtable.h"
namespace mozilla {
namespace dom {
class URLClassifierChild : public PURLClassifierChild
{
public:
URLClassifierChild() = default;
- void SetCallback(nsIURIClassifierCallback* aCallback)
- {
- mCallback = aCallback;
- }
- mozilla::ipc::IPCResult Recv__delete__(const MaybeInfo& aInfo,
- const nsresult& aResult) override;
+ bool Classify(const Principal& principal,
+ const bool& useTrackingProtection,
+ nsIURIClassifierCallback* callback,
+ bool* success);
+
+ bool AsyncClassifyLocal(const URIParams& uri,
+ const nsCString& tables,
+ nsIURIClassifierCallback* callback);
+
+ mozilla::ipc::IPCResult
+ RecvOnClassifyComplete(const MaybeInfo& aInfo,
+ const nsresult& aResult,
+ const uint32_t& aCallbackId) override;
+
+ ~URLClassifierChild();
private:
- ~URLClassifierChild() = default;
+ void ActorDestroy (ActorDestroyReason aWhy) override { mIPCOpen = false; }
+
+ uint32_t GenNextCallbackId(nsIURIClassifierCallback* aCallback);
- nsCOMPtr<nsIURIClassifierCallback> mCallback;
+ nsDataHashtable<nsUint32HashKey,
+ RefPtr<nsIURIClassifierCallback>> mCallbacks;
+
+ uint32_t mCurCallbackId = 0;
+
+ bool mIPCOpen = true;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_URLClassifierChild_h
--- a/dom/ipc/URLClassifierParent.cpp
+++ b/dom/ipc/URLClassifierParent.cpp
@@ -7,42 +7,86 @@
#include "URLClassifierParent.h"
#include "nsComponentManagerUtils.h"
#include "mozilla/Unused.h"
#include "URIUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
-NS_IMPL_ISUPPORTS(URLClassifierParent, nsIURIClassifierCallback)
+NS_IMPL_ISUPPORTS(URLClassifierParent, nsISupports)
+
+namespace {
+
+class MyCallback : public nsIURIClassifierCallback {
+public:
+ MyCallback(uint32_t aId, URLClassifierParent* aClosure)
+ : mId(aId)
+ , mClosure(aClosure)
+ {
+ }
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIURICLASSIFIERCALLBACK;
+
+private:
+ ~MyCallback() = default;
+
+ uint32_t mId;
+ RefPtr<URLClassifierParent> mClosure;
+};
+
+NS_IMPL_ISUPPORTS(MyCallback, nsIURIClassifierCallback)
+
+NS_IMETHODIMP
+MyCallback::OnClassifyComplete(nsresult aErrorCode,
+ const nsACString& aList,
+ const nsACString& aProvider,
+ const nsACString& aPrefix)
+{
+ ClassifierInfo info;
+ info.list() = aList;
+ info.prefix() = aPrefix;
+ info.provider() = aProvider;
+
+ if (mClosure->IsIPCOpen()) {
+ Unused << mClosure->SendOnClassifyComplete(info, aErrorCode, mId);
+ }
+
+ // What can we do if IPC has been closed?
+
+ return NS_OK;
+}
+
+} // end of unnamed namespace.
mozilla::ipc::IPCResult
URLClassifierParent::StartClassify(nsIPrincipal* aPrincipal,
bool aUseTrackingProtection,
+ const uint32_t& aCallbackId,
bool* aSuccess)
{
*aSuccess = false;
nsresult rv = NS_OK;
// Note that in safe mode, the URL classifier service isn't available, so we
// should handle the service not being present gracefully.
nsCOMPtr<nsIURIClassifier> uriClassifier =
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
+ RefPtr<MyCallback> cb(new MyCallback(aCallbackId, this));
rv = uriClassifier->Classify(aPrincipal, aUseTrackingProtection,
- this, aSuccess);
+ cb, aSuccess);
}
if (NS_FAILED(rv) || !*aSuccess) {
// We treat the case where we fail to classify and the case where the
// classifier returns successfully but doesn't perform a lookup as the
- // classification not yielding any results, so we just kill the child actor
- // without ever calling out callback in both cases.
+ // classification not yielding any results.
// This means that code using this in the child process will only get a hit
// on its callback if some classification actually happens.
*aSuccess = false;
- ClassificationFailed();
}
return IPC_OK();
}
mozilla::ipc::IPCResult
URLClassifierParent::RecvClassifyLocal(const URIParams& aURI,
const nsCString& aTables,
nsresult *aRv,
@@ -59,65 +103,38 @@ URLClassifierParent::RecvClassifyLocal(c
return IPC_FAIL_NO_REASON(this);
}
*aRv = uriClassifier->ClassifyLocalWithTables(uri, aTables, *aResults);
return IPC_OK();
}
mozilla::ipc::IPCResult
URLClassifierParent::RecvAsyncClassifyLocal(const URIParams& aURI,
- const nsCString& aTables)
+ const nsCString& aTables,
+ const uint32_t& aCallbackId)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIURIClassifier> uriClassifier =
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
if (!uri) {
return IPC_FAIL_NO_REASON(this);
}
- rv = uriClassifier->AsyncClassifyLocalWithTables(uri, aTables, this);
+ RefPtr<MyCallback> cb(new MyCallback(aCallbackId, this));
+ rv = uriClassifier->AsyncClassifyLocalWithTables(uri, aTables, cb);
}
if (NS_FAILED(rv)) {
- // We treat the case where we fail to classify and the case where the
- // classifier returns successfully but doesn't perform a lookup as the
- // classification not yielding any results, so we just kill the child actor
- // without ever calling out callback in both cases.
- // This means that code using this in the child process will only get a hit
- // on its callback if some classification actually happens.
- ClassificationFailed();
+ Unused << SendOnClassifyComplete(ClassifierInfo(),
+ NS_OK, // Implies not on the list.
+ aCallbackId);
}
return IPC_OK();
}
-nsresult
-URLClassifierParent::OnClassifyComplete(nsresult aErrorCode,
- const nsACString& aList,
- const nsACString& aProvider,
- const nsACString& aPrefix)
-{
- if (mIPCOpen) {
- ClassifierInfo info;
- info.list() = aList;
- info.prefix() = aPrefix;
- info.provider() = aProvider;
-
- Unused << Send__delete__(this, info, aErrorCode);
- }
- return NS_OK;
-}
-
-void
-URLClassifierParent::ClassificationFailed()
-{
- if (mIPCOpen) {
- Unused << Send__delete__(this, void_t(), NS_ERROR_FAILURE);
- }
-}
-
void
URLClassifierParent::ActorDestroy(ActorDestroyReason aWhy)
{
mIPCOpen = false;
}
--- a/dom/ipc/URLClassifierParent.h
+++ b/dom/ipc/URLClassifierParent.h
@@ -3,59 +3,61 @@
/* 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_dom_URLClassifierParent_h
#define mozilla_dom_URLClassifierParent_h
#include "mozilla/dom/PURLClassifierParent.h"
-#include "nsIURIClassifier.h"
+#include "nsISupports.h"
namespace mozilla {
namespace dom {
-class URLClassifierParent : public nsIURIClassifierCallback,
+class URLClassifierParent : public nsISupports,
public PURLClassifierParent
{
public:
URLClassifierParent() = default;
NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSIURICLASSIFIERCALLBACK
void ActorDestroy(ActorDestroyReason aWhy) override;
- void ClassificationFailed();
-
// PURLClassifierParent messages.
virtual mozilla::ipc::IPCResult
RecvClassify(const Principal& aPrincipal,
const bool& aUseTrackingProtection,
+ const uint32_t& aCallbackId,
bool* aSuccess) override
{
nsCOMPtr<nsIPrincipal> principal(aPrincipal);
- return StartClassify(principal, aUseTrackingProtection, aSuccess);
+ return StartClassify(principal, aUseTrackingProtection, aCallbackId, aSuccess);
}
virtual mozilla::ipc::IPCResult
RecvAsyncClassifyLocal(const URIParams& aURI,
- const nsCString& aTables) override;
+ const nsCString& aTables,
+ const uint32_t& aCallbackId) override;
virtual mozilla::ipc::IPCResult
RecvClassifyLocal(const URIParams& aURI,
const nsCString& aTables,
nsresult* aRv,
nsTArray<nsCString>* aResults) override;
+ bool IsIPCOpen() const { return mIPCOpen; }
+
private:
~URLClassifierParent() = default;
mozilla::ipc::IPCResult StartClassify(nsIPrincipal* aPrincipal,
bool aUseTrackingProtection,
+ const uint32_t& aCallbackId,
bool* aSuccess);
bool mIPCOpen = true;
};
} // namespace dom
} // namespace mozilla
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -1382,16 +1382,20 @@ nsUrlClassifierDBService::nsUrlClassifie
, mCheckPhishing(CHECK_PHISHING_DEFAULT)
, mCheckBlockedURIs(CHECK_BLOCKED_DEFAULT)
, mInUpdate(false)
{
}
nsUrlClassifierDBService::~nsUrlClassifierDBService()
{
+ if (XRE_IsContentProcess()) {
+ // XXX: Is this a good point to delete actors?
+ mActor = nullptr;
+ }
sUrlClassifierDBService = nullptr;
}
nsresult
nsUrlClassifierDBService::ReadTablesFromPrefs()
{
nsCString allTables;
nsCString tables;
@@ -1458,16 +1462,19 @@ nsUrlClassifierDBService::Init()
case GeckoProcessType_Default:
// The parent process is supported.
break;
case GeckoProcessType_Content:
// In a content process, we simply forward all requests to the parent process,
// so we can skip the initialization steps here.
// Note that since we never register an observer, Shutdown() will also never
// be called in the content process.
+ using namespace mozilla::dom;
+ mActor = static_cast<URLClassifierChild*>
+ (ContentChild::GetSingleton()->SendPURLClassifierConstructor());
return NS_OK;
default:
// No other process type is supported!
return NS_ERROR_NOT_AVAILABLE;
}
// Retrieve all the preferences.
mCheckMalware = Preferences::GetBool(CHECK_MALWARE_PREF,
@@ -1608,25 +1615,23 @@ NS_IMETHODIMP
nsUrlClassifierDBService::Classify(nsIPrincipal* aPrincipal,
bool aTrackingProtectionEnabled,
nsIURIClassifierCallback* c,
bool* result)
{
NS_ENSURE_ARG(aPrincipal);
if (XRE_IsContentProcess()) {
- using namespace mozilla::dom;
- auto actor = static_cast<URLClassifierChild*>
- (ContentChild::GetSingleton()->SendPURLClassifierConstructor());
- if (actor) {
- actor->SetCallback(c);
- actor->SendClassify(IPC::Principal(aPrincipal),
- aTrackingProtectionEnabled,
- result);
+ if (!mActor) {
+ return NS_ERROR_FAILURE;
}
+ mActor->Classify(IPC::Principal(aPrincipal),
+ aTrackingProtectionEnabled,
+ c,
+ result);
return NS_OK;
}
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
if (!(mCheckMalware || mCheckPhishing || aTrackingProtectionEnabled ||
mCheckBlockedURIs)) {
*result = false;
@@ -1681,27 +1686,24 @@ nsUrlClassifierDBService::AsyncClassifyL
{
MOZ_ASSERT(NS_IsMainThread(), "AsyncClassifyLocalWithTables must be called "
"on main thread");
// Check and deal with content process case.
if (XRE_IsContentProcess()) {
using namespace mozilla::dom;
using namespace mozilla::ipc;
- auto actor = static_cast<URLClassifierChild*>
- (ContentChild::GetSingleton()->SendPURLClassifierConstructor());
- if (!actor) {
+ if (!mActor) {
return NS_ERROR_FAILURE;
}
URIParams uri;
SerializeURI(aURI, uri);
nsAutoCString tables(aTables);
- actor->SetCallback(aCallback);
- actor->SendAsyncClassifyLocal(uri, tables);
+ mActor->AsyncClassifyLocal(uri, tables, aCallback);
return NS_OK;
}
if (gShuttingDownThread) {
return NS_ERROR_ABORT;
}
using namespace mozilla::Telemetry;
@@ -1770,26 +1772,24 @@ nsUrlClassifierDBService::ClassifyLocalW
if (gShuttingDownThread) {
return NS_ERROR_ABORT;
}
nsresult rv;
if (XRE_IsContentProcess()) {
using namespace mozilla::dom;
using namespace mozilla::ipc;
- auto actor = static_cast<URLClassifierChild*>
- (ContentChild::GetSingleton()->SendPURLClassifierConstructor());
- if (!actor) {
+ if (!mActor) {
return NS_ERROR_FAILURE;
}
URIParams uri;
SerializeURI(aURI, uri);
nsAutoCString tables(aTables);
- if (!actor->SendClassifyLocal(uri, tables, &rv, &aTableResults)) {
+ if (!mActor->SendClassifyLocal(uri, tables, &rv, &aTableResults)) {
return NS_ERROR_FAILURE;
}
return rv;
}
PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_CLASSIFYLOCAL_TIME> timer;
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.h
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.h
@@ -52,16 +52,21 @@ namespace safebrowsing {
class Classifier;
class ProtocolParser;
class TableUpdate;
nsresult
TablesToResponse(const nsACString& tables);
} // namespace safebrowsing
+
+namespace dom {
+ class URLClassifierChild;
+}
+
} // namespace mozilla
// This is a proxy class that just creates a background thread and delagates
// calls to the background thread.
class nsUrlClassifierDBService final : public nsIUrlClassifierDBService,
public nsIURIClassifier,
public nsIObserver
{
@@ -140,16 +145,18 @@ private:
// The list of tables that can use the default hash completer object.
nsTArray<nsCString> mGethashTables;
// The list of tables that should never be hash completed.
nsTArray<nsCString> mDisallowCompletionsTables;
// Thread that we do the updates on.
static nsIThread* gDbBackgroundThread;
+
+ nsAutoPtr<mozilla::dom::URLClassifierChild> mActor;
};
class nsUrlClassifierDBServiceWorker final : public nsIUrlClassifierDBService
{
public:
nsUrlClassifierDBServiceWorker();
NS_DECL_THREADSAFE_ISUPPORTS