commit 89226c03e3aed9c1ff3c740e0dcdcb0ac7e8e5ff Author: Kathy Brade brade@pearlcrescent.com Date: Fri Jan 29 16:47:26 2016 -0500
fixup! Bug 16620: Clear window.name when no referrer sent
Only clear window.name for the top document, not for frames. This fixes Bug 18168: iframe-based AJAX call opening in new tab and more closely matches the behavior of Torbutton's old JavaScript-based implementation. --- docshell/base/nsDocShell.cpp | 18 +++-- docshell/test/mochitest.ini | 1 + docshell/test/test_tor_bug16620.html | 131 ++++++++++++++++++++++++++++------- docshell/test/tor_bug16620_form.html | 51 ++++++++++++++ 4 files changed, 173 insertions(+), 28 deletions(-)
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 0c404fa..3f059673 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -8993,8 +8993,9 @@ nsDocShell::CreateContentViewer(const char* aContentType, } FirePageHideNotification(!mSavingOldViewer);
- // Tor bug # 16620: Clear window.name if there is no referrer. We make an - // exception for new windows, e.g., window.open(url, "MyName"). + // Tor bug 16620: Clear window.name of top-level documents if + // there is no referrer. We make an exception for new windows, + // e.g., window.open(url, "MyName"). bool isNewWindowTarget = false; nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aRequest, &rv)); if (props) { @@ -9008,6 +9009,13 @@ nsDocShell::CreateContentViewer(const char* aContentType, if (httpChannel) httpChannel->GetReferrer(getter_AddRefs(httpReferrer));
+ bool isTopFrame = true; + nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem; + rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem)); + if (NS_SUCCEEDED(rv) && targetParentTreeItem) { + isTopFrame = false; + } + #ifdef DEBUG_WINDOW_NAME printf("DOCSHELL %p CreateContentViewer - possibly clearing window.name:\n", this); printf(" current window.name: "%s"\n", @@ -9020,6 +9028,7 @@ nsDocShell::CreateContentViewer(const char* aContentType, mLoadingURI->GetSpec(loadingSpec); printf(" current URI: %s\n", curSpec.get()); printf(" loading URI: %s\n", loadingSpec.get()); + printf(" is top document: %s\n", isTopFrame ? "Yes" : "No");
if (!httpReferrer) { printf(" referrer: None\n"); @@ -9030,12 +9039,13 @@ nsDocShell::CreateContentViewer(const char* aContentType, } #endif
- if (!httpReferrer) + bool clearName = isTopFrame && !httpReferrer; + if (clearName) SetName(NS_LITERAL_STRING(""));
#ifdef DEBUG_WINDOW_NAME printf(" action taken: %s window.name\n", - httpReferrer ? "Preserved" : "Cleared"); + clearName ? "Cleared" : "Preserved"); #endif }
diff --git a/docshell/test/mochitest.ini b/docshell/test/mochitest.ini index a1325b9..274a77e 100644 --- a/docshell/test/mochitest.ini +++ b/docshell/test/mochitest.ini @@ -35,6 +35,7 @@ support-files = file_pushState_after_document_open.html historyframes.html tor_bug16620.html + tor_bug16620_form.html
[test_anchor_scroll_after_document_open.html] [test_bfcache_plus_hash.html] diff --git a/docshell/test/test_tor_bug16620.html b/docshell/test/test_tor_bug16620.html index 0fe9603..d528e17 100644 --- a/docshell/test/test_tor_bug16620.html +++ b/docshell/test/test_tor_bug16620.html @@ -17,36 +17,80 @@
// ## Test constants const kTestPath = "/tests/docshell/test/"; -const kFile = "tor_bug16620.html"; +const kLinkFile = "tor_bug16620.html"; +const kFormFile = "tor_bug16620_form.html"; const kBaseURL1 = "http://example.com"; +const kBaseURL1_https = "https://example.com"; const kBaseURL2 = "http://example.net"; +const kSendReferrerPref = "network.http.sendRefererHeader"; +const kSendReferrerNever = 0; +const kSendReferrerForUserAction = 1; +const kSendReferrerAlways = 2;
let gTests = [ - // Test #1: Same domain: + // Test #1: Same domain; never send referrer. { startURL: kBaseURL1, destURL: kBaseURL1, + referrerPref: kSendReferrerNever, + expectIsolation: true }, + + // Test #2: Same domain; send referrer upon user action. + { startURL: kBaseURL1, destURL: kBaseURL1, + referrerPref: kSendReferrerForUserAction, expectIsolation: false },
- // Test #2: Different top-level domains: + // Test #3: Same domain; always send referrer. + { startURL: kBaseURL1, destURL: kBaseURL1, + referrerPref: kSendReferrerAlways, + expectIsolation: false }, + + // Test #4: Different top-level domains; never send referrer. + { startURL: kBaseURL1, destURL: kBaseURL2, + referrerPref: kSendReferrerNever, + expectIsolation: true }, + + // Test #5: Different top-level domains; send referrer upon user action. { startURL: kBaseURL1, destURL: kBaseURL2, + referrerPref: kSendReferrerForUserAction, expectIsolation: false },
- // Test #3: Same domain, rel="noreferrer" on link: + // Test #6: Different top-level domains; always send referrer. + { startURL: kBaseURL1, destURL: kBaseURL2, + referrerPref: kSendReferrerAlways, + expectIsolation: false }, + + // Test #7: https -> http transition. + { startURL: kBaseURL1_https, destURL: kBaseURL1, + referrerPref: kSendReferrerForUserAction, + expectIsolation: true }, + + // Test #8: Same domain, rel="noreferrer" on link. { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerOnLink: true, + referrerPref: kSendReferrerAlways, expectIsolation: true },
- // Test #4: Same domain, "no-referrer" meta tag in document: + // Test #9: Same domain, "no-referrer" meta tag in document. { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerInMetaTag: true, + referrerPref: kSendReferrerAlways, expectIsolation: true },
- // Test #5: Like test 4, but reset window.name during unload: + // Test #10: Like test #9, but reset window.name during unload. // (similar to http://www.thomasfrank.se/sessvarsTestPage1.html) { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerInMetaTag: true, resetInUnload: true, + referrerPref: kSendReferrerAlways, expectIsolation: true },
- // Test #6: Data URL as destination (no referrer): + // Test #11: Data URL as destination (no referrer). { startURL: kBaseURL1, + referrerPref: kSendReferrerAlways, expectIsolation: true }, + + // Test #12: Ensure that window.name is preserved when a dynamically loaded + // iframe is used to perform a form post (regression test for Tor bug 18168). + { startURL: kBaseURL1, + isFormTest: true, + referrerPref: kSendReferrerAlways, + expectIsolation: false }, ];
let gCurTest = 0; @@ -65,9 +109,19 @@ function startNextTest() { SimpleTest.finish(); } else { let curTest = gTests[gCurTest - 1]; - let url = curTest.startURL + kTestPath + kFile + "?firstDocLoaded"; + if ("referrerPref" in curTest) + SpecialPowers.setIntPref(kSendReferrerPref, curTest.referrerPref); + else + SpecialPowers.setIntPref(kSendReferrerPref, kSendReferrerForUserAction); gCurWinName = generateRandomName(); - gChildWin = window.open(url, gCurWinName); + let url = curTest.startURL + kTestPath; + if (curTest.isFormTest === true) { + url += kFormFile + "?" + gCurWinName; + gChildWin = window.open(url, undefined); + } else { + url += kLinkFile + "?firstDocLoaded"; + gChildWin = window.open(url, gCurWinName); + } } }
@@ -78,16 +132,22 @@ window.addEventListener("message", function(aEvent) {
// console.log("parent received message:" + JSON.stringify(aEvent.data));
+ let proceedToNextTest = false; let curTest = gTests[gCurTest - 1]; let state = aEvent.data.state; let winName = aEvent.data.winName; if ("firstDocLoaded" == state) { - ok(winName === gCurWinName, "Test #" + gCurTest + + // Process response from step one of the link-based tests. + let step1Passed = (winName === gCurWinName); + if (!step1Passed) { + ok(step1Passed, "Test #" + gCurTest + " - first document's name matches window.open parameter"); + proceedToNextTest = true; + }
// Send an "openURL" message to the loaded document. let url2 = (curTest.destURL) - ? curTest.destURL + kTestPath + kFile + "?secondDocLoaded" + ? curTest.destURL + kTestPath + kLinkFile + "?secondDocLoaded" : gDataURL; let noReferrerOnLink = (curTest.noReferrerOnLink === true); let noReferrerInMetaTag = (curTest.noReferrerInMetaTag === true); @@ -98,6 +158,7 @@ window.addEventListener("message", function(aEvent) { resetInUnload: resetInUnload }, aEvent.origin); } else if ("secondDocLoaded" == state) { + // Process response from step two of the link-based tests. if (curTest.expectIsolation) { ok(winName === "", "Test #" + gCurTest + " - second document: name was cleared"); @@ -105,25 +166,47 @@ window.addEventListener("message", function(aEvent) { ok(winName === gCurWinName, "Test #" + gCurTest + " - second document: name was preserved"); } + proceedToNextTest = true; + } else if ("formPostDone" == state) { + // Process response from the form post tests. + if (curTest.expectIsolation) { + ok(winName === "", + "Test #" + gCurTest + " - iframe form post: name was cleared"); + } else { + ok(winName === gCurWinName, + "Test #" + gCurTest + " - iframe form post: name was preserved"); + } + proceedToNextTest = true; + + }
+ if (proceedToNextTest) { gChildWin.close(); startNextTest(); } }, false);
-SimpleTest.waitForExplicitFinish(); - -// Read file contents, construct a data URL (used by some tests), and -// then start the first test. -let url = kTestPath + kFile; -let xhr = new XMLHttpRequest(); -xhr.open("GET", url); -xhr.onload = function() { - gDataURL = "data:text/html;charset=utf-8," - + encodeURIComponent(this.responseText); - startNextTest(); -} -xhr.send(); + SimpleTest.waitForExplicitFinish(); + + if (SpecialPowers.getBoolPref("security.nocertdb")) { + // Mochitests don't simulate https correctly with "security.nocertdb" + // enabled. See https://bugs.torproject.org/18087 + ok(false, "Please disable the pref `security.nocertdb` before running this test."); + SimpleTest.finish(); + } else { + + // Read file contents, construct a data URL (used by some tests), and + // then start the first test. + let url = kTestPath + kLinkFile; + let xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.onload = function() { + gDataURL = "data:text/html;charset=utf-8," + + encodeURIComponent(this.responseText); + startNextTest(); + } + xhr.send(); + } </script> </body> </html> diff --git a/docshell/test/tor_bug16620_form.html b/docshell/test/tor_bug16620_form.html new file mode 100644 index 0000000..3b6e6c7 --- /dev/null +++ b/docshell/test/tor_bug16620_form.html @@ -0,0 +1,51 @@ +<!DOCTYPE HTML> +<html> +<!-- + Tor Bug 16620: Clear window.name when no referrer sent. + https://trac.torproject.org/projects/tor/ticket/16620 + + Regression test for bug 18168: iframe-based AJAX call opening in new tab +--> +<head> + <meta charset="UTF-8"> + <title>Supporting Form-based Doc for Tor Bug 16620 Tests</title> +</head> +<body> + +<script type="application/javascript;version=1.7"> +document.addEventListener("DOMContentLoaded", function () { + addPostTarget(); +}, false); + + +function addPostTarget() +{ + let frameName = location.search.substr(1); + let form = document.getElementById("postform"); + let iframe = document.createElement("iframe"); + iframe.style.border = "1px solid red"; + iframe.src = "about:blank"; + form.target = iframe.name = iframe.id = frameName; + document.body.appendChild(iframe); + + let didSubmit = false; + iframe.onload = function() { + if (!didSubmit) { + didSubmit = true; + let submitButton = document.getElementById("submitButton"); + submitButton.click(); + } else { + // Form submission complete. Report iframe's name to test driver. + opener.postMessage({ state: "formPostDone", winName: iframe.name }, "*"); + } + }; +} + +</script> +<form name="postform" id="postform" + action="data:text/plain;charset=utf-8,Hello%20world" + method="POST" enctype="multipart/form-data"> + <input type="hidden" name="field1" value="value1"><br> + <input id="submitButton" type="submit" value="Post It"> +</body> +</html>