author | Boris Zbarsky <bzbarsky@mit.edu> |
Wed, 27 Nov 2013 11:16:07 -0500 | |
changeset 157829 | 200590163c1f20fc9af1373fc54f67306d7ce668 |
parent 157828 | c4883720cfb3191da8c79b2605abe6e4bda09bcb |
child 157830 | 63a7d0d3dd83862dede3ad9b770dd4077ee3fd16 |
push id | 25726 |
push user | cbook@mozilla.com |
push date | Thu, 28 Nov 2013 10:47:25 +0000 |
treeherder | mozilla-central@cdca43b7657d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bholley |
bugs | 943418 |
milestone | 28.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -902,17 +902,17 @@ public: return outer && outer->IsBackground(); } /** * Return the inner window used as the script compilation scope for * this document. If you're not absolutely sure you need this, use * GetWindow(). */ - nsPIDOMWindow* GetInnerWindow() + nsPIDOMWindow* GetInnerWindow() const { return mRemovedFromDocShell ? nullptr : mWindow; } /** * Return the outer window ID. */ uint64_t OuterWindowID() const @@ -1608,17 +1608,20 @@ public: /** * Return whether the document and all its ancestors are visible in the sense of * pageshow / hide. */ bool IsVisibleConsideringAncestors() const; /** * Return true when this document is active, i.e., the active document - * in a content viewer. + * in a content viewer. Note that this will return true for bfcached + * documents, so this does NOT match the "active document" concept in + * the WHATWG spec. That would correspond to GetInnerWindow() && + * GetInnerWindow()->IsCurrentInnerWindow(). */ bool IsActive() const { return mDocumentContainer && !mRemovedFromDocShell; } void RegisterFreezableElement(nsIContent* aContent); bool UnregisterFreezableElement(nsIContent* aContent); typedef void (* FreezableElementEnumerator)(nsIContent*, void*); void EnumerateFreezableElements(FreezableElementEnumerator aEnumerator, void* aData);
--- a/dom/base/nsHistory.cpp +++ b/dom/base/nsHistory.cpp @@ -65,17 +65,17 @@ nsHistory::WrapObject(JSContext* aCx, JS { return HistoryBinding::Wrap(aCx, aScope, this); } uint32_t nsHistory::GetLength(ErrorResult& aRv) const { nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow)); - if (!win || !win->IsCurrentInnerWindow()) { + if (!win || !win->HasActiveDocument()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return 0; } // Get session History from docshell nsCOMPtr<nsISHistory> sHistory = GetSessionHistory(); if (!sHistory) { @@ -101,17 +101,17 @@ nsHistory::GetState(JSContext* aCx, Erro { nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow)); if (!win) { aRv.Throw(NS_ERROR_NOT_AVAILABLE); return JS::UndefinedValue(); } - if (!win->IsCurrentInnerWindow()) { + if (!win->HasActiveDocument()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return JS::UndefinedValue(); } nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDoc()); if (!doc) { @@ -141,17 +141,17 @@ nsHistory::GetState(JSContext* aCx, Erro return JS::UndefinedValue(); } void nsHistory::Go(int32_t aDelta, ErrorResult& aRv) { nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow)); - if (!win || !win->IsCurrentInnerWindow()) { + if (!win || !win->HasActiveDocument()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } if (!aDelta) { nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(GetDocShell())); @@ -197,17 +197,17 @@ nsHistory::Go(int32_t aDelta, ErrorResul // from GotoIndex() can lead to exceptions and a possible leak // of history length } void nsHistory::Back(ErrorResult& aRv) { nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow)); - if (!win || !win->IsCurrentInnerWindow()) { + if (!win || !win->HasActiveDocument()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } nsCOMPtr<nsISHistory> sHistory = GetSessionHistory(); nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory)); if (!webNav) { @@ -218,17 +218,17 @@ nsHistory::Back(ErrorResult& aRv) webNav->GoBack(); } void nsHistory::Forward(ErrorResult& aRv) { nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow)); - if (!win || !win->IsCurrentInnerWindow()) { + if (!win || !win->HasActiveDocument()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } nsCOMPtr<nsISHistory> sHistory = GetSessionHistory(); nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory)); if (!webNav) { @@ -263,17 +263,17 @@ nsHistory::PushOrReplaceState(JSContext* { nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow)); if (!win) { aRv.Throw(NS_ERROR_NOT_AVAILABLE); return; } - if (!win->IsCurrentInnerWindow()) { + if (!win->HasActiveDocument()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } // Check that PushState hasn't been pref'ed off. if (!Preferences::GetBool(aReplace ? sAllowReplaceStatePrefStr : sAllowPushStatePrefStr, false)) {
--- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -331,16 +331,27 @@ public: // window of that outer. Only call this on inner windows. bool IsCurrentInnerWindow() const { MOZ_ASSERT(IsInnerWindow(), "It doesn't make sense to call this on outer windows."); return mOuterWindow && mOuterWindow->GetCurrentInnerWindow() == this; } + // Returns true if the document of this window is the active document. This + // is not identical to IsCurrentInnerWindow() because document.open() will + // keep the same document active but create a new window. + bool HasActiveDocument() + { + return IsCurrentInnerWindow() || + (GetOuterWindow() && + GetOuterWindow()->GetCurrentInnerWindow() && + GetOuterWindow()->GetCurrentInnerWindow()->GetDoc() == mDoc); + } + bool IsOuterWindow() const { return !IsInnerWindow(); } virtual bool WouldReuseInnerWindow(nsIDocument *aNewDocument) = 0; /**
--- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -13,16 +13,17 @@ support-files = [test_document.all_unqualified.html] [test_domcursor.html] [test_domrequest.html] [test_e4x_for_each.html] [test_error.html] [test_gsp-qualified.html] [test_gsp-quirks.html] [test_gsp-standards.html] +[test_history_document_open.html] [test_innersize_scrollport.html] [test_messageChannel.html] [test_messageChannel_cloning.html] [test_messageChannel_pingpong.html] [test_messageChannel_post.html] [test_messageChannel_pref.html] [test_messageChannel_start.html] [test_messageChannel_transferable.html]
new file mode 100644 --- /dev/null +++ b/dom/base/test/test_history_document_open.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=943418 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 943418</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 943418 **/ + SimpleTest.waitForExplicitFinish(); + + function continueTest(f) { + // Make sure we're the entry script so errors get reported here + setTimeout(finishTest, 0, f); + } + + function finishTest(f) { + f(); + ok(true, "Got here"); + SimpleTest.finish(); + } + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=943418">Mozilla Bug 943418</a> +<p id="display"></p> +<div id="content" style="display: none"> +<iframe src="data:text/html,<script>function f() { history.length; } window.onload = function() { var f = window.f; document.open(); document.close(); parent.continueTest(f); }</script>" </script> +</div> +<pre id="test"> +</pre> +</body> +</html>