mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1068412: Forward dynamically registered resource URI mappings to content processes. r=billm
This commit is contained in:
parent
36a0d7dcf7
commit
88fec784af
@ -43,6 +43,12 @@ struct ResourceMapping
|
||||
{
|
||||
nsCString resource;
|
||||
SerializedURI resolvedURI;
|
||||
|
||||
bool operator ==(const ResourceMapping& rhs) const
|
||||
{
|
||||
return resource.Equals(rhs.resource) &&
|
||||
resolvedURI == rhs.resolvedURI;
|
||||
}
|
||||
};
|
||||
|
||||
struct OverrideMapping
|
||||
|
@ -453,17 +453,21 @@ nsChromeRegistryChrome::SendRegisteredChrome(
|
||||
};
|
||||
mPackagesHash.EnumerateRead(CollectPackages, &args);
|
||||
|
||||
nsCOMPtr<nsIIOService> io (do_GetIOService());
|
||||
NS_ENSURE_TRUE_VOID(io);
|
||||
// If we were passed a parent then a new child process has been created and
|
||||
// has requested all of the chrome so send it the resources too. Otherwise
|
||||
// resource mappings are sent by the resource protocol handler dynamically.
|
||||
if (aParent) {
|
||||
nsCOMPtr<nsIIOService> io (do_GetIOService());
|
||||
NS_ENSURE_TRUE_VOID(io);
|
||||
|
||||
nsCOMPtr<nsIProtocolHandler> ph;
|
||||
nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
nsCOMPtr<nsIProtocolHandler> ph;
|
||||
nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
//FIXME: Some substitutions are set up lazily and might not exist yet
|
||||
nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph));
|
||||
nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
|
||||
rph->CollectSubstitutions(resources);
|
||||
nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph));
|
||||
nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
|
||||
rph->CollectSubstitutions(resources);
|
||||
}
|
||||
|
||||
mOverrideTable.EnumerateRead(&EnumerateOverride, &overrides);
|
||||
|
||||
|
@ -1574,6 +1574,10 @@ ContentChild::RecvRegisterChromeItem(const ChromeRegistryItem& item)
|
||||
chromeRegistry->RegisterOverride(item.get_OverrideMapping());
|
||||
break;
|
||||
|
||||
case ChromeRegistryItem::TResourceMapping:
|
||||
chromeRegistry->RegisterResource(item.get_ResourceMapping());
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(false, "bad chrome item");
|
||||
return false;
|
||||
|
@ -71,6 +71,7 @@ union ChromeRegistryItem
|
||||
{
|
||||
ChromePackage;
|
||||
OverrideMapping;
|
||||
ResourceMapping;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -4,6 +4,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/chrome/RegistryMessageUtils.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#include "nsResProtocolHandler.h"
|
||||
#include "nsIIOService.h"
|
||||
@ -14,6 +16,9 @@
|
||||
|
||||
#include "mozilla/Omnijar.h"
|
||||
|
||||
using mozilla::dom::ContentParent;
|
||||
using mozilla::unused;
|
||||
|
||||
static NS_DEFINE_CID(kResURLCID, NS_RESURL_CID);
|
||||
|
||||
static nsResProtocolHandler *gResHandler = nullptr;
|
||||
@ -304,11 +309,37 @@ nsResProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
|
||||
// nsResProtocolHandler::nsIResProtocolHandler
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
SendResourceSubstitution(const nsACString& root, nsIURI* baseURI)
|
||||
{
|
||||
if (GeckoProcessType_Content == XRE_GetProcessType()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceMapping resourceMapping;
|
||||
resourceMapping.resource = root;
|
||||
if (baseURI) {
|
||||
baseURI->GetSpec(resourceMapping.resolvedURI.spec);
|
||||
baseURI->GetOriginCharset(resourceMapping.resolvedURI.charset);
|
||||
}
|
||||
|
||||
nsTArray<ContentParent*> parents;
|
||||
ContentParent::GetAll(parents);
|
||||
if (!parents.Length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < parents.Length(); i++) {
|
||||
unused << parents[i]->SendRegisterChromeItem(resourceMapping);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsResProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI)
|
||||
{
|
||||
if (!baseURI) {
|
||||
mSubstitutions.Remove(root);
|
||||
SendResourceSubstitution(root, baseURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -318,6 +349,7 @@ nsResProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!scheme.EqualsLiteral("resource")) {
|
||||
mSubstitutions.Put(root, baseURI);
|
||||
SendResourceSubstitution(root, baseURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -332,6 +364,7 @@ nsResProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSubstitutions.Put(root, newBaseURI);
|
||||
SendResourceSubstitution(root, newBaseURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
dummy.html
|
||||
|
||||
[browser_NetUtil.js]
|
||||
[browser_child_resource.js]
|
||||
|
213
netwerk/test/browser/browser_child_resource.js
Normal file
213
netwerk/test/browser/browser_child_resource.js
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// This must be loaded in the remote process for this test to be useful
|
||||
const TEST_URL = "http://example.com/browser/netwerk/test/browser/dummy.html";
|
||||
|
||||
const expectedRemote = gMultiProcessBrowser ? "true" : "";
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
const resProtocol = Cc["@mozilla.org/network/protocol;1?name=resource"]
|
||||
.getService(Ci.nsIResProtocolHandler);
|
||||
|
||||
function frameScript() {
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
let resProtocol = Components.classes["@mozilla.org/network/protocol;1?name=resource"]
|
||||
.getService(Components.interfaces.nsIResProtocolHandler);
|
||||
|
||||
addMessageListener("Test:ResolveURI", function({ data: uri }) {
|
||||
uri = Services.io.newURI(uri, null, null);
|
||||
try {
|
||||
let resolved = resProtocol.resolveURI(uri);
|
||||
sendAsyncMessage("Test:ResolvedURI", resolved);
|
||||
}
|
||||
catch (e) {
|
||||
sendAsyncMessage("Test:ResolvedURI", null);
|
||||
}
|
||||
});
|
||||
|
||||
addMessageListener("Test:Crash", function() {
|
||||
dump("Crashing\n");
|
||||
privateNoteIntentionalCrash();
|
||||
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
||||
let zero = new ctypes.intptr_t(8);
|
||||
let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
|
||||
badptr.contents
|
||||
});
|
||||
}
|
||||
|
||||
function waitForEvent(obj, name, capturing, chromeEvent) {
|
||||
info("Waiting for " + name);
|
||||
return new Promise((resolve) => {
|
||||
function listener(event) {
|
||||
info("Saw " + name);
|
||||
obj.removeEventListener(name, listener, capturing, chromeEvent);
|
||||
resolve(event);
|
||||
}
|
||||
|
||||
obj.addEventListener(name, listener, capturing, chromeEvent);
|
||||
});
|
||||
}
|
||||
|
||||
function resolveURI(uri) {
|
||||
uri = Services.io.newURI(uri, null, null);
|
||||
try {
|
||||
return resProtocol.resolveURI(uri);
|
||||
}
|
||||
catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function remoteResolveURI(uri) {
|
||||
return new Promise((resolve) => {
|
||||
let manager = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
function listener({ data: resolved }) {
|
||||
manager.removeMessageListener("Test:ResolvedURI", listener);
|
||||
resolve(resolved);
|
||||
}
|
||||
|
||||
manager.addMessageListener("Test:ResolvedURI", listener);
|
||||
manager.sendAsyncMessage("Test:ResolveURI", uri);
|
||||
});
|
||||
}
|
||||
|
||||
let loadTestTab = Task.async(function*() {
|
||||
gBrowser.selectedTab = gBrowser.addTab(TEST_URL);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
yield waitForEvent(browser, "load", true);
|
||||
browser.messageManager.loadFrameScript("data:,(" + frameScript.toString() + ")();", true);
|
||||
return browser;
|
||||
});
|
||||
|
||||
// Restarts the child process by crashing it then reloading the tab
|
||||
let restart = Task.async(function*() {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
// If the tab isn't remote this would crash the main process so skip it
|
||||
if (browser.getAttribute("remote") != "true")
|
||||
return browser;
|
||||
|
||||
browser.messageManager.sendAsyncMessage("Test:Crash");
|
||||
yield waitForEvent(browser, "AboutTabCrashedLoad", false, true);
|
||||
|
||||
browser.reload();
|
||||
|
||||
yield waitForEvent(browser, "load", true);
|
||||
is(browser.getAttribute("remote"), expectedRemote, "Browser should be in the right process");
|
||||
browser.messageManager.loadFrameScript("data:,(" + frameScript.toString() + ")();", true);
|
||||
return browser;
|
||||
});
|
||||
|
||||
// Sanity check that this test is going to be useful
|
||||
add_task(function*() {
|
||||
let browser = yield loadTestTab();
|
||||
|
||||
// This must be loaded in the remote process for this test to be useful
|
||||
is(browser.getAttribute("remote"), expectedRemote, "Browser should be in the right process");
|
||||
|
||||
let local = resolveURI("resource://gre/modules/Services.jsm");
|
||||
let remote = yield remoteResolveURI("resource://gre/modules/Services.jsm");
|
||||
is(local, remote, "Services.jsm should resolve in both processes");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
// Add a mapping, update it then remove it
|
||||
add_task(function*() {
|
||||
let browser = yield loadTestTab();
|
||||
|
||||
info("Set");
|
||||
resProtocol.setSubstitution("testing", Services.io.newURI("chrome://global/content", null, null));
|
||||
let local = resolveURI("resource://testing/test.js");
|
||||
let remote = yield remoteResolveURI("resource://testing/test.js");
|
||||
is(local, "chrome://global/content/test.js", "Should resolve in main process");
|
||||
is(remote, "chrome://global/content/test.js", "Should resolve in child process");
|
||||
|
||||
info("Change");
|
||||
resProtocol.setSubstitution("testing", Services.io.newURI("chrome://global/skin", null, null));
|
||||
local = resolveURI("resource://testing/test.js");
|
||||
remote = yield remoteResolveURI("resource://testing/test.js");
|
||||
is(local, "chrome://global/skin/test.js", "Should resolve in main process");
|
||||
is(remote, "chrome://global/skin/test.js", "Should resolve in child process");
|
||||
|
||||
info("Clear");
|
||||
resProtocol.setSubstitution("testing", null);
|
||||
local = resolveURI("resource://testing/test.js");
|
||||
remote = yield remoteResolveURI("resource://testing/test.js");
|
||||
is(local, null, "Shouldn't resolve in main process");
|
||||
is(remote, null, "Shouldn't resolve in child process");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
// Add a mapping, restart the child process then check it is still there
|
||||
add_task(function*() {
|
||||
let browser = yield loadTestTab();
|
||||
|
||||
info("Set");
|
||||
resProtocol.setSubstitution("testing", Services.io.newURI("chrome://global/content", null, null));
|
||||
let local = resolveURI("resource://testing/test.js");
|
||||
let remote = yield remoteResolveURI("resource://testing/test.js");
|
||||
is(local, "chrome://global/content/test.js", "Should resolve in main process");
|
||||
is(remote, "chrome://global/content/test.js", "Should resolve in child process");
|
||||
|
||||
yield restart();
|
||||
|
||||
local = resolveURI("resource://testing/test.js");
|
||||
remote = yield remoteResolveURI("resource://testing/test.js");
|
||||
is(local, "chrome://global/content/test.js", "Should resolve in main process");
|
||||
is(remote, "chrome://global/content/test.js", "Should resolve in child process");
|
||||
|
||||
info("Change");
|
||||
resProtocol.setSubstitution("testing", Services.io.newURI("chrome://global/skin", null, null));
|
||||
|
||||
yield restart();
|
||||
|
||||
local = resolveURI("resource://testing/test.js");
|
||||
remote = yield remoteResolveURI("resource://testing/test.js");
|
||||
is(local, "chrome://global/skin/test.js", "Should resolve in main process");
|
||||
is(remote, "chrome://global/skin/test.js", "Should resolve in child process");
|
||||
|
||||
info("Clear");
|
||||
resProtocol.setSubstitution("testing", null);
|
||||
|
||||
yield restart();
|
||||
|
||||
local = resolveURI("resource://testing/test.js");
|
||||
remote = yield remoteResolveURI("resource://testing/test.js");
|
||||
is(local, null, "Shouldn't resolve in main process");
|
||||
is(remote, null, "Shouldn't resolve in child process");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
// Adding a mapping to a resource URI should work
|
||||
add_task(function*() {
|
||||
let browser = yield loadTestTab();
|
||||
|
||||
info("Set");
|
||||
resProtocol.setSubstitution("testing", Services.io.newURI("chrome://global/content", null, null));
|
||||
resProtocol.setSubstitution("testing2", Services.io.newURI("resource://testing", null, null));
|
||||
let local = resolveURI("resource://testing2/test.js");
|
||||
let remote = yield remoteResolveURI("resource://testing2/test.js");
|
||||
is(local, "chrome://global/content/test.js", "Should resolve in main process");
|
||||
is(remote, "chrome://global/content/test.js", "Should resolve in child process");
|
||||
|
||||
info("Clear");
|
||||
resProtocol.setSubstitution("testing", null);
|
||||
local = resolveURI("resource://testing2/test.js");
|
||||
remote = yield remoteResolveURI("resource://testing2/test.js");
|
||||
is(local, "chrome://global/content/test.js", "Should resolve in main process");
|
||||
is(remote, "chrome://global/content/test.js", "Should resolve in child process");
|
||||
|
||||
resProtocol.setSubstitution("testing2", null);
|
||||
local = resolveURI("resource://testing2/test.js");
|
||||
remote = yield remoteResolveURI("resource://testing2/test.js");
|
||||
is(local, null, "Shouldn't resolve in main process");
|
||||
is(remote, null, "Shouldn't resolve in child process");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
7
netwerk/test/browser/dummy.html
Normal file
7
netwerk/test/browser/dummy.html
Normal file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<p>Dummy Page</p>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user