diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 7311f90d1156..05949c9069ba 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -4787,7 +4787,7 @@ nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI, realChannel->SetTopWindowURI(mTopWindowURI); realChannel->StoreTaintedOriginFlag( - ShouldTaintReplacementChannelOrigin(newURI)); + ShouldTaintReplacementChannelOrigin(newChannel, redirectFlags)); } // update the DocumentURI indicator since we are being redirected. @@ -4864,20 +4864,29 @@ nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI, return NS_OK; } -bool HttpBaseChannel::ShouldTaintReplacementChannelOrigin(nsIURI* aNewURI) { +bool HttpBaseChannel::ShouldTaintReplacementChannelOrigin( + nsIChannel* aNewChannel, uint32_t aRedirectFlags) { if (LoadTaintedOriginFlag()) { return true; } + if (NS_IsInternalSameURIRedirect(this, aNewChannel, aRedirectFlags) || + NS_IsHSTSUpgradeRedirect(this, aNewChannel, aRedirectFlags)) { + return false; + } + nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); if (!ssm) { return true; } - nsresult rv = ssm->CheckSameOriginURI(aNewURI, mURI, false, false); + + nsCOMPtr newURI; + NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI)); + nsresult rv = ssm->CheckSameOriginURI(newURI, mURI, false, false); if (NS_SUCCEEDED(rv)) { return false; } - // If aNewURI <-> mURI are not same-origin we need to taint unless + // If newURI <-> mURI are not same-origin we need to taint unless // mURI <-> mOriginalURI/LoadingPrincipal are same origin. if (mLoadInfo->GetLoadingPrincipal()) { diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index fa20f920a052..9e97abe7e1c4 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -570,7 +570,8 @@ class HttpBaseChannel : public nsHashPropertyBag, nsIURI*, nsIChannel*, bool preserveMethod, uint32_t redirectFlags); // WHATWG Fetch Standard 4.4. HTTP-redirect fetch, step 10 - virtual bool ShouldTaintReplacementChannelOrigin(nsIURI* aNewURI); + virtual bool ShouldTaintReplacementChannelOrigin(nsIChannel* aNewChannel, + uint32_t aRedirectFlags); // bundle calling OMR observers and marking flag into one function inline void CallOnModifyRequestObservers() { diff --git a/netwerk/protocol/http/TRRServiceChannel.h b/netwerk/protocol/http/TRRServiceChannel.h index 3bec408bf8de..deee6fefb1af 100644 --- a/netwerk/protocol/http/TRRServiceChannel.h +++ b/netwerk/protocol/http/TRRServiceChannel.h @@ -142,7 +142,8 @@ class TRRServiceChannel : public HttpBaseChannel, nsIURI* aNewURI, nsIChannel* aNewChannel, bool aPreserveMethod, uint32_t aRedirectFlags) override; // Skip this check for TRRServiceChannel. - virtual bool ShouldTaintReplacementChannelOrigin(nsIURI* aNewURI) override { + virtual bool ShouldTaintReplacementChannelOrigin( + nsIChannel* aNewChannel, uint32_t aRedirectFlags) override { return false; } virtual bool SameOriginWithOriginalUri(nsIURI* aURI) override; diff --git a/netwerk/test/unit/test_httpssvc_https_upgrade.js b/netwerk/test/unit/test_httpssvc_https_upgrade.js index 7e9e699a28e0..f49a56cb378e 100644 --- a/netwerk/test/unit/test_httpssvc_https_upgrade.js +++ b/netwerk/test/unit/test_httpssvc_https_upgrade.js @@ -18,6 +18,12 @@ const { TestUtils } = ChromeUtils.importESModule( "resource://testing-common/TestUtils.sys.mjs" ); +const ReferrerInfo = Components.Constructor( + "@mozilla.org/referrer-info;1", + "nsIReferrerInfo", + "init" +); + add_setup(async function setup() { trr_test_setup(); @@ -307,3 +313,43 @@ add_task(async function testHttpRequestBlocked() { dnsRequestObserver.unregister(); await new Promise(resolve => httpserv.stop(resolve)); }); + +function createPrincipal(url) { + return Services.scriptSecurityManager.createContentPrincipal( + Services.io.newURI(url), + {} + ); +} + +// Test if the Origin header stays the same after an internal HTTPS upgrade +// caused by HTTPS RR. +add_task(async function testHTTPSRRUpgradeWithOriginHeader() { + dns.clearCache(true); + + const url = "http://test.httpssvc.com:80/origin_header"; + const originURL = "http://example.com"; + let chan = Services.io + .newChannelFromURIWithProxyFlags( + Services.io.newURI(url), + null, + Ci.nsIProtocolProxyService.RESOLVE_ALWAYS_TUNNEL, + null, + createPrincipal(originURL), + createPrincipal(url), + Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, + Ci.nsIContentPolicy.TYPE_DOCUMENT + ) + .QueryInterface(Ci.nsIHttpChannel); + chan.referrerInfo = new ReferrerInfo( + Ci.nsIReferrerInfo.EMPTY, + true, + NetUtil.newURI(url) + ); + chan.setRequestHeader("Origin", originURL, false); + + let [req, buf] = await channelOpenPromise(chan); + + req.QueryInterface(Ci.nsIHttpChannel); + Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); + Assert.equal(buf, originURL); +}); diff --git a/testing/xpcshell/moz-http2/moz-http2.js b/testing/xpcshell/moz-http2/moz-http2.js index 5075dbab4005..ebc18294ce36 100644 --- a/testing/xpcshell/moz-http2/moz-http2.js +++ b/testing/xpcshell/moz-http2/moz-http2.js @@ -1851,6 +1851,14 @@ function handleRequest(req, res) { res.writeHead(200); res.end(""); return; + } else if (u.pathname === "/origin_header") { + let originHeader = req.headers.origin; + res.setHeader("Content-Length", originHeader.length); + res.setHeader("Content-Type", "text/plain"); + res.writeHead(200); + res.write(originHeader); + res.end(); + return; } res.setHeader("Content-Type", "text/html"); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_dnr_without_webrequest.js b/toolkit/components/extensions/test/xpcshell/test_ext_dnr_without_webrequest.js index ed88b516c0bc..f7bea03a3b36 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_dnr_without_webrequest.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_dnr_without_webrequest.js @@ -257,10 +257,8 @@ add_task(async function upgradeScheme_declarativeNetRequestWithHostAccess() { // https://github.com/w3c/webappsec-upgrade-insecure-requests/issues/32 Assert.equal( (await contentFetch("http://dummy/", "http://redir/never_reached")).url, - // TODO bug 1800990: despite the mirrored Origin in ACAO, the CORS check - // fails after a request is upgraded. Once fixed, update this expectation: - undefined, // Should be: "http://dummy/cors_202?from_https", - "TODO 1800990: upgradeScheme + host access should upgrade (cross-origin request)" + "http://dummy/cors_202?from_https", + "upgradeScheme + host access should upgrade (cross-origin request)" ); // The DNR extension does not have example.net in host_permissions.