// This is called when the channel is redirected. NS_IMETHODIMP FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags, nsIAsyncVerifyRedirectCallback *aCallback) { NS_PRECONDITION(aNewChannel, "Redirect without a channel?"); nsresult rv; // Section 4.2, Step 4.6-4.7, enforcing a redirect count is done by Necko. // The pref used is "network.http.redirection-limit" which is set to 20 by // default. // // Step 4.8. We only unset this for spec compatibility. Any actions we take // on mRequest here do not affect what the channel does. mRequest->UnsetSameOriginDataURL(); // // Requests that require preflight are not permitted to redirect. // Fetch spec section 4.2 "HTTP Fetch", step 4.9 just uses the manual // redirect flag to decide whether to execute step 4.10 or not. We do not // represent it in our implementation. // The only thing we do is to check if the request requires a preflight (part // of step 4.9), in which case we abort. This part cannot be done by // nsCORSListenerProxy since it does not have access to mRequest. // which case. Step 4.10.3 is handled by OnRedirectVerifyCallback(), and all // the other steps are handled by nsCORSListenerProxy. if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) { rv = DoesNotRequirePreflight(aNewChannel); if (NS_FAILED(rv)) { NS_WARNING("FetchDriver::OnChannelRedirect: " "DoesNotRequirePreflight returned failure"); return rv; } } mRedirectCallback = aCallback; mOldRedirectChannel = aOldChannel; mNewRedirectChannel = aNewChannel; nsCOMPtr<nsIChannelEventSink> outer = do_GetInterface(mNotificationCallbacks); if (outer) { // The callee is supposed to call OnRedirectVerifyCallback() on success, // and nobody has to call it on failure, so we can just return after this // block. rv = outer->AsyncOnChannelRedirect(aOldChannel, aNewChannel, aFlags, this); if (NS_FAILED(rv)) { aOldChannel->Cancel(rv); mRedirectCallback = nullptr; mOldRedirectChannel = nullptr; mNewRedirectChannel = nullptr; } return rv; } (void) OnRedirectVerifyCallback(NS_OK); return NS_OK; }
NS_IMETHODIMP nsCORSPreflightListener::AsyncOnChannelRedirect(nsIChannel *aOldChannel, nsIChannel *aNewChannel, PRUint32 aFlags, nsIAsyncVerifyRedirectCallback *callback) { // Only internal redirects allowed for now. if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) return NS_ERROR_DOM_BAD_URI; callback->OnRedirectVerifyCallback(NS_OK); return NS_OK; }
NS_IMETHODIMP nsCrossSiteListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel, nsIChannel *aNewChannel, PRUint32 aFlags, nsIAsyncVerifyRedirectCallback *cb) { nsresult rv; if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) { rv = CheckRequestApproved(aOldChannel, PR_TRUE); if (NS_FAILED(rv)) { if (nsXMLHttpRequest::sAccessControlCache) { nsCOMPtr<nsIURI> oldURI; NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI)); if (oldURI) { nsXMLHttpRequest::sAccessControlCache-> RemoveEntries(oldURI, mRequestingPrincipal); } } aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI); return NS_ERROR_DOM_BAD_URI; } } // Prepare to receive callback mRedirectCallback = cb; mOldRedirectChannel = aOldChannel; mNewRedirectChannel = aNewChannel; nsCOMPtr<nsIChannelEventSink> outer = do_GetInterface(mOuterNotificationCallbacks); if (outer) { rv = outer->AsyncOnChannelRedirect(aOldChannel, aNewChannel, aFlags, this); if (NS_FAILED(rv)) { aOldChannel->Cancel(rv); // is this necessary...? mRedirectCallback = nsnull; mOldRedirectChannel = nsnull; mNewRedirectChannel = nsnull; } return rv; } (void) OnRedirectVerifyCallback(NS_OK); return NS_OK; }
NS_IMETHODIMP nsCrossSiteListenerProxy::OnChannelRedirect(nsIChannel *aOldChannel, nsIChannel *aNewChannel, PRUint32 aFlags) { nsChannelCanceller canceller(aOldChannel); nsresult rv; if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) { rv = CheckRequestApproved(aOldChannel, PR_TRUE); if (NS_FAILED(rv)) { if (nsXMLHttpRequest::sAccessControlCache) { nsCOMPtr<nsIURI> oldURI; aOldChannel->GetURI(getter_AddRefs(oldURI)); if (oldURI) { nsXMLHttpRequest::sAccessControlCache-> RemoveEntries(oldURI, mRequestingPrincipal); } } return NS_ERROR_DOM_BAD_URI; } } nsCOMPtr<nsIChannelEventSink> outer = do_GetInterface(mOuterNotificationCallbacks); if (outer) { rv = outer->OnChannelRedirect(aOldChannel, aNewChannel, aFlags); NS_ENSURE_SUCCESS(rv, rv); } rv = UpdateChannel(aNewChannel); NS_ENSURE_SUCCESS(rv, rv); canceller.DontCancel(); return NS_OK; }