Bug 1147911 Part 7: Create browsing context with no opener if URI needs different process. r=smaug

This also means window.open returns null in the same circumstance.
This commit is contained in:
Bob Owen 2016-11-24 15:08:31 +00:00
Родитель 6b86819989
Коммит f5830d5e44
9 изменённых файлов: 320 добавлений и 164 удалений

Просмотреть файл

@ -622,6 +622,10 @@ var WebBrowserChrome = {
return true;
},
shouldLoadURIInThisProcess: function(aURI) {
return E10SUtils.shouldLoadURIInThisProcess(aURI);
},
// Try to reload the currently active or currently loading page in a new process.
reloadInFreshProcess: function(aDocShell, aURI, aReferrer) {
E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, true);

Просмотреть файл

@ -47,12 +47,13 @@ class PBrowserParent;
class Promise;
class TabParent;
class MutableTabContext;
} // namespace dom
namespace ipc {
class StructuredCloneData;
} // namespace ipc
} // namespace dom
namespace layout {
class RenderFrameParent;
} // namespace layout

Просмотреть файл

@ -655,6 +655,43 @@ ContentChild::ProvideWindow(mozIDOMWindowProxy* aParent,
aForceNoOpener, aWindowIsNew, aReturn);
}
static nsresult
GetWindowParamsFromParent(mozIDOMWindowProxy* aParent,
nsACString& aBaseURIString, float* aFullZoom,
DocShellOriginAttributes& aOriginAttributes)
{
*aFullZoom = 1.0f;
auto* opener = nsPIDOMWindowOuter::From(aParent);
if (!opener) {
return NS_OK;
}
nsCOMPtr<nsIDocument> doc = opener->GetDoc();
nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
if (!baseURI) {
NS_ERROR("nsIDocument didn't return a base URI");
return NS_ERROR_FAILURE;
}
baseURI->GetSpec(aBaseURIString);
RefPtr<nsDocShell> openerDocShell =
static_cast<nsDocShell*>(opener->GetDocShell());
if (!openerDocShell) {
return NS_OK;
}
aOriginAttributes = openerDocShell->GetOriginAttributes();
nsCOMPtr<nsIContentViewer> cv;
nsresult rv = openerDocShell->GetContentViewer(getter_AddRefs(cv));
if (NS_SUCCEEDED(rv) && cv) {
cv->GetFullZoom(aFullZoom);
}
return NS_OK;
}
nsresult
ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
mozIDOMWindowProxy* aParent,
@ -674,8 +711,43 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
nsAutoPtr<IPCTabContext> ipcContext;
TabId openerTabId = TabId(0);
nsAutoCString features(aFeatures);
nsresult rv;
if (aTabOpener) {
// Check to see if the target URI can be loaded in this process.
// If not create and load it in an unrelated tab/window.
nsCOMPtr<nsIWebBrowserChrome3> browserChrome3;
rv = aTabOpener->GetWebBrowserChrome(getter_AddRefs(browserChrome3));
if (NS_SUCCEEDED(rv) && browserChrome3) {
bool shouldLoad;
rv = browserChrome3->ShouldLoadURIInThisProcess(aURI, &shouldLoad);
if (NS_SUCCEEDED(rv) && !shouldLoad) {
nsAutoCString baseURIString;
float fullZoom;
DocShellOriginAttributes originAttributes;
rv = GetWindowParamsFromParent(aParent, baseURIString, &fullZoom,
originAttributes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
URIParams uriToLoad;
SerializeURI(aURI, uriToLoad);
Unused << SendCreateWindowInDifferentProcess(aTabOpener, aChromeFlags,
aCalledFromJS,
aPositionSpecified,
aSizeSpecified,
uriToLoad, features,
baseURIString,
originAttributes, fullZoom);
// We return NS_ERROR_ABORT, so that the caller knows that we've abandoned
// the window open as far as it is concerned.
return NS_ERROR_ABORT;
}
}
PopupIPCTabContext context;
openerTabId = aTabOpener->GetTabId();
context.opener() = openerTabId;
@ -714,7 +786,6 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
GetID(), IsForBrowser());
nsString name(aName);
nsAutoCString features(aFeatures);
nsTArray<FrameScriptInfo> frameScripts;
nsCString urlToLoad;
@ -740,40 +811,20 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
&layersId);
} else {
nsAutoCString baseURIString;
if (aTabOpener) {
auto* opener = nsPIDOMWindowOuter::From(aParent);
nsCOMPtr<nsIDocument> doc = opener->GetDoc();
nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
if (!baseURI) {
NS_ERROR("nsIDocument didn't return a base URI");
return NS_ERROR_FAILURE;
}
baseURI->GetSpec(baseURIString);
float fullZoom;
DocShellOriginAttributes originAttributes;
rv = GetWindowParamsFromParent(aParent, baseURIString, &fullZoom,
originAttributes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
auto* opener = nsPIDOMWindowOuter::From(aParent);
nsIDocShell* openerShell;
RefPtr<nsDocShell> openerDocShell;
float fullZoom = 1.0f;
if (opener && (openerShell = opener->GetDocShell())) {
openerDocShell = static_cast<nsDocShell*>(openerShell);
nsCOMPtr<nsIContentViewer> cv;
openerDocShell->GetContentViewer(getter_AddRefs(cv));
if (cv) {
cv->GetFullZoom(&fullZoom);
}
}
nsresult rv;
if (!SendCreateWindow(aTabOpener, newChild, renderFrame,
aChromeFlags, aCalledFromJS, aPositionSpecified,
aSizeSpecified,
features,
baseURIString,
openerDocShell
? openerDocShell->GetOriginAttributes()
: DocShellOriginAttributes(),
originAttributes,
fullZoom,
&rv,
aWindowIsNew,

Просмотреть файл

@ -107,6 +107,7 @@
#include "nsConsoleService.h"
#include "nsContentUtils.h"
#include "nsDebugImpl.h"
#include "nsFrameLoader.h"
#include "nsFrameMessageManager.h"
#include "nsHashPropertyBag.h"
#include "nsIAlertsService.h"
@ -4157,6 +4158,130 @@ ContentParent::DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumen
return true;
}
mozilla::ipc::IPCResult
ContentParent::CommonCreateWindow(PBrowserParent* aThisTab,
bool aSetOpener,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
nsIURI* aURIToLoad,
const nsCString& aFeatures,
const nsCString& aBaseURI,
const DocShellOriginAttributes& aOpenerOriginAttributes,
const float& aFullZoom,
nsresult& aResult,
nsCOMPtr<nsITabParent>& aNewTabParent,
bool* aWindowIsNew)
{
// The content process should never be in charge of computing whether or
// not a window should be private or remote - the parent will do that.
const uint32_t badFlags = nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW |
nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW |
nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME |
nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
if (!!(aChromeFlags & badFlags)) {
return IPC_FAIL(this, "Forbidden aChromeFlags passed");
}
TabParent* thisTabParent = TabParent::GetFrom(aThisTab);
nsCOMPtr<nsIContent> frame;
if (thisTabParent) {
frame = do_QueryInterface(thisTabParent->GetOwnerElement());
if (NS_WARN_IF(thisTabParent->IsMozBrowser())) {
return IPC_FAIL(this, "aThisTab is not a MozBrowser");
}
}
nsCOMPtr<nsPIDOMWindowOuter> outerWin;
if (frame) {
outerWin = frame->OwnerDoc()->GetWindow();
// If our chrome window is in the process of closing, don't try to open a
// new tab in it.
if (outerWin && outerWin->Closed()) {
outerWin = nullptr;
}
}
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
if (thisTabParent) {
browserDOMWin = thisTabParent->GetBrowserDOMWindow();
}
// If we haven't found a chrome window to open in, just use the most recently
// opened one.
if (!outerWin) {
outerWin = nsContentUtils::GetMostRecentNonPBWindow();
if (NS_WARN_IF(!outerWin)) {
aResult = NS_ERROR_FAILURE;
return IPC_OK();
}
nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(outerWin);
if (rootChromeWin) {
rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
}
}
int32_t openLocation = nsWindowWatcher::GetWindowOpenLocation(
outerWin, aChromeFlags, aCalledFromJS, aPositionSpecified, aSizeSpecified);
MOZ_ASSERT(openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
openLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW);
if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
if (NS_WARN_IF(!browserDOMWin)) {
aResult = NS_ERROR_ABORT;
return IPC_OK();
}
bool isPrivate = false;
if (thisTabParent) {
nsCOMPtr<nsILoadContext> loadContext = thisTabParent->GetLoadContext();
loadContext->GetUsePrivateBrowsing(&isPrivate);
}
nsCOMPtr<nsIOpenURIInFrameParams> params =
new nsOpenURIInFrameParams(aOpenerOriginAttributes);
params->SetReferrer(NS_ConvertUTF8toUTF16(aBaseURI));
params->SetIsPrivate(isPrivate);
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
aResult = browserDOMWin->OpenURIInFrame(aURIToLoad, params, openLocation,
nsIBrowserDOMWindow::OPEN_NEW,
getter_AddRefs(frameLoaderOwner));
if (NS_SUCCEEDED(aResult) && frameLoaderOwner) {
RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
if (frameLoader) {
frameLoader->GetTabParent(getter_AddRefs(aNewTabParent));
}
} else {
*aWindowIsNew = false;
}
return IPC_OK();
}
nsCOMPtr<nsPIWindowWatcher> pwwatch =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &aResult);
if (NS_WARN_IF(NS_FAILED(aResult))) {
return IPC_OK();
}
if (aSetOpener && thisTabParent) {
aResult = pwwatch->OpenWindowWithTabParent(thisTabParent, aFeatures,
aCalledFromJS, aFullZoom,
getter_AddRefs(aNewTabParent));
} else {
aResult = pwwatch->OpenWindowWithoutParent(getter_AddRefs(aNewTabParent));
}
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
PBrowserParent* aNewTab,
@ -4180,26 +4305,6 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
*aWindowIsNew = true;
*aResult = NS_OK;
// The content process should never be in charge of computing whether or
// not a window should be private or remote - the parent will do that.
const uint32_t badFlags =
nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
| nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW
| nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME
| nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
if (!!(aChromeFlags & badFlags)) {
return IPC_FAIL_NO_REASON(this);
}
TabParent* thisTabParent = nullptr;
if (aThisTab) {
thisTabParent = TabParent::GetFrom(aThisTab);
}
if (NS_WARN_IF(thisTabParent && thisTabParent->IsMozBrowser())) {
return IPC_FAIL_NO_REASON(this);
}
TabParent* newTab = TabParent::GetFrom(aNewTab);
MOZ_ASSERT(newTab);
@ -4215,106 +4320,16 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
// we must have an opener.
newTab->SetHasContentOpener(true);
nsCOMPtr<nsIContent> frame;
if (thisTabParent) {
frame = do_QueryInterface(thisTabParent->GetOwnerElement());
}
nsCOMPtr<nsPIDOMWindowOuter> parent;
if (frame) {
parent = frame->OwnerDoc()->GetWindow();
// If our chrome window is in the process of closing, don't try to open a
// new tab in it.
if (parent && parent->Closed()) {
parent = nullptr;
}
}
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
if (thisTabParent) {
browserDOMWin = thisTabParent->GetBrowserDOMWindow();
}
// If we haven't found a chrome window to open in, just use the most recently
// opened one.
if (!parent) {
parent = nsContentUtils::GetMostRecentNonPBWindow();
if (NS_WARN_IF(!parent)) {
*aResult = NS_ERROR_FAILURE;
return IPC_OK();
}
nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(parent);
if (rootChromeWin) {
rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
}
}
int32_t openLocation =
nsWindowWatcher::GetWindowOpenLocation(parent, aChromeFlags, aCalledFromJS,
aPositionSpecified, aSizeSpecified);
MOZ_ASSERT(openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
openLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW);
// Opening new tabs is the easy case...
if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
if (NS_WARN_IF(!browserDOMWin)) {
*aResult = NS_ERROR_ABORT;
return IPC_OK();
}
bool isPrivate = false;
if (thisTabParent) {
nsCOMPtr<nsILoadContext> loadContext = thisTabParent->GetLoadContext();
loadContext->GetUsePrivateBrowsing(&isPrivate);
}
nsCOMPtr<nsIOpenURIInFrameParams> params =
new nsOpenURIInFrameParams(aOpenerOriginAttributes);
params->SetReferrer(NS_ConvertUTF8toUTF16(aBaseURI));
params->SetIsPrivate(isPrivate);
TabParent::AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
browserDOMWin->OpenURIInFrame(nullptr, params,
openLocation,
nsIBrowserDOMWindow::OPEN_NEW,
getter_AddRefs(frameLoaderOwner));
if (!frameLoaderOwner) {
*aWindowIsNew = false;
}
newTab->SwapFrameScriptsFrom(*aFrameScripts);
RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
if (!newTab->SetRenderFrame(rfp) ||
!newTab->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
*aResult = NS_ERROR_FAILURE;
}
return IPC_OK();
}
TabParent::AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
nsCOMPtr<nsPIWindowWatcher> pwwatch =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, aResult);
if (NS_WARN_IF(NS_FAILED(*aResult))) {
return IPC_OK();
}
nsCOMPtr<nsITabParent> newRemoteTab;
if (!thisTabParent) {
// Because we weren't passed an opener tab, the content process has asked us
// to open a new window that is unrelated to a pre-existing tab.
*aResult = pwwatch->OpenWindowWithoutParent(getter_AddRefs(newRemoteTab));
} else {
*aResult = pwwatch->OpenWindowWithTabParent(thisTabParent, aFeatures, aCalledFromJS,
aFullZoom, getter_AddRefs(newRemoteTab));
mozilla::ipc::IPCResult ipcResult =
CommonCreateWindow(aThisTab, /* aSetOpener = */ true, aChromeFlags,
aCalledFromJS, aPositionSpecified, aSizeSpecified,
nullptr, aFeatures, aBaseURI, aOpenerOriginAttributes,
aFullZoom, *aResult, newRemoteTab, aWindowIsNew);
if (!ipcResult) {
return ipcResult;
}
if (NS_WARN_IF(NS_FAILED(*aResult))) {
@ -4334,6 +4349,39 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvCreateWindowInDifferentProcess(
PBrowserParent* aThisTab,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const URIParams& aURIToLoad,
const nsCString& aFeatures,
const nsCString& aBaseURI,
const DocShellOriginAttributes& aOpenerOriginAttributes,
const float& aFullZoom)
{
nsCOMPtr<nsITabParent> newRemoteTab;
bool windowIsNew;
nsCOMPtr<nsIURI> uriToLoad = DeserializeURI(aURIToLoad);
nsresult rv;
mozilla::ipc::IPCResult ipcResult =
CommonCreateWindow(aThisTab, /* aSetOpener = */ false, aChromeFlags,
aCalledFromJS, aPositionSpecified, aSizeSpecified,
uriToLoad, aFeatures, aBaseURI, aOpenerOriginAttributes,
aFullZoom, rv, newRemoteTab, &windowIsNew);
if (!ipcResult) {
return ipcResult;
}
if (NS_FAILED(rv)) {
NS_WARNING("Call to CommonCreateWindow failed.");
}
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvProfile(const nsCString& aProfile)
{

Просмотреть файл

@ -40,6 +40,7 @@
class nsConsoleService;
class nsICycleCollectorLogSink;
class nsIDumpGCAndCCLogsCallback;
class nsITabParent;
class nsITimer;
class ParentIdleListener;
class nsIWidget;
@ -484,23 +485,36 @@ public:
void ForkNewProcess(bool aBlocking);
virtual mozilla::ipc::IPCResult RecvCreateWindow(PBrowserParent* aThisTabParent,
PBrowserParent* aOpener,
layout::PRenderFrameParent* aRenderFrame,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const nsCString& aFeatures,
const nsCString& aBaseURI,
const DocShellOriginAttributes& aOpenerOriginAttributes,
const float& aFullZoom,
nsresult* aResult,
bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts,
nsCString* aURLToLoad,
layers::TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint64_t* aLayersId) override;
virtual mozilla::ipc::IPCResult
RecvCreateWindow(PBrowserParent* aThisTabParent,
PBrowserParent* aNewTab,
layout::PRenderFrameParent* aRenderFrame,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const nsCString& aFeatures,
const nsCString& aBaseURI,
const DocShellOriginAttributes& aOpenerOriginAttributes,
const float& aFullZoom,
nsresult* aResult,
bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts,
nsCString* aURLToLoad,
layers::TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint64_t* aLayersId) override;
virtual mozilla::ipc::IPCResult RecvCreateWindowInDifferentProcess(
PBrowserParent* aThisTab,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const URIParams& aURIToLoad,
const nsCString& aFeatures,
const nsCString& aBaseURI,
const DocShellOriginAttributes& aOpenerOriginAttributes,
const float& aFullZoom) override;
static bool AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId);
@ -584,6 +598,22 @@ private:
const bool& aIsForBrowser) override;
using PContentParent::SendPTestShellConstructor;
mozilla::ipc::IPCResult
CommonCreateWindow(PBrowserParent* aThisTab,
bool aSetOpener,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
nsIURI* aURIToLoad,
const nsCString& aFeatures,
const nsCString& aBaseURI,
const DocShellOriginAttributes& aOpenerOriginAttributes,
const float& aFullZoom,
nsresult& aResult,
nsCOMPtr<nsITabParent>& aNewTabParent,
bool* aWindowIsNew);
FORWARD_SHMEM_ALLOCATOR_TO(PContentParent)
ContentParent(ContentParent* aOpener,

Просмотреть файл

@ -1081,6 +1081,18 @@ parent:
TextureFactoryIdentifier textureFactoryIdentifier,
uint64_t layersId);
async CreateWindowInDifferentProcess(
PBrowser aThisTab,
uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
URIParams aURIToLoad,
nsCString aFeatures,
nsCString aBaseURI,
DocShellOriginAttributes aOpenerOriginAttributes,
float aFullZoom);
sync GetDeviceStorageLocation(nsString type)
returns (nsString path);

Просмотреть файл

@ -220,7 +220,7 @@ TabChildBase::DispatchMessageManagerMessage(const nsAString& aMessageName,
{
AutoSafeJSContext cx;
JS::Rooted<JS::Value> json(cx, JS::NullValue());
StructuredCloneData data;
dom::ipc::StructuredCloneData data;
if (JS_ParseJSON(cx,
static_cast<const char16_t*>(aJSONData.BeginReading()),
aJSONData.Length(),

Просмотреть файл

@ -48,6 +48,8 @@ interface nsIWebBrowserChrome3 : nsIWebBrowserChrome2
in nsIURI aURI,
in nsIURI aReferrer);
bool shouldLoadURIInThisProcess(in nsIURI aURI);
/**
* Attempts to load the currently loaded page into a fresh process to increase
* available memory.

Просмотреть файл

@ -404,6 +404,14 @@ NS_IMETHODIMP nsContentTreeOwner::ShouldLoadURI(nsIDocShell *aDocShell,
return NS_OK;
}
NS_IMETHODIMP nsContentTreeOwner::ShouldLoadURIInThisProcess(nsIURI* aURI,
bool* aRetVal)
{
MOZ_ASSERT_UNREACHABLE("Should only be called in child process.");
*aRetVal = true;
return NS_OK;
}
NS_IMETHODIMP nsContentTreeOwner::ReloadInFreshProcess(nsIDocShell* aDocShell,
nsIURI* aURI,
nsIURI* aReferrer,