author | Phil Ames <philames@google.com> |
Mon, 27 Aug 2012 15:46:24 -0400 | |
changeset 103599 | 72755799451cc5e8d79dfc0e1c430634f19df023 |
parent 103598 | 721ff7492145e230ba54431548dc8afb7865c1c1 |
child 103600 | 8ac55d26cf220716f85cc55471b2eb5cbdc5069f |
push id | 14069 |
push user | bzbarsky@mozilla.com |
push date | Mon, 27 Aug 2012 19:46:40 +0000 |
treeherder | mozilla-inbound@72755799451c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bzbarsky |
bugs | 690168 |
milestone | 17.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/test/file_x-frame-options_main.html +++ b/content/base/test/file_x-frame-options_main.html @@ -14,11 +14,13 @@ window.addEventListener('load', parent.t <iframe id="deny" src="http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny"></iframe><br> <iframe id="sameorigin1" src="http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin1&xfo=sameorigin"></iframe><br> <iframe id="sameorigin2" src="http://example.com/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin2&xfo=sameorigin"></iframe><br> <iframe id="sameorigin5" src="http://example.com/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin5&xfo=sameorigin2"></iframe><br> <iframe id="sameorigin6" src="http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin6&xfo=sameorigin2"></iframe><br> <iframe id="sameorigin7" src="http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin7&xfo=sameorigin3"></iframe><br> <iframe id="sameorigin8" src="http://example.com/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin8&xfo=sameorigin3"></iframe><br> <iframe id="mixedpolicy" src="http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=mixedpolicy&xfo=mixedpolicy"></iframe><br> +<iframe id="allow-from-allow" src="http://example.com/tests/content/base/test/file_x-frame-options_page.sjs?testid=allow-from-allow&xfo=afa"></iframe><br> +<iframe id="allow-from-deny" src="http://example.com/tests/content/base/test/file_x-frame-options_page.sjs?testid=allow-from-deny&xfo=afd"></iframe><br> </body> </html>
--- a/content/base/test/file_x-frame-options_page.sjs +++ b/content/base/test/file_x-frame-options_page.sjs @@ -21,13 +21,19 @@ function handleRequest(request, response response.setHeader("X-Frame-Options", "SAMEORIGIN, SAMEORIGIN", false); } else if (query['xfo'] == "sameorigin3") { response.setHeader("X-Frame-Options", "SAMEORIGIN,SAMEORIGIN , SAMEORIGIN", false); } else if (query['xfo'] == "mixedpolicy") { response.setHeader("X-Frame-Options", "DENY,SAMEORIGIN", false); } + else if (query['xfo'] == "afa") { + response.setHeader("X-Frame-Options", "ALLOW-FROM http://mochi.test:8888/", false); + } + else if (query['xfo'] == "afd") { + response.setHeader("X-Frame-Options", "ALLOW-FROM http://example.com/", false); + } // from the test harness we'll be checking for the presence of this element // to test if the page loaded response.write("<h1 id=\"test\">" + query["testid"] + "</h1>"); }
--- a/content/base/test/test_x-frame-options.html +++ b/content/base/test/test_x-frame-options.html @@ -103,16 +103,26 @@ var testFramesLoaded = function() { var test9 = frame.contentDocument.getElementById("test"); is(test9, null, "test sameorigin8"); // iframe from same origin, X-F-O: DENY,SAMEORIGIN - should not load frame = harness.contentDocument.getElementById("mixedpolicy"); var test10 = frame.contentDocument.getElementById("test"); is(test10, null, "test mixedpolicy"); + // iframe from different origin, allow-from: this origin - should load + frame = harness.contentDocument.getElementById("allow-from-allow"); + var test11 = frame.contentDocument.getElementById("test").textContent; + is(test11, "allow-from-allow", "test allow-from-allow"); + + // iframe from different origin, with allow-from: other - should not load + frame = harness.contentDocument.getElementById("allow-from-deny"); + var test12 = frame.contentDocument.getElementById("test"); + is(test12, null, "test allow-from-deny"); + // call tests to check principal comparison, e.g. a document can open a window // to a data: or javascript: document which frames an // X-Frame-Options: SAMEORIGIN document and the frame should load testFrameInJSURI(); } // test that a document can be framed under a javascript: URL opened by the // same site as the frame
--- a/docshell/base/nsDSURIContentListener.cpp +++ b/docshell/base/nsDSURIContentListener.cpp @@ -6,16 +6,17 @@ #include "nsDocShell.h" #include "nsDSURIContentListener.h" #include "nsIChannel.h" #include "nsServiceManagerUtils.h" #include "nsXPIDLString.h" #include "nsDocShellCID.h" #include "nsIWebNavigationInfo.h" #include "nsIDOMWindow.h" +#include "nsNetUtil.h" #include "nsAutoPtr.h" #include "nsIHttpChannel.h" #include "nsIScriptSecurityManager.h" #include "nsError.h" #include "nsCharSeparatedTokenizer.h" #include "mozilla/Preferences.h" using namespace mozilla; @@ -253,19 +254,25 @@ nsDSURIContentListener::SetParentContent mWeakParentContentListener = nullptr; mParentContentListener = nullptr; } return NS_OK; } bool nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIRequest *request, const nsAString& policy) { - // return early if header does not have one of the two values with meaning + static const char allowFrom[] = "allow-from "; + const PRUint32 allowFromLen = ArrayLength(allowFrom) - 1; + bool isAllowFrom = + StringHead(policy, allowFromLen).LowerCaseEqualsLiteral(allowFrom); + + // return early if header does not have one of the values with meaning if (!policy.LowerCaseEqualsLiteral("deny") && - !policy.LowerCaseEqualsLiteral("sameorigin")) + !policy.LowerCaseEqualsLiteral("sameorigin") && + !isAllowFrom) return true; nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request); if (!httpChannel) { return true; } if (mDocShell) { @@ -337,28 +344,42 @@ bool nsDSURIContentListener::CheckOneFra // If the value of the header is DENY, and the previous condition is // not met (current docshell is not the top docshell), prohibit the // load. if (policy.LowerCaseEqualsLiteral("deny")) { return false; } + topDoc = do_GetInterface(curDocShellItem); + nsCOMPtr<nsIURI> topUri; + topDoc->NodePrincipal()->GetURI(getter_AddRefs(topUri)); + nsCOMPtr<nsIURI> uri; + // If the X-Frame-Options value is SAMEORIGIN, then the top frame in the // parent chain must be from the same origin as this document. if (policy.LowerCaseEqualsLiteral("sameorigin")) { - nsCOMPtr<nsIURI> uri; httpChannel->GetURI(getter_AddRefs(uri)); - topDoc = do_GetInterface(curDocShellItem); - nsCOMPtr<nsIURI> topUri; - topDoc->NodePrincipal()->GetURI(getter_AddRefs(topUri)); rv = ssm->CheckSameOriginURI(uri, topUri, true); if (NS_FAILED(rv)) return false; /* wasn't same-origin */ } + + // If the X-Frame-Options value is "allow-from [uri]", then the top + // frame in the parent chain must be from that origin + if (isAllowFrom) { + rv = NS_NewURI(getter_AddRefs(uri), + Substring(policy, allowFromLen)); + if (NS_FAILED(rv)) + return false; + + rv = ssm->CheckSameOriginURI(uri, topUri, true); + if (NS_FAILED(rv)) + return false; + } } return true; } // Check if X-Frame-Options permits this document to be loaded as a subdocument. // This will iterate through and check any number of X-Frame-Options policies // in the request (comma-separated in a header, multiple headers, etc).
--- a/dom/browser-element/mochitest/Makefile.in +++ b/dom/browser-element/mochitest/Makefile.in @@ -58,16 +58,20 @@ MOCHITEST_FILES = \ test_browserElement_inproc_XFrameOptions.html \ file_browserElement_XFrameOptions.sjs \ browserElement_XFrameOptionsDeny.js \ test_browserElement_inproc_XFrameOptionsDeny.html \ file_browserElement_XFrameOptionsDeny.html \ browserElement_XFrameOptionsSameOrigin.js \ test_browserElement_inproc_XFrameOptionsSameOrigin.html \ file_browserElement_XFrameOptionsSameOrigin.html \ + browserElement_XFrameOptionsAllowFrom.js \ + test_browserElement_inproc_XFrameOptionsAllowFrom.html \ + file_browserElement_XFrameOptionsAllowFrom.html \ + file_browserElement_XFrameOptionsAllowFrom.sjs \ browserElement_Alert.js \ test_browserElement_inproc_Alert.html \ browserElement_AlertInFrame.js \ test_browserElement_inproc_AlertInFrame.html \ file_browserElement_AlertInFrame.html \ file_browserElement_AlertInFrame_Inner.html \ browserElement_TargetTop.js \ test_browserElement_inproc_TargetTop.html \ @@ -149,16 +153,17 @@ MOCHITEST_FILES += \ test_browserElement_oop_GetScreenshot.html \ test_browserElement_oop_SetVisible.html \ test_browserElement_oop_SetVisibleFrames.html \ test_browserElement_oop_SetVisibleFrames2.html \ test_browserElement_oop_KeyEvents.html \ test_browserElement_oop_XFrameOptions.html \ test_browserElement_oop_XFrameOptionsDeny.html \ test_browserElement_oop_XFrameOptionsSameOrigin.html \ + test_browserElement_oop_XFrameOptionsAllowFrom.html \ test_browserElement_oop_Alert.html \ test_browserElement_oop_AlertInFrame.html \ test_browserElement_oop_TargetTop.html \ test_browserElement_oop_ForwardName.html \ test_browserElement_oop_TargetBlank.html \ test_browserElement_oop_PromptCheck.html \ test_browserElement_oop_PromptConfirm.html \ test_browserElement_oop_Close.html \
new file mode 100644 --- /dev/null +++ b/dom/browser-element/mochitest/browserElement_XFrameOptionsAllowFrom.js @@ -0,0 +1,53 @@ +/* Any copyright is dedicated to the public domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Bug 690168 - Support Allow-From notation for X-Frame-Options header. +"use strict"; + +SimpleTest.waitForExplicitFinish(); + +var initialScreenshot = null; + +function runTest() { + browserElementTestHelpers.setEnabledPref(true); + browserElementTestHelpers.addPermission(); + var count = 0; + + var iframe = document.createElement('iframe'); + iframe.mozbrowser = true; + iframe.height = '1000px'; + + // The innermost page we load will fire an alert when it successfully loads. + iframe.addEventListener('mozbrowsershowmodalprompt', function(e) { + switch (e.detail.message) { + case 'step 1': + // Make the page wait for us to unblock it (which we do after we finish + // taking the screenshot). + e.preventDefault(); + + iframe.getScreenshot().onsuccess = function(sshot) { + if (initialScreenshot == null) + initialScreenshot = sshot.target.result; + e.detail.unblock(); + }; + break; + case 'step 2': + ok(false, 'cross origin page loaded'); + break; + case 'finish': + // The page has now attempted to load the X-Frame-Options page; take + // another screenshot. + iframe.getScreenshot().onsuccess = function(sshot) { + is(sshot.target.result, initialScreenshot, "Screenshots should be identical"); + SimpleTest.finish(); + }; + break; + } + }); + + document.body.appendChild(iframe); + + iframe.src = 'http://example.com/tests/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html'; +} + +runTest();
new file mode 100644 --- /dev/null +++ b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html @@ -0,0 +1,43 @@ +<html> +<body> + + <!-- Try to load in a frame a cross-origin page which sends: + "X-Frame-Options: Allow-From http://mochi.test:8888/", + and a cross-origin page which sends + "X-Frame-Options: Allow-From http://example.com/". --> + +<script> + +// Make sure these iframes aren't too tall; they both need to fit inside the +// iframe this page is contained in, without scrolling, in order for the test's +// screenshots to work properly. + +var frame_src = 'http://example.com/tests/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs'; + +var iframe1 = document.createElement('iframe'); +iframe1.height = '300px'; +var iframe2 = document.createElement('iframe'); +iframe2.height = '300px'; +document.body.appendChild(iframe1); +document.body.appendChild(iframe2); + +iframe1.addEventListener('load', function iframe1Load() { + iframe1.removeEventListener('load', iframe1Load); + // This causes our embedder to take a screenshot (and blocks until the + // screenshot is completed). + var iframe2Loaded = false; + iframe2.addEventListener('load', function iframe2Load() { + iframe2.removeEventListener('load', iframe2Load); + iframe2Loaded = true; + alert('finish'); + }); + + setTimeout(function() { iframe2.src = frame_src; }, 1000); +}); + + +iframe1.src = frame_src + '?iframe1'; +</script> + +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs @@ -0,0 +1,16 @@ +function handleRequest(request, response) +{ + var content = 'step 1'; + if (request.queryString == "iframe1") { + response.setHeader("X-Frame-Options", "Allow-From http://mochi.test:8888/") + content = 'finish'; + } else { + response.setHeader("X-Frame-Options", "Allow-From http://example.com") + } + + response.setHeader("Content-Type", "text/html", false); + + // Tests rely on this page not being entirely blank, because they take + // screenshots to determine whether this page was loaded. + response.write("<html><body>XFrameOptions test<script>alert('" + content + "')</script></body></html>"); +}
new file mode 100644 --- /dev/null +++ b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsAllowFrom.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Bug 690168</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="browserElementTestHelpers.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<script type="application/javascript;version=1.7" src="browserElement_XFrameOptionsAllowFrom.js"> +</script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsAllowFrom.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Bug 690168</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="browserElementTestHelpers.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<script type="application/javascript;version=1.7" src="browserElement_XFrameOptionsAllowFrom.js"> +</script> +</body> +</html>