NS_IMETHODIMP nsIncrementalDownload::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel, uint32_t flags, nsIAsyncVerifyRedirectCallback *cb) { // In response to a redirect, we need to propagate the Range header. See bug // 311595. Any failure code returned from this function aborts the redirect. nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(oldChannel); NS_ENSURE_STATE(http); nsCOMPtr<nsIHttpChannel> newHttpChannel = do_QueryInterface(newChannel); NS_ENSURE_STATE(newHttpChannel); NS_NAMED_LITERAL_CSTRING(rangeHdr, "Range"); nsresult rv = ClearRequestHeader(newHttpChannel); if (NS_FAILED(rv)) return rv; // If we didn't have a Range header, then we must be doing a full download. nsAutoCString rangeVal; http->GetRequestHeader(rangeHdr, rangeVal); if (!rangeVal.IsEmpty()) { rv = newHttpChannel->SetRequestHeader(rangeHdr, rangeVal, false); NS_ENSURE_SUCCESS(rv, rv); } // A redirection changes the validator mPartialValidator.Truncate(); if (mCacheBust) { newHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Cache-Control"), NS_LITERAL_CSTRING("no-cache"), false); newHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Pragma"), NS_LITERAL_CSTRING("no-cache"), false); } // Prepare to receive callback mRedirectCallback = cb; mNewRedirectChannel = newChannel; // Give the observer a chance to see this redirect notification. nsCOMPtr<nsIChannelEventSink> sink = do_GetInterface(mObserver); if (sink) { rv = sink->AsyncOnChannelRedirect(oldChannel, newChannel, flags, this); if (NS_FAILED(rv)) { mRedirectCallback = nullptr; mNewRedirectChannel = nullptr; } return rv; } (void) OnRedirectVerifyCallback(NS_OK); return NS_OK; }
nsresult nsIncrementalDownload::ProcessTimeout() { NS_ASSERTION(!mChannel, "how can we have a channel?"); // Handle existing error conditions if (NS_FAILED(mStatus)) { CallOnStopRequest(); return NS_OK; } // Fetch next chunk nsCOMPtr<nsIChannel> channel; nsresult rv = NS_NewChannel(getter_AddRefs(channel), mFinalURI, nsnull, nsnull, this, mLoadFlags); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(channel, &rv); if (NS_FAILED(rv)) return rv; NS_ASSERTION(mCurrentSize != PRInt64(-1), "we should know the current file size by now"); rv = ClearRequestHeader(http); if (NS_FAILED(rv)) return rv; // Don't bother making a range request if we are just going to fetch the // entire document. if (mInterval || mCurrentSize != PRInt64(0)) { nsCAutoString range; MakeRangeSpec(mCurrentSize, mTotalSize, mChunkSize, mInterval == 0, range); rv = http->SetRequestHeader(NS_LITERAL_CSTRING("Range"), range, PR_FALSE); if (NS_FAILED(rv)) return rv; } rv = channel->AsyncOpen(this, nsnull); if (NS_FAILED(rv)) return rv; // Wait to assign mChannel when we know we are going to succeed. This is // important because we don't want to introduce a reference cycle between // mChannel and this until we know for a fact that AsyncOpen has succeeded, // thus ensuring that our stream listener methods will be invoked. mChannel = channel; return NS_OK; }
NS_IMETHODIMP nsIncrementalDownload::OnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel, PRUint32 flags) { // In response to a redirect, we need to propagate the Range header. See bug // 311595. Any failure code returned from this function aborts the redirect. nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(oldChannel); NS_ENSURE_STATE(http); nsCOMPtr<nsIHttpChannel> newHttpChannel = do_QueryInterface(newChannel); NS_ENSURE_STATE(newHttpChannel); NS_NAMED_LITERAL_CSTRING(rangeHdr, "Range"); nsresult rv = ClearRequestHeader(newHttpChannel); if (NS_FAILED(rv)) return rv; // If we didn't have a Range header, then we must be doing a full download. nsCAutoString rangeVal; http->GetRequestHeader(rangeHdr, rangeVal); if (!rangeVal.IsEmpty()) { rv = newHttpChannel->SetRequestHeader(rangeHdr, rangeVal, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); } // Give the observer a chance to see this redirect notification. nsCOMPtr<nsIChannelEventSink> sink = do_GetInterface(mObserver); if (sink) rv = sink->OnChannelRedirect(oldChannel, newChannel, flags); // Update mChannel, so we can Cancel the new channel. if (NS_SUCCEEDED(rv)) mChannel = newChannel; return rv; }
nsresult nsIncrementalDownload::ProcessTimeout() { NS_ASSERTION(!mChannel, "how can we have a channel?"); // Handle existing error conditions if (NS_FAILED(mStatus)) { CallOnStopRequest(); return NS_OK; } // Fetch next chunk nsCOMPtr<nsIChannel> channel; nsresult rv = NS_NewChannel(getter_AddRefs(channel), mFinalURI, nsContentUtils::GetSystemPrincipal(), nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, nsIContentPolicy::TYPE_OTHER, nullptr, // loadGroup this, // aCallbacks mLoadFlags); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(channel, &rv); if (NS_FAILED(rv)) return rv; NS_ASSERTION(mCurrentSize != int64_t(-1), "we should know the current file size by now"); rv = ClearRequestHeader(http); if (NS_FAILED(rv)) return rv; // Don't bother making a range request if we are just going to fetch the // entire document. if (mInterval || mCurrentSize != int64_t(0)) { nsAutoCString range; MakeRangeSpec(mCurrentSize, mTotalSize, mChunkSize, mInterval == 0, range); rv = http->SetRequestHeader(NS_LITERAL_CSTRING("Range"), range, false); if (NS_FAILED(rv)) return rv; if (!mPartialValidator.IsEmpty()) http->SetRequestHeader(NS_LITERAL_CSTRING("If-Range"), mPartialValidator, false); if (mCacheBust) { http->SetRequestHeader(NS_LITERAL_CSTRING("Cache-Control"), NS_LITERAL_CSTRING("no-cache"), false); http->SetRequestHeader(NS_LITERAL_CSTRING("Pragma"), NS_LITERAL_CSTRING("no-cache"), false); } } rv = channel->AsyncOpen2(this); if (NS_FAILED(rv)) return rv; // Wait to assign mChannel when we know we are going to succeed. This is // important because we don't want to introduce a reference cycle between // mChannel and this until we know for a fact that AsyncOpen has succeeded, // thus ensuring that our stream listener methods will be invoked. mChannel = channel; return NS_OK; }