зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1708238 - Stop relying on messagemanager in ExtensionPolicyService r=robwu,geckoview-reviewers,agi
Patch mostly by Nika Layzell; test, some tweaks (and all bugs) by me. Differential Revision: https://phabricator.services.mozilla.com/D114060
This commit is contained in:
Родитель
611ced6f1e
Коммит
c5fa3a1d8d
|
@ -500,6 +500,7 @@ function createBrowser() {
|
|||
browser.setAttribute("maychangeremoteness", "true");
|
||||
browser.setAttribute("remote", "true");
|
||||
browser.setAttribute("remoteType", E10SUtils.DEFAULT_REMOTE_TYPE);
|
||||
browser.setAttribute("messagemanagergroup", "browsers");
|
||||
|
||||
return browser;
|
||||
}
|
||||
|
|
|
@ -1172,6 +1172,7 @@ class HiddenXULWindow {
|
|||
const browser = chromeDoc.createXULElement("browser");
|
||||
browser.setAttribute("type", "content");
|
||||
browser.setAttribute("disableglobalhistory", "true");
|
||||
browser.setAttribute("messagemanagergroup", "webext-browsers");
|
||||
|
||||
for (const [name, value] of Object.entries(xulAttributes)) {
|
||||
if (value != null) {
|
||||
|
|
|
@ -15,18 +15,17 @@
|
|||
#include "mozilla/Services.h"
|
||||
#include "mozilla/SimpleEnumerator.h"
|
||||
#include "mozilla/StaticPrefs_extensions.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/BrowsingContextGroup.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentFrameMessageManager.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/Promise-inl.h"
|
||||
#include "mozIExtensionProcessScript.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "nsGlobalWindowOuter.h"
|
||||
#include "nsILoadInfo.h"
|
||||
|
@ -43,7 +42,6 @@ namespace mozilla {
|
|||
using namespace extensions;
|
||||
|
||||
using dom::AutoJSAPI;
|
||||
using dom::ContentFrameMessageManager;
|
||||
using dom::Document;
|
||||
using dom::Promise;
|
||||
|
||||
|
@ -207,7 +205,6 @@ ExtensionPolicyService::CollectReports(nsIHandleReportCallback* aHandleReport,
|
|||
|
||||
void ExtensionPolicyService::RegisterObservers() {
|
||||
mObs->AddObserver(this, kDocElementInserted, false);
|
||||
mObs->AddObserver(this, "tab-content-frameloader-created", false);
|
||||
if (XRE_IsContentProcess()) {
|
||||
mObs->AddObserver(this, "http-on-opening-request", false);
|
||||
mObs->AddObserver(this, "document-on-opening-request", false);
|
||||
|
@ -218,7 +215,6 @@ void ExtensionPolicyService::RegisterObservers() {
|
|||
|
||||
void ExtensionPolicyService::UnregisterObservers() {
|
||||
mObs->RemoveObserver(this, kDocElementInserted);
|
||||
mObs->RemoveObserver(this, "tab-content-frameloader-created");
|
||||
if (XRE_IsContentProcess()) {
|
||||
mObs->RemoveObserver(this, "http-on-opening-request");
|
||||
mObs->RemoveObserver(this, "document-on-opening-request");
|
||||
|
@ -241,13 +237,6 @@ nsresult ExtensionPolicyService::Observe(nsISupports* aSubject,
|
|||
if (chan) {
|
||||
CheckRequest(chan);
|
||||
}
|
||||
} else if (!strcmp(aTopic, "tab-content-frameloader-created")) {
|
||||
RefPtr<ContentFrameMessageManager> mm = do_QueryObject(aSubject);
|
||||
NS_ENSURE_TRUE(mm, NS_ERROR_UNEXPECTED);
|
||||
|
||||
mMessageManagers.Insert(mm);
|
||||
|
||||
mm->AddSystemEventListener(u"unload"_ns, this, false, false);
|
||||
} else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
||||
const nsCString converted = NS_ConvertUTF16toUTF8(aData);
|
||||
const char* pref = converted.get();
|
||||
|
@ -258,28 +247,6 @@ nsresult ExtensionPolicyService::Observe(nsISupports* aSubject,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult ExtensionPolicyService::HandleEvent(dom::Event* aEvent) {
|
||||
RefPtr<ContentFrameMessageManager> mm = do_QueryObject(aEvent->GetTarget());
|
||||
MOZ_ASSERT(mm);
|
||||
if (mm) {
|
||||
mMessageManagers.Remove(mm);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult ForEachDocShell(
|
||||
nsIDocShell* aDocShell,
|
||||
const std::function<nsresult(nsIDocShell*)>& aCallback) {
|
||||
nsTArray<RefPtr<nsIDocShell>> docShells;
|
||||
MOZ_TRY(aDocShell->GetAllDocShellsInSubtree(
|
||||
nsIDocShell::typeContent, nsIDocShell::ENUMERATE_FORWARDS, docShells));
|
||||
|
||||
for (auto& docShell : docShells) {
|
||||
MOZ_TRY(aCallback(docShell));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> ExtensionPolicyService::ExecuteContentScript(
|
||||
nsPIDOMWindowInner* aWindow, WebExtensionContentScript& aScript) {
|
||||
if (!aWindow->IsCurrentInnerWindow()) {
|
||||
|
@ -307,68 +274,88 @@ RefPtr<Promise> ExtensionPolicyService::ExecuteContentScripts(
|
|||
return promise;
|
||||
}
|
||||
|
||||
// Use browser's MessageManagerGroup to decide if we care about it, to inject
|
||||
// extension APIs or content scripts. Tabs use "browsers", and all custom
|
||||
// extension browsers use "webext-browsers", including popups & sidebars,
|
||||
// background & options pages, and xpcshell tests.
|
||||
static bool IsTabOrExtensionBrowser(dom::BrowsingContext* aBC) {
|
||||
const auto& group = aBC->Top()->GetMessageManagerGroup();
|
||||
return group == u"browsers"_ns || group == u"webext-browsers"_ns;
|
||||
}
|
||||
|
||||
static nsTArray<RefPtr<dom::BrowsingContext>> GetAllInProcessContentBCs() {
|
||||
nsTArray<RefPtr<dom::BrowsingContext>> contentBCs;
|
||||
nsTArray<RefPtr<dom::BrowsingContextGroup>> groups;
|
||||
dom::BrowsingContextGroup::GetAllGroups(groups);
|
||||
for (const auto& group : groups) {
|
||||
for (const auto& toplevel : group->Toplevels()) {
|
||||
if (!toplevel->IsContent() || toplevel->IsDiscarded() ||
|
||||
!IsTabOrExtensionBrowser(toplevel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
toplevel->PreOrderWalk([&](dom::BrowsingContext* aContext) {
|
||||
contentBCs.AppendElement(aContext);
|
||||
});
|
||||
}
|
||||
}
|
||||
return contentBCs;
|
||||
}
|
||||
|
||||
nsresult ExtensionPolicyService::InjectContentScripts(
|
||||
WebExtensionPolicy* aExtension) {
|
||||
AutoJSAPI jsapi;
|
||||
MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope()));
|
||||
|
||||
for (ContentFrameMessageManager* mm : mMessageManagers) {
|
||||
nsCOMPtr<nsIDocShell> docShell = mm->GetDocShell(IgnoreErrors());
|
||||
NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED);
|
||||
auto contentBCs = GetAllInProcessContentBCs();
|
||||
for (dom::BrowsingContext* bc : contentBCs) {
|
||||
auto* win = bc->GetDOMWindow();
|
||||
|
||||
auto result =
|
||||
ForEachDocShell(docShell, [&](nsIDocShell* aDocShell) -> nsresult {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> win = aDocShell->GetWindow();
|
||||
if (!win->GetDocumentURI()) {
|
||||
return NS_OK;
|
||||
}
|
||||
DocInfo docInfo(win);
|
||||
if (bc->Top()->IsDiscarded() || !win || !win->GetDocumentURI()) {
|
||||
continue;
|
||||
}
|
||||
DocInfo docInfo(win);
|
||||
|
||||
using RunAt = dom::ContentScriptRunAt;
|
||||
namespace RunAtValues = dom::ContentScriptRunAtValues;
|
||||
using Scripts = AutoTArray<RefPtr<WebExtensionContentScript>, 8>;
|
||||
using RunAt = dom::ContentScriptRunAt;
|
||||
namespace RunAtValues = dom::ContentScriptRunAtValues;
|
||||
using Scripts = AutoTArray<RefPtr<WebExtensionContentScript>, 8>;
|
||||
|
||||
Scripts scripts[RunAtValues::Count];
|
||||
Scripts scripts[RunAtValues::Count];
|
||||
|
||||
auto GetScripts = [&](RunAt aRunAt) -> Scripts&& {
|
||||
static_assert(sizeof(aRunAt) == 1, "Our cast is wrong");
|
||||
return std::move(scripts[uint8_t(aRunAt)]);
|
||||
};
|
||||
auto GetScripts = [&](RunAt aRunAt) -> Scripts&& {
|
||||
static_assert(sizeof(aRunAt) == 1, "Our cast is wrong");
|
||||
return std::move(scripts[uint8_t(aRunAt)]);
|
||||
};
|
||||
|
||||
for (const auto& script : aExtension->ContentScripts()) {
|
||||
if (script->Matches(docInfo)) {
|
||||
GetScripts(script->RunAt()).AppendElement(script);
|
||||
}
|
||||
}
|
||||
for (const auto& script : aExtension->ContentScripts()) {
|
||||
if (script->Matches(docInfo)) {
|
||||
GetScripts(script->RunAt()).AppendElement(script);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> inner = win->GetCurrentInnerWindow();
|
||||
nsCOMPtr<nsPIDOMWindowInner> inner = win->GetCurrentInnerWindow();
|
||||
|
||||
MOZ_TRY(ExecuteContentScripts(jsapi.cx(), inner,
|
||||
GetScripts(RunAt::Document_start))
|
||||
->ThenWithCycleCollectedArgs(
|
||||
[](JSContext* aCx, JS::HandleValue aValue,
|
||||
ExtensionPolicyService* aSelf,
|
||||
nsPIDOMWindowInner* aInner, Scripts&& aScripts) {
|
||||
return aSelf
|
||||
->ExecuteContentScripts(aCx, aInner, aScripts)
|
||||
.forget();
|
||||
},
|
||||
this, inner, GetScripts(RunAt::Document_end))
|
||||
.andThen([&](auto aPromise) {
|
||||
return aPromise->ThenWithCycleCollectedArgs(
|
||||
[](JSContext* aCx, JS::HandleValue aValue,
|
||||
ExtensionPolicyService* aSelf,
|
||||
nsPIDOMWindowInner* aInner, Scripts&& aScripts) {
|
||||
return aSelf
|
||||
->ExecuteContentScripts(aCx, aInner, aScripts)
|
||||
.forget();
|
||||
},
|
||||
this, inner, GetScripts(RunAt::Document_idle));
|
||||
}));
|
||||
|
||||
return NS_OK;
|
||||
});
|
||||
MOZ_TRY(result);
|
||||
MOZ_TRY(ExecuteContentScripts(jsapi.cx(), inner,
|
||||
GetScripts(RunAt::Document_start))
|
||||
->ThenWithCycleCollectedArgs(
|
||||
[](JSContext* aCx, JS::HandleValue aValue,
|
||||
ExtensionPolicyService* aSelf,
|
||||
nsPIDOMWindowInner* aInner, Scripts&& aScripts) {
|
||||
return aSelf->ExecuteContentScripts(aCx, aInner, aScripts)
|
||||
.forget();
|
||||
},
|
||||
this, inner, GetScripts(RunAt::Document_end))
|
||||
.andThen([&](auto aPromise) {
|
||||
return aPromise->ThenWithCycleCollectedArgs(
|
||||
[](JSContext* aCx, JS::HandleValue aValue,
|
||||
ExtensionPolicyService* aSelf,
|
||||
nsPIDOMWindowInner* aInner, Scripts&& aScripts) {
|
||||
return aSelf
|
||||
->ExecuteContentScripts(aCx, aInner, aScripts)
|
||||
.forget();
|
||||
},
|
||||
this, inner, GetScripts(RunAt::Document_idle));
|
||||
}));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -438,20 +425,7 @@ static bool CheckParentFrames(nsPIDOMWindowOuter* aWindow,
|
|||
void ExtensionPolicyService::CheckDocument(Document* aDocument) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> win = aDocument->GetWindow();
|
||||
if (win) {
|
||||
nsIDocShell* docShell = win->GetDocShell();
|
||||
RefPtr<ContentFrameMessageManager> mm = docShell->GetMessageManager();
|
||||
nsString group = win->GetBrowsingContext()->Top()->GetMessageManagerGroup();
|
||||
|
||||
// Currently, we use frame scripts to select specific kinds of browsers
|
||||
// where we want to run content scripts.
|
||||
if ((!mm || !mMessageManagers.Contains(mm)) &&
|
||||
// With Fission, OOP iframes don't have a frame message manager, so we
|
||||
// use the browser's MessageManagerGroup attribute to decide if content
|
||||
// scripts should run. The "browsers" group includes iframes from tabs,
|
||||
// and the "webext-browsers" group includes custom browsers for
|
||||
// extension popups/sidebars and xpcshell tests.
|
||||
!group.EqualsLiteral("browsers") &&
|
||||
!group.EqualsLiteral("webext-browsers")) {
|
||||
if (!IsTabOrExtensionBrowser(win->GetBrowsingContext())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -627,7 +601,6 @@ NS_IMPL_CYCLE_COLLECTION(ExtensionPolicyService, mExtensions, mExtensionHosts,
|
|||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionPolicyService)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAddonPolicyService)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMemoryReporter)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAddonPolicyService)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "nsHashKeys.h"
|
||||
#include "nsIAddonPolicyService.h"
|
||||
#include "nsAtom.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
@ -30,7 +29,6 @@ class nsIPIDOMWindowOuter;
|
|||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentFrameMessageManager;
|
||||
class Promise;
|
||||
} // namespace dom
|
||||
namespace extensions {
|
||||
|
@ -44,7 +42,6 @@ using extensions::WebExtensionPolicy;
|
|||
|
||||
class ExtensionPolicyService final : public nsIAddonPolicyService,
|
||||
public nsIObserver,
|
||||
public nsIDOMEventListener,
|
||||
public nsIMemoryReporter {
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ExtensionPolicyService,
|
||||
|
@ -52,7 +49,6 @@ class ExtensionPolicyService final : public nsIAddonPolicyService,
|
|||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_NSIADDONPOLICYSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
|
||||
static ExtensionPolicyService& GetSingleton();
|
||||
|
@ -114,8 +110,6 @@ class ExtensionPolicyService final : public nsIAddonPolicyService,
|
|||
nsRefPtrHashtable<nsPtrHashKey<const nsAtom>, WebExtensionPolicy> mExtensions;
|
||||
nsRefPtrHashtable<nsCStringHashKey, WebExtensionPolicy> mExtensionHosts;
|
||||
|
||||
nsTHashSet<RefPtr<dom::ContentFrameMessageManager>> mMessageManagers;
|
||||
|
||||
nsRefPtrHashtable<nsPtrHashKey<const extensions::DocumentObserver>,
|
||||
extensions::DocumentObserver>
|
||||
mObservers;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
add_task(async function test_content_script_cross_origin_frame() {
|
||||
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
const extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [{
|
||||
matches: ["http://example.net/*/file_sample.html"],
|
||||
|
@ -84,17 +84,26 @@ add_task(async function test_content_script_cross_origin_frame() {
|
|||
port.postMessage(7);
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
await extension.startup();
|
||||
info("Load first extension");
|
||||
let ext1 = ExtensionTestUtils.loadExtension(extensionData);
|
||||
await ext1.startup();
|
||||
|
||||
info("Load a page, test content scripts in new frame with extension loaded");
|
||||
let base = "http://example.org/tests/toolkit/components/extensions/test";
|
||||
let win = window.open(`${base}/mochitest/file_with_xorigin_frame.html`);
|
||||
|
||||
await extension.awaitFinish();
|
||||
win.close();
|
||||
await ext1.awaitFinish();
|
||||
await ext1.unload();
|
||||
|
||||
await extension.unload();
|
||||
info("Load second extension, test content scripts in existing frame");
|
||||
let ext2 = ExtensionTestUtils.loadExtension(extensionData);
|
||||
await ext2.startup();
|
||||
await ext2.awaitFinish();
|
||||
|
||||
win.close();
|
||||
await ext2.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
@ -2379,6 +2379,7 @@ class InlineOptionsBrowser extends HTMLElement {
|
|||
let browser = document.createXULElement("browser");
|
||||
browser.setAttribute("type", "content");
|
||||
browser.setAttribute("disableglobalhistory", "true");
|
||||
browser.setAttribute("messagemanagergroup", "webext-browsers");
|
||||
browser.setAttribute("id", "addon-inline-options");
|
||||
browser.setAttribute("transparent", "true");
|
||||
browser.setAttribute("forcemessagemanager", "true");
|
||||
|
|
Загрузка…
Ссылка в новой задаче