зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1576188 - Handle save-as for cross process iframes. r=peterv
Depends on D70388 Differential Revision: https://phabricator.services.mozilla.com/D70389
This commit is contained in:
Родитель
91925ee89e
Коммит
55a186014d
|
@ -567,6 +567,7 @@ class ContextMenuChild extends JSWindowActorChild {
|
|||
} = doc;
|
||||
docLocation = docLocation && docLocation.spec;
|
||||
let frameOuterWindowID = WebNavigationFrames.getFrameId(doc.defaultView);
|
||||
let frameBrowsingContextID = doc.defaultView.docShell.browsingContext.id;
|
||||
let loginFillInfo = LoginManagerChild.forWindow(
|
||||
doc.defaultView
|
||||
).getFieldContext(aEvent.composedTarget);
|
||||
|
@ -683,6 +684,7 @@ class ContextMenuChild extends JSWindowActorChild {
|
|||
customMenuItems,
|
||||
contentDisposition,
|
||||
frameOuterWindowID,
|
||||
frameBrowsingContextID,
|
||||
disableSetDesktopBackground,
|
||||
parentAllowsMixedContent,
|
||||
};
|
||||
|
@ -902,6 +904,9 @@ class ContextMenuChild extends JSWindowActorChild {
|
|||
context.target.ownerGlobal
|
||||
);
|
||||
|
||||
context.frameBrowsingContextID =
|
||||
context.target.ownerGlobal.docShell.browsingContext.id;
|
||||
|
||||
// Check if we are in the PDF Viewer.
|
||||
context.inPDFViewer =
|
||||
context.target.ownerDocument.nodePrincipal.origin == "resource://pdf.js";
|
||||
|
|
|
@ -52,6 +52,7 @@ function openContextMenu(aMessage, aBrowser, aActor) {
|
|||
contentType: data.contentType,
|
||||
contentDisposition: data.contentDisposition,
|
||||
frameOuterWindowID: data.frameOuterWindowID,
|
||||
frameBrowsingContext: BrowsingContext.get(data.frameBrowsingContextID),
|
||||
selectionInfo: data.selectionInfo,
|
||||
disableSetDesktopBackground: data.disableSetDesktopBackground,
|
||||
loginFillInfo: data.loginFillInfo,
|
||||
|
@ -231,6 +232,9 @@ class nsContextMenu {
|
|||
this.principal = context.principal;
|
||||
this.storagePrincipal = context.storagePrincipal;
|
||||
this.frameOuterWindowID = context.frameOuterWindowID;
|
||||
this.frameBrowsingContext = BrowsingContext.get(
|
||||
context.frameBrowsingContextID
|
||||
);
|
||||
|
||||
this.inSyntheticDoc = context.inSyntheticDoc;
|
||||
this.inAboutDevtoolsToolbox = context.inAboutDevtoolsToolbox;
|
||||
|
@ -1395,7 +1399,7 @@ class nsContextMenu {
|
|||
|
||||
// Save URL of clicked-on frame.
|
||||
saveFrame() {
|
||||
saveBrowser(this.browser, false, this.frameOuterWindowID);
|
||||
saveBrowser(this.browser, false, this.frameBrowsingContext);
|
||||
}
|
||||
|
||||
// Helper function to wait for appropriate MIME-type headers and
|
||||
|
|
|
@ -1320,7 +1320,7 @@ const JsonView = {
|
|||
// principal is from the child. Null principals don't survive crossing
|
||||
// over IPC, so there's no other principal that'll work.
|
||||
const persistable = browser.frameLoader;
|
||||
persistable.startPersistence(0, {
|
||||
persistable.startPersistence(null, {
|
||||
onDocumentReady(doc) {
|
||||
const uri = chrome.makeURI(doc.documentURI, doc.characterSet);
|
||||
const filename = chrome.getDefaultFileName(undefined, uri, doc, null);
|
||||
|
|
|
@ -97,6 +97,16 @@ BrowsingContext* BrowsingContext::GetParent() const {
|
|||
return mParentWindow ? mParentWindow->GetBrowsingContext() : nullptr;
|
||||
}
|
||||
|
||||
bool BrowsingContext::IsInSubtreeOf(BrowsingContext* aContext) {
|
||||
BrowsingContext* bc = this;
|
||||
do {
|
||||
if (bc == aContext) {
|
||||
return true;
|
||||
}
|
||||
} while ((bc = bc->mParent));
|
||||
return false;
|
||||
}
|
||||
|
||||
BrowsingContext* BrowsingContext::Top() {
|
||||
BrowsingContext* bc = this;
|
||||
while (bc->mParentWindow) {
|
||||
|
|
|
@ -215,6 +215,12 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
void SetDocShell(nsIDocShell* aDocShell);
|
||||
void ClearDocShell() { mDocShell = nullptr; }
|
||||
|
||||
// Get the Document for this BrowsingContext if it is in-process, or
|
||||
// null if it's not.
|
||||
Document* GetDocument() const {
|
||||
return mDocShell ? mDocShell->GetDocument() : nullptr;
|
||||
}
|
||||
|
||||
// This cleans up remote outer window proxies that might have been left behind
|
||||
// when the browsing context went from being remote to local. It does this by
|
||||
// turning them into cross-compartment wrappers to aOuter. If there is already
|
||||
|
@ -279,6 +285,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
|
||||
bool IsTopContent() const { return IsContent() && !GetParent(); }
|
||||
|
||||
bool IsInSubtreeOf(BrowsingContext* aContext);
|
||||
|
||||
bool IsContentSubframe() const { return IsContent() && GetParent(); }
|
||||
uint64_t Id() const { return mBrowsingContextId; }
|
||||
|
||||
|
|
|
@ -3203,25 +3203,27 @@ void nsFrameLoader::DestroyBrowserFrameScripts() {
|
|||
}
|
||||
|
||||
void nsFrameLoader::StartPersistence(
|
||||
uint64_t aOuterWindowID, nsIWebBrowserPersistDocumentReceiver* aRecv,
|
||||
BrowsingContext* aContext, nsIWebBrowserPersistDocumentReceiver* aRecv,
|
||||
ErrorResult& aRv) {
|
||||
MOZ_ASSERT(aRecv);
|
||||
RefPtr<BrowsingContext> context = aContext ? aContext : GetBrowsingContext();
|
||||
|
||||
if (auto* browserParent = GetBrowserParent()) {
|
||||
browserParent->StartPersistence(aOuterWindowID, aRecv, aRv);
|
||||
if (!context || !context->IsInSubtreeOf(GetBrowsingContext())) {
|
||||
aRecv->OnError(NS_ERROR_NO_CONTENT);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> rootDoc =
|
||||
GetDocShell() ? GetDocShell()->GetDocument() : nullptr;
|
||||
nsCOMPtr<Document> foundDoc;
|
||||
if (aOuterWindowID) {
|
||||
foundDoc = nsContentUtils::GetSubdocumentWithOuterWindowId(rootDoc,
|
||||
aOuterWindowID);
|
||||
} else {
|
||||
foundDoc = rootDoc;
|
||||
if (!context->GetDocShell() && XRE_IsParentProcess()) {
|
||||
CanonicalBrowsingContext* canonical =
|
||||
CanonicalBrowsingContext::Cast(context);
|
||||
RefPtr<BrowserParent> browserParent =
|
||||
canonical->GetCurrentWindowGlobal()->GetBrowserParent();
|
||||
browserParent->StartPersistence(canonical, aRecv, aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> foundDoc = context->GetDocument();
|
||||
|
||||
if (!foundDoc) {
|
||||
aRecv->OnError(NS_ERROR_NO_CONTENT);
|
||||
} else {
|
||||
|
|
|
@ -221,7 +221,7 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
nsIWebProgressListener* aProgressListener,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
void StartPersistence(uint64_t aOuterWindowID,
|
||||
void StartPersistence(BrowsingContext* aContext,
|
||||
nsIWebBrowserPersistDocumentReceiver* aRecv,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
/* -*- 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/.
|
||||
*/
|
||||
|
||||
interface LoadContext;
|
||||
interface RemoteTab;
|
||||
interface URI;
|
||||
interface nsIDocShell;
|
||||
interface nsIPrintSettings;
|
||||
interface nsIWebBrowserPersistDocumentReceiver;
|
||||
interface nsIWebProgressListener;
|
||||
|
||||
[ChromeOnly,
|
||||
Exposed=Window]
|
||||
interface FrameLoader {
|
||||
/**
|
||||
* Get the docshell from the frame loader.
|
||||
*/
|
||||
[GetterThrows]
|
||||
readonly attribute nsIDocShell? docShell;
|
||||
|
||||
/**
|
||||
* Get this frame loader's RemoteTab, if it has a remote frame. Otherwise,
|
||||
* returns null.
|
||||
*/
|
||||
readonly attribute RemoteTab? remoteTab;
|
||||
|
||||
/**
|
||||
* Get an nsILoadContext for the top-level docshell. For remote
|
||||
* frames, a shim is returned that contains private browsing and app
|
||||
* information.
|
||||
*/
|
||||
readonly attribute LoadContext loadContext;
|
||||
|
||||
/**
|
||||
* Get the root BrowsingContext within the frame.
|
||||
* This may be null immediately after creating a remote frame.
|
||||
*/
|
||||
readonly attribute BrowsingContext? browsingContext;
|
||||
|
||||
/**
|
||||
* Find out whether the loader's frame is at too great a depth in
|
||||
* the frame tree. This can be used to decide what operations may
|
||||
* or may not be allowed on the loader's docshell.
|
||||
*/
|
||||
[Pure]
|
||||
readonly attribute boolean depthTooGreat;
|
||||
|
||||
/**
|
||||
* Find out whether the loader's frame is a remote frame.
|
||||
*/
|
||||
readonly attribute boolean isRemoteFrame;
|
||||
|
||||
/**
|
||||
* Activate remote frame.
|
||||
* Throws an exception with non-remote frames.
|
||||
*/
|
||||
[Throws]
|
||||
void activateRemoteFrame();
|
||||
|
||||
/**
|
||||
* Deactivate remote frame.
|
||||
* Throws an exception with non-remote frames.
|
||||
*/
|
||||
[Throws]
|
||||
void deactivateRemoteFrame();
|
||||
|
||||
/**
|
||||
* @see nsIDOMWindowUtils sendMouseEvent.
|
||||
*/
|
||||
[Throws]
|
||||
void sendCrossProcessMouseEvent(DOMString aType,
|
||||
float aX,
|
||||
float aY,
|
||||
long aButton,
|
||||
long aClickCount,
|
||||
long aModifiers,
|
||||
optional boolean aIgnoreRootScrollFrame = false);
|
||||
|
||||
/**
|
||||
* Activate event forwarding from client (remote frame) to parent.
|
||||
*/
|
||||
[Throws]
|
||||
void activateFrameEvent(DOMString aType, boolean capture);
|
||||
|
||||
// Note, when frameloaders are swapped, also messageManagers are swapped.
|
||||
readonly attribute MessageSender? messageManager;
|
||||
|
||||
/**
|
||||
* Request that the next time a remote layer transaction has been
|
||||
* received by the Compositor, a MozAfterRemoteFrame event be sent
|
||||
* to the window.
|
||||
*/
|
||||
void requestNotifyAfterRemotePaint();
|
||||
|
||||
/**
|
||||
* Force a remote browser to recompute its dimension and screen position.
|
||||
*/
|
||||
[Throws]
|
||||
void requestUpdatePosition();
|
||||
|
||||
/**
|
||||
* Force a TabStateFlush from native sessionStoreListeners.
|
||||
* Return true if the flush requires async ipc call.
|
||||
*/
|
||||
boolean requestTabStateFlush(unsigned long aFlushId);
|
||||
|
||||
/**
|
||||
* Force Epoch update in native sessionStoreListeners.
|
||||
*/
|
||||
void requestEpochUpdate(unsigned long aEpoch);
|
||||
|
||||
/**
|
||||
* Request a session history update in native sessionStoreListeners.
|
||||
*/
|
||||
void requestSHistoryUpdate(boolean aImmediately);
|
||||
|
||||
/**
|
||||
* Print the current document.
|
||||
*
|
||||
* @param aOuterWindowID the ID of the outer window to print
|
||||
* @param aPrintSettings optional print settings to use; printSilent can be
|
||||
* set to prevent prompting.
|
||||
* @param aProgressListener optional print progress listener.
|
||||
*/
|
||||
[Throws]
|
||||
void print(unsigned long long aOuterWindowID,
|
||||
nsIPrintSettings aPrintSettings,
|
||||
optional nsIWebProgressListener? aProgressListener = null);
|
||||
|
||||
/**
|
||||
* The element which owns this frame loader.
|
||||
*
|
||||
* For example, if this is a frame loader for an <iframe>, this attribute
|
||||
* returns the iframe element.
|
||||
*/
|
||||
[Pure]
|
||||
readonly attribute Element? ownerElement;
|
||||
|
||||
|
||||
/**
|
||||
* Cached childID of the ContentParent owning the RemoteTab in this frame
|
||||
* loader. This can be used to obtain the childID after the RemoteTab died.
|
||||
*/
|
||||
[Pure]
|
||||
readonly attribute unsigned long long childID;
|
||||
|
||||
/**
|
||||
* Find out whether the owner content really is a mozbrowser. <xul:browser>
|
||||
* is not considered to be a mozbrowser frame.
|
||||
*/
|
||||
[Pure]
|
||||
readonly attribute boolean ownerIsMozBrowserFrame;
|
||||
|
||||
/**
|
||||
* The last known width of the frame. Reading this property will not trigger
|
||||
* a reflow, and therefore may not reflect the current state of things. It
|
||||
* should only be used in asynchronous APIs where values are not guaranteed
|
||||
* to be up-to-date when received.
|
||||
*/
|
||||
[Pure]
|
||||
readonly attribute unsigned long lazyWidth;
|
||||
|
||||
/**
|
||||
* The last known height of the frame. Reading this property will not trigger
|
||||
* a reflow, and therefore may not reflect the current state of things. It
|
||||
* should only be used in asynchronous APIs where values are not guaranteed
|
||||
* to be up-to-date when received.
|
||||
*/
|
||||
[Pure]
|
||||
readonly attribute unsigned long lazyHeight;
|
||||
|
||||
/**
|
||||
* Is `true` if the frameloader is dead (destroy has been called on it)
|
||||
*/
|
||||
[Pure]
|
||||
readonly attribute boolean isDead;
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface for objects which represent a document that can be
|
||||
* serialized with nsIWebBrowserPersist. This interface is
|
||||
* asynchronous because the actual document can be in another process
|
||||
* (e.g., if this object is a FrameLoader for an out-of-process
|
||||
* frame).
|
||||
*
|
||||
* @see nsIWebBrowserPersistDocumentReceiver
|
||||
* @see nsIWebBrowserPersistDocument
|
||||
* @see nsIWebBrowserPersist
|
||||
*
|
||||
* @param aContext
|
||||
* The browsing context of the subframe we'd like to persist.
|
||||
* If set to nullptr, WebBrowserPersistable will attempt to persist
|
||||
* the top-level document. If the browsing context is for a subframe
|
||||
* that is not held beneath the WebBrowserPersistable, aRecv's onError
|
||||
* method will be called with NS_ERROR_NO_CONTENT.
|
||||
* @param aRecv
|
||||
* The nsIWebBrowserPersistDocumentReceiver is a callback that
|
||||
* will be fired once the document is ready for persisting.
|
||||
*/
|
||||
interface mixin WebBrowserPersistable
|
||||
{
|
||||
[Throws]
|
||||
void startPersistence(BrowsingContext? aContext,
|
||||
nsIWebBrowserPersistDocumentReceiver aRecv);
|
||||
};
|
||||
|
||||
FrameLoader includes WebBrowserPersistable;
|
|
@ -45,6 +45,7 @@ WEBIDL_FILES = [
|
|||
'DOMLocalization.webidl',
|
||||
'Flex.webidl',
|
||||
'Fluent.webidl',
|
||||
'FrameLoader.webidl',
|
||||
'HeapSnapshot.webidl',
|
||||
'InspectorUtils.webidl',
|
||||
'IteratorResult.webidl',
|
||||
|
|
|
@ -3896,12 +3896,12 @@ bool BrowserParent::AsyncPanZoomEnabled() const {
|
|||
}
|
||||
|
||||
void BrowserParent::StartPersistence(
|
||||
uint64_t aOuterWindowID, nsIWebBrowserPersistDocumentReceiver* aRecv,
|
||||
ErrorResult& aRv) {
|
||||
CanonicalBrowsingContext* aContext,
|
||||
nsIWebBrowserPersistDocumentReceiver* aRecv, ErrorResult& aRv) {
|
||||
auto* actor = new WebBrowserPersistDocumentParent();
|
||||
actor->SetOnReady(aRecv);
|
||||
bool ok = Manager()->SendPWebBrowserPersistDocumentConstructor(
|
||||
actor, this, aOuterWindowID);
|
||||
bool ok = Manager()->SendPWebBrowserPersistDocumentConstructor(actor, this,
|
||||
aContext);
|
||||
if (!ok) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
|
|
@ -612,7 +612,7 @@ class BrowserParent final : public PBrowserParent,
|
|||
|
||||
bool GetGlobalJSObject(JSContext* cx, JSObject** globalp);
|
||||
|
||||
void StartPersistence(uint64_t aOuterWindowID,
|
||||
void StartPersistence(CanonicalBrowsingContext* aContext,
|
||||
nsIWebBrowserPersistDocumentReceiver* aRecv,
|
||||
ErrorResult& aRv);
|
||||
|
||||
|
|
|
@ -2947,26 +2947,24 @@ bool ContentChild::DeallocPContentPermissionRequestChild(
|
|||
|
||||
PWebBrowserPersistDocumentChild*
|
||||
ContentChild::AllocPWebBrowserPersistDocumentChild(
|
||||
PBrowserChild* aBrowser, const uint64_t& aOuterWindowID) {
|
||||
PBrowserChild* aBrowser, const MaybeDiscarded<BrowsingContext>& aContext) {
|
||||
return new WebBrowserPersistDocumentChild();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvPWebBrowserPersistDocumentConstructor(
|
||||
PWebBrowserPersistDocumentChild* aActor, PBrowserChild* aBrowser,
|
||||
const uint64_t& aOuterWindowID) {
|
||||
const MaybeDiscarded<BrowsingContext>& aContext) {
|
||||
if (NS_WARN_IF(!aBrowser)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
nsCOMPtr<Document> rootDoc =
|
||||
static_cast<BrowserChild*>(aBrowser)->GetTopLevelDocument();
|
||||
nsCOMPtr<Document> foundDoc;
|
||||
if (aOuterWindowID) {
|
||||
foundDoc = nsContentUtils::GetSubdocumentWithOuterWindowId(rootDoc,
|
||||
aOuterWindowID);
|
||||
} else {
|
||||
foundDoc = rootDoc;
|
||||
|
||||
if (aContext.IsNullOrDiscarded()) {
|
||||
aActor->SendInitFailure(NS_ERROR_NO_CONTENT);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> foundDoc = aContext.get()->GetDocument();
|
||||
|
||||
if (!foundDoc) {
|
||||
aActor->SendInitFailure(NS_ERROR_NO_CONTENT);
|
||||
} else {
|
||||
|
|
|
@ -216,11 +216,11 @@ class ContentChild final
|
|||
const FileDescriptor& aGCLog, const FileDescriptor& aCCLog) override;
|
||||
|
||||
PWebBrowserPersistDocumentChild* AllocPWebBrowserPersistDocumentChild(
|
||||
PBrowserChild* aBrowser, const uint64_t& aOuterWindowID);
|
||||
PBrowserChild* aBrowser, const MaybeDiscarded<BrowsingContext>& aContext);
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvPWebBrowserPersistDocumentConstructor(
|
||||
PWebBrowserPersistDocumentChild* aActor, PBrowserChild* aBrowser,
|
||||
const uint64_t& aOuterWindowID) override;
|
||||
const MaybeDiscarded<BrowsingContext>& aContext) override;
|
||||
|
||||
bool DeallocPWebBrowserPersistDocumentChild(
|
||||
PWebBrowserPersistDocumentChild* aActor);
|
||||
|
|
|
@ -4539,7 +4539,7 @@ bool ContentParent::DeallocPContentPermissionRequestParent(
|
|||
|
||||
PWebBrowserPersistDocumentParent*
|
||||
ContentParent::AllocPWebBrowserPersistDocumentParent(
|
||||
PBrowserParent* aBrowser, const uint64_t& aOuterWindowID) {
|
||||
PBrowserParent* aBrowser, const MaybeDiscarded<BrowsingContext>& aContext) {
|
||||
return new WebBrowserPersistDocumentParent();
|
||||
}
|
||||
|
||||
|
|
|
@ -966,7 +966,8 @@ class ContentParent final
|
|||
#endif
|
||||
|
||||
PWebBrowserPersistDocumentParent* AllocPWebBrowserPersistDocumentParent(
|
||||
PBrowserParent* aBrowser, const uint64_t& aOuterWindowID);
|
||||
PBrowserParent* aBrowser,
|
||||
const MaybeDiscarded<BrowsingContext>& aContext);
|
||||
|
||||
bool DeallocPWebBrowserPersistDocumentParent(
|
||||
PWebBrowserPersistDocumentParent* aActor);
|
||||
|
|
|
@ -435,12 +435,12 @@ child:
|
|||
both:
|
||||
async PFileDescriptorSet(FileDescriptor fd);
|
||||
|
||||
// For parent->child, aBrowser must be non-null; aOuterWindowID can
|
||||
// be 0 to indicate the browser's current root document, or nonzero
|
||||
// For parent->child, aBrowser must be non-null; aContext can
|
||||
// be null to indicate the browser's current root document, or non-null
|
||||
// to persist a subdocument. For child->parent, arguments are
|
||||
// ignored and should be null/zero.
|
||||
// ignored and should be null.
|
||||
async PWebBrowserPersistDocument(nullable PBrowser aBrowser,
|
||||
uint64_t aOuterWindowID);
|
||||
MaybeDiscardedBrowsingContext aContext);
|
||||
|
||||
child:
|
||||
async InitGMPService(Endpoint<PGMPServiceChild> service);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
include protocol PWebBrowserPersistDocument;
|
||||
|
||||
using mozilla::dom::MaybeDiscardedBrowsingContext from "mozilla/dom/BrowsingContext.h";
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// == nsIWebBrowserPersistResourceVisitor
|
||||
|
@ -19,6 +21,8 @@ parent:
|
|||
// before exposing it with a visitDocument call.
|
||||
async VisitDocument(PWebBrowserPersistDocument aSubDocument);
|
||||
|
||||
async VisitBrowsingContext(MaybeDiscardedBrowsingContext aContext);
|
||||
|
||||
// This reflects the endVisit method.
|
||||
async __delete__(nsresult aStatus);
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "WebBrowserPersistDocumentParent.h"
|
||||
|
||||
#include "mozilla/dom/Attr.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/Comment.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLAnchorElement.h"
|
||||
|
@ -287,12 +288,17 @@ nsresult ResourceReader::OnWalkSubframe(nsINode* aNode) {
|
|||
RefPtr<nsFrameLoader> loader = loaderOwner->GetFrameLoader();
|
||||
NS_ENSURE_STATE(loader);
|
||||
|
||||
RefPtr<dom::BrowsingContext> context = loader->GetBrowsingContext();
|
||||
NS_ENSURE_STATE(context);
|
||||
|
||||
if (loader->IsRemoteFrame()) {
|
||||
mVisitor->VisitBrowsingContext(mParent, context);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
++mOutstandingDocuments;
|
||||
// Pass in 0 as the outer window ID so that we start
|
||||
// persisting the root of this subframe, and not some other
|
||||
// subframe child of this subframe.
|
||||
ErrorResult err;
|
||||
loader->StartPersistence(0, this, err);
|
||||
loader->StartPersistence(context, this, err);
|
||||
nsresult rv = err.StealNSResult();
|
||||
if (NS_FAILED(rv)) {
|
||||
if (rv == NS_ERROR_NO_CONTENT) {
|
||||
|
|
|
@ -38,7 +38,7 @@ WebBrowserPersistResourcesChild::VisitDocument(
|
|||
// persistence started does not necessarily exist at this point;
|
||||
// see bug 1203602.
|
||||
if (!Manager()->Manager()->SendPWebBrowserPersistDocumentConstructor(
|
||||
subActor, nullptr, 0)) {
|
||||
subActor, nullptr, nullptr)) {
|
||||
// NOTE: subActor is freed at this point.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -57,6 +57,14 @@ WebBrowserPersistResourcesChild::VisitDocument(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebBrowserPersistResourcesChild::VisitBrowsingContext(
|
||||
nsIWebBrowserPersistDocument* aDocument,
|
||||
dom::BrowsingContext* aBrowsingContext) {
|
||||
SendVisitBrowsingContext(aBrowsingContext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebBrowserPersistResourcesChild::EndVisit(
|
||||
nsIWebBrowserPersistDocument* aDocument, nsresult aStatus) {
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_ISUPPORTS(WebBrowserPersistResourcesParent,
|
||||
|
@ -58,6 +63,18 @@ mozilla::ipc::IPCResult WebBrowserPersistResourcesParent::RecvVisitDocument(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
WebBrowserPersistResourcesParent::RecvVisitBrowsingContext(
|
||||
const dom::MaybeDiscarded<dom::BrowsingContext>& aContext) {
|
||||
if (aContext.IsNullOrDiscarded()) {
|
||||
// Nothing useful to do but ignore the discarded context.
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mVisitor->VisitBrowsingContext(mDocument, aContext.get());
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebBrowserPersistResourcesParent::OnDocumentReady(
|
||||
nsIWebBrowserPersistDocument* aSubDocument) {
|
||||
|
|
|
@ -30,6 +30,9 @@ class WebBrowserPersistResourcesParent final
|
|||
virtual mozilla::ipc::IPCResult RecvVisitDocument(
|
||||
PWebBrowserPersistDocumentParent* aSubDocument) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvVisitBrowsingContext(
|
||||
const dom::MaybeDiscarded<dom::BrowsingContext>& aContext) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult Recv__delete__(
|
||||
const nsresult& aStatus) override;
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ interface nsIWebBrowserPersistWriteCompletion;
|
|||
interface nsIReferrerInfo;
|
||||
interface nsISHEntry;
|
||||
|
||||
webidl BrowsingContext;
|
||||
|
||||
native SHEntryRef(already_AddRefed<nsISHEntry>);
|
||||
|
||||
/**
|
||||
|
@ -147,6 +149,7 @@ interface nsIWebBrowserPersistResourceVisitor : nsISupports
|
|||
void visitResource(in nsIWebBrowserPersistDocument aDocument,
|
||||
in AUTF8String aURI,
|
||||
in nsContentPolicyType aContentPolicyType);
|
||||
|
||||
/**
|
||||
* Indicates a subdocument resource; e.g., a frame or iframe.
|
||||
*
|
||||
|
@ -156,6 +159,16 @@ interface nsIWebBrowserPersistResourceVisitor : nsISupports
|
|||
void visitDocument(in nsIWebBrowserPersistDocument aDocument,
|
||||
in nsIWebBrowserPersistDocument aSubDocument);
|
||||
|
||||
/**
|
||||
* Indicates a cross origin subdocument resource; e.g., a frame
|
||||
* or iframe loaded in another process.
|
||||
*
|
||||
* @param aDocument The document containing the reference.
|
||||
* @param aContext The referenced document's browsing context.
|
||||
*/
|
||||
void visitBrowsingContext(in nsIWebBrowserPersistDocument aDocument,
|
||||
in BrowsingContext aContext);
|
||||
|
||||
/**
|
||||
* Indicates that the document traversal is complete.
|
||||
*
|
||||
|
|
|
@ -139,7 +139,11 @@ class nsWebBrowserPersist::OnWalk final
|
|||
: public nsIWebBrowserPersistResourceVisitor {
|
||||
public:
|
||||
OnWalk(nsWebBrowserPersist* aParent, nsIURI* aFile, nsIFile* aDataPath)
|
||||
: mParent(aParent), mFile(aFile), mDataPath(aDataPath) {}
|
||||
: mParent(aParent),
|
||||
mFile(aFile),
|
||||
mDataPath(aDataPath),
|
||||
mPendingDocuments(1),
|
||||
mStatus(NS_OK) {}
|
||||
|
||||
NS_DECL_NSIWEBBROWSERPERSISTRESOURCEVISITOR
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -148,12 +152,34 @@ class nsWebBrowserPersist::OnWalk final
|
|||
nsCOMPtr<nsIURI> mFile;
|
||||
nsCOMPtr<nsIFile> mDataPath;
|
||||
|
||||
uint32_t mPendingDocuments;
|
||||
nsresult mStatus;
|
||||
|
||||
virtual ~OnWalk() = default;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsWebBrowserPersist::OnWalk,
|
||||
nsIWebBrowserPersistResourceVisitor)
|
||||
|
||||
class nsWebBrowserPersist::OnRemoteWalk final
|
||||
: public nsIWebBrowserPersistDocumentReceiver {
|
||||
public:
|
||||
OnRemoteWalk(nsIWebBrowserPersistResourceVisitor* aVisitor,
|
||||
nsIWebBrowserPersistDocument* aDocument)
|
||||
: mVisitor(aVisitor), mDocument(aDocument) {}
|
||||
|
||||
NS_DECL_NSIWEBBROWSERPERSISTDOCUMENTRECEIVER
|
||||
NS_DECL_ISUPPORTS
|
||||
private:
|
||||
nsCOMPtr<nsIWebBrowserPersistResourceVisitor> mVisitor;
|
||||
nsCOMPtr<nsIWebBrowserPersistDocument> mDocument;
|
||||
|
||||
virtual ~OnRemoteWalk() = default;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsWebBrowserPersist::OnRemoteWalk,
|
||||
nsIWebBrowserPersistDocumentReceiver)
|
||||
|
||||
class nsWebBrowserPersist::OnWrite final
|
||||
: public nsIWebBrowserPersistWriteCompletion {
|
||||
public:
|
||||
|
@ -1568,18 +1594,73 @@ nsWebBrowserPersist::OnWalk::VisitDocument(
|
|||
return mParent->SaveSubframeContent(aSubDoc, aDoc, uriSpec, data);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWebBrowserPersist::OnWalk::VisitBrowsingContext(
|
||||
nsIWebBrowserPersistDocument* aDoc, BrowsingContext* aContext) {
|
||||
RefPtr<dom::CanonicalBrowsingContext> context = aContext->Canonical();
|
||||
|
||||
UniquePtr<WebBrowserPersistDocumentParent> actor(
|
||||
new WebBrowserPersistDocumentParent());
|
||||
|
||||
nsCOMPtr<nsIWebBrowserPersistDocumentReceiver> receiver =
|
||||
new OnRemoteWalk(this, aDoc);
|
||||
actor->SetOnReady(receiver);
|
||||
|
||||
RefPtr<dom::BrowserParent> browserParent =
|
||||
context->GetCurrentWindowGlobal()->GetBrowserParent();
|
||||
|
||||
bool ok =
|
||||
context->GetContentParent()->SendPWebBrowserPersistDocumentConstructor(
|
||||
actor.release(), browserParent, context);
|
||||
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
// (The actor will be destroyed on constructor failure.)
|
||||
EndVisit(nullptr, NS_ERROR_FAILURE);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
++mPendingDocuments;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWebBrowserPersist::OnWalk::EndVisit(nsIWebBrowserPersistDocument* aDoc,
|
||||
nsresult aStatus) {
|
||||
if (NS_FAILED(mStatus)) {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
if (NS_FAILED(aStatus)) {
|
||||
mStatus = aStatus;
|
||||
mParent->SendErrorStatusChange(true, aStatus, nullptr, mFile);
|
||||
mParent->EndDownload(aStatus);
|
||||
return aStatus;
|
||||
}
|
||||
|
||||
if (--mPendingDocuments) {
|
||||
// We're not done yet, wait for more.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mParent->FinishSaveDocumentInternal(mFile, mDataPath);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWebBrowserPersist::OnRemoteWalk::OnDocumentReady(
|
||||
nsIWebBrowserPersistDocument* aSubDocument) {
|
||||
mVisitor->VisitDocument(mDocument, aSubDocument);
|
||||
mVisitor->EndVisit(mDocument, NS_OK);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWebBrowserPersist::OnRemoteWalk::OnError(nsresult aFailure) {
|
||||
mVisitor->EndVisit(nullptr, aFailure);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsWebBrowserPersist::FinishSaveDocumentInternal(nsIURI* aFile,
|
||||
nsIFile* aDataPath) {
|
||||
// If there are things to persist, create a directory to hold them
|
||||
|
|
|
@ -74,6 +74,7 @@ class nsWebBrowserPersist final : public nsIInterfaceRequestor,
|
|||
struct WalkData;
|
||||
|
||||
class OnWalk;
|
||||
class OnRemoteWalk;
|
||||
class OnWrite;
|
||||
class FlatURIMap;
|
||||
friend class OnWalk;
|
||||
|
|
|
@ -540,7 +540,6 @@ WEBIDL_FILES = [
|
|||
'FontFaceSet.webidl',
|
||||
'FontFaceSource.webidl',
|
||||
'FormData.webidl',
|
||||
'FrameLoader.webidl',
|
||||
'Function.webidl',
|
||||
'GainNode.webidl',
|
||||
'Gamepad.webidl',
|
||||
|
|
|
@ -13,7 +13,7 @@ function one_test(delay, continuation) {
|
|||
BrowserTestUtils.openNewForegroundTab(gBrowser, testPageURL).then(tab => {
|
||||
browser = tab.linkedBrowser;
|
||||
let persistable = browser.frameLoader;
|
||||
persistable.startPersistence(/* outer window ID: */ 0, {
|
||||
persistable.startPersistence(null, {
|
||||
onDocumentReady,
|
||||
onError(status) {
|
||||
ok(false, new Components.Exception("startPersistence failed", status));
|
||||
|
|
|
@ -22,7 +22,7 @@ add_task(async function checkFormStateSaved() {
|
|||
await SpecialPowers.spawn(browser, [{ textareas, textboxes }], fillform);
|
||||
let fileURISpec = await new Promise((resolve, reject) => {
|
||||
let stack = Components.stack.caller;
|
||||
browser.frameLoader.startPersistence(0, {
|
||||
browser.frameLoader.startPersistence(null, {
|
||||
onDocumentReady(document) {
|
||||
// Note that 'document' here is going to be an nsIWebBrowserPersistDocument,
|
||||
// not a regular DOM document.
|
||||
|
|
|
@ -84,7 +84,7 @@ function saveURL(
|
|||
|
||||
// Save the current document inside any browser/frame-like element,
|
||||
// whether in-process or out-of-process.
|
||||
function saveBrowser(aBrowser, aSkipPrompt, aOuterWindowID = 0) {
|
||||
function saveBrowser(aBrowser, aSkipPrompt, aBrowsingContext = null) {
|
||||
if (!aBrowser) {
|
||||
throw new Error("Must have a browser when calling saveBrowser");
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ function saveBrowser(aBrowser, aSkipPrompt, aOuterWindowID = 0) {
|
|||
return;
|
||||
}
|
||||
let stack = Components.stack.caller;
|
||||
persistable.startPersistence(aOuterWindowID, {
|
||||
persistable.startPersistence(aBrowsingContext, {
|
||||
onDocumentReady(document) {
|
||||
if (!document || !(document instanceof Ci.nsIWebBrowserPersistDocument)) {
|
||||
throw new Error("Must have an nsIWebBrowserPersistDocument!");
|
||||
|
|
Загрузка…
Ссылка в новой задаче