Bug 455311. Treat .url files as redirects. r+sr=biesi

This commit is contained in:
Boris Zbarsky 2008-09-29 17:02:44 -04:00
parent 82a62c8b90
commit 6c7a1a881c
13 changed files with 127 additions and 44 deletions

View File

@ -62,7 +62,7 @@ class ScopedRequestSuspender {
public:
ScopedRequestSuspender(nsIRequest *request)
: mRequest(request) {
if (NS_FAILED(mRequest->Suspend())) {
if (mRequest && NS_FAILED(mRequest->Suspend())) {
NS_WARNING("Couldn't suspend pump");
mRequest = nsnull;
}
@ -94,7 +94,8 @@ nsBaseChannel::nsBaseChannel()
}
nsresult
nsBaseChannel::Redirect(nsIChannel *newChannel, PRUint32 redirectFlags)
nsBaseChannel::Redirect(nsIChannel *newChannel, PRUint32 redirectFlags,
PRBool openNewChannel)
{
SUSPEND_PUMP_FOR_SCOPE();
@ -147,9 +148,11 @@ nsBaseChannel::Redirect(nsIChannel *newChannel, PRUint32 redirectFlags)
// unaffected, so we defer tearing down our channel until we have succeeded
// with the redirect.
rv = newChannel->AsyncOpen(mListener, mListenerContext);
if (NS_FAILED(rv))
return rv;
if (openNewChannel) {
rv = newChannel->AsyncOpen(mListener, mListenerContext);
if (NS_FAILED(rv))
return rv;
}
// close down this channel
Cancel(NS_BINDING_REDIRECTED);
@ -216,10 +219,17 @@ nsresult
nsBaseChannel::BeginPumpingData()
{
nsCOMPtr<nsIInputStream> stream;
nsresult rv = OpenContentStream(PR_TRUE, getter_AddRefs(stream));
nsCOMPtr<nsIChannel> channel;
nsresult rv = OpenContentStream(PR_TRUE, getter_AddRefs(stream),
getter_AddRefs(channel));
if (NS_FAILED(rv))
return rv;
NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?");
if (channel)
return NS_DispatchToCurrentThread(new RedirectRunnable(this, channel));
// By assigning mPump, we flag this channel as pending (see IsPending). 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)
@ -234,6 +244,29 @@ nsBaseChannel::BeginPumpingData()
return rv;
}
void
nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel)
{
NS_ASSERTION(!mPump, "Shouldn't have gotten here");
nsresult rv = Redirect(newChannel, nsIChannelEventSink::REDIRECT_INTERNAL,
PR_TRUE);
if (NS_FAILED(rv)) {
// Notify our consumer ourselves
Cancel(rv);
mListener->OnStartRequest(this, mListenerContext);
mListener->OnStopRequest(this, mListenerContext, mStatus);
mListener = nsnull;
mListenerContext = nsnull;
}
if (mLoadGroup)
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
// Drop notification callbacks to prevent cycles.
mCallbacks = nsnull;
CallbacksChanged();
}
//-----------------------------------------------------------------------------
// nsBaseChannel::nsISupports
@ -451,8 +484,15 @@ nsBaseChannel::Open(nsIInputStream **result)
NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
nsresult rv = OpenContentStream(PR_FALSE, result);
if (rv == NS_ERROR_NOT_IMPLEMENTED)
nsCOMPtr<nsIChannel> chan;
nsresult rv = OpenContentStream(PR_FALSE, result, getter_AddRefs(chan));
NS_ASSERTION(!chan || !*result, "Got both a channel and a stream?");
if (NS_SUCCEEDED(rv) && chan) {
rv = Redirect(chan, nsIChannelEventSink::REDIRECT_INTERNAL, PR_FALSE);
if (NS_FAILED(rv))
return rv;
rv = chan->Open(result);
} else if (rv == NS_ERROR_NOT_IMPLEMENTED)
return NS_ImplementChannelOpen(this, result);
mWasOpened = NS_SUCCEEDED(rv);

View File

@ -52,6 +52,7 @@
#include "nsIInterfaceRequestor.h"
#include "nsIProgressEventSink.h"
#include "nsITransport.h"
#include "nsThreadUtils.h"
//-----------------------------------------------------------------------------
// nsBaseChannel is designed to be subclassed. The subclass is responsible for
@ -103,7 +104,12 @@ private:
// need to implement ReadSegments. If async is false, this method may return
// NS_ERROR_NOT_IMPLEMENTED to cause the basechannel to implement Open in
// terms of AsyncOpen (see NS_ImplementChannelOpen).
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **stream) = 0;
// A callee is allowed to return an nsIChannel instead of an nsIInputStream.
// That case will be treated as a redirect to the new channel. By default
// *channel will be set to null by the caller, so callees who don't want to
// return one an just not touch it.
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **stream,
nsIChannel** channel) = 0;
// The basechannel calls this method from its OnTransportStatus method to
// determine whether to call nsIProgressEventSink::OnStatus in addition to
@ -126,12 +132,14 @@ public:
// Methods provided for use by the derived class:
// Redirect to another channel. This method takes care of notifying
// observers of this redirect as well as of opening the new channel. It also
// cancels |this| with the status code NS_BINDING_REDIRECTED. A failure
// return from this method means that the redirect could not be performed (no
// channel was opened; this channel wasn't canceled.) The redirectFlags
// parameter consists of the flag values defined on nsIChannelEventSink.
nsresult Redirect(nsIChannel *newChannel, PRUint32 redirectFlags);
// observers of this redirect as well as of opening the new channel, if asked
// to do so. It also cancels |this| with the status code
// NS_BINDING_REDIRECTED. A failure return from this method means that the
// redirect could not be performed (no channel was opened; this channel
// wasn't canceled.) The redirectFlags parameter consists of the flag values
// defined on nsIChannelEventSink.
nsresult Redirect(nsIChannel *newChannel, PRUint32 redirectFlags,
PRBool openNewChannel);
// Tests whether a type hint was set. Subclasses can use this to decide
// whether to call SetContentType.
@ -233,6 +241,31 @@ private:
OnCallbacksChanged();
}
// Handle an async redirect callback. This will only be called if we
// returned success from AsyncOpen while posting a redirect runnable.
void HandleAsyncRedirect(nsIChannel* newChannel);
class RedirectRunnable : public nsRunnable
{
public:
RedirectRunnable(nsBaseChannel* chan, nsIChannel* newChannel)
: mChannel(chan), mNewChannel(newChannel)
{
NS_PRECONDITION(newChannel, "Must have channel to redirect to");
}
NS_IMETHOD Run()
{
mChannel->HandleAsyncRedirect(mNewChannel);
return NS_OK;
}
private:
nsRefPtr<nsBaseChannel> mChannel;
nsCOMPtr<nsIChannel> mNewChannel;
};
friend class RedirectRunnable;
nsRefPtr<nsInputStreamPump> mPump;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsIProgressEventSink> mProgressSink;

View File

@ -41,7 +41,8 @@
// nsInputStreamChannel
nsresult
nsInputStreamChannel::OpenContentStream(PRBool async, nsIInputStream **result)
nsInputStreamChannel::OpenContentStream(PRBool async, nsIInputStream **result,
nsIChannel** channel)
{
NS_ENSURE_TRUE(mContentStream, NS_ERROR_NOT_INITIALIZED);

View File

@ -55,7 +55,8 @@ public:
protected:
virtual ~nsInputStreamChannel() {}
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result);
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result,
nsIChannel** channel);
private:
nsCOMPtr<nsIInputStream> mContentStream;

View File

@ -51,7 +51,8 @@
#include "prmem.h"
nsresult
nsDataChannel::OpenContentStream(PRBool async, nsIInputStream **result)
nsDataChannel::OpenContentStream(PRBool async, nsIInputStream **result,
nsIChannel** channel)
{
NS_ENSURE_TRUE(URI(), NS_ERROR_NOT_INITIALIZED);

View File

@ -52,7 +52,8 @@ public:
}
protected:
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result);
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result,
nsIChannel** channel);
};
#endif /* nsDataChannel_h___ */

View File

@ -307,7 +307,8 @@ nsFileChannel::MakeFileInputStream(nsIFile *file,
}
nsresult
nsFileChannel::OpenContentStream(PRBool async, nsIInputStream **result)
nsFileChannel::OpenContentStream(PRBool async, nsIInputStream **result,
nsIChannel** channel)
{
// NOTE: the resulting file is a clone, so it is safe to pass it to the
// file input stream which will be read on a background thread.
@ -316,6 +317,24 @@ nsFileChannel::OpenContentStream(PRBool async, nsIInputStream **result)
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIFileProtocolHandler> fileHandler;
rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIURI> newURI;
rv = fileHandler->ReadURLFile(file, getter_AddRefs(newURI));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIChannel> newChannel;
rv = NS_NewChannel(getter_AddRefs(newChannel), newURI);
if (NS_FAILED(rv))
return rv;
*result = nsnull;
newChannel.forget(channel);
return NS_OK;
}
nsCOMPtr<nsIInputStream> stream;
if (mUploadStream) {

View File

@ -65,7 +65,8 @@ protected:
nsresult MakeFileInputStream(nsIFile *file, nsCOMPtr<nsIInputStream> &stream,
nsCString &contentType);
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result);
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result,
nsIChannel** channel);
private:
nsCOMPtr<nsIInputStream> mUploadStream;

View File

@ -278,30 +278,12 @@ nsFileProtocolHandler::NewURI(const nsACString &spec,
NS_IMETHODIMP
nsFileProtocolHandler::NewChannel(nsIURI *uri, nsIChannel **result)
{
nsresult rv;
// This file may be a url file
nsCOMPtr<nsIFileURL> url(do_QueryInterface(uri));
if (url) {
nsCOMPtr<nsIFile> file;
rv = url->GetFile(getter_AddRefs(file));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIURI> uri;
rv = ReadURLFile(file, getter_AddRefs(uri));
if (NS_SUCCEEDED(rv)) {
rv = NS_NewChannel(result, uri);
if (NS_SUCCEEDED(rv))
return rv;
}
}
}
nsFileChannel *chan = new nsFileChannel(uri);
if (!chan)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(chan);
rv = chan->Init();
nsresult rv = chan->Init();
if (NS_FAILED(rv)) {
NS_RELEASE(chan);
return rv;

View File

@ -143,7 +143,8 @@ nsFtpChannel::GetProxyInfo(nsIProxyInfo** aProxyInfo)
//-----------------------------------------------------------------------------
nsresult
nsFtpChannel::OpenContentStream(PRBool async, nsIInputStream **result)
nsFtpChannel::OpenContentStream(PRBool async, nsIInputStream **result,
nsIChannel** channel)
{
if (!async)
return NS_ERROR_NOT_IMPLEMENTED;

View File

@ -117,7 +117,8 @@ public:
protected:
virtual ~nsFtpChannel() {}
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result);
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result,
nsIChannel** channel);
virtual PRBool GetStatusArg(nsresult status, nsString &statusArg);
virtual void OnCallbacksChanged();

View File

@ -469,7 +469,8 @@ nsGopherChannel::GetProxyInfo(nsIProxyInfo** aProxyInfo)
}
nsresult
nsGopherChannel::OpenContentStream(PRBool async, nsIInputStream **result)
nsGopherChannel::OpenContentStream(PRBool async, nsIInputStream **result,
nsIChannel** channel)
{
// Implement nsIChannel::Open in terms of nsIChannel::AsyncOpen
if (!async)

View File

@ -59,7 +59,8 @@ public:
protected:
virtual ~nsGopherChannel() {}
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result);
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result,
nsIChannel** channel);
virtual PRBool GetStatusArg(nsresult status, nsString &statusArg);
private: