Skip to content

Commit bed80e4

Browse files
committed
Bug 1503681 - rel=noopener implicit for target=_blank in anchor and area elements when no rel attribute is set, r=nika
In case anchor and area elements have target=_blank and no rel=opener/noopener, this patch makes so that rel=noopener is implied. This feature is behind pref 'dom_targetBlankNoOpener_enabled'. See: whatwg/html#4078
1 parent 6d5a049 commit bed80e4

File tree

6 files changed

+128
-1
lines changed

6 files changed

+128
-1
lines changed

docshell/base/nsDocShell.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13281,18 +13281,43 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent,
1328113281
nsAutoString referrer;
1328213282
aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, referrer);
1328313283
nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(referrer);
13284+
13285+
bool targetBlank = aTargetSpec.LowerCaseEqualsLiteral("_blank");
13286+
bool explicitOpenerSet = false;
13287+
13288+
// The opener behaviour follows a hierarchy, such that if a higher priority
13289+
// behaviour is specified, it always takes priority. That priority is
13290+
// currently: norefrerer > noopener > opener > default
13291+
1328413292
while (tok.hasMoreTokens()) {
1328513293
const nsAString& token = tok.nextToken();
1328613294
if (token.LowerCaseEqualsLiteral("noreferrer")) {
1328713295
flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER |
1328813296
INTERNAL_LOAD_FLAGS_NO_OPENER;
13289-
// We now have all the flags we could possibly have, so just stop.
13297+
// noreferrer cannot be overwritten by a 'rel=opener'.
13298+
explicitOpenerSet = true;
1329013299
break;
1329113300
}
13301+
1329213302
if (token.LowerCaseEqualsLiteral("noopener")) {
1329313303
flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
13304+
explicitOpenerSet = true;
13305+
}
13306+
13307+
if (targetBlank &&
13308+
StaticPrefs::dom_targetBlankNoOpener_enabled() &&
13309+
token.LowerCaseEqualsLiteral("opener") &&
13310+
!explicitOpenerSet) {
13311+
explicitOpenerSet = true;
1329413312
}
1329513313
}
13314+
13315+
if (targetBlank &&
13316+
StaticPrefs::dom_targetBlankNoOpener_enabled() &&
13317+
!explicitOpenerSet) {
13318+
flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
13319+
}
13320+
1329613321
if (aNoOpenerImplied) {
1329713322
flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
1329813323
}

dom/html/test/browser.ini

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,7 @@ skip-if = os == 'mac' # bug 1494843
3737
[browser_refresh_wyciwyg_url.js]
3838
support-files =
3939
file_refresh_wyciwyg_url.html
40+
[browser_targetBlankNoOpener.js]
41+
support-files =
42+
empty.html
43+
image_yellow.png
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
const TEST_URL = "http://mochi.test:8888/browser/dom/html/test/empty.html";
2+
3+
async function checkOpener(browser, elm, name, rel) {
4+
let p = BrowserTestUtils.waitForNewTab(gBrowser, null, true, true);
5+
6+
await ContentTask.spawn(browser, {url: TEST_URL, name, rel, elm }, async obj => {
7+
let element;
8+
9+
if (obj.elm == "anchor") {
10+
element = content.document.createElement("a");
11+
content.document.body.appendChild(element);
12+
element.appendChild(content.document.createTextNode(obj.name));
13+
} else {
14+
let img = content.document.createElement('img');
15+
img.src = "image_yellow.png";
16+
content.document.body.appendChild(img);
17+
18+
element = content.document.createElement("area");
19+
img.appendChild(element);
20+
21+
element.setAttribute("shape", "rect");
22+
element.setAttribute("coords", "0,0,100,100");
23+
}
24+
25+
element.setAttribute("target", "_blank");
26+
element.setAttribute("href", obj.url);
27+
28+
if (obj.rel) {
29+
element.setAttribute("rel", obj.rel);
30+
}
31+
32+
element.click();
33+
});
34+
35+
let newTab = await p;
36+
let newBrowser = gBrowser.getBrowserForTab(newTab);
37+
38+
let hasOpener = await ContentTask.spawn(newTab.linkedBrowser, null, _ => !!content.window.opener);
39+
40+
BrowserTestUtils.removeTab(newTab);
41+
return hasOpener;
42+
}
43+
44+
async function runTests(browser, elm) {
45+
info("Creating an " + elm + " with target=_blank rel=opener");
46+
ok(!!(await checkOpener(browser, elm, "rel=opener", "opener")), "We want the opener with rel=opener");
47+
48+
info("Creating an " + elm + " with target=_blank rel=noopener");
49+
ok(!(await checkOpener(browser, elm, "rel=noopener", "noopener")), "We don't want the opener with rel=noopener");
50+
51+
info("Creating an " + elm + " with target=_blank");
52+
ok(!(await checkOpener(browser, elm, "no rel", null)), "We don't want the opener with no rel is passed");
53+
54+
info("Creating an " + elm + " with target=_blank rel='noopener opener'");
55+
ok(!(await checkOpener(browser, elm, "rel=noopener+opener", "noopener opener")), "noopener wins with rel=noopener+opener");
56+
57+
info("Creating an " + elm + " with target=_blank rel='noreferrer opener'");
58+
ok(!(await checkOpener(browser, elm, "noreferrer wins", "noreferrer opener")), "We don't want the opener with rel=noreferrer+opener");
59+
60+
info("Creating an " + elm + " with target=_blank rel='opener noreferrer'");
61+
ok(!(await checkOpener(browser, elm, "noreferrer wins again", "noreferrer opener")), "We don't want the opener with rel=opener+noreferrer");
62+
}
63+
64+
add_task(async _ => {
65+
await SpecialPowers.flushPrefEnv();
66+
await SpecialPowers.pushPrefEnv({"set": [
67+
["dom.block_multiple_popups", false],
68+
["dom.disable_open_during_load", true],
69+
["dom.targetBlankNoOpener.enabled", true],
70+
]});
71+
72+
let tab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
73+
gBrowser.selectedTab = tab;
74+
75+
let browser = gBrowser.getBrowserForTab(tab);
76+
await BrowserTestUtils.browserLoaded(browser);
77+
78+
await runTests(browser, 'anchor');
79+
await runTests(browser, 'area');
80+
81+
info("Removing the tab");
82+
BrowserTestUtils.removeTab(tab);
83+
});

dom/html/test/empty.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<html><body></body></html>

dom/html/test/image_yellow.png

95 Bytes
Loading

modules/libpref/init/StaticPrefList.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,20 @@ VARCACHE_PREF(
460460
bool, true
461461
)
462462

463+
// For area and anchor elements with target=_blank and no rel set to
464+
// opener/noopener, this pref sets noopener by default.
465+
#ifdef EARLY_BETA_OR_EARLIER
466+
#define PREF_VALUE true
467+
#else
468+
#define PREF_VALUE false
469+
#endif
470+
VARCACHE_PREF(
471+
"dom.targetBlankNoOpener.enabled",
472+
dom_targetBlankNoOpener_enabled,
473+
bool, PREF_VALUE
474+
)
475+
#undef PREF_VALUE
476+
463477
//---------------------------------------------------------------------------
464478
// Clear-Site-Data prefs
465479
//---------------------------------------------------------------------------

0 commit comments

Comments
 (0)