Bug 915024 - Add ForcePending for HttpChannel. r=jduell

This commit is contained in:
Dragana Damjanovic 2014-07-10 10:13:00 -04:00
parent ca29747d5e
commit 2cd40ad8a5
10 changed files with 124 additions and 38 deletions

View File

@ -43,6 +43,7 @@ XPIDL_SOURCES += [
'nsIExternalProtocolHandler.idl',
'nsIFileStreams.idl',
'nsIFileURL.idl',
'nsIForcePendingChannel.idl',
'nsIIncrementalDownload.idl',
'nsIInputStreamChannel.idl',
'nsIInputStreamPump.idl',

View File

@ -0,0 +1,22 @@
/* 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/. */
#include "nsISupports.idl"
/**
* nsIForcePending interface exposes a function that enables overwriting of the normal
* behavior for the channel's IsPending(), forcing 'true' to be returned.
*/
[scriptable, uuid(225ab092-1554-423a-9492-606f6db3b4fb)]
interface nsIForcePendingChannel : nsISupports
{
/**
* forcePending(true) overrides the normal behavior for the
* channel's IsPending(), forcing 'true' to be returned. A call to
* forcePending(false) reverts IsPending() back to normal behavior.
*/
void forcePending(in boolean aForcePending);
};

View File

@ -9,6 +9,9 @@
#include "nsFTPChannel.h"
#include "nsNetUtil.h"
#include "nsFtpProtocolHandler.h"
#include "nsIEncodedChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIForcePendingChannel.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/unused.h"
@ -57,7 +60,8 @@ NS_IMPL_ISUPPORTS(FTPChannelParent,
nsIStreamListener,
nsIParentChannel,
nsIInterfaceRequestor,
nsIRequestObserver)
nsIRequestObserver,
nsIChannelEventSink)
//-----------------------------------------------------------------------------
// FTPChannelParent::PFTPChannelParent
@ -114,13 +118,16 @@ FTPChannelParent::DoAsyncOpen(const URIParams& aURI,
if (NS_FAILED(rv))
return SendFailedAsyncOpen(rv);
mChannel = static_cast<nsFtpChannel*>(chan.get());
mChannel = chan;
// later on mChannel may become an HTTP channel (we'll be redirected to one
// if we're using a proxy), but for now this is safe
nsFtpChannel* ftpChan = static_cast<nsFtpChannel*>(mChannel.get());
if (mPBOverride != kPBOverride_Unset) {
mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
ftpChan->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
}
rv = mChannel->SetNotificationCallbacks(this);
rv = ftpChan->SetNotificationCallbacks(this);
if (NS_FAILED(rv))
return SendFailedAsyncOpen(rv);
@ -128,16 +135,16 @@ FTPChannelParent::DoAsyncOpen(const URIParams& aURI,
nsCOMPtr<nsIInputStream> upload = DeserializeInputStream(aUploadStream, fds);
if (upload) {
// contentType and contentLength are ignored
rv = mChannel->SetUploadStream(upload, EmptyCString(), 0);
rv = ftpChan->SetUploadStream(upload, EmptyCString(), 0);
if (NS_FAILED(rv))
return SendFailedAsyncOpen(rv);
}
rv = mChannel->ResumeAt(aStartPos, aEntityID);
rv = ftpChan->ResumeAt(aStartPos, aEntityID);
if (NS_FAILED(rv))
return SendFailedAsyncOpen(rv);
rv = mChannel->AsyncOpen(this, nullptr);
rv = ftpChan->AsyncOpen(this, nullptr);
if (NS_FAILED(rv))
return SendFailedAsyncOpen(rv);
@ -154,7 +161,7 @@ FTPChannelParent::ConnectChannel(const uint32_t& channelId)
nsCOMPtr<nsIChannel> channel;
rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel));
if (NS_SUCCEEDED(rv))
mChannel = static_cast<nsFtpChannel*>(channel.get());
mChannel = channel;
LOG((" found channel %p, rv=%08x", mChannel.get(), rv));
@ -240,7 +247,10 @@ FTPChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
// Reset fake pending status in case OnStopRequest has already been called.
if (mChannel) {
mChannel->ForcePending(false);
nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
if (forcePendingIChan) {
forcePendingIChan->ForcePending(false);
}
}
OnStopRequest(mChannel, nullptr, status);
@ -297,14 +307,14 @@ FTPChannelParent::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
resChan->GetEntityID(entityID);
}
nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(aRequest);
PRTime lastModified = 0;
nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(aRequest);
if (ftpChan) {
ftpChan->GetLastModifiedTime(&lastModified);
} else {
// Temporary hack: if we were redirected to use an HTTP channel (ie FTP is
// using an HTTP proxy), cancel, as we don't support those redirects yet.
aRequest->Cancel(NS_ERROR_NOT_IMPLEMENTED);
}
nsCOMPtr<nsIHttpChannelInternal> httpChan = do_QueryInterface(aRequest);
if (httpChan) {
httpChan->GetLastModifiedTime(&lastModified);
}
URIParams uriparam;
@ -499,7 +509,10 @@ FTPChannelParent::StartDiversion()
// Fake pending status in case OnStopRequest has already been called.
if (mChannel) {
mChannel->ForcePending(true);
nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
if (forcePendingIChan) {
forcePendingIChan->ForcePending(true);
}
}
// Call OnStartRequest for the "DivertTo" listener.
@ -567,8 +580,10 @@ FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
MOZ_RELEASE_ASSERT(mChannel);
mChannel->Cancel(aErrorCode);
mChannel->ForcePending(false);
nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
if (forcePendingIChan) {
forcePendingIChan->ForcePending(false);
}
bool isPending = false;
nsresult rv = mChannel->IsPending(&isPending);
@ -581,9 +596,15 @@ FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
// Channel has already sent OnStartRequest to the child, so ensure that we
// call it here if it hasn't already been called.
if (!mDivertedOnStartRequest) {
mChannel->ForcePending(true);
nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
if (forcePendingIChan) {
forcePendingIChan->ForcePending(true);
}
mDivertToListener->OnStartRequest(mChannel, nullptr);
mChannel->ForcePending(false);
if (forcePendingIChan) {
forcePendingIChan->ForcePending(false);
}
}
// If the channel is pending, it will call OnStopRequest itself; otherwise, do
// it here.
@ -598,6 +619,29 @@ FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
}
}
//-----------------------------------------------------------------------------
// FTPChannelParent::nsIChannelEventSink
//-----------------------------------------------------------------------------
NS_IMETHODIMP
FTPChannelParent::AsyncOnChannelRedirect(
nsIChannel *oldChannel,
nsIChannel *newChannel,
uint32_t redirectFlags,
nsIAsyncVerifyRedirectCallback* callback)
{
nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(newChannel);
if (!ftpChan) {
// when FTP is set to use HTTP proxying, we wind up getting redirected to an HTTP channel.
nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(newChannel);
if (!httpChan)
return NS_ERROR_UNEXPECTED;
}
mChannel = newChannel;
callback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
//---------------------
} // namespace net
} // namespace mozilla

View File

@ -24,6 +24,7 @@ class FTPChannelParent : public PFTPChannelParent
, public nsIParentChannel
, public nsIInterfaceRequestor
, public ADivertableParentChannel
, public nsIChannelEventSink
{
public:
NS_DECL_ISUPPORTS
@ -31,6 +32,7 @@ public:
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIPARENTCHANNEL
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
FTPChannelParent(nsILoadContext* aLoadContext, PBOverrideStatus aOverrideStatus);
@ -77,7 +79,8 @@ protected:
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
nsRefPtr<nsFtpChannel> mChannel;
// if configured to use HTTP proxy for FTP, this can an an HTTP channel.
nsCOMPtr<nsIChannel> mChannel;
bool mIPCClosed;

View File

@ -29,7 +29,8 @@ NS_IMPL_ISUPPORTS_INHERITED(nsFtpChannel,
nsIUploadChannel,
nsIResumableChannel,
nsIFTPChannel,
nsIProxiedChannel)
nsIProxiedChannel,
nsIForcePendingChannel)
//-----------------------------------------------------------------------------
@ -199,7 +200,7 @@ nsFtpChannel::GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult)
aResult = mFTPEventSink;
}
void
NS_IMETHODIMP
nsFtpChannel::ForcePending(bool aForcePending)
{
// Set true here so IsPending will return true.
@ -207,6 +208,8 @@ nsFtpChannel::ForcePending(bool aForcePending)
// OnStopRequest can be called in the parent before callbacks are diverted
// back from the child to the listener in the parent.
mForcePending = aForcePending;
return NS_OK;
}
NS_IMETHODIMP

View File

@ -12,6 +12,7 @@
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIFTPChannel.h"
#include "nsIForcePendingChannel.h"
#include "nsIUploadChannel.h"
#include "nsIProxyInfo.h"
#include "nsIProxiedChannel.h"
@ -23,7 +24,8 @@ class nsFtpChannel : public nsBaseChannel,
public nsIFTPChannel,
public nsIUploadChannel,
public nsIResumableChannel,
public nsIProxiedChannel
public nsIProxiedChannel,
public nsIForcePendingChannel
{
public:
NS_DECL_ISUPPORTS_INHERITED
@ -88,8 +90,8 @@ public:
// Helper function for getting the nsIFTPEventSink.
void GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult);
public: /* Internal Necko use only. */
void ForcePending(bool aForcePending);
public:
NS_IMETHOD ForcePending(bool aForcePending);
protected:
virtual ~nsFtpChannel() {}

View File

@ -164,6 +164,7 @@ NS_INTERFACE_MAP_BEGIN(HttpBaseChannel)
NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
NS_INTERFACE_MAP_ENTRY(nsIForcePendingChannel)
NS_INTERFACE_MAP_ENTRY(nsIRedirectHistory)
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
@ -1638,6 +1639,18 @@ HttpBaseChannel::ForcePending(bool aForcePending)
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetLastModifiedTime(PRTime* lastModifiedTime)
{
if (!mResponseHead)
return NS_ERROR_NOT_AVAILABLE;
uint32_t lastMod;
mResponseHead->GetLastModifiedValue(&lastMod);
*lastModifiedTime = lastMod;
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpBaseChannel::nsISupportsPriority
//-----------------------------------------------------------------------------

View File

@ -19,6 +19,7 @@
#include "nsIHttpChannel.h"
#include "nsHttpHandler.h"
#include "nsIHttpChannelInternal.h"
#include "nsIForcePendingChannel.h"
#include "nsIRedirectHistory.h"
#include "nsIUploadChannel.h"
#include "nsIUploadChannel2.h"
@ -63,6 +64,7 @@ class HttpBaseChannel : public nsHashPropertyBag
, public nsITraceableChannel
, public PrivateBrowsingChannel<HttpBaseChannel>
, public nsITimedChannel
, public nsIForcePendingChannel
{
protected:
virtual ~HttpBaseChannel();
@ -173,6 +175,7 @@ public:
NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable);
NS_IMETHOD AddRedirect(nsIPrincipal *aRedirect);
NS_IMETHOD ForcePending(bool aForcePending);
NS_IMETHOD GetLastModifiedTime(PRTime* lastModifiedTime);
inline void CleanRedirectCacheChainIfNecessary()
{

View File

@ -200,10 +200,5 @@ interface nsIHttpChannelInternal : nsISupports
*/
void addRedirect(in nsIPrincipal aPrincipal);
/**
* ForcePending(true) overrides the normal behavior for the
* channel's IsPending(), forcing 'true' to be returned. A call to
* ForcePending(false) reverts IsPending() back to normal behavior.
*/
void ForcePending(in boolean aForcePending);
readonly attribute PRTime lastModifiedTime;
};

View File

@ -17,7 +17,7 @@
#include "nsIViewSourceChannel.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIForcePendingChannel.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
@ -204,9 +204,9 @@ nsUnknownDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt,
// Make sure channel listeners see channel as pending while we call
// OnStartRequest/OnDataAvailable, even though the underlying channel
// has already hit OnStopRequest.
nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(request);
if (httpChannel) {
httpChannel->ForcePending(true);
nsCOMPtr<nsIForcePendingChannel> forcePendingChannel = do_QueryInterface(request);
if (forcePendingChannel) {
forcePendingChannel->ForcePending(true);
}
rv = FireListenerNotifications(request, aCtxt);
@ -216,8 +216,8 @@ nsUnknownDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt,
}
// now we need to set pending state to false before calling OnStopRequest
if (httpChannel) {
httpChannel->ForcePending(false);
if (forcePendingChannel) {
forcePendingChannel->ForcePending(false);
}
}