Bug 1480198 - Construct nsDocShell objects inside BrowsingContext. r=peterv

Differential Revision: https://phabricator.services.mozilla.com/D7400

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andreas Farre 2018-11-05 12:43:10 +00:00
Родитель a35bbfce87
Коммит 89cb220346
17 изменённых файлов: 408 добавлений и 300 удалений

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

@ -9,14 +9,15 @@
#include "mozilla/dom/ChromeBrowsingContext.h"
#include "mozilla/dom/BrowsingContextBinding.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/Assertions.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Logging.h"
#include "mozilla/StaticPtr.h"
#include "nsDataHashtable.h"
#include "nsDocShell.h"
#include "nsRefPtrHashtable.h"
#include "nsIDocShell.h"
#include "nsContentUtils.h"
#include "nsThreadUtils.h"
@ -35,6 +36,31 @@ static StaticAutoPtr<nsDataHashtable<nsUint64HashKey, BrowsingContext*>>
static StaticAutoPtr<nsRefPtrHashtable<nsUint64HashKey, BrowsingContext>>
sCachedBrowsingContexts;
static void
Register(BrowsingContext* aBrowsingContext)
{
auto entry = sBrowsingContexts->LookupForAdd(aBrowsingContext->Id());
MOZ_RELEASE_ASSERT(!entry, "Duplicate BrowsingContext ID");
entry.OrInsert([&] { return aBrowsingContext; });
}
static void
Sync(BrowsingContext* aBrowsingContext)
{
if (!XRE_IsContentProcess()) {
return;
}
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
nsAutoString name;
aBrowsingContext->GetName(name);
RefPtr<BrowsingContext> parent = aBrowsingContext->GetParent();
cc->SendAttachBrowsingContext(BrowsingContextId(parent ? parent->Id() : 0),
BrowsingContextId(aBrowsingContext->Id()),
name);
}
/* static */ void
BrowsingContext::Init()
{
@ -70,38 +96,86 @@ BrowsingContext::Get(uint64_t aId)
}
/* static */ already_AddRefed<BrowsingContext>
BrowsingContext::Create(nsIDocShell* aDocShell)
BrowsingContext::Create(BrowsingContext* aParent,
const nsAString& aName,
Type aType)
{
MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->mType == aType);
uint64_t id = nsContentUtils::GenerateBrowsingContextId();
MOZ_LOG(GetLog(),
LogLevel::Debug,
("Creating 0x%08" PRIx64 " in %s",
id,
XRE_IsParentProcess() ? "Parent" : "Child"));
RefPtr<BrowsingContext> context;
if (XRE_IsParentProcess()) {
context = new ChromeBrowsingContext(aDocShell);
context = new ChromeBrowsingContext(aParent, aName, id, /* aProcessId */ 0, aType);
} else {
// TODO(farre): will we ever create BrowsingContexts on processes
// other than content and parent?
MOZ_ASSERT(XRE_IsContentProcess());
context = new BrowsingContext(aDocShell);
context = new BrowsingContext(aParent, aName, id, aType);
}
Register(context);
// Attach the browsing context to the tree.
context->Attach();
return context.forget();
}
BrowsingContext::BrowsingContext(nsIDocShell* aDocShell)
: mBrowsingContextId(nsContentUtils::GenerateBrowsingContextId())
, mDocShell(aDocShell)
/* static */ already_AddRefed<BrowsingContext>
BrowsingContext::CreateFromIPC(BrowsingContext* aParent, const nsAString& aName,
uint64_t aId, ContentParent* aOriginProcess)
{
sBrowsingContexts->Put(mBrowsingContextId, this);
MOZ_DIAGNOSTIC_ASSERT(aOriginProcess || XRE_IsContentProcess(),
"Parent Process IPC contexts need a Content Process.");
MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->IsContent());
MOZ_LOG(GetLog(),
LogLevel::Debug,
("Creating 0x%08" PRIx64 " from IPC (origin=0x%08" PRIx64 ")",
aId, aOriginProcess ? uint64_t(aOriginProcess->ChildID()) : 0));
RefPtr<BrowsingContext> context;
if (XRE_IsParentProcess()) {
context = new ChromeBrowsingContext(
aParent, aName, aId, aOriginProcess->ChildID(), Type::Content);
} else {
context = new BrowsingContext(aParent, aName, aId, Type::Content);
}
Register(context);
context->Attach();
return context.forget();
}
BrowsingContext::BrowsingContext(uint64_t aBrowsingContextId,
const nsAString& aName)
: mBrowsingContextId(aBrowsingContextId)
BrowsingContext::BrowsingContext(BrowsingContext* aParent,
const nsAString& aName,
uint64_t aBrowsingContextId,
Type aType)
: mType(aType)
, mBrowsingContextId(aBrowsingContextId)
, mParent(aParent)
, mName(aName)
{
sBrowsingContexts->Put(mBrowsingContextId, this);
}
void
BrowsingContext::Attach(BrowsingContext* aParent)
BrowsingContext::SetDocShell(nsIDocShell* aDocShell)
{
// XXX(nika): We should communicate that we are now an active BrowsingContext
// process to the parent & do other validation here.
MOZ_RELEASE_ASSERT(nsDocShell::Cast(aDocShell)->GetBrowsingContext() == this);
mDocShell = aDocShell;
}
void
BrowsingContext::Attach()
{
if (isInList()) {
MOZ_LOG(GetLog(),
@ -109,7 +183,7 @@ BrowsingContext::Attach(BrowsingContext* aParent)
("%s: Connecting already existing 0x%08" PRIx64 " to 0x%08" PRIx64,
XRE_IsParentProcess() ? "Parent" : "Child",
Id(),
aParent ? aParent->Id() : 0));
mParent ? mParent->Id() : 0));
MOZ_DIAGNOSTIC_ASSERT(sBrowsingContexts->Contains(Id()));
MOZ_DIAGNOSTIC_ASSERT(!IsCached());
return;
@ -123,22 +197,12 @@ BrowsingContext::Attach(BrowsingContext* aParent)
XRE_IsParentProcess() ? "Parent" : "Child",
wasCached ? "Re-connecting" : "Connecting",
Id(),
aParent ? aParent->Id() : 0));
mParent ? mParent->Id() : 0));
auto* children = aParent ? &aParent->mChildren : sRootBrowsingContexts.get();
auto* children = mParent ? &mParent->mChildren : sRootBrowsingContexts.get();
children->insertBack(this);
mParent = aParent;
if (!XRE_IsContentProcess()) {
return;
}
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendAttachBrowsingContext(
BrowsingContextId(mParent ? mParent->Id() : 0),
BrowsingContextId(Id()),
mName);
Sync(this);
}
void

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

@ -25,6 +25,8 @@ class LogModule;
namespace dom {
class ContentParent;
// BrowsingContext, in this context, is the cross process replicated
// environment in which information about documents is stored. In
// particular the tree structure of nested browsing contexts is
@ -37,23 +39,51 @@ namespace dom {
// to the parent process, making it possible to traverse the
// BrowsingContext tree for a tab, in both the parent and the child
// process.
//
// Trees of BrowsingContexts should only ever contain nodes of the
// same BrowsingContext::Type. This is enforced by asserts in the
// BrowsingContext::Create* methods.
class BrowsingContext
: public nsWrapperCache
, public SupportsWeakPtr<BrowsingContext>
, public LinkedListElement<RefPtr<BrowsingContext>>
{
public:
enum class Type
{
Chrome,
Content
};
static void Init();
static LogModule* GetLog();
static void CleanupContexts(uint64_t aProcessId);
// Look up a BrowsingContext in the current process by ID.
static already_AddRefed<BrowsingContext> Get(uint64_t aId);
static already_AddRefed<BrowsingContext> Create(nsIDocShell* aDocShell);
// Attach the current BrowsingContext to its parent, in both the
// child and the parent process. If 'aParent' is null, 'this' is
// taken to be a root BrowsingContext.
void Attach(BrowsingContext* aParent);
// Create a brand-new BrowsingContext object.
static already_AddRefed<BrowsingContext> Create(BrowsingContext* aParent,
const nsAString& aName,
Type aType);
// Create a BrowsingContext object from over IPC.
static already_AddRefed<BrowsingContext> CreateFromIPC(
BrowsingContext* aParent,
const nsAString& aName,
uint64_t aId,
ContentParent* aOriginProcess);
// Get the DocShell for this BrowsingContext if it is in-process, or
// null if it's not.
nsIDocShell* GetDocShell() { return mDocShell; }
void SetDocShell(nsIDocShell* aDocShell);
// Attach the current BrowsingContext to its parent, in both the child and the
// parent process. BrowsingContext objects are created attached by default, so
// this method need only be called when restoring cached BrowsingContext
// objects.
void Attach();
// Detach the current BrowsingContext from its parent, in both the
// child and the parent process.
@ -63,27 +93,24 @@ public:
// them to allow them to be attached again.
void CacheChildren();
// Determine if the current BrowsingContext was 'cached' by the logic in
// CacheChildren.
bool IsCached();
// TODO(farre): We should sync changes from SetName to the parent
// process. [Bug 1490303]
void SetName(const nsAString& aName) { mName = aName; }
void GetName(nsAString& aName) { aName = mName; }
bool NameEquals(const nsAString& aName) { return mName.Equals(aName); }
uint64_t Id() const { return mBrowsingContextId; }
uint64_t OwnerProcessId() const;
bool IsContent() const { return mType == Type::Content; }
already_AddRefed<BrowsingContext> GetParent()
{
return do_AddRef(mParent.get());
}
uint64_t Id() const { return mBrowsingContextId; }
BrowsingContext* GetParent() { return mParent; }
void GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren);
already_AddRefed<nsIDocShell> GetDocShell()
{
return do_AddRef(mDocShell.get());
}
static void GetRootBrowsingContexts(
nsTArray<RefPtr<BrowsingContext>>& aBrowsingContexts);
@ -99,16 +126,19 @@ public:
protected:
virtual ~BrowsingContext();
// Create a new BrowsingContext for 'aDocShell'. The id will be
// generated so that it is unique across all content child processes
// and the content parent process.
explicit BrowsingContext(nsIDocShell* aDocShell);
BrowsingContext(uint64_t aBrowsingContextId,
const nsAString& aName);
BrowsingContext(BrowsingContext* aParent,
const nsAString& aName,
uint64_t aBrowsingContextId,
Type aType);
private:
// Type of BrowsingContent
const Type mType;
// Unique id identifying BrowsingContext
const uint64_t mBrowsingContextId;
WeakPtr<BrowsingContext> mParent;
Children mChildren;
nsCOMPtr<nsIDocShell> mDocShell;

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

@ -6,13 +6,17 @@
#include "ChromeBrowsingContext.h"
#include "mozilla/dom/ContentParent.h"
namespace mozilla {
namespace dom {
ChromeBrowsingContext::ChromeBrowsingContext(uint64_t aBrowsingContextId,
ChromeBrowsingContext::ChromeBrowsingContext(BrowsingContext* aParent,
const nsAString& aName,
uint64_t aProcessId)
: BrowsingContext(aBrowsingContextId, aName)
uint64_t aBrowsingContextId,
uint64_t aProcessId,
BrowsingContext::Type aType)
: BrowsingContext(aParent, aName, aBrowsingContextId, aType)
, mProcessId(aProcessId)
{
// You are only ever allowed to create ChromeBrowsingContexts in the
@ -20,15 +24,6 @@ ChromeBrowsingContext::ChromeBrowsingContext(uint64_t aBrowsingContextId,
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
}
ChromeBrowsingContext::ChromeBrowsingContext(nsIDocShell* aDocShell)
: BrowsingContext(aDocShell)
, mProcessId(0)
{
// You are only ever allowed to create ChromeBrowsingContexts in the
// parent process.
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
}
// TODO(farre): ChromeBrowsingContext::CleanupContexts starts from the
// list of root BrowsingContexts. This isn't enough when separate
// BrowsingContext nodes of a BrowsingContext tree, not in a crashing
@ -61,13 +56,11 @@ ChromeBrowsingContext::Cast(BrowsingContext* aContext)
return static_cast<ChromeBrowsingContext*>(aContext);
}
/* static */ already_AddRefed<ChromeBrowsingContext>
ChromeBrowsingContext::Create(
uint64_t aBrowsingContextId,
const nsAString& aName,
uint64_t aProcessId)
/* static */ const ChromeBrowsingContext*
ChromeBrowsingContext::Cast(const BrowsingContext* aContext)
{
return do_AddRef(new ChromeBrowsingContext(aBrowsingContextId, aName, aProcessId));
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
return static_cast<const ChromeBrowsingContext*>(aContext);
}
} // namespace dom

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

@ -27,10 +27,7 @@ public:
static void CleanupContexts(uint64_t aProcessId);
static already_AddRefed<ChromeBrowsingContext> Get(uint64_t aId);
static ChromeBrowsingContext* Cast(BrowsingContext* aContext);
static already_AddRefed<ChromeBrowsingContext> Create(
uint64_t aBrowsingContextId,
const nsAString& aName,
uint64_t aProcessId);
static const ChromeBrowsingContext* Cast(const BrowsingContext* aContext);
bool IsOwnedByProcess(uint64_t aProcessId) const
{
@ -40,15 +37,18 @@ public:
protected:
void Traverse(nsCycleCollectionTraversalCallback& cb) {}
void Unlink() {}
ChromeBrowsingContext(uint64_t aBrowsingContextId,
using Type = BrowsingContext::Type;
ChromeBrowsingContext(BrowsingContext* aParent,
const nsAString& aName,
uint64_t aProcessId);
uint64_t aBrowsingContextId,
uint64_t aProcessId,
Type aType = Type::Chrome);
private:
friend class BrowsingContext;
explicit ChromeBrowsingContext(nsIDocShell* aDocShell);
// XXX(farre): Store a ContentParent pointer here rather than mProcessId?
// Indicates which process owns the docshell.
uint64_t mProcessId;
};

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

@ -449,44 +449,70 @@ nsDocShell::~nsDocShell()
#endif
}
nsresult
nsDocShell::Init()
/* static */ already_AddRefed<nsDocShell>
nsDocShell::Create(BrowsingContext* aBrowsingContext)
{
MOZ_ASSERT(!mIsBeingDestroyed);
MOZ_ASSERT(aBrowsingContext, "DocShell without a BrowsingContext!");
nsresult rv = nsDocLoader::Init();
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv;
RefPtr<nsDocShell> ds = new nsDocShell();
ds->mBrowsingContext = aBrowsingContext;
NS_ASSERTION(mLoadGroup, "Something went wrong!");
// Initialize the underlying nsDocLoader.
rv = ds->nsDocLoader::Init();
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
mContentListener = new nsDSURIContentListener(this);
rv = mContentListener->Init();
NS_ENSURE_SUCCESS(rv, rv);
// Create our ContentListener
ds->mContentListener = new nsDSURIContentListener(ds);
rv = ds->mContentListener->Init();
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
// If parent intercept is not enabled then we must forward to
// the network controller from docshell. We also enable if we're
// in the parent process in order to support non-e10s configurations.
if (!ServiceWorkerParentInterceptEnabled() || XRE_IsParentProcess()) {
mInterceptController = new ServiceWorkerInterceptController();
ds->mInterceptController = new ServiceWorkerInterceptController();
}
// We want to hold a strong ref to the loadgroup, so it better hold a weak
// ref to us... use an InterfaceRequestorProxy to do this.
nsCOMPtr<nsIInterfaceRequestor> proxy =
new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>(this));
mLoadGroup->SetNotificationCallbacks(proxy);
nsCOMPtr<nsIInterfaceRequestor> proxy = new InterfaceRequestorProxy(ds);
ds->mLoadGroup->SetNotificationCallbacks(proxy);
rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
NS_ENSURE_SUCCESS(rv, rv);
// XXX(nika): We have our BrowsingContext, so we might be able to skip this.
// It could be nice to directly set up our DocLoader tree?
rv = nsDocLoader::AddDocLoaderAsChildOfRoot(ds);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
mBrowsingContext = BrowsingContext::Create(this);
// Add |ds| as a progress listener to itself. A little weird, but simpler
// than reproducing all the listener-notification logic in overrides of the
// various methods via which nsDocLoader can be notified. Note that this
// holds an nsWeakPtr to |ds|, so it's ok.
rv = ds->AddProgressListener(ds,
nsIWebProgress::NOTIFY_STATE_DOCUMENT |
nsIWebProgress::NOTIFY_STATE_NETWORK);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
// Add as |this| a progress listener to itself. A little weird, but
// simpler than reproducing all the listener-notification logic in
// overrides of the various methods via which nsDocLoader can be
// notified. Note that this holds an nsWeakPtr to ourselves, so it's ok.
return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
nsIWebProgress::NOTIFY_STATE_NETWORK);
// Set our DocShellTreeItem type based on our BrowsingContext
ds->SetItemType(aBrowsingContext->IsContent() ? typeContent : typeChrome);
// If our parent is present in this process, set up our parent now.
RefPtr<BrowsingContext> parent = aBrowsingContext->GetParent();
if (parent && parent->GetDocShell()) {
parent->GetDocShell()->AddChild(ds);
}
// Make |ds| the primary DocShell for the given context.
aBrowsingContext->SetDocShell(ds);
return ds.forget();
}
void
@ -3501,8 +3527,6 @@ nsDocShell::AddChild(nsIDocShellTreeItem* aChild)
return NS_OK;
}
childAsDocShell->AttachBrowsingContext(this);
// charset, style-disabling, and zoom will be inherited in SetupNewViewer()
// Now take this document's charset and set the child's parentCharset field
@ -3565,11 +3589,6 @@ nsDocShell::RemoveChild(nsIDocShellTreeItem* aChild)
nsresult rv = RemoveChildLoader(childAsDocLoader);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
if (childAsDocShell) {
childAsDocShell->DetachBrowsingContext();
}
aChild->SetTreeOwner(nullptr);
return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
@ -7784,6 +7803,14 @@ nsDocShell::BeginRestore(nsIContentViewer* aContentViewer, bool aTop)
}
}
// When re-attaching browsing context, a mozbrowser docshell will be
// considered as top level, but its browsing context will have a
// parent.
MOZ_DIAGNOSTIC_ASSERT(
(aTop && !mBrowsingContext->GetParent()) ||
((!aTop || GetIsMozBrowser()) && mBrowsingContext->GetParent()));
mBrowsingContext->Attach();
if (!aTop) {
// This point corresponds to us having gotten OnStartRequest or
// STATE_START, so do the same thing that CreateContentViewer does at
@ -14093,11 +14120,10 @@ nsDocShell::IsForceReloading()
return IsForceReloadType(mLoadType);
}
already_AddRefed<BrowsingContext>
BrowsingContext*
nsDocShell::GetBrowsingContext() const
{
RefPtr<BrowsingContext> browsingContext = mBrowsingContext;
return browsingContext.forget();
return mBrowsingContext;
}
NS_IMETHODIMP
@ -14106,24 +14132,3 @@ nsDocShell::GetBrowsingContext(BrowsingContext** aBrowsingContext)
*aBrowsingContext = do_AddRef(mBrowsingContext).take();
return NS_OK;
}
void
nsIDocShell::AttachBrowsingContext(nsIDocShell* aParentDocShell)
{
RefPtr<BrowsingContext> childContext =
nsDocShell::Cast(this)->GetBrowsingContext();
RefPtr<BrowsingContext> parentContext;
if (aParentDocShell) {
parentContext =
nsDocShell::Cast(aParentDocShell)->GetBrowsingContext();
}
childContext->Attach(parentContext);
}
void
nsIDocShell::DetachBrowsingContext()
{
RefPtr<BrowsingContext> browsingContext =
nsDocShell::Cast(this)->GetBrowsingContext();
browsingContext->Detach();
}

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

@ -182,8 +182,9 @@ public:
// nsIWebProgressListener has methods with identical names...
NS_FORWARD_NSISECURITYEVENTSINK(nsDocLoader::)
nsDocShell();
virtual nsresult Init() override;
// Create a new nsDocShell object, initializing it.
static already_AddRefed<nsDocShell>
Create(mozilla::dom::BrowsingContext* aBrowsingContext);
NS_IMETHOD Stop() override
{
@ -380,13 +381,16 @@ public:
// shift while triggering reload)
bool IsForceReloading();
already_AddRefed<mozilla::dom::BrowsingContext>
GetBrowsingContext() const;
/**
* Native getter for a DocShell's BrowsingContext.
*/
mozilla::dom::BrowsingContext* GetBrowsingContext() const;
private: // member functions
friend class nsDSURIContentListener;
friend class FramingChecker;
friend class OnLinkClickEvent;
friend class nsIDocShell;
// It is necessary to allow adding a timeline marker wherever a docshell
// instance is available. This operation happens frequently and needs to
@ -405,6 +409,8 @@ private: // member functions
friend void mozilla::TimelineConsumers::PopMarkers(nsDocShell*,
JSContext*, nsTArray<dom::ProfileTimelineMarker>&);
nsDocShell();
// Security checks to prevent frameset spoofing. See comments at
// implementation sites.
static bool CanAccessItem(nsIDocShellTreeItem* aTargetItem,

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

@ -1232,9 +1232,6 @@ interface nsIDocShell : nsIDocShellTreeItem
*/
mozilla::HTMLEditor* GetHTMLEditor();
nsresult SetHTMLEditor(mozilla::HTMLEditor* aHTMLEditor);
void AttachBrowsingContext(nsIDocShell* aParentDocShell);
void DetachBrowsingContext();
%}
/**

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

@ -14,17 +14,6 @@
*/
#define NS_WEBNAVIGATION_INFO_CONTRACTID "@mozilla.org/webnavigation-info;1"
/**
* Class and contract ID for the docshell. This is the container for a web
* navigation context. It implements too many interfaces to count, and the
* exact ones keep changing; if they stabilize somewhat that will get
* documented.
*/
#define NS_DOCSHELL_CID \
{ 0xf1eac762, 0x87e9, 0x11d3, \
{ 0xaf, 0x80, 0x00, 0xa0, 0x24, 0xff, 0xc0, 0x8c } }
#define NS_DOCSHELL_CONTRACTID "@mozilla.org/docshell/html;1"
/**
* Contract ID to obtain the IHistory interface. This is a non-scriptable
* interface used to interact with history in an asynchronous manner.

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

@ -66,8 +66,6 @@ Shutdown()
gInitialized = false;
}
// docshell
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDocShell, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDefaultURIFixup)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWebNavigationInfo, Init)
@ -94,7 +92,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsOSPermissionRequest)
// session history
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSHEntry)
NS_DEFINE_NAMED_CID(NS_DOCSHELL_CID);
NS_DEFINE_NAMED_CID(NS_DEFAULTURIFIXUP_CID);
NS_DEFINE_NAMED_CID(NS_WEBNAVIGATION_INFO_CID);
NS_DEFINE_NAMED_CID(NS_ABOUT_REDIRECTOR_MODULE_CID);
@ -117,7 +114,6 @@ NS_DEFINE_NAMED_CID(NS_CONTENTHANDLERSERVICE_CID);
const mozilla::Module::CIDEntry kDocShellCIDs[] = {
// clang-format off
{ &kNS_DOCSHELL_CID, false, nullptr, nsDocShellConstructor },
{ &kNS_DEFAULTURIFIXUP_CID, false, nullptr, nsDefaultURIFixupConstructor },
{ &kNS_WEBNAVIGATION_INFO_CID, false, nullptr, nsWebNavigationInfoConstructor },
{ &kNS_ABOUT_REDIRECTOR_MODULE_CID, false, nullptr, nsAboutRedirector::Create },
@ -144,7 +140,6 @@ const mozilla::Module::CIDEntry kDocShellCIDs[] = {
const mozilla::Module::ContractIDEntry kDocShellContracts[] = {
// clang-format off
{ "@mozilla.org/docshell;1", &kNS_DOCSHELL_CID },
{ NS_URIFIXUP_CONTRACTID, &kNS_DEFAULTURIFIXUP_CID },
{ NS_WEBNAVIGATION_INFO_CONTRACTID, &kNS_WEBNAVIGATION_INFO_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "about", &kNS_ABOUT_REDIRECTOR_MODULE_CID },

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

@ -1,6 +1,7 @@
function destroy_transient_docshell() {
var docshell = Cc["@mozilla.org/docshell;1"].createInstance(Ci.nsIDocShell);
docshell.setOriginAttributes({privateBrowsingId : 1});
let windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
windowlessBrowser.docshell.setOriginAttributes({privateBrowsingId : 1});
windowlessBrowser.close();
do_test_pending();
do_timeout(0, Cu.forceGC);
}

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

@ -1,5 +1,7 @@
var gNotifications = 0;
ChromeUtils.import("resource://gre/modules/Services.jsm");
var observer = {
QueryInterface: function(iid) {
if (Ci.nsIPrivacyTransitionObserver.equals(iid) ||
@ -8,16 +10,17 @@ var observer = {
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
privateModeChanged: function(enabled) {
gNotifications++;
}
}
function run_test() {
var docshell = Cc["@mozilla.org/docshell;1"].createInstance(Ci.nsIDocShell);
docshell.addWeakPrivacyTransitionObserver(observer);
docshell.setOriginAttributes({ privateBrowsingId : 1 });
docshell.setOriginAttributes({ privateBrowsingId : 0 });
let windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
windowlessBrowser.docShell.addWeakPrivacyTransitionObserver(observer);
windowlessBrowser.docShell.setOriginAttributes({privateBrowsingId : 1});
windowlessBrowser.docShell.setOriginAttributes({privateBrowsingId : 0});
windowlessBrowser.close();
Assert.equal(gNotifications, 2);
}
}

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

@ -562,61 +562,49 @@ SetTreeOwnerAndChromeEventHandlerOnDocshellTree(nsIDocShellTreeItem* aItem,
}
}
static bool
CheckDocShellType(mozilla::dom::Element* aOwnerContent,
nsIDocShellTreeItem* aDocShell,
nsAtom* aAtom)
{
bool isContent = aOwnerContent->AttrValueIs(
kNameSpaceID_None, aAtom, nsGkAtoms::content, eIgnoreCase);
if (!isContent) {
nsCOMPtr<nsIMozBrowserFrame> mozbrowser = aOwnerContent->GetAsMozBrowserFrame();
if (mozbrowser) {
mozbrowser->GetMozbrowser(&isContent);
}
}
if (isContent) {
return aDocShell->ItemType() == nsIDocShellTreeItem::typeContent;
}
nsCOMPtr<nsIDocShellTreeItem> parent;
aDocShell->GetParent(getter_AddRefs(parent));
return parent && parent->ItemType() == aDocShell->ItemType();
}
/**
* Set the type of the treeitem and hook it up to the treeowner.
* Hook up a given TreeItem to its tree owner. aItem's type must have already
* been set, and it should already be part of the DocShellTree.
* @param aItem the treeitem we're working with
* @param aTreeOwner the relevant treeowner; might be null
* @param aParentType the nsIDocShellTreeItem::GetType of our parent docshell
* @param aParentNode if non-null, the docshell we should be added as a child to
*
* @return whether aItem is top-level content
*/
bool
void
nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
nsIDocShellTreeOwner* aOwner,
int32_t aParentType,
nsIDocShell* aParentNode)
nsIDocShellTreeOwner* aOwner)
{
MOZ_ASSERT(aItem, "Must have docshell treeitem");
MOZ_ASSERT(mOwnerContent, "Must have owning content");
nsAutoString value;
bool isContent = mOwnerContent->AttrValueIs(
kNameSpaceID_None, TypeAttrName(), nsGkAtoms::content, eIgnoreCase);
// Force mozbrowser frames to always be typeContent, even if the
// mozbrowser interfaces are disabled.
nsCOMPtr<nsIDOMMozBrowserFrame> mozbrowser =
do_QueryInterface(mOwnerContent);
if (mozbrowser) {
bool isMozbrowser = false;
mozbrowser->GetMozbrowser(&isMozbrowser);
isContent |= isMozbrowser;
}
if (isContent) {
// The web shell's type is content.
aItem->SetItemType(nsIDocShellTreeItem::typeContent);
} else {
// Inherit our type from our parent docshell. If it is
// chrome, we'll be chrome. If it is content, we'll be
// content.
aItem->SetItemType(aParentType);
}
// Now that we have our type set, add ourselves to the parent, as needed.
if (aParentNode) {
aParentNode->AddChild(aItem);
} else if (nsCOMPtr<nsIDocShell> childAsDocShell = do_QueryInterface(aItem)) {
childAsDocShell->AttachBrowsingContext(aParentNode);
}
bool retval = false;
if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) {
retval = true;
MOZ_DIAGNOSTIC_ASSERT(
CheckDocShellType(mOwnerContent, aItem, TypeAttrName()),
"Correct ItemType should be set when creating BrowsingContext");
if (mIsTopLevelContent) {
bool is_primary =
mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
nsGkAtoms::_true, eIgnoreCase);
@ -626,8 +614,6 @@ nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
aOwner->ContentShellAdded(aItem, is_primary);
}
}
return retval;
}
static bool
@ -1499,9 +1485,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
SetOwnerContent(otherContent);
aOther->SetOwnerContent(ourContent);
AddTreeItemToTreeOwner(ourDocshell, otherOwner, otherParentType, nullptr);
aOther->AddTreeItemToTreeOwner(otherDocshell, ourOwner, ourParentType,
nullptr);
AddTreeItemToTreeOwner(ourDocshell, otherOwner);
aOther->AddTreeItemToTreeOwner(otherDocshell, ourOwner);
// SetSubDocumentFor nulls out parent documents on the old child doc if a
// new non-null document is passed in, so just go ahead and remove both
@ -1904,6 +1889,23 @@ nsFrameLoader::IsRemoteFrame()
return false;
}
static already_AddRefed<BrowsingContext>
CreateBrowsingContext(BrowsingContext* aParentContext,
const nsAString& aName,
bool aIsContent)
{
// If we're content but our parent isn't, we're going to want to start a new
// browsing context tree.
if (aIsContent && !aParentContext->IsContent()) {
aParentContext = nullptr;
}
BrowsingContext::Type type =
aIsContent ? BrowsingContext::Type::Content : BrowsingContext::Type::Chrome;
return BrowsingContext::Create(aParentContext, aName, type);
}
nsresult
nsFrameLoader::MaybeCreateDocShell()
{
@ -1936,22 +1938,16 @@ nsFrameLoader::MaybeCreateDocShell()
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIDocShell> parentDocShell = doc->GetDocShell();
nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(parentDocShell);
NS_ENSURE_STATE(parentAsWebNav);
// Create the docshell...
mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
if (!mNetworkCreated) {
if (mDocShell) {
mDocShell->SetCreatedDynamically(true);
}
// Determine our parent nsDocShell
RefPtr<nsDocShell> parentDocShell = nsDocShell::Cast(doc->GetDocShell());
if (NS_WARN_IF(!parentDocShell)) {
return NS_ERROR_UNEXPECTED;
}
// Get the frame name and tell the docshell about it.
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
RefPtr<BrowsingContext> parentBC = parentDocShell->GetBrowsingContext();
MOZ_ASSERT(parentBC, "docShell must have BrowsingContext");
// Determine the frame name for the new browsing context.
nsAutoString frameName;
int32_t namespaceID = mOwnerContent->GetNameSpaceID();
@ -1966,45 +1962,55 @@ nsFrameLoader::MaybeCreateDocShell()
}
}
if (!frameName.IsEmpty()) {
mDocShell->SetName(frameName);
// Check if our new context is chrome or content
bool isContent = parentBC->IsContent() ||
mOwnerContent->AttrValueIs(kNameSpaceID_None, TypeAttrName(),
nsGkAtoms::content, eIgnoreCase);
// Force mozbrowser frames to always be content, even if the mozbrowser
// interfaces are disabled.
nsCOMPtr<nsIMozBrowserFrame> mozbrowser =
mOwnerContent->GetAsMozBrowserFrame();
if (!isContent && mozbrowser) {
mozbrowser->GetMozbrowser(&isContent);
}
// Inform our docShell that it has a new child.
// Note: This logic duplicates a lot of logic in
// nsSubDocumentFrame::AttributeChanged. We should fix that.
RefPtr<BrowsingContext> browsingContext = CreateBrowsingContext(parentBC, frameName, isContent);
const int32_t parentType = parentDocShell->ItemType();
mDocShell = nsDocShell::Create(browsingContext);
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
// XXXbz why is this in content code, exactly? We should handle
// this some other way..... Not sure how yet.
nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
parentDocShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
NS_ENSURE_STATE(parentTreeOwner);
mIsTopLevelContent =
AddTreeItemToTreeOwner(mDocShell, parentTreeOwner, parentType,
parentDocShell);
mIsTopLevelContent = isContent && !parentBC->IsContent();
if (!mNetworkCreated && !mIsTopLevelContent) {
mDocShell->SetCreatedDynamically(true);
}
if (mIsTopLevelContent) {
mDocShell->SetCreatedDynamically(false);
// Manually add ourselves to our parent's docshell, as BrowsingContext won't
// have done this for us.
//
// XXX(nika): Consider removing the DocShellTree in the future, for
// consistency between local and remote frames..
parentDocShell->AddChild(mDocShell);
}
// Make sure all shells have links back to the content element
// in the nearest enclosing chrome shell.
// Now that we are part of the DocShellTree, attach our DocShell to our
// parent's TreeOwner.
nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
parentDocShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
AddTreeItemToTreeOwner(mDocShell, parentTreeOwner);
// Make sure all nsDocShells have links back to the content element in the
// nearest enclosing chrome shell.
RefPtr<EventTarget> chromeEventHandler;
if (parentType == nsIDocShellTreeItem::typeChrome) {
// Our parent shell is a chrome shell. It is therefore our nearest
// enclosing chrome shell.
chromeEventHandler = mOwnerContent;
NS_ASSERTION(chromeEventHandler,
"This mContent should implement this.");
} else {
// Our parent shell is a content shell. Get the chrome event
// handler from it and use that for our shell as well.
if (parentBC->IsContent()) {
// Our parent shell is a content shell. Get the chrome event handler from it
// and use that for our shell as well.
parentDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
} else {
// Our parent shell is a chrome shell. It is therefore our nearest enclosing
// chrome shell.
chromeEventHandler = mOwnerContent;
}
mDocShell->SetChromeEventHandler(chromeEventHandler);
@ -2015,32 +2021,34 @@ nsFrameLoader::MaybeCreateDocShell()
// the right chrome event handler.
// Tell the window about the frame that hosts it.
nsCOMPtr<Element> frame_element = mOwnerContent;
NS_ASSERTION(frame_element, "frame loader owner element not a DOM element!");
nsCOMPtr<nsPIDOMWindowOuter> newWindow = mDocShell->GetWindow();
if (NS_WARN_IF(!newWindow)) {
// Do not call Destroy() here. See bug 472312.
NS_WARNING("Something wrong when creating the docshell for a frameloader!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsPIDOMWindowOuter> win_private(mDocShell->GetWindow());
nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
if (win_private) {
win_private->SetFrameElementInternal(frame_element);
newWindow->SetFrameElementInternal(mOwnerContent);
// Set the opener window if we have one provided here
if (mOpener) {
win_private->SetOpenerWindow(mOpener, true);
mOpener = nullptr;
}
// Set the opener window if we have one provided here
// XXX(nika): We should tell our BrowsingContext this as we create it.
if (mOpener) {
newWindow->SetOpenerWindow(mOpener, true);
mOpener = nullptr;
}
// Allow scripts to close the docshell if specified.
if (win_private && mOwnerContent->IsXULElement(nsGkAtoms::browser) &&
if (mOwnerContent->IsXULElement(nsGkAtoms::browser) &&
mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::allowscriptstoclose,
nsGkAtoms::_true, eCaseMatters)) {
nsGlobalWindowOuter::Cast(win_private)->AllowScriptsToClose();
nsGlobalWindowOuter::Cast(newWindow)->AllowScriptsToClose();
}
// This is kinda whacky, this call doesn't really create anything,
// but it must be called to make sure things are properly
// initialized.
if (NS_FAILED(base_win->Create()) || !win_private) {
nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
if (NS_FAILED(baseWin->Create())) {
// Do not call Destroy() here. See bug 472312.
NS_WARNING("Something wrong when creating the docshell for a frameloader!");
return NS_ERROR_FAILURE;
@ -2060,7 +2068,7 @@ nsFrameLoader::MaybeCreateDocShell()
OriginAttributes attrs;
if (parentDocShell->ItemType() == mDocShell->ItemType()) {
attrs = nsDocShell::Cast(parentDocShell)->GetOriginAttributes();
attrs = parentDocShell->GetOriginAttributes();
}
// Inherit origin attributes from parent document if
@ -2070,7 +2078,7 @@ nsFrameLoader::MaybeCreateDocShell()
//
// For example, firstPartyDomain is computed from top-level document, it
// doesn't exist in the top-level docshell.
if (parentType == nsIDocShellTreeItem::typeContent &&
if (parentBC->IsContent() &&
!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()) &&
!OwnerIsMozBrowserFrame()) {
OriginAttributes oa = doc->NodePrincipal()->OriginAttributesRef();
@ -2116,10 +2124,7 @@ nsFrameLoader::MaybeCreateDocShell()
}
bool isPrivate = false;
nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(parentDocShell);
NS_ENSURE_STATE(parentContext);
rv = parentContext->GetUsePrivateBrowsing(&isPrivate);
rv = parentDocShell->GetUsePrivateBrowsing(&isPrivate);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2158,7 +2163,7 @@ nsFrameLoader::MaybeCreateDocShell()
// those cases.
nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
if (!mDocShell->GetIsMozBrowser() &&
parentType == mDocShell->ItemType() &&
parentDocShell->ItemType() == mDocShell->ItemType() &&
!doc->IsStaticDocument() && win) {
// Propagate through the ancestor principals.
nsTArray<nsCOMPtr<nsIPrincipal>> ancestorPrincipals;

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

@ -423,10 +423,8 @@ private:
bool ShowRemoteFrame(const mozilla::ScreenIntSize& size,
nsSubDocumentFrame *aFrame = nullptr);
bool AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
nsIDocShellTreeOwner* aOwner,
int32_t aParentType,
nsIDocShell* aParentNode);
void AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
nsIDocShellTreeOwner* aOwner);
nsAtom* TypeAttrName() const {
return mOwnerContent->IsXULElement()

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

@ -6122,9 +6122,8 @@ ContentParent::RecvAttachBrowsingContext(
}
if (!child) {
child = ChromeBrowsingContext::Create(aChildId, aName, ChildID());
child = BrowsingContext::CreateFromIPC(parent, aName, (uint64_t)aChildId, this);
}
child->Attach(parent);
return IPC_OK();
}

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

@ -14,6 +14,9 @@
#include "nsIDocShellTreeItem.h"
#include "nsIBaseWindow.h"
#include "nsIDocument.h"
#include "nsDocShell.h"
#include "mozilla/dom/BrowsingContext.h"
//---------------------------------------------------
//-- nsPrintObject Class Impl
@ -56,11 +59,21 @@ nsPrintObject::Init(nsIDocShell* aDocShell, nsIDocument* aDoc,
mDocShell = aDocShell;
} else {
mTreeOwner = do_GetInterface(aDocShell);
// Create a new BrowsingContext to create our DocShell in.
RefPtr<BrowsingContext> bc = BrowsingContext::Create(
nullptr,
EmptyString(),
aDocShell->ItemType() == nsIDocShellTreeItem::typeContent
? BrowsingContext::Type::Content
: BrowsingContext::Type::Chrome);
// Create a container docshell for printing.
mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
mDocShell = nsDocShell::Create(bc);
NS_ENSURE_TRUE(mDocShell, NS_ERROR_OUT_OF_MEMORY);
mDidCreateDocShell = true;
mDocShell->SetItemType(aDocShell->ItemType());
MOZ_ASSERT(mDocShell->ItemType() == aDocShell->ItemType());
mDocShell->SetTreeOwner(mTreeOwner);
}
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
@ -104,4 +117,3 @@ nsPrintObject::DestroyPresentation()
mPresContext = nullptr;
mViewManager = nullptr;
}

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

@ -37,6 +37,7 @@
#include "nsDocShell.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/BrowsingContext.h"
// for painting the background window
#include "mozilla/LookAndFeel.h"
@ -979,10 +980,22 @@ nsWebBrowser::Create()
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIDocShell> docShell(
do_CreateInstance("@mozilla.org/docshell;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsDocShell::Cast(docShell)->SetOriginAttributes(mOriginAttributes);
// XXX(nika): Consider supporting creating nsWebBrowser for an existing
// BrowsingContext (e.g. during a X-process load).
// XXX(nika): Get window opener information into nsWebBrowser::Create.
using BrowsingContext = mozilla::dom::BrowsingContext;
RefPtr<mozilla::dom::BrowsingContext> browsingContext =
BrowsingContext::Create(nullptr,
mInitInfo->name,
mContentType != typeChromeWrapper
? BrowsingContext::Type::Content
: BrowsingContext::Type::Chrome);
RefPtr<nsDocShell> docShell = nsDocShell::Create(browsingContext);
if (NS_WARN_IF(!docShell)) {
return NS_ERROR_UNEXPECTED;
}
docShell->SetOriginAttributes(mOriginAttributes);
rv = SetDocShell(docShell);
NS_ENSURE_SUCCESS(rv, rv);
@ -1006,14 +1019,7 @@ nsWebBrowser::Create()
mInitInfo->cx, mInitInfo->cy),
NS_ERROR_FAILURE);
mDocShell->SetName(mInitInfo->name);
if (mContentType == typeChromeWrapper) {
mDocShell->SetItemType(nsIDocShellTreeItem::typeChrome);
} else {
mDocShell->SetItemType(nsIDocShellTreeItem::typeContent);
}
mDocShell->SetTreeOwner(mDocShellTreeOwner);
mDocShell->AttachBrowsingContext(nullptr);
// If the webbrowser is a content docshell item then we won't hear any
// events from subframes. To solve that we install our own chrome event

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

@ -56,12 +56,15 @@
#include "nsIBaseWindow.h"
#include "nsIDocShellTreeItem.h"
#include "nsDocShell.h"
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/dom/BrowsingContext.h"
#include "nsPIWindowRoot.h"
#include "gfxPlatform.h"
@ -179,9 +182,14 @@ nsresult nsWebShellWindow::Initialize(nsIXULWindow* aParent,
mWindow->SetBackgroundColor(NS_RGB(255,255,255));
// Create web shell
mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
RefPtr<BrowsingContext> browsingContext =
BrowsingContext::Create(nullptr, EmptyString(), BrowsingContext::Type::Chrome);
mDocShell = nsDocShell::Create(browsingContext);
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
// XXX(nika): This is used to handle propagating opener across remote tab
// creation. We should come up with a better system for doing this (probably
// based on BrowsingContext).
mDocShell->SetOpener(aOpeningTab);
// Make sure to set the item type on the docshell _before_ calling
@ -191,9 +199,6 @@ nsresult nsWebShellWindow::Initialize(nsIXULWindow* aParent,
NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE);
docShellAsItem->SetTreeOwner(mChromeTreeOwner);
docShellAsItem->SetItemType(nsIDocShellTreeItem::typeChrome);
mDocShell->AttachBrowsingContext(nullptr);
r.MoveTo(0, 0);
nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));