diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index d271e12125..14998ec00c 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -4749,6 +4749,16 @@ null false 0 + + + + + + + diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm index 94f9e103ec..5d98779bd3 100644 --- a/browser/components/sessionstore/SessionStore.jsm +++ b/browser/components/sessionstore/SessionStore.jsm @@ -2996,6 +2996,10 @@ let SessionStoreInternal = { else tabbrowser.showTab(tab); + if (tabData.userContextId) { + tab.setUserContextId(tabData.userContextId); + } + if ("attributes" in tabData) { // Ensure that we persist tab attributes restored from previous sessions. Object.keys(tabData.attributes).forEach(a => TabAttributes.persist(a)); diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 7277377e05..19817d6173 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -2521,20 +2521,25 @@ nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed) // Assume false until we determine otherwise... *aFullscreenAllowed = false; - // For non-browsers/apps, check that the enclosing iframe element - // has the allowfullscreen attribute set to true. If any ancestor - // iframe does not have mozallowfullscreen=true, then fullscreen is - // prohibited. nsCOMPtr win = GetWindow(); if (!win) { return NS_OK; } nsCOMPtr frameElement = win->GetFrameElementInternal(); - if (frameElement && - frameElement->IsHTMLElement(nsGkAtoms::iframe) && - !frameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) && - !frameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)) { - return NS_OK; + if (frameElement && !frameElement->IsXULElement()) { + // We do not allow document inside any containing element other + // than iframe to enter fullscreen. + if (!frameElement->IsHTMLElement(nsGkAtoms::iframe)) { + return NS_OK; + } + // If any ancestor iframe does not have allowfullscreen attribute + // set, then fullscreen is not allowed. + if (!frameElement->HasAttr(kNameSpaceID_None, + nsGkAtoms::allowfullscreen) && + !frameElement->HasAttr(kNameSpaceID_None, + nsGkAtoms::mozallowfullscreen)) { + return NS_OK; + } } // If we have no parent then we're the root docshell; no ancestor of the @@ -3292,23 +3297,23 @@ nsDocShell::SetDocLoaderParent(nsDocLoader* aParent) nsString customUserAgent; nsCOMPtr parentAsDocShell(do_QueryInterface(parent)); if (parentAsDocShell) { - if (NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) { + if (mAllowPlugins && NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) { SetAllowPlugins(value); } - if (NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) { + if (mAllowJavascript && NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) { SetAllowJavascript(value); } - if (NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) { + if (mAllowMetaRedirects && NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) { SetAllowMetaRedirects(value); } - if (NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))) { + if (mAllowSubframes && NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))) { SetAllowSubframes(value); } if (NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value))) { SetAllowImages(value); } - SetAllowMedia(parentAsDocShell->GetAllowMedia()); - if (NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) { + SetAllowMedia(parentAsDocShell->GetAllowMedia() && mAllowMedia); + if (mAllowWindowControl && NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) { SetAllowWindowControl(value); } SetAllowContentRetargeting( @@ -3326,7 +3331,7 @@ nsDocShell::SetDocLoaderParent(nsDocLoader* aParent) if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) { value = false; } - SetAllowDNSPrefetch(value); + SetAllowDNSPrefetch(mAllowDNSPrefetch && value); value = parentAsDocShell->GetAffectPrivateSessionLifetime(); SetAffectPrivateSessionLifetime(value); uint32_t flags; @@ -3470,18 +3475,23 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem, nsCOMPtr targetDS = do_QueryInterface(aTargetItem); nsCOMPtr accessingDS = do_QueryInterface(aAccessingItem); - if (!!targetDS != !!accessingDS) { - // We must be able to convert both or neither to nsIDocShell. + if (!targetDS || !accessingDS) { + // We must be able to convert both to nsIDocShell. return false; } - if (targetDS && accessingDS && - (targetDS->GetIsInBrowserElement() != - accessingDS->GetIsInBrowserElement() || - targetDS->GetAppId() != accessingDS->GetAppId())) { + if (targetDS->GetIsInBrowserElement() != accessingDS->GetIsInBrowserElement() || + targetDS->GetAppId() != accessingDS->GetAppId()) { return false; } + // A private document can't access a non-private one, and vice versa. + if (static_cast(targetDS.get())->UsePrivateBrowsing() != + static_cast(accessingDS.get())->UsePrivateBrowsing()) { + return false; + } + + nsCOMPtr accessingRoot; aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot)); @@ -3984,6 +3994,7 @@ nsDocShell::AddChild(nsIDocShellTreeItem* aChild) } aChild->SetTreeOwner(mTreeOwner); + childDocShell->SetUserContextId(mUserContextId); nsCOMPtr childAsDocShell(do_QueryInterface(aChild)); if (!childAsDocShell) { @@ -12580,13 +12591,9 @@ nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel* aChannel) } // figure out if SH should be saving layout state - nsCOMPtr securityInfo; - bool noStore = false, noCache = false; - aChannel->GetSecurityInfo(getter_AddRefs(securityInfo)); + bool noStore = false; aChannel->IsNoStoreResponse(&noStore); - aChannel->IsNoCacheResponse(&noCache); - - return (noStore || (noCache && securityInfo)); + return noStore; } NS_IMETHODIMP @@ -13911,6 +13918,17 @@ NS_IMETHODIMP nsDocShell::SetUserContextId(uint32_t aUserContextId) { mUserContextId = aUserContextId; + + nsTObserverArray::ForwardIterator iter(mChildList); + while (iter.HasMore()) { + nsCOMPtr docshell = do_QueryObject(iter.GetNext()); + if (!docshell || docshell->ItemType() != ItemType()) { + continue; + } + + docshell->SetUserContextId(aUserContextId); + } + return NS_OK; } @@ -14066,7 +14084,9 @@ nsDocShell::GetAsyncPanZoomEnabled(bool* aOut) return NS_OK; } - *aOut = false; + // If we don't have a presShell, fall back to the default platform value of + // whether or not APZ is enabled. + *aOut = gfxPlatform::AsyncPanZoomEnabled(); return NS_OK; } @@ -14396,9 +14416,11 @@ nsDocShell::InFrameSwap() NS_IMETHODIMP nsDocShell::IssueWarning(uint32_t aWarning, bool aAsError) { - nsCOMPtr doc = mContentViewer->GetDocument(); - if (doc) { - doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError); + if (mContentViewer) { + nsCOMPtr doc = mContentViewer->GetDocument(); + if (doc) { + doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError); + } } return NS_OK; } diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index a68a40f386..70e1f32065 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -235,7 +235,6 @@ public: NS_IMETHOD GetUseRemoteTabs(bool*) override; NS_IMETHOD SetRemoteTabs(bool) override; NS_IMETHOD GetOriginAttributes(JS::MutableHandle) override; - NS_IMETHOD SetUserContextId(uint32_t); // Restores a cached presentation from history (mLSHE). // This method swaps out the content viewer and simulates loads for diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index c78b5e44b6..9aa4889a83 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -46,7 +46,7 @@ interface nsITabParent; typedef unsigned long nsLoadFlags; -[scriptable, builtinclass, uuid(bc3524bd-023c-4fc8-ace1-472bc999fb12)] +[scriptable, builtinclass, uuid(98358234-3936-4b95-b051-fcda4e55b52d)] interface nsIDocShell : nsIDocShellTreeItem { /** @@ -1079,6 +1079,11 @@ interface nsIDocShell : nsIDocShellTreeItem * @see https://html.spec.whatwg.org/#dom-history-scroll-restoration */ attribute boolean currentScrollRestorationIsManual; + + /* + * Sets the user context ID for this docshell. + */ + void setUserContextId(in unsigned long aUserContextId); }; [scriptable, builtinclass, uuid(395c6a79-80ae-4ede-9e05-93bee6c3d9a1)] diff --git a/docshell/test/chrome/bug112564_window.xul b/docshell/test/chrome/bug112564_window.xul index 3f79a7c767..3e3fb66457 100644 --- a/docshell/test/chrome/bug112564_window.xul +++ b/docshell/test/chrome/bug112564_window.xul @@ -84,8 +84,9 @@ } function testsIterator() { - // Load a secure page with a no-store header, followed by a simple page - // On pagehide, first page should report it is not being persisted + // Load a secure page with a no-cache header, followed by a simple page. + // no-cache should not interfere with the bfcache in the way no-store + // does. var test1DocURI = "https://example.com:443/tests/docshell/test/chrome/112564_nocache.html"; gExpected = [{type: "pagehide", persisted: true}, @@ -97,18 +98,16 @@ var test2Doc = "data:text/html,test2" + "test2"; - gExpected = [{type: "pagehide", title: "test1", persisted: false}, - {type: "unload", title: "test1"}, + gExpected = [{type: "pagehide", title: "test1", persisted: true}, {type: "load", title: "test2"}, {type: "pageshow", title: "test2", persisted: false}]; gBrowser.loadURI(test2Doc); yield undefined; - // Now go back in history. First page should not have been cached. + // Now go back in history. First page has been cached. // Check persisted property to confirm gExpected = [{type: "pagehide", title: "test2", persisted: true}, - {type: "load", title: "test1"}, - {type: "pageshow", title: "test1", persisted: false}]; + {type: "pageshow", title: "test1", persisted: true}]; gBrowser.goBack(); yield undefined; } diff --git a/docshell/test/chrome/bug215405_window.xul b/docshell/test/chrome/bug215405_window.xul index ef2dc7f90c..d06df4eb74 100644 --- a/docshell/test/chrome/bug215405_window.xul +++ b/docshell/test/chrome/bug215405_window.xul @@ -113,7 +113,8 @@ // https no-cache testName = "[nocache]"; - // Load a page with a no-cache header + // Load a page with a no-cache header. This should not be + // restricted like no-store (bug 567365) gBrowser.loadURI(nocacheURI); yield undefined; @@ -141,19 +142,19 @@ yield undefined; - // Now go back in history. First page should not have been cached. + // Now go back in history to the cached page. gBrowser.goBack(); yield undefined; - // First uncacheable page will now be reloaded. Check scroll position - // restored, and form contents not + // First page will now be reloaded. Check scroll position + // and form contents are restored is(gBrowser.contentWindow.scrollX, scrollX, testName + " horizontal axis scroll position not correctly restored"); is(gBrowser.contentWindow.scrollY, scrollY, testName + " vertical axis scroll position not correctly restored"); var formValue = gBrowser.contentDocument.getElementById("inp").value; - isnot(formValue, text, testName + " form value incorrectly restored"); + is(formValue, text, testName + " form value not correctly restored"); // nextTest has to be called from here, as no events are fired in this // step diff --git a/dom/base/nsAttrValueInlines.h b/dom/base/nsAttrValueInlines.h index 7c8cb21ecf..c873c7fa05 100644 --- a/dom/base/nsAttrValueInlines.h +++ b/dom/base/nsAttrValueInlines.h @@ -1,3 +1,5 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */ @@ -8,18 +10,11 @@ #include #include "nsAttrValue.h" +#include "mozilla/Attributes.h" struct MiscContainer; -namespace mozilla { -template<> -struct HasDangerousPublicDestructor -{ - static const bool value = true; -}; -} - -struct MiscContainer +struct MiscContainer final { typedef nsAttrValue::ValueType ValueType; @@ -70,6 +65,10 @@ struct MiscContainer mValue.mCached = 0; } +protected: + // Only nsAttrValue should be able to delete us. + friend class nsAttrValue; + ~MiscContainer() { if (IsRefCounted()) { @@ -79,6 +78,7 @@ struct MiscContainer MOZ_COUNT_DTOR(MiscContainer); } +public: bool GetString(nsAString& aString) const; inline bool IsRefCounted() const diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index e75b5441b6..52777001c3 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -11961,18 +11961,15 @@ nsDocument::IsFullScreenEnabled(bool aCallerIsChrome, bool aLogFailure) return false; } - // Ensure that all ancestor