mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-08 05:29:36 +00:00
290 lines
9.5 KiB
C++
290 lines
9.5 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set sw=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/. */
|
|
|
|
// HttpLog.h should generally be included first
|
|
#include "HttpLog.h"
|
|
|
|
#include "HttpChannelParentListener.h"
|
|
#include "mozilla/net/HttpChannelParent.h"
|
|
#include "mozilla/unused.h"
|
|
#include "nsIRedirectChannelRegistrar.h"
|
|
#include "nsIHttpEventSink.h"
|
|
#include "nsIPackagedAppChannelListener.h"
|
|
|
|
using mozilla::Unused;
|
|
|
|
namespace mozilla {
|
|
namespace net {
|
|
|
|
HttpChannelParentListener::HttpChannelParentListener(HttpChannelParent* aInitialChannel)
|
|
: mNextListener(aInitialChannel)
|
|
, mRedirectChannelId(0)
|
|
, mSuspendedForDiversion(false)
|
|
{
|
|
}
|
|
|
|
HttpChannelParentListener::~HttpChannelParentListener()
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// HttpChannelParentListener::nsISupports
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMPL_ISUPPORTS(HttpChannelParentListener,
|
|
nsIInterfaceRequestor,
|
|
nsIStreamListener,
|
|
nsIRequestObserver,
|
|
nsIChannelEventSink,
|
|
nsIPackagedAppChannelListener,
|
|
nsIRedirectResultListener)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// HttpChannelParentListener::nsIRequestObserver
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
HttpChannelParentListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
|
|
{
|
|
MOZ_RELEASE_ASSERT(!mSuspendedForDiversion,
|
|
"Cannot call OnStartRequest if suspended for diversion!");
|
|
|
|
if (!mNextListener)
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
LOG(("HttpChannelParentListener::OnStartRequest [this=%p]\n", this));
|
|
return mNextListener->OnStartRequest(aRequest, aContext);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
HttpChannelParentListener::OnStopRequest(nsIRequest *aRequest,
|
|
nsISupports *aContext,
|
|
nsresult aStatusCode)
|
|
{
|
|
MOZ_RELEASE_ASSERT(!mSuspendedForDiversion,
|
|
"Cannot call OnStopRequest if suspended for diversion!");
|
|
|
|
if (!mNextListener)
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
LOG(("HttpChannelParentListener::OnStopRequest: [this=%p status=%ul]\n",
|
|
this, aStatusCode));
|
|
nsresult rv = mNextListener->OnStopRequest(aRequest, aContext, aStatusCode);
|
|
|
|
mNextListener = nullptr;
|
|
return rv;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// HttpChannelParentListener::nsIStreamListener
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
HttpChannelParentListener::OnDataAvailable(nsIRequest *aRequest,
|
|
nsISupports *aContext,
|
|
nsIInputStream *aInputStream,
|
|
uint64_t aOffset,
|
|
uint32_t aCount)
|
|
{
|
|
MOZ_RELEASE_ASSERT(!mSuspendedForDiversion,
|
|
"Cannot call OnDataAvailable if suspended for diversion!");
|
|
|
|
if (!mNextListener)
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
LOG(("HttpChannelParentListener::OnDataAvailable [this=%p]\n", this));
|
|
return mNextListener->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// HttpChannelParentListener::nsIPackagedAppChannelListener
|
|
//-----------------------------------------------------------------------------
|
|
NS_IMETHODIMP
|
|
HttpChannelParentListener::OnStartSignedPackageRequest(const nsACString& aPackageId)
|
|
{
|
|
nsCOMPtr<nsIPackagedAppChannelListener> listener = do_QueryInterface(mNextListener);
|
|
if (listener) {
|
|
listener->OnStartSignedPackageRequest(aPackageId);
|
|
} else {
|
|
NS_WARNING("mNextListener is not nsIPackagedAppChannelListener");
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// HttpChannelParentListener::nsIInterfaceRequestor
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
HttpChannelParentListener::GetInterface(const nsIID& aIID, void **result)
|
|
{
|
|
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink)) ||
|
|
aIID.Equals(NS_GET_IID(nsIHttpEventSink)) ||
|
|
aIID.Equals(NS_GET_IID(nsIRedirectResultListener)))
|
|
{
|
|
return QueryInterface(aIID, result);
|
|
}
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> ir;
|
|
if (mNextListener &&
|
|
NS_SUCCEEDED(CallQueryInterface(mNextListener.get(),
|
|
getter_AddRefs(ir))))
|
|
{
|
|
return ir->GetInterface(aIID, result);
|
|
}
|
|
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// HttpChannelParentListener::nsIChannelEventSink
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
HttpChannelParentListener::AsyncOnChannelRedirect(
|
|
nsIChannel *oldChannel,
|
|
nsIChannel *newChannel,
|
|
uint32_t redirectFlags,
|
|
nsIAsyncVerifyRedirectCallback* callback)
|
|
{
|
|
nsresult rv;
|
|
|
|
// Register the new channel and obtain id for it
|
|
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
|
|
do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = registrar->RegisterChannel(newChannel, &mRedirectChannelId);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
LOG(("Registered %p channel under id=%d", newChannel, mRedirectChannelId));
|
|
|
|
nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel =
|
|
do_QueryInterface(mNextListener);
|
|
if (!activeRedirectingChannel) {
|
|
NS_RUNTIMEABORT("Channel got a redirect response, but doesn't implement "
|
|
"nsIParentRedirectingChannel to handle it.");
|
|
}
|
|
|
|
return activeRedirectingChannel->StartRedirect(mRedirectChannelId,
|
|
newChannel,
|
|
redirectFlags,
|
|
callback);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// HttpChannelParentListener::nsIRedirectResultListener
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
HttpChannelParentListener::OnRedirectResult(bool succeeded)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIParentChannel> redirectChannel;
|
|
if (mRedirectChannelId) {
|
|
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
|
|
do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = registrar->GetParentChannel(mRedirectChannelId,
|
|
getter_AddRefs(redirectChannel));
|
|
if (NS_FAILED(rv) || !redirectChannel) {
|
|
// Redirect might get canceled before we got AsyncOnChannelRedirect
|
|
LOG(("Registered parent channel not found under id=%d", mRedirectChannelId));
|
|
|
|
nsCOMPtr<nsIChannel> newChannel;
|
|
rv = registrar->GetRegisteredChannel(mRedirectChannelId,
|
|
getter_AddRefs(newChannel));
|
|
MOZ_ASSERT(newChannel, "Already registered channel not found");
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
newChannel->Cancel(NS_BINDING_ABORTED);
|
|
}
|
|
|
|
// Release all previously registered channels, they are no longer need to be
|
|
// kept in the registrar from this moment.
|
|
registrar->DeregisterChannels(mRedirectChannelId);
|
|
|
|
mRedirectChannelId = 0;
|
|
}
|
|
|
|
if (!redirectChannel) {
|
|
succeeded = false;
|
|
}
|
|
|
|
nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel =
|
|
do_QueryInterface(mNextListener);
|
|
MOZ_ASSERT(activeRedirectingChannel,
|
|
"Channel finished a redirect response, but doesn't implement "
|
|
"nsIParentRedirectingChannel to complete it.");
|
|
|
|
if (activeRedirectingChannel) {
|
|
activeRedirectingChannel->CompleteRedirect(succeeded);
|
|
} else {
|
|
succeeded = false;
|
|
}
|
|
|
|
if (succeeded) {
|
|
// Switch to redirect channel and delete the old one.
|
|
nsCOMPtr<nsIParentChannel> parent;
|
|
parent = do_QueryInterface(mNextListener);
|
|
MOZ_ASSERT(parent);
|
|
parent->Delete();
|
|
mNextListener = do_QueryInterface(redirectChannel);
|
|
MOZ_ASSERT(mNextListener);
|
|
redirectChannel->SetParentListener(this);
|
|
} else if (redirectChannel) {
|
|
// Delete the redirect target channel: continue using old channel
|
|
redirectChannel->Delete();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
nsresult
|
|
HttpChannelParentListener::SuspendForDiversion()
|
|
{
|
|
if (NS_WARN_IF(mSuspendedForDiversion)) {
|
|
MOZ_ASSERT(!mSuspendedForDiversion, "Cannot SuspendForDiversion twice!");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
// While this is set, no OnStart/OnData/OnStop callbacks should be forwarded
|
|
// to mNextListener.
|
|
mSuspendedForDiversion = true;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
HttpChannelParentListener::ResumeForDiversion()
|
|
{
|
|
MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!");
|
|
|
|
// Allow OnStart/OnData/OnStop callbacks to be forwarded to mNextListener.
|
|
mSuspendedForDiversion = false;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
HttpChannelParentListener::DivertTo(nsIStreamListener* aListener)
|
|
{
|
|
MOZ_ASSERT(aListener);
|
|
MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!");
|
|
|
|
mNextListener = aListener;
|
|
|
|
return ResumeForDiversion();
|
|
}
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|