Bug 1425104: Part 1c - Add MozDocumentObserver class to notify on new pattern-matched documents. r?zombie
MozReview-Commit-ID: 29CsJ2mya36
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -579,16 +579,20 @@ DOMInterfaces = {
'notflattened': True
},
'MozDocumentMatcher': {
'nativeType': 'mozilla::extensions::MozDocumentMatcher',
'headerFile': 'mozilla/extensions/WebExtensionContentScript.h',
},
+'MozDocumentObserver': {
+ 'nativeType': 'mozilla::extensions::DocumentObserver',
+},
+
'MozStorageAsyncStatementParams': {
'headerFile': 'mozilla/storage/mozStorageAsyncStatementParams.h',
'nativeType': 'mozilla::storage::AsyncStatementParams',
},
'MozStorageStatementParams': {
'headerFile': 'mozilla/storage/mozStorageStatementParams.h',
'nativeType': 'mozilla::storage::StatementParams',
new file mode 100644
--- /dev/null
+++ b/dom/chrome-webidl/MozDocumentObserver.webidl
@@ -0,0 +1,17 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+callback interface MozDocumentCallback {
+ void onNewDocument(MozDocumentMatcher matcher, WindowProxy window);
+ void onPreloadDocument(MozDocumentMatcher matcher, LoadInfo loadInfo);
+};
+
+[ChromeOnly, Constructor(MozDocumentCallback callbacks), Exposed=System]
+interface MozDocumentObserver {
+ [Throws]
+ void observe(sequence<MozDocumentMatcher> matchers);
+ void disconnect();
+};
--- a/dom/chrome-webidl/moz.build
+++ b/dom/chrome-webidl/moz.build
@@ -32,16 +32,17 @@ PREPROCESSED_WEBIDL_FILES = [
WEBIDL_FILES = [
'ChannelWrapper.webidl',
'DominatorTree.webidl',
'HeapSnapshot.webidl',
'InspectorUtils.webidl',
'MatchGlob.webidl',
'MatchPattern.webidl',
'MessageManager.webidl',
+ 'MozDocumentObserver.webidl',
'MozStorageAsyncStatementParams.webidl',
'MozStorageStatementParams.webidl',
'MozStorageStatementRow.webidl',
'PrecompiledScript.webidl',
'PromiseDebugging.webidl',
'StructuredCloneHolder.webidl',
'WebExtensionContentScript.webidl',
'WebExtensionPolicy.webidl',
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/DocumentObserver.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* 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_extensions_DocumentObserver_h
+#define mozilla_extensions_DocumentObserver_h
+
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/MozDocumentObserverBinding.h"
+
+#include "mozilla/extensions/WebExtensionContentScript.h"
+
+class nsILoadInfo;
+class nsPIDOMWindowOuter;
+
+namespace mozilla {
+namespace extensions {
+
+class DocumentObserver final : public nsISupports
+ , public nsWrapperCache
+{
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DocumentObserver)
+
+ static already_AddRefed<DocumentObserver>
+ Constructor(dom::GlobalObject& aGlobal,
+ dom::MozDocumentCallback& aCallbacks,
+ ErrorResult& aRv);
+
+ void Observe(const dom::Sequence<OwningNonNull<MozDocumentMatcher>>& matchers, ErrorResult& aRv);
+
+ void Disconnect();
+
+ const nsTArray<RefPtr<MozDocumentMatcher>>& Matchers() const { return mMatchers; }
+
+ void NotifyMatch(MozDocumentMatcher& aMatcher, nsPIDOMWindowOuter* aWindow);
+ void NotifyMatch(MozDocumentMatcher& aMatcher, nsILoadInfo* aLoadInfo);
+
+ nsISupports* GetParentObject() const { return mParent; }
+ JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+protected:
+ virtual ~DocumentObserver() = default;
+
+private:
+ explicit DocumentObserver(nsISupports* aParent, dom::MozDocumentCallback& aCallbacks)
+ : mParent(aParent)
+ , mCallbacks(&aCallbacks)
+ {}
+
+ nsCOMPtr<nsISupports> mParent;
+ RefPtr<dom::MozDocumentCallback> mCallbacks;
+ nsTArray<RefPtr<MozDocumentMatcher>> mMatchers;
+};
+
+} // namespace extensions
+} // namespace mozilla
+
+#endif // mozilla_extensions_DocumentObserver_h
+
--- a/toolkit/components/extensions/ExtensionPolicyService.cpp
+++ b/toolkit/components/extensions/ExtensionPolicyService.cpp
@@ -1,14 +1,15 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* 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 "mozilla/ExtensionPolicyService.h"
+#include "mozilla/extensions/DocumentObserver.h"
#include "mozilla/extensions/WebExtensionContentScript.h"
#include "mozilla/extensions/WebExtensionPolicy.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Preferences.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/Services.h"
#include "mozilla/dom/ContentChild.h"
@@ -151,16 +152,38 @@ ExtensionPolicyService::UnregisterExtens
return false;
}
mExtensions.Remove(aPolicy.Id());
mExtensionHosts.Remove(aPolicy.MozExtensionHostname());
return true;
}
+bool
+ExtensionPolicyService::RegisterObserver(DocumentObserver& aObserver)
+{
+ if (mObservers.GetWeak(&aObserver)) {
+ return false;
+ }
+
+ mObservers.Put(&aObserver, &aObserver);
+ return true;
+}
+
+bool
+ExtensionPolicyService::UnregisterObserver(DocumentObserver& aObserver)
+{
+ if (!mObservers.GetWeak(&aObserver)) {
+ return false;
+ }
+
+ mObservers.Remove(&aObserver);
+ return true;
+}
+
void
ExtensionPolicyService::BaseCSP(nsAString& aBaseCSP) const
{
nsresult rv;
rv = Preferences::GetString("extensions.webextensions.base-content-security-policy", aBaseCSP);
if (NS_FAILED(rv)) {
@@ -346,16 +369,30 @@ ExtensionPolicyService::CheckContentScri
if (aIsPreload) {
ProcessScript().PreloadContentScript(script);
} else {
ProcessScript().LoadContentScript(script, aDocInfo.GetWindow());
}
}
}
}
+
+ for (auto iter = mObservers.Iter(); !iter.Done(); iter.Next()) {
+ RefPtr<DocumentObserver> observer = iter.Data();
+
+ for (auto& matcher : observer->Matchers()) {
+ if (matcher->Matches(aDocInfo)) {
+ if (aIsPreload) {
+ observer->NotifyMatch(*matcher, aDocInfo.GetLoadInfo());
+ } else {
+ observer->NotifyMatch(*matcher, aDocInfo.GetWindow());
+ }
+ }
+ }
+ }
}
/*****************************************************************************
* nsIAddonPolicyService
*****************************************************************************/
nsresult
--- a/toolkit/components/extensions/ExtensionPolicyService.h
+++ b/toolkit/components/extensions/ExtensionPolicyService.h
@@ -23,16 +23,17 @@
class nsIChannel;
class nsIObserverService;
class nsIDocument;
class nsIPIDOMWindowOuter;
namespace mozilla {
namespace extensions {
class DocInfo;
+ class DocumentObserver;
}
using extensions::DocInfo;
using extensions::WebExtensionPolicy;
class ExtensionPolicyService final : public nsIAddonPolicyService
, public nsIObserver
, public nsIMemoryReporter
@@ -71,16 +72,19 @@ public:
return mExtensionHosts.GetWeak(aHost);
}
void GetAll(nsTArray<RefPtr<WebExtensionPolicy>>& aResult);
bool RegisterExtension(WebExtensionPolicy& aPolicy);
bool UnregisterExtension(WebExtensionPolicy& aPolicy);
+ bool RegisterObserver(extensions::DocumentObserver& aPolicy);
+ bool UnregisterObserver(extensions::DocumentObserver& aPolicy);
+
void BaseCSP(nsAString& aDefaultCSP) const;
void DefaultCSP(nsAString& aDefaultCSP) const;
bool UseRemoteExtensions() const;
bool IsExtensionProcess() const;
protected:
virtual ~ExtensionPolicyService();
@@ -95,16 +99,19 @@ private:
void CheckDocument(nsIDocument* aDocument);
void CheckWindow(nsPIDOMWindowOuter* aWindow);
void CheckContentScripts(const DocInfo& aDocInfo, bool aIsPreload);
nsRefPtrHashtable<nsPtrHashKey<const nsAtom>, WebExtensionPolicy> mExtensions;
nsRefPtrHashtable<nsCStringHashKey, WebExtensionPolicy> mExtensionHosts;
+ nsRefPtrHashtable<nsPtrHashKey<const extensions::DocumentObserver>,
+ extensions::DocumentObserver> mObservers;
+
nsCOMPtr<nsIObserverService> mObs;
static bool sRemoteExtensions;
};
} // namespace mozilla
#endif // mozilla_ExtensionPolicyService_h
--- a/toolkit/components/extensions/WebExtensionContentScript.h
+++ b/toolkit/components/extensions/WebExtensionContentScript.h
@@ -57,16 +57,24 @@ public:
nsPIDOMWindowOuter* GetWindow() const
{
if (mObj.is<Window>()) {
return mObj.as<Window>();
}
return nullptr;
}
+ nsILoadInfo* GetLoadInfo() const
+ {
+ if (mObj.is<LoadInfo>()) {
+ return mObj.as<LoadInfo>();
+ }
+ return nullptr;
+ }
+
private:
void SetURL(const URLInfo& aURL);
const URLInfo mURL;
mutable Maybe<const URLInfo> mPrincipalURL;
mutable Maybe<bool> mIsTopLevel;
--- a/toolkit/components/extensions/WebExtensionPolicy.cpp
+++ b/toolkit/components/extensions/WebExtensionPolicy.cpp
@@ -1,14 +1,15 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* 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 "mozilla/ExtensionPolicyService.h"
+#include "mozilla/extensions/DocumentObserver.h"
#include "mozilla/extensions/WebExtensionContentScript.h"
#include "mozilla/extensions/WebExtensionPolicy.h"
#include "mozilla/AddonManagerWebAPI.h"
#include "mozilla/ResultExtensions.h"
#include "nsEscape.h"
#include "nsIDocShell.h"
#include "nsIObserver.h"
@@ -574,16 +575,82 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Mo
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozDocumentMatcher)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(MozDocumentMatcher)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MozDocumentMatcher)
+/*****************************************************************************
+ * MozDocumentObserver
+ *****************************************************************************/
+
+/* static */ already_AddRefed<DocumentObserver>
+DocumentObserver::Constructor(GlobalObject& aGlobal,
+ dom::MozDocumentCallback& aCallbacks,
+ ErrorResult& aRv)
+{
+ RefPtr<DocumentObserver> matcher = new DocumentObserver(aGlobal.GetAsSupports(), aCallbacks);
+ return matcher.forget();
+}
+
+
+void
+DocumentObserver::Observe(const dom::Sequence<OwningNonNull<MozDocumentMatcher>>& matchers, ErrorResult& aRv)
+{
+ if (!EPS().RegisterObserver(*this)) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ }
+ mMatchers.Clear();
+ for (auto& matcher : matchers) {
+ if (!mMatchers.AppendElement(matcher, fallible)) {
+ aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ }
+ }
+}
+
+void
+DocumentObserver::Disconnect()
+{
+ Unused << EPS().UnregisterObserver(*this);
+}
+
+
+void
+DocumentObserver::NotifyMatch(MozDocumentMatcher& aMatcher, nsPIDOMWindowOuter* aWindow)
+{
+ IgnoredErrorResult rv;
+ mCallbacks->OnNewDocument(aMatcher, aWindow, rv);
+}
+
+void
+DocumentObserver::NotifyMatch(MozDocumentMatcher& aMatcher, nsILoadInfo* aLoadInfo)
+{
+ IgnoredErrorResult rv;
+ mCallbacks->OnPreloadDocument(aMatcher, aLoadInfo, rv);
+}
+
+
+JSObject*
+DocumentObserver::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
+{
+ return MozDocumentObserverBinding::Wrap(aCx, this, aGivenProto);
+}
+
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DocumentObserver, mCallbacks, mMatchers, mParent)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DocumentObserver)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DocumentObserver)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DocumentObserver)
/*****************************************************************************
* DocInfo
*****************************************************************************/
DocInfo::DocInfo(const URLInfo& aURL, nsILoadInfo* aLoadInfo)
: mURL(aURL)
, mObj(AsVariant(aLoadInfo))
--- a/toolkit/components/extensions/moz.build
+++ b/toolkit/components/extensions/moz.build
@@ -53,16 +53,17 @@ XPIDL_SOURCES += [
XPIDL_MODULE = 'webextensions'
EXPORTS.mozilla = [
'ExtensionPolicyService.h',
]
EXPORTS.mozilla.extensions = [
+ 'DocumentObserver.h',
'MatchGlob.h',
'MatchPattern.h',
'WebExtensionContentScript.h',
'WebExtensionPolicy.h',
]
UNIFIED_SOURCES += [
'ExtensionPolicyService.cpp',