diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index f83379634f99..ff7caa611355 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -443,7 +443,7 @@ nsCORSListenerProxy::Init(nsIChannel* aChannel, DataURIHandling aAllowDataURI) aChannel->GetNotificationCallbacks(getter_AddRefs(mOuterNotificationCallbacks)); aChannel->SetNotificationCallbacks(this); - nsresult rv = UpdateChannel(aChannel, aAllowDataURI); + nsresult rv = UpdateChannel(aChannel, aAllowDataURI, UpdateType::Default); if (NS_FAILED(rv)) { mOuterListener = nullptr; mRequestingPrincipal = nullptr; @@ -636,8 +636,22 @@ nsCORSListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel, nsIAsyncVerifyRedirectCallback *aCb) { nsresult rv; - if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags) && - !NS_IsHSTSUpgradeRedirect(aOldChannel, aNewChannel, aFlags)) { + if (NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags) || + NS_IsHSTSUpgradeRedirect(aOldChannel, aNewChannel, aFlags)) { + // Internal redirects still need to be updated in order to maintain + // the correct headers. We use DataURIHandling::Allow, since unallowed + // data URIs should have been blocked before we got to the internal + // redirect. + rv = UpdateChannel(aNewChannel, DataURIHandling::Allow, + UpdateType::InternalOrHSTSRedirect); + if (NS_FAILED(rv)) { + NS_WARNING("nsCORSListenerProxy::AsyncOnChannelRedirect: " + "internal redirect UpdateChannel() returned failure"); + aOldChannel->Cancel(rv); + return rv; + } + } else { + // A real, external redirect. Perform CORS checking on new URL. rv = CheckRequestApproved(aOldChannel); if (NS_FAILED(rv)) { nsCOMPtr oldURI; @@ -698,7 +712,8 @@ nsCORSListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel, } } - rv = UpdateChannel(aNewChannel, DataURIHandling::Disallow); + rv = UpdateChannel(aNewChannel, DataURIHandling::Disallow, + UpdateType::Default); if (NS_FAILED(rv)) { NS_WARNING("nsCORSListenerProxy::AsyncOnChannelRedirect: " "UpdateChannel() returned failure"); @@ -800,7 +815,8 @@ CheckUpgradeInsecureRequestsPreventsCORS(nsIPrincipal* aRequestingPrincipal, nsresult nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, - DataURIHandling aAllowDataURI) + DataURIHandling aAllowDataURI, + UpdateType aUpdateType) { nsCOMPtr uri, originalURI; nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); @@ -870,7 +886,7 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, // Check if we need to do a preflight, and if so set one up. This must be // called once we know that the request is going, or has gone, cross-origin. - rv = CheckPreflightNeeded(aChannel); + rv = CheckPreflightNeeded(aChannel, aUpdateType); NS_ENSURE_SUCCESS(rv, rv); // It's a cross site load @@ -909,7 +925,7 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, } nsresult -nsCORSListenerProxy::CheckPreflightNeeded(nsIChannel* aChannel) +nsCORSListenerProxy::CheckPreflightNeeded(nsIChannel* aChannel, UpdateType aUpdateType) { // If this caller isn't using AsyncOpen2, or if this *is* a preflight channel, // then we shouldn't initiate preflight for this channel. @@ -962,7 +978,9 @@ nsCORSListenerProxy::CheckPreflightNeeded(nsIChannel* aChannel) // A preflight is needed. But if we've already been cross-site, then // we already did a preflight when that happened, and so we're not allowed // to do another preflight again. - NS_ENSURE_FALSE(mHasBeenCrossSite, NS_ERROR_DOM_BAD_URI); + if (aUpdateType != UpdateType::InternalOrHSTSRedirect) { + NS_ENSURE_FALSE(mHasBeenCrossSite, NS_ERROR_DOM_BAD_URI); + } nsCOMPtr internal = do_QueryInterface(http); NS_ENSURE_TRUE(internal, NS_ERROR_DOM_BAD_URI); diff --git a/netwerk/protocol/http/nsCORSListenerProxy.h b/netwerk/protocol/http/nsCORSListenerProxy.h index 32ce8d252712..75918fc46d3e 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.h +++ b/netwerk/protocol/http/nsCORSListenerProxy.h @@ -37,6 +37,12 @@ enum class DataURIHandling Disallow }; +enum class UpdateType +{ + Default, + InternalOrHSTSRedirect +}; + class nsCORSListenerProxy final : public nsIStreamListener, public nsIInterfaceRequestor, public nsIChannelEventSink, @@ -78,9 +84,10 @@ private: ~nsCORSListenerProxy(); - nsresult UpdateChannel(nsIChannel* aChannel, DataURIHandling aAllowDataURI); + nsresult UpdateChannel(nsIChannel* aChannel, DataURIHandling aAllowDataURI, + UpdateType aUpdateType); nsresult CheckRequestApproved(nsIRequest* aRequest); - nsresult CheckPreflightNeeded(nsIChannel* aChannel); + nsresult CheckPreflightNeeded(nsIChannel* aChannel, UpdateType aUpdateType); nsCOMPtr mOuterListener; // The principal that originally kicked off the request