diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index c9a7391b1bc7..7bd4a247294b 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -2500,27 +2500,6 @@ XMLHttpRequestMainThread::CreateChannel() secFlags |= nsILoadInfo::SEC_COOKIES_OMIT; } - nsCOMPtr ep = do_QueryInterface(mPrincipal); - if (ep) { - // If we have an expanded principal, instead of using that, select the - // principal in the whitelist which can load our URL, and use that instead. - nsTArray>* whitelist = nullptr; - ep->GetWhiteList(&whitelist); - if (!whitelist) { - return NS_ERROR_FAILURE; - } - MOZ_ASSERT(!(secFlags & nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS)); - bool dataInherits = (secFlags & - (nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS | - nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS)) != 0; - for (const auto& principal : *whitelist) { - if (NS_SUCCEEDED(principal->CheckMayLoad(mRequestURL, false, dataInherits))) { - mPrincipal = principal; - break; - } - } - } - // Use the responsibleDocument if we have it, except for dedicated workers // where it will be the parent document, which is not the one we want to use. nsresult rv; @@ -2559,6 +2538,35 @@ XMLHttpRequestMainThread::CreateChannel() } } + // Using the provided principal as the triggeringPrincipal is fine, since we + // want to be able to access any of the origins that the principal has access + // to during the security checks, but we don't want a document to inherit an + // expanded principal, so in that case we need to select the principal in the + // expanded principal's whitelist that can load our URL as principalToInherit. + nsCOMPtr resultingDocumentPrincipal(mPrincipal); + nsCOMPtr ep = do_QueryInterface(mPrincipal); + if (ep) { + nsTArray>* whitelist = nullptr; + ep->GetWhiteList(&whitelist); + if (!whitelist) { + return NS_ERROR_FAILURE; + } + MOZ_ASSERT(!(secFlags & nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS)); + bool dataInherits = (secFlags & + (nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS | + nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS)) != 0; + for (const auto& principal : *whitelist) { + if (NS_SUCCEEDED(principal->CheckMayLoad(mRequestURL, false, dataInherits))) { + resultingDocumentPrincipal = principal; + break; + } + } + } + + nsCOMPtr loadInfo = mChannel->GetLoadInfo(); + rv = loadInfo->SetPrincipalToInherit(resultingDocumentPrincipal); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; } diff --git a/js/xpconnect/tests/unit/test_allowedDomainsXHR.js b/js/xpconnect/tests/unit/test_allowedDomainsXHR.js index fd7c17c34de3..71bfe942ba02 100644 --- a/js/xpconnect/tests/unit/test_allowedDomainsXHR.js +++ b/js/xpconnect/tests/unit/test_allowedDomainsXHR.js @@ -4,12 +4,16 @@ cu.import("resource://testing-common/httpd.js"); var httpserver = new HttpServer(); var httpserver2 = new HttpServer(); +var httpserver3 = new HttpServer(); var testpath = "/simple"; +var redirectpath = "/redirect"; var negativetestpath = "/negative"; var httpbody = "0123456789"; var sb = cu.Sandbox(["http://www.example.com", - "http://localhost:4444/simple"], + "http://localhost:4444/redirect", + "http://localhost:4444/simple", + "http://localhost:4446/redirect"], { wantGlobalProperties: ["XMLHttpRequest"] }); function createXHR(loc, async) @@ -35,7 +39,7 @@ function checkResults(xhr) var httpServersClosed = 0; function finishIfDone() { - if (++httpServersClosed == 2) + if (++httpServersClosed == 3) do_test_finished(); } @@ -44,11 +48,15 @@ function run_test() do_test_pending(); httpserver.registerPathHandler(testpath, serverHandler); + httpserver.registerPathHandler(redirectpath, redirectHandler1); httpserver.start(4444); httpserver2.registerPathHandler(negativetestpath, serverHandler); httpserver2.start(4445); + httpserver3.registerPathHandler(redirectpath, redirectHandler2); + httpserver3.start(4446); + // Test sync XHR sending cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb); var res = cu.evalInSandbox('var sync = createXHR("4444/simple"); sync.send(null); sync', sb); @@ -68,7 +76,21 @@ function run_test() do_check_true(true); } + // Test redirect handling. + // This request bounces to server 2 and then back to server 1. Neither of + // these servers support CORS, but if the expanded principal is used as the + // triggering principal, this should work. + cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb); + var res = cu.evalInSandbox('var sync = createXHR("4444/redirect"); sync.send(null); sync', sb); + do_check_true(checkResults(res)); + + var principal = res.responseXML.nodePrincipal; + do_check_true(principal.isCodebasePrincipal); + var requestURL = "http://localhost:4444/simple"; + do_check_eq(principal.URI.spec, requestURL); + httpserver2.stop(finishIfDone); + httpserver3.stop(finishIfDone); // Test async XHR sending sb.finish = function(){ @@ -95,8 +117,20 @@ function run_test() async.send(null); } -function serverHandler(metadata, response) +function serverHandler(request, response) { response.setHeader("Content-Type", "text/xml", false); response.bodyOutputStream.write(httpbody, httpbody.length); } + +function redirectHandler1(request, response) +{ + response.setStatusLine(request.httpVersion, 302, "Found"); + response.setHeader("Location", "http://localhost:4446/redirect", false); +} + +function redirectHandler2(request, response) +{ + response.setStatusLine(request.httpVersion, 302, "Found"); + response.setHeader("Location", "http://localhost:4444/simple", false); +}