Skip to content

Commit 9812cb2

Browse files
committed
Bug 543435 - Only reuse inner window for uncommitted initial documents. r=smaug,asuth,credential-management-reviewers,webrtc-reviewers,pehrsons,hsivonen,dimi
The conceptual change is small but it requires several test changes. In principle, tests cannot open a new empty window, modify the global, then load their target document and expect their modifications to stick. Only if the target URI is opened directly, the synchronously available window is reused. So either tests need to do that, or rely on messages. Differential Revision: https://phabricator.services.mozilla.com/D265268
1 parent 967fc6d commit 9812cb2

File tree

37 files changed

+408
-406
lines changed

37 files changed

+408
-406
lines changed

docshell/base/nsDocShell.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2527,7 +2527,8 @@ Maybe<ClientInfo> nsDocShell::GetInitialClientInfo() const {
25272527
mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindow() : nullptr;
25282528
Document* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr;
25292529

2530-
if (!doc || !doc->IsInitialDocument()) {
2530+
if (!doc || !doc->IsUncommittedInitialDocument()) {
2531+
// We won't reuse the inner window so let the channel determine one
25312532
return Maybe<ClientInfo>();
25322533
}
25332534

docshell/test/chrome/test_bug608669.xhtml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ function* doTest() {
4949
is(notificationCount, 0, "initial count");
5050

5151
// create a new window
52-
var testWin = chromeWindow.open("", "bug 608669", "chrome,width=600,height=600");
52+
var testWin = chromeWindow.open("bug608669.xhtml", "bug 608669", "chrome,width=600,height=600");
53+
// Synchronously modify the transient about:blank window
5354
testWin.x = "y";
55+
is(testWin.location.href, 'about:blank');
5456
is(notificationCount, 0, "after created window");
5557

56-
// Try loading in the window
57-
testWin.location = "bug608669.xhtml";
58+
// Wait for the window to load
5859
chromeWindow.onmessage = nextTest;
5960
yield undefined;
6061
is(notificationCount, 1, "after first load");

docshell/test/mochitest/test_bug1729662.html

Lines changed: 34 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -9,59 +9,46 @@
99
SimpleTest.waitForExplicitFinish();
1010
SimpleTest.requestFlakyTimeout("Need to wait to make sure an event does not fire");
1111

12-
async function runTest() {
13-
let win = window.open();
14-
let goneBackAndForwardOnce = new Promise((resolve) => {
15-
let timeoutID;
16-
17-
// We should only get one load event in win.
18-
let bc = new BroadcastChannel("bug1729662");
19-
bc.addEventListener("message", () => {
20-
bc.addEventListener("message", () => {
21-
clearTimeout(timeoutID);
22-
resolve(false);
23-
});
24-
}, { once: true });
25-
26-
let goneBack = false, goneForward = false;
27-
win.addEventListener("popstate", ({ state }) => {
28-
// We should only go back and forward once, if we get another
29-
// popstate after that then we should fall through to the
30-
// failure case below.
31-
if (!(goneBack && goneForward)) {
32-
// Check if this is the popstate for the forward (the one for
33-
// back will have state == undefined).
34-
if (state == 1) {
35-
ok(goneBack, "We should have gone back before going forward");
36-
37-
goneForward = true;
38-
39-
// Wait a bit to make sure there are no more popstate events.
40-
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
41-
timeoutID = setTimeout(resolve, 1000, true);
42-
43-
return;
44-
}
12+
function waitForEvent(target, event) {
13+
return new Promise(resolve =>
14+
target.addEventListener(event, resolve, { once: true }));
15+
}
4516

46-
// Check if we've gone back once before, if we get another
47-
// popstate after that then we should fall through to the
48-
// failure case below.
49-
if (!goneBack) {
50-
goneBack = true;
17+
async function runTest() {
18+
// Target page needs to be the initial load so that the synchronously
19+
// available window is reused and we can attach popstate listeners.
20+
const win = window.open('file_bug1729662.html');
21+
22+
let timeoutID;
23+
let loadCount = 0;
24+
let bc = new BroadcastChannel("bug1729662");
25+
bc.onmessage = ({ data }) => {
26+
if (data != 'load') return;
27+
if (++loadCount > 1) {
28+
// We should only get one load event in win
29+
clearTimeout(timeoutID);
30+
}
31+
};
5132

52-
return;
53-
}
54-
}
33+
// We should only go back and forward once
34+
// The popstate for back will have state == null, see file_bug1729662.html
35+
const state1 = await waitForEvent(win, 'popstate');
36+
is(state1.state, null, 'got expected state for history.back');
5537

56-
clearTimeout(timeoutID);
57-
resolve(false);
58-
});
59-
});
38+
const state2 = await waitForEvent(win, 'popstate');
39+
is(state2.state, 1, 'got expected state for history.forward');
6040

61-
win.location = "file_bug1729662.html";
41+
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
42+
const timeout = new Promise(resolve => timeoutID = setTimeout(resolve, 1000, 'timeout'));
43+
const result = await Promise.race([
44+
waitForEvent(win, 'popstate'),
45+
timeout
46+
]);
47+
is(result, 'timeout', 'Got no more popstate');
6248

63-
ok(await goneBackAndForwardOnce, "Stopped navigating history");
49+
is(loadCount, isXOrigin ? 0 : 1, 'Got exactly one (zero for xorigin) load events in win');
6450

51+
clearTimeout(timeoutID);
6552
win.close();
6653

6754
SimpleTest.finish();

dom/base/nsGlobalWindowInner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1916,7 +1916,7 @@ nsresult nsGlobalWindowInner::EnsureClientSource() {
19161916

19171917
// Try to get the reserved client from the LoadInfo. A Client is
19181918
// reserved at the start of the channel load if there is not an
1919-
// initial about:blank document that will be reused. It is also
1919+
// initial uncommitted about:blank whose window will be reused. It is also
19201920
// created if the channel load encounters a cross-origin redirect.
19211921
if (loadInfo) {
19221922
UniquePtr<ClientSource> reservedClient =

dom/base/nsGlobalWindowOuter.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,7 +1716,9 @@ nsIScriptContext* nsGlobalWindowOuter::GetScriptContext() { return mContext; }
17161716

17171717
bool nsGlobalWindowOuter::WouldReuseInnerWindow(Document* aNewDocument) {
17181718
// We reuse the inner window when:
1719-
// a. We are currently at our original document.
1719+
// a. The current document is transient, i.e. a temporary placeholder while
1720+
// an async load is ongoing. This is equivalent to the uncommitted initial
1721+
// document.
17201722
// b. At least one of the following conditions are true:
17211723
// -- The new document is the same as the old document. This means that we're
17221724
// getting called from document.open().
@@ -1726,7 +1728,7 @@ bool nsGlobalWindowOuter::WouldReuseInnerWindow(Document* aNewDocument) {
17261728
return false;
17271729
}
17281730

1729-
if (!mDoc->IsInitialDocument()) {
1731+
if (!mDoc->IsUncommittedInitialDocument()) {
17301732
return false;
17311733
}
17321734

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
addEventListener('unload', () => {
3+
window.opener.postMessage('unload', '*');
4+
});
5+
</script>

dom/base/test/mochitest.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ support-files = [
175175
"referrer_change_server.sjs",
176176
"file_change_policy_redirect.html",
177177
"file_bug1198095.js",
178+
"file_bug1126851_post_unload.html",
178179
"file_bug1250148.sjs",
179180
"file_bug1268962.sjs",
180181
"iframe_meta_refresh.sjs",

dom/base/test/test_bug1126851.html

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
let gotUnload = false;
1818

1919
function runTest() {
20-
win = window.open("about:blank", "");
21-
win.onunload = function() {
20+
win = window.open("file_bug1126851_post_unload.html", "");
21+
// Reload replaces the inner window so we cannot wait for win.onunload
22+
// and instead must rely on messages from the popup.
23+
window.onmessage = function() {
2224
if (gotUnload) {
2325
SimpleTest.finish();
2426
} else {
@@ -36,8 +38,10 @@
3638
win.location.reload();
3739
}
3840
}
39-
evt = new win.Event("resize", { bubbles: true });
40-
win.document.dispatchEvent(evt);
41+
win.onload = function() {
42+
evt = new win.Event("resize", { bubbles: true });
43+
win.document.dispatchEvent(evt);
44+
}
4145
}
4246

4347

dom/base/test/test_window_focus_by_close_and_open.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,17 @@
99
SimpleTest.waitForExplicitFinish();
1010

1111
function start() {
12-
var w = window.open("", "_blank");
12+
var w = window.open("file_window_focus_by_close_and_open.html", "_blank");
1313
w.finished = function() {
1414
ok(true, "1st new window had focus");
1515
w.close();
16-
w = window.open("", "_blank");
16+
w = window.open("file_window_focus_by_close_and_open.html", "_blank");
1717
w.finished = function() {
1818
ok(true, "2nd new window had focus");
1919
w.close();
2020
SimpleTest.finish();
2121
};
22-
w.location = "file_window_focus_by_close_and_open.html";
2322
};
24-
w.location = "file_window_focus_by_close_and_open.html";
2523
}
2624
</script>
2725
</head>

dom/encoding/test/test_submit_euckr.html

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,17 @@
1414
</form>
1515
<script>
1616

17-
runTest();
17+
async_test((t) => {
18+
const form = document.forms[0];
19+
const iframe = document.querySelector('iframe');
1820

19-
function runTest() {
20-
var t = async_test("Test for euc-kr encoded form submission");
21-
var f = document.forms[0];
22-
var ifr = frames.ifr;
23-
ifr.onload = function() {
24-
t.step(function() {
25-
assert_equals("".split.call(ifr.location, "?")[1], "a=%81A");
26-
});
27-
t.done();
28-
};
29-
f.submit();
30-
}
21+
// note: listener must be on the iframe, not the window that will be replaced
22+
iframe.onload = t.step_func_done(() =>
23+
assert_equals("".split.call(iframe.contentWindow.location, "?")[1], "a=%81A")
24+
);
25+
26+
form.submit();
27+
}, "Test for euc-kr encoded form submission");
3128

3229
</script>
3330
</body>

0 commit comments

Comments
 (0)