/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set sw=2 sts=2 ts=8 et tw=80 : */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This class is used to suspend a request across a function scope. class ScopedRequestSuspender { public: explicit ScopedRequestSuspender(nsIRequest* request) : mRequest(request) { if (mRequest && NS_FAILED(mRequest->Suspend())) {
NS_WARNING("Couldn't suspend pump");
mRequest = nullptr;
}
}
~ScopedRequestSuspender() { if (mRequest) mRequest->Resume();
}
private:
nsIRequest* mRequest;
};
// Used to suspend data events from mRequest within a function scope. This is // usually needed when a function makes callbacks that could process events. #define SUSPEND_PUMP_FOR_SCOPE() \
ScopedRequestSuspender pump_suspender__(mRequest)
// make a copy of the loadinfo, append to the redirectchain // and set it on the new channel
nsSecurityFlags secFlags =
mLoadInfo->GetSecurityFlags() & ~nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
nsCOMPtr<nsILoadInfo> newLoadInfo = static_cast<net::LoadInfo*>(mLoadInfo.get())
->CloneWithNewSecFlags(secFlags);
// Ensure the channel's loadInfo's result principal URI so that it's // either non-null or updated to the redirect target URI. // We must do this because in case the loadInfo's result principal URI // is null, it would be taken from OriginalURI of the channel. But we // overwrite it with the whole redirect chain first URI before opening // the target channel, hence the information would be lost. // If the protocol handler that created the channel wants to use // the originalURI of the channel as the principal URI, it has left // the result principal URI on the load info null.
nsCOMPtr<nsIURI> resultPrincipalURI;
nsCOMPtr<nsILoadInfo> existingLoadInfo = newChannel->LoadInfo(); if (existingLoadInfo) {
existingLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
} if (!resultPrincipalURI) {
newChannel->GetOriginalURI(getter_AddRefs(resultPrincipalURI));
}
// Preserve the privacy bit if it has been overridden if (mPrivateBrowsingOverriden) {
nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
do_QueryInterface(newChannel); if (newPBChannel) {
newPBChannel->SetPrivate(mPrivateBrowsing);
}
}
if (nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel)) {
nsHashPropertyBag::CopyFrom(bag, static_cast<nsIPropertyBag2*>(this));
}
// Notify consumer, giving chance to cancel redirect.
auto redirectCallbackHelper = MakeRefPtr<net::nsAsyncRedirectVerifyHelper>();
if (checkRedirectSynchronously && NS_FAILED(mStatus)) return mStatus;
return NS_OK;
}
nsresult nsBaseChannel::ContinueRedirect() { // Make sure to do this _after_ making all the OnChannelRedirect calls
mRedirectChannel->SetOriginalURI(OriginalURI());
// If we fail to open the new channel, then we want to leave this channel // unaffected, so we defer tearing down our channel until we have succeeded // with the redirect.
NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?");
if (channel) {
nsCOMPtr<nsIRunnable> runnable = new RedirectRunnable(this, channel);
rv = Dispatch(runnable.forget()); if (NS_SUCCEEDED(rv)) mWaitingOnAsyncRedirect = true; return rv;
}
// By assigning mPump, we flag this channel as pending (see Pending). It's // important that the pending flag is set when we call into the stream (the // call to AsyncRead results in the stream's AsyncWait method being called) // and especially when we call into the loadgroup. Our caller takes care to // release mPump if we return an error.
void nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel) {
NS_ASSERTION(!mPumpingData, "Shouldn't have gotten here");
nsresult rv = mStatus; if (NS_SUCCEEDED(mStatus)) {
rv = Redirect(newChannel, nsIChannelEventSink::REDIRECT_TEMPORARY, true); if (NS_SUCCEEDED(rv)) { // OnRedirectVerifyCallback will be called asynchronously return;
}
}
if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
// Drop notification callbacks to prevent cycles.
mCallbacks = nullptr;
CallbacksChanged();
}
void nsBaseChannel::ClassifyURI() { // For channels created in the child process, delegate to the parent to // classify URIs. if (!XRE_IsParentProcess()) { return;
}
if (NS_ShouldClassifyChannel(this)) { auto classifier = MakeRefPtr<net::nsChannelClassifier>(this);
classifier->Start();
}
}
// For safety reasons ensure the filename doesn't contain null characters and // replace them with underscores. We may later pass the extension to system // MIME APIs that expect null terminated strings.
mContentDispositionFilename->ReplaceChar(char16_t(0), '_');
// Store the listener and context early so that OpenContentStream and the // stream's AsyncWait method (called by AsyncRead) can have access to them // via the StreamListener methods. However, since // this typically introduces a reference cycle between this and the listener, // we need to be sure to break the reference if this method does not succeed.
mListener = listener;
// This method assigns mPump as a side-effect. We need to clear mPump if // this method fails.
rv = BeginPumpingData(); if (NS_FAILED(rv)) {
mPump = nullptr;
mRequest = nullptr;
mPumpingData = false;
ChannelDone();
mCallbacks = nullptr; return rv;
}
// At this point, we are going to return success no matter what.
mWasOpened = true;
SUSPEND_PUMP_FOR_SCOPE();
if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr);
NS_IMETHODIMP
nsBaseChannel::OnTransportStatus(nsITransport* transport, nsresult status,
int64_t progress, int64_t progressMax) { // In some cases, we may wish to suppress transport-layer status events.
if (!mPumpingData || NS_FAILED(mStatus)) { return NS_OK;
}
SUSPEND_PUMP_FOR_SCOPE();
// Lazily fetch mProgressSink if (!mProgressSink) { if (mQueriedProgressSink) { return NS_OK;
}
GetCallback(mProgressSink);
mQueriedProgressSink = true; if (!mProgressSink) { return NS_OK;
}
}
if (!HasLoadFlag(LOAD_BACKGROUND)) {
nsAutoString statusArg; if (GetStatusArg(status, statusArg)) {
mProgressSink->OnStatus(this, status, statusArg.get());
}
}
if (progress) {
mProgressSink->OnProgress(this, progress, progressMax);
}
if (mPump) { // If our content type is unknown, use the content type // sniffer. If the sniffer is not available for some reason, then we just // keep going as-is. if (NS_SUCCEEDED(mStatus) &&
mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
}
// Now, the general type sniffers. Skip this if we have none. if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) {
mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));
}
}
SUSPEND_PUMP_FOR_SCOPE();
if (mListener) { // null in case of redirect return mListener->OnStartRequest(this);
} return NS_OK;
}
NS_IMETHODIMP
nsBaseChannel::OnStopRequest(nsIRequest* request, nsresult status) { // If both mStatus and status are failure codes, we keep mStatus as-is since // that is consistent with our GetStatus and Cancel methods. if (NS_SUCCEEDED(mStatus)) mStatus = status;
// Cause Pending to return false.
mPump = nullptr;
mRequest = nullptr;
mCancelableAsyncRequest = nullptr;
mPumpingData = false;
if (mListener) { // null in case of redirect
mListener->OnStopRequest(this, mStatus);
}
ChannelDone();
// No need to suspend pump in this scope since we will not be receiving // any more events from it.
if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
// Drop notification callbacks to prevent cycles.
mCallbacks = nullptr;
CallbacksChanged();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.