Beispiel #1
0
// 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;
}