зеркало из https://github.com/mozilla/pjs.git
backing out my latest patch for bug 312760 to clear Tp regression.
This commit is contained in:
Родитель
3d690cd807
Коммит
6942519245
|
@ -1011,17 +1011,4 @@ NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor *callbacks,
|
|||
return NS_NewInterfaceRequestorAggregation(callbacks, cbs, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for testing online/offline state of the browser.
|
||||
*/
|
||||
inline PRBool
|
||||
NS_IsOffline()
|
||||
{
|
||||
PRBool offline = PR_TRUE;
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService();
|
||||
if (ios)
|
||||
ios->GetOffline(&offline);
|
||||
return offline;
|
||||
}
|
||||
|
||||
#endif // !nsNetUtil_h__
|
||||
|
|
|
@ -219,31 +219,6 @@ nsBaseChannel::PushStreamConverter(const char *fromType,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBaseChannel::BeginPumpingData()
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsresult rv = OpenContentStream(PR_TRUE, getter_AddRefs(stream));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// 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)
|
||||
// and especially when we call into the loadgroup. Our caller takes care to
|
||||
// release mPump if we return an error.
|
||||
|
||||
mPump = new nsInputStreamPump();
|
||||
if (!mPump)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = mPump->Init(stream, -1, -1, 0, 0, PR_TRUE);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mPump->AsyncRead(this, nsnull);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsISupports
|
||||
|
||||
|
@ -475,25 +450,28 @@ nsBaseChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Store the listener and context early so that OpenContentStream and the
|
||||
// stream's AsyncWait method (called by AsyncRead) can have access to them
|
||||
// via PushStreamConverter and 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;
|
||||
mListenerContext = ctxt;
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = OpenContentStream(PR_TRUE, getter_AddRefs(stream));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// This method assigns mPump as a side-effect. We need to clear mPump if
|
||||
// this method fails.
|
||||
rv = BeginPumpingData();
|
||||
mPump = new nsInputStreamPump();
|
||||
if (!mPump)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = mPump->Init(stream, -1, -1, 0, 0, PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
mPump = nsnull;
|
||||
mListener = nsnull;
|
||||
mListenerContext = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// At this point, we are going to return success no matter what.
|
||||
rv = mPump->AsyncRead(this, nsnull);
|
||||
if (NS_FAILED(rv)) {
|
||||
mPump = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
mListener = listener;
|
||||
mListenerContext = ctxt;
|
||||
|
||||
SUSPEND_PUMP_FOR_SCOPE();
|
||||
|
||||
|
@ -575,8 +553,6 @@ nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
mPump->PeekStream(CallTypeSniffers, NS_STATIC_CAST(nsIChannel*, this));
|
||||
}
|
||||
|
||||
SUSPEND_PUMP_FOR_SCOPE();
|
||||
|
||||
return mListener->OnStartRequest(this, mListenerContext);
|
||||
}
|
||||
|
||||
|
@ -617,8 +593,6 @@ nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
|||
nsIInputStream *stream, PRUint32 offset,
|
||||
PRUint32 count)
|
||||
{
|
||||
SUSPEND_PUMP_FOR_SCOPE();
|
||||
|
||||
nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream,
|
||||
offset, count);
|
||||
if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
|
||||
|
|
|
@ -85,13 +85,11 @@ public:
|
|||
return nsHashPropertyBag::Init();
|
||||
}
|
||||
|
||||
protected:
|
||||
// -----------------------------------------------
|
||||
// Methods to be implemented by the derived class:
|
||||
|
||||
virtual ~nsBaseChannel() {}
|
||||
|
||||
private:
|
||||
// Implemented by subclass to supply data stream. The parameter, async, is
|
||||
// true when called from nsIChannel::AsyncOpen and false otherwise. When
|
||||
// async is true, the resulting stream will be used with a nsIInputStreamPump
|
||||
|
@ -117,11 +115,6 @@ private:
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Called when the callbacks available to this channel may have changed.
|
||||
virtual void OnCallbacksChanged() {
|
||||
}
|
||||
|
||||
public:
|
||||
// ----------------------------------------------
|
||||
// Methods provided for use by the derived class:
|
||||
|
||||
|
@ -199,15 +192,6 @@ public:
|
|||
mSynthProgressEvents = enable;
|
||||
}
|
||||
|
||||
// Some subclasses may wish to manually insert a stream listener between this
|
||||
// and the channel's listener. The following methods make that possible.
|
||||
void SetStreamListener(nsIStreamListener *listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
nsIStreamListener *StreamListener() {
|
||||
return mListener;
|
||||
}
|
||||
|
||||
// Pushes a new stream converter in front of the channel's stream listener.
|
||||
// The fromType and toType values are passed to nsIStreamConverterService's
|
||||
// AsyncConvertData method. If invalidatesContentLength is true, then the
|
||||
|
@ -223,14 +207,10 @@ private:
|
|||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
// Called to setup mPump and call AsyncRead on it.
|
||||
nsresult BeginPumpingData();
|
||||
|
||||
// Called when the callbacks available to this channel may have changed.
|
||||
void CallbacksChanged() {
|
||||
mProgressSink = nsnull;
|
||||
mQueriedProgressSink = PR_FALSE;
|
||||
OnCallbacksChanged();
|
||||
}
|
||||
|
||||
nsRefPtr<nsInputStreamPump> mPump;
|
||||
|
|
|
@ -107,10 +107,6 @@ nsBaseContentStream::ReadSegments(nsWriteSegmentFun fun, void *closure,
|
|||
if (mStatus == NS_BASE_STREAM_CLOSED)
|
||||
return NS_OK;
|
||||
|
||||
// No data yet
|
||||
if (!IsClosed() && IsNonBlocking())
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
|
@ -156,15 +152,9 @@ nsBaseContentStream::AsyncWait(nsIInputStreamCallback *callback, PRUint32 flags,
|
|||
mCallback = callback;
|
||||
mCallbackTarget = target;
|
||||
|
||||
if (!mCallback)
|
||||
return NS_OK;
|
||||
|
||||
// If we're already closed, then dispatch this callback immediately.
|
||||
if (IsClosed()) {
|
||||
if (IsClosed())
|
||||
DispatchCallback();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
OnCallbackPending();
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -96,14 +96,6 @@ public:
|
|||
// Helper function to make code more self-documenting.
|
||||
void DispatchCallbackSync() { DispatchCallback(PR_FALSE); }
|
||||
|
||||
protected:
|
||||
virtual ~nsBaseContentStream() {}
|
||||
|
||||
private:
|
||||
// Called from the base stream's AsyncWait method when a pending callback
|
||||
// is installed on the stream.
|
||||
virtual void OnCallbackPending() {}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
nsCOMPtr<nsIEventTarget> mCallbackTarget;
|
||||
|
|
|
@ -57,17 +57,6 @@ static PRLogModuleInfo *gStreamPumpLog = nsnull;
|
|||
#endif
|
||||
#define LOG(args) PR_LOG(gStreamPumpLog, PR_LOG_DEBUG, args)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static NS_METHOD
|
||||
GetBytesAvailable(nsIInputStream *stream, void *closure, const char *segment,
|
||||
PRUint32 offset, PRUint32 count, PRUint32 *result)
|
||||
{
|
||||
PRUint32 *avail = NS_STATIC_CAST(PRUint32 *, closure);
|
||||
*avail = count;
|
||||
return NS_ERROR_ABORT; // return from ReadSegments call
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsInputStreamPump methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -362,11 +351,11 @@ nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream)
|
|||
// this function has been called from a PLEvent, so we can safely call
|
||||
// any listener or progress sink methods directly from here.
|
||||
|
||||
mWaiting = PR_FALSE;
|
||||
|
||||
for (;;) {
|
||||
if (mSuspendCount || mState == STATE_IDLE)
|
||||
if (mSuspendCount || mState == STATE_IDLE) {
|
||||
mWaiting = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
PRUint32 nextState;
|
||||
switch (mState) {
|
||||
|
@ -385,6 +374,7 @@ nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream)
|
|||
NS_ASSERTION(mState == STATE_TRANSFER, "unexpected state");
|
||||
NS_ASSERTION(NS_SUCCEEDED(mStatus), "unexpected status");
|
||||
|
||||
mWaiting = PR_FALSE;
|
||||
mStatus = EnsureWaiting();
|
||||
if (NS_SUCCEEDED(mStatus))
|
||||
break;
|
||||
|
@ -520,20 +510,13 @@ nsInputStreamPump::OnStateTransfer()
|
|||
if (NS_SUCCEEDED(mStatus)) {
|
||||
if (NS_FAILED(rv))
|
||||
mStatus = rv;
|
||||
else {
|
||||
// Check to see if stream will have more data. If so, then stay in
|
||||
// the STATE_TRANSFER state. Otherwise, advance to STATE_STOP.
|
||||
//
|
||||
// NOTE: Calling Available is insufficient since that method could
|
||||
// return 0 bytes available and NS_OK when it is at end-of-
|
||||
// file but not closed. We would not be able to distinguish
|
||||
// that case from a stream that is merely waiting for more
|
||||
// data to become available. By using ReadSegments we can
|
||||
// tell if the stream will ever have more data.
|
||||
//
|
||||
PRUint32 n;
|
||||
rv = mAsyncStream->ReadSegments(GetBytesAvailable, &avail, 1, &n);
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK || (NS_SUCCEEDED(rv) && avail))
|
||||
else if (avail) {
|
||||
// if stream is now closed, advance to STATE_STOP right away.
|
||||
// Available may return 0 bytes available at the moment; that
|
||||
// would not mean that we are done.
|
||||
// XXX async streams should have a GetStatus method!
|
||||
rv = mAsyncStream->Available(&avail);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return STATE_TRANSFER;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -417,7 +417,7 @@ nsSocketInputStream::AsyncWait(nsIInputStreamCallback *callback,
|
|||
{
|
||||
nsAutoLock lock(mTransport->mLock);
|
||||
|
||||
if (callback && target) {
|
||||
if (target) {
|
||||
//
|
||||
// build event proxy
|
||||
//
|
||||
|
@ -648,7 +648,7 @@ nsSocketOutputStream::AsyncWait(nsIOutputStreamCallback *callback,
|
|||
{
|
||||
nsAutoLock lock(mTransport->mLock);
|
||||
|
||||
if (callback && target) {
|
||||
if (target) {
|
||||
//
|
||||
// build event proxy
|
||||
//
|
||||
|
|
|
@ -35,26 +35,20 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIChannel.idl"
|
||||
interface nsIRequestObserver;
|
||||
|
||||
/**
|
||||
* This interface may be used to determine if a channel is a FTP channel.
|
||||
*/
|
||||
[scriptable, uuid(2315d831-8b40-446a-9138-fe09ebb1b720)]
|
||||
interface nsIFTPChannel : nsISupports
|
||||
// this interface provides a way for the FTP connection to
|
||||
// synchronize with the owning channel.
|
||||
|
||||
[scriptable, uuid(3476df52-1dd2-11b2-b928-925d89b33bc0)]
|
||||
interface nsIFTPChannel : nsIChannel
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* This interface may be defined as a notification callback on the FTP
|
||||
* channel. It allows a consumer to receive a log of the FTP control
|
||||
* connection conversation.
|
||||
*/
|
||||
[scriptable, uuid(455d4234-0330-43d2-bbfb-99afbecbfeb0)]
|
||||
interface nsIFTPEventSink : nsISupports
|
||||
{
|
||||
/**
|
||||
* XXX document this method! (see bug 328915)
|
||||
*/
|
||||
void OnFTPControlLog(in boolean server, in string msg);
|
||||
};
|
||||
|
||||
|
|
|
@ -36,9 +36,8 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsFTPChannel.h"
|
||||
#include "nsFtpConnectionThread.h" // defines nsFtpState
|
||||
|
||||
#include "nsFTPChannel.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -59,7 +58,12 @@ extern PRLogModuleInfo* gFTPLog;
|
|||
static inline PRUint32
|
||||
PRTimeToSeconds(PRTime t_usec)
|
||||
{
|
||||
return PRUint32(t_usec / PR_USEC_PER_SEC);
|
||||
PRTime usec_per_sec;
|
||||
PRUint32 t_sec;
|
||||
LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
|
||||
LL_DIV(t_usec, t_usec, usec_per_sec);
|
||||
LL_L2I(t_sec, t_usec);
|
||||
return t_sec;
|
||||
}
|
||||
|
||||
#define NowInSeconds() PRTimeToSeconds(PR_Now())
|
||||
|
@ -74,53 +78,209 @@ PRTimeToSeconds(PRTime t_usec)
|
|||
// initiated by the server (PORT command) or by the client (PASV command).
|
||||
// Client initiation is the most common case and is attempted first.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
nsFTPChannel::nsFTPChannel()
|
||||
: mIsPending(0),
|
||||
mLoadFlags(LOAD_NORMAL),
|
||||
mSourceOffset(0),
|
||||
mAmount(0),
|
||||
mContentLength(-1),
|
||||
mFTPState(nsnull),
|
||||
mStatus(NS_OK),
|
||||
mCanceled(PR_FALSE),
|
||||
mStartPos(LL_MaxUint())
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED3(nsFtpChannel,
|
||||
nsBaseChannel,
|
||||
nsIUploadChannel,
|
||||
nsIResumableChannel,
|
||||
nsIFTPChannel)
|
||||
nsFTPChannel::~nsFTPChannel()
|
||||
{
|
||||
#if defined(PR_LOGGING)
|
||||
nsCAutoString spec;
|
||||
mURL->GetAsciiSpec(spec);
|
||||
PR_LOG(gFTPLog, PR_LOG_ALWAYS, ("~nsFTPChannel() for %s", spec.get()));
|
||||
#endif
|
||||
NS_IF_RELEASE(mFTPState);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMPL_ADDREF_INHERITED(nsFTPChannel, nsHashPropertyBag)
|
||||
NS_IMPL_RELEASE_INHERITED(nsFTPChannel, nsHashPropertyBag)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsFTPChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFTPChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequest)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICacheListener)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
|
||||
|
||||
nsresult
|
||||
nsFTPChannel::Init(nsIURI* uri, nsIProxyInfo* proxyInfo, nsICacheSession* session)
|
||||
{
|
||||
nsresult rv = nsHashPropertyBag::Init();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// setup channel state
|
||||
mURL = uri;
|
||||
mProxyInfo = proxyInfo;
|
||||
|
||||
mIOService = do_GetIOService(&rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mCacheSession = session;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIRequest methods:
|
||||
|
||||
// The FTP channel doesn't maintain any connection state. Nor does it
|
||||
// interpret the protocol. The FTP connection thread is responsible for
|
||||
// these things and thus, the FTP channel simply calls through to the
|
||||
// FTP connection thread using an xpcom proxy object to make the
|
||||
// cross thread call.
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFtpChannel::SetUploadStream(nsIInputStream *stream,
|
||||
const nsACString &contentType,
|
||||
PRInt32 contentLength)
|
||||
nsFTPChannel::GetName(nsACString &result)
|
||||
{
|
||||
NS_ENSURE_TRUE(!IsPending(), NS_ERROR_IN_PROGRESS);
|
||||
return mURL->GetSpec(result);
|
||||
}
|
||||
|
||||
mUploadStream = stream;
|
||||
|
||||
// NOTE: contentLength is intentionally ignored here.
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::IsPending(PRBool *result) {
|
||||
*result = mIsPending;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFtpChannel::GetUploadStream(nsIInputStream **stream)
|
||||
nsFTPChannel::GetStatus(nsresult *status)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(stream);
|
||||
*stream = mUploadStream;
|
||||
NS_IF_ADDREF(*stream);
|
||||
*status = mStatus;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::Cancel(nsresult status) {
|
||||
|
||||
PR_LOG(gFTPLog,
|
||||
PR_LOG_DEBUG,
|
||||
("nsFTPChannel::Cancel() called [this=%x, status=%x, mCanceled=%d]\n",
|
||||
this, status, mCanceled));
|
||||
|
||||
NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
|
||||
|
||||
if (mCanceled)
|
||||
return NS_OK;
|
||||
|
||||
mCanceled = PR_TRUE;
|
||||
|
||||
mStatus = status;
|
||||
|
||||
if (mFTPState)
|
||||
(void)mFTPState->Cancel(status);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFtpChannel::ResumeAt(PRUint64 aStartPos, const nsACString& aEntityID)
|
||||
nsFTPChannel::Suspend(void) {
|
||||
|
||||
PR_LOG(gFTPLog, PR_LOG_DEBUG,
|
||||
("nsFTPChannel::Suspend() called [this=%x]\n", this));
|
||||
|
||||
if (mFTPState) {
|
||||
return mFTPState->Suspend();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::Resume(void) {
|
||||
|
||||
PR_LOG(gFTPLog, PR_LOG_DEBUG,
|
||||
("nsFTPChannel::Resume() called [this=%x]\n", this));
|
||||
|
||||
if (mFTPState) {
|
||||
return mFTPState->Resume();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIChannel methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetOriginalURI(nsIURI* *aURL)
|
||||
{
|
||||
*aURL = mOriginalURI ? mOriginalURI : mURL;
|
||||
NS_ADDREF(*aURL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::SetOriginalURI(nsIURI* aURL)
|
||||
{
|
||||
mOriginalURI = aURL;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetURI(nsIURI* *aURL)
|
||||
{
|
||||
*aURL = mURL;
|
||||
NS_ADDREF(*aURL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::Open(nsIInputStream **result)
|
||||
{
|
||||
return NS_ImplementChannelOpen(this, result);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFTPChannel::GenerateCacheKey(nsACString &cacheKey)
|
||||
{
|
||||
cacheKey.SetLength(0);
|
||||
|
||||
nsCAutoString spec;
|
||||
mURL->GetAsciiSpec(spec);
|
||||
|
||||
// Strip any trailing #ref from the URL before using it as the key
|
||||
const char *p = strchr(spec.get(), '#');
|
||||
if (p)
|
||||
cacheKey.Append(Substring(spec, 0, p - spec.get()));
|
||||
else
|
||||
cacheKey.Append(spec);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
||||
{
|
||||
nsresult rv = AsyncOpenAt(listener, ctxt, mStartPos, mEntityID);
|
||||
// mEntityID no longer needed, clear it to avoid returning a wrong entity
|
||||
// id when someone asks us
|
||||
mEntityID.Truncate();
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::ResumeAt(PRUint64 aStartPos, const nsACString& aEntityID)
|
||||
{
|
||||
NS_ENSURE_TRUE(!IsPending(), NS_ERROR_IN_PROGRESS);
|
||||
mEntityID = aEntityID;
|
||||
mStartPos = aStartPos;
|
||||
mResumeRequested = (mStartPos || !mEntityID.IsEmpty());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFtpChannel::GetEntityID(nsACString& entityID)
|
||||
nsFTPChannel::GetEntityID(nsACString& entityID)
|
||||
{
|
||||
if (mEntityID.IsEmpty())
|
||||
return NS_ERROR_NOT_RESUMABLE;
|
||||
|
@ -129,48 +289,70 @@ nsFtpChannel::GetEntityID(nsACString& entityID)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
nsFtpChannel::OpenContentStream(PRBool async, nsIInputStream **result)
|
||||
nsFTPChannel::AsyncOpenAt(nsIStreamListener *listener, nsISupports *ctxt,
|
||||
PRUint64 startPos, const nsACString& entityID)
|
||||
{
|
||||
if (!async)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
nsFtpState *state = new nsFtpState();
|
||||
if (!state)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(state);
|
||||
|
||||
nsresult rv = state->Init(this);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(state);
|
||||
PRInt32 port;
|
||||
nsresult rv = mURL->GetPort(&port);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = NS_CheckPortSafety(port, "ftp", mIOService);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::AsyncOpen() called\n"));
|
||||
|
||||
mListener = listener;
|
||||
mUserContext = ctxt;
|
||||
|
||||
// Add this request to the load group
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->AddRequest(this, nsnull);
|
||||
PRBool offline;
|
||||
|
||||
// If we're starting from the beginning, then its OK to use the cache,
|
||||
// because the entire file must be there (the cache doesn't support
|
||||
// partial entries yet)
|
||||
// Note that ftp doesn't store metadata, so disable caching if there was
|
||||
// an entityID. Storing this metadata isn't worth it until we can
|
||||
// get partial data out of the cache anyway...
|
||||
if (mCacheSession && !mUploadStream && entityID.IsEmpty() &&
|
||||
(startPos==0 || startPos==PRUint32(-1))) {
|
||||
mIOService->GetOffline(&offline);
|
||||
|
||||
// Set the desired cache access mode accordingly...
|
||||
nsCacheAccessMode accessRequested;
|
||||
if (offline) {
|
||||
// Since we are offline, we can only read from the cache.
|
||||
accessRequested = nsICache::ACCESS_READ;
|
||||
}
|
||||
else if (mLoadFlags & LOAD_BYPASS_CACHE)
|
||||
accessRequested = nsICache::ACCESS_WRITE; // replace cache entry
|
||||
else
|
||||
accessRequested = nsICache::ACCESS_READ_WRITE; // normal browsing
|
||||
|
||||
nsCAutoString cacheKey;
|
||||
GenerateCacheKey(cacheKey);
|
||||
|
||||
rv = mCacheSession->AsyncOpenCacheEntry(cacheKey,
|
||||
accessRequested,
|
||||
this);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return rv;
|
||||
|
||||
// If we failed to use the cache, try without
|
||||
PR_LOG(gFTPLog, PR_LOG_DEBUG,
|
||||
("Opening cache entry failed [rv=%x]", rv));
|
||||
}
|
||||
|
||||
*result = state;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsFtpChannel::GetStatusArg(nsresult status, nsString &statusArg)
|
||||
{
|
||||
nsCAutoString host;
|
||||
URI()->GetHost(host);
|
||||
CopyUTF8toUTF16(host, statusArg);
|
||||
return PR_TRUE;
|
||||
|
||||
return SetupState(startPos, entityID);
|
||||
// XXX this function must not fail since we have already called AddRequest!
|
||||
}
|
||||
|
||||
void
|
||||
nsFtpChannel::OnCallbacksChanged()
|
||||
{
|
||||
mFTPEventSink = nsnull;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
nsFtpChannel::GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult)
|
||||
nsFTPChannel::GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult)
|
||||
{
|
||||
if (!mFTPEventSink) {
|
||||
nsCOMPtr<nsIFTPEventSink> ftpSink;
|
||||
|
@ -184,3 +366,369 @@ nsFtpChannel::GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult)
|
|||
}
|
||||
aResult = mFTPEventSink;
|
||||
}
|
||||
|
||||
void
|
||||
nsFTPChannel::InitProgressSink()
|
||||
{
|
||||
// Build a proxy for the progress event sink since we may need to call it
|
||||
// while we are deep inside some of our state logic, and we wouldn't want
|
||||
// to worry about some weird re-entrancy scenario.
|
||||
nsCOMPtr<nsIProgressEventSink> progressSink;
|
||||
NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, progressSink);
|
||||
if (progressSink)
|
||||
NS_GetProxyForObject(NS_CURRENT_EVENTQ,
|
||||
NS_GET_IID(nsIProgressEventSink),
|
||||
progressSink,
|
||||
PROXY_ASYNC | PROXY_ALWAYS,
|
||||
getter_AddRefs(mProgressSink));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFTPChannel::SetupState(PRUint64 startPos, const nsACString& entityID)
|
||||
{
|
||||
if (!mFTPState) {
|
||||
NS_NEWXPCOM(mFTPState, nsFtpState);
|
||||
if (!mFTPState) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(mFTPState);
|
||||
}
|
||||
nsresult rv = mFTPState->Init(this,
|
||||
mCacheEntry,
|
||||
mProxyInfo,
|
||||
startPos,
|
||||
entityID);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
(void) mFTPState->SetWriteStream(mUploadStream);
|
||||
|
||||
rv = mFTPState->Connect();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mIsPending = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetLoadFlags(PRUint32 *aLoadFlags)
|
||||
{
|
||||
*aLoadFlags = mLoadFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::SetLoadFlags(PRUint32 aLoadFlags)
|
||||
{
|
||||
mLoadFlags = aLoadFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// FTP does not provide a file typing mechanism. We fallback to file
|
||||
// extension mapping.
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetContentType(nsACString &aContentType)
|
||||
{
|
||||
if (mContentType.IsEmpty()) {
|
||||
aContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
|
||||
} else {
|
||||
aContentType = mContentType;
|
||||
}
|
||||
|
||||
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::GetContentType() returned %s\n", PromiseFlatCString(aContentType).get()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::SetContentType(const nsACString &aContentType)
|
||||
{
|
||||
PRBool dummy;
|
||||
net_ParseContentType(aContentType, mContentType, mContentCharset, &dummy);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetContentCharset(nsACString &aContentCharset)
|
||||
{
|
||||
aContentCharset = mContentCharset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::SetContentCharset(const nsACString &aContentCharset)
|
||||
{
|
||||
mContentCharset = aContentCharset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetContentLength(PRInt32 *aContentLength)
|
||||
{
|
||||
*aContentLength = mContentLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::SetContentLength(PRInt32 aContentLength)
|
||||
{
|
||||
mContentLength = aContentLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
|
||||
{
|
||||
*aLoadGroup = mLoadGroup;
|
||||
NS_IF_ADDREF(*aLoadGroup);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
mLoadGroup = aLoadGroup;
|
||||
mProgressSink = nsnull;
|
||||
mFTPEventSink = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetOwner(nsISupports* *aOwner)
|
||||
{
|
||||
*aOwner = mOwner.get();
|
||||
NS_IF_ADDREF(*aOwner);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::SetOwner(nsISupports* aOwner)
|
||||
{
|
||||
mOwner = aOwner;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
|
||||
{
|
||||
NS_IF_ADDREF(*aNotificationCallbacks = mCallbacks);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
|
||||
{
|
||||
mCallbacks = aNotificationCallbacks;
|
||||
mProgressSink = nsnull;
|
||||
mFTPEventSink = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
|
||||
{
|
||||
*aSecurityInfo = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIInterfaceRequestor method
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetInterface(const nsIID &aIID, void **aResult)
|
||||
{
|
||||
// capture the progress event sink stuff. pass the rest through.
|
||||
if (aIID.Equals(NS_GET_IID(nsIProgressEventSink))) {
|
||||
*aResult = NS_STATIC_CAST(nsIProgressEventSink*, this);
|
||||
NS_ADDREF(this);
|
||||
return NS_OK;
|
||||
}
|
||||
NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, aIID, aResult);
|
||||
return aResult ? NS_OK : NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
// nsIProgressEventSink methods
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::OnStatus(nsIRequest *request, nsISupports *aContext,
|
||||
nsresult aStatus, const PRUnichar* aStatusArg)
|
||||
{
|
||||
if (!mProgressSink)
|
||||
InitProgressSink();
|
||||
|
||||
if (aStatus == NS_NET_STATUS_CONNECTED_TO)
|
||||
{
|
||||
// The state machine needs to know that the data connection
|
||||
// was successfully started so that it can issue data commands
|
||||
// securely.
|
||||
if (mFTPState)
|
||||
mFTPState->DataConnectionEstablished();
|
||||
else
|
||||
NS_ERROR("ftp state is null.");
|
||||
}
|
||||
|
||||
if (!mProgressSink || (mLoadFlags & LOAD_BACKGROUND) || !mIsPending || NS_FAILED(mStatus))
|
||||
return NS_OK;
|
||||
|
||||
nsCAutoString host;
|
||||
mURL->GetHost(host);
|
||||
return mProgressSink->OnStatus(this, mUserContext, aStatus,
|
||||
NS_ConvertUTF8toUTF16(host).get());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::OnProgress(nsIRequest *request, nsISupports* aContext,
|
||||
PRUint64 aProgress, PRUint64 aProgressMax)
|
||||
{
|
||||
if (!mProgressSink)
|
||||
InitProgressSink();
|
||||
|
||||
if (!mProgressSink || (mLoadFlags & LOAD_BACKGROUND) || !mIsPending)
|
||||
return NS_OK;
|
||||
|
||||
return mProgressSink->OnProgress(this, mUserContext,
|
||||
aProgress, aProgressMax);
|
||||
}
|
||||
|
||||
|
||||
// nsIRequestObserver methods.
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::OnStopRequest(nsIRequest *request, nsISupports* aContext,
|
||||
nsresult aStatus)
|
||||
{
|
||||
PR_LOG(gFTPLog,
|
||||
PR_LOG_DEBUG,
|
||||
("nsFTPChannel::OnStopRequest() called [this=%x, request=%x, aStatus=%x]\n",
|
||||
this, request, aStatus));
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (NS_SUCCEEDED(mStatus))
|
||||
mStatus = aStatus;
|
||||
|
||||
if (mListener) {
|
||||
(void) mListener->OnStopRequest(this, mUserContext, mStatus);
|
||||
}
|
||||
if (mLoadGroup) {
|
||||
(void) mLoadGroup->RemoveRequest(this, nsnull, mStatus);
|
||||
}
|
||||
|
||||
if (mCacheEntry) {
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
(void) mCacheEntry->SetExpirationTime( NowInSeconds() + 900 ); // valid for 15 minutes.
|
||||
(void) mCacheEntry->MarkValid();
|
||||
}
|
||||
else {
|
||||
(void) mCacheEntry->Doom();
|
||||
}
|
||||
mCacheEntry->Close();
|
||||
mCacheEntry = 0;
|
||||
}
|
||||
|
||||
if (mUploadStream)
|
||||
mUploadStream->Close();
|
||||
|
||||
if (mFTPState) {
|
||||
mFTPState->DataConnectionComplete();
|
||||
NS_RELEASE(mFTPState);
|
||||
}
|
||||
mIsPending = PR_FALSE;
|
||||
|
||||
// Drop notification callbacks to prevent cycles.
|
||||
mCallbacks = nsnull;
|
||||
mProgressSink = nsnull;
|
||||
mFTPEventSink = nsnull;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::OnStartRequest(nsIRequest *request, nsISupports *aContext)
|
||||
{
|
||||
PR_LOG(gFTPLog,
|
||||
PR_LOG_DEBUG,
|
||||
("nsFTPChannel::OnStartRequest() called [this=%x, request=%x]\n",
|
||||
this, request));
|
||||
|
||||
if (NS_SUCCEEDED(mStatus))
|
||||
request->GetStatus(&mStatus);
|
||||
|
||||
nsCOMPtr<nsIResumableChannel> resumable = do_QueryInterface(request);
|
||||
if (resumable) {
|
||||
resumable->GetEntityID(mEntityID);
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (mListener) {
|
||||
if (mContentType.IsEmpty()) {
|
||||
// Time to sniff!
|
||||
nsCOMPtr<nsIStreamConverterService> serv =
|
||||
do_GetService("@mozilla.org/streamConverters;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIStreamListener> converter;
|
||||
rv = serv->AsyncConvertData(UNKNOWN_CONTENT_TYPE,
|
||||
"*/*",
|
||||
mListener,
|
||||
mUserContext,
|
||||
getter_AddRefs(converter));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mListener = converter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rv = mListener->OnStartRequest(this, mUserContext);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// nsIStreamListener method
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::OnDataAvailable(nsIRequest *request, nsISupports* aContext,
|
||||
nsIInputStream *aInputStream, PRUint32 aSourceOffset,
|
||||
PRUint32 aLength) {
|
||||
return mListener->OnDataAvailable(this, mUserContext, aInputStream, aSourceOffset, aLength);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsFTPChannel::nsICacheListener
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry,
|
||||
nsCacheAccessMode access,
|
||||
nsresult status)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (mCanceled) {
|
||||
NS_ASSERTION(NS_FAILED(mStatus), "Must be canceled with a failure status code");
|
||||
OnStartRequest(NS_STATIC_CAST(nsIRequest*, this), nsnull);
|
||||
OnStopRequest(NS_STATIC_CAST(nsIRequest*, this), nsnull, mStatus);
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
mCacheEntry = entry;
|
||||
}
|
||||
|
||||
rv = SetupState(PRUint32(-1), EmptyCString());
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
Cancel(rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::SetUploadStream(nsIInputStream *stream, const nsACString &contentType, PRInt32 contentLength)
|
||||
{
|
||||
mUploadStream = stream;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::GetUploadStream(nsIInputStream **stream)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(stream);
|
||||
*stream = mUploadStream;
|
||||
NS_IF_ADDREF(*stream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set ts=4 sw=4 sts=4 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -41,8 +40,6 @@
|
|||
#ifndef nsFTPChannel_h___
|
||||
#define nsFTPChannel_h___
|
||||
|
||||
#include "nsBaseChannel.h"
|
||||
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsString.h"
|
||||
|
@ -75,63 +72,94 @@
|
|||
#define FTP_DATA_CHANNEL_SEG_SIZE (4*1024)
|
||||
#define FTP_DATA_CHANNEL_SEG_COUNT 8
|
||||
|
||||
class nsFtpChannel : public nsBaseChannel,
|
||||
#define FTP_CACHE_CONTROL_CONNECTION 1
|
||||
|
||||
class nsFTPChannel : public nsHashPropertyBag,
|
||||
public nsIFTPChannel,
|
||||
public nsIUploadChannel,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIProgressEventSink,
|
||||
public nsIStreamListener,
|
||||
public nsICacheListener,
|
||||
public nsIResumableChannel
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_NSICHANNEL
|
||||
NS_DECL_NSIUPLOADCHANNEL
|
||||
NS_DECL_NSIFTPCHANNEL
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIPROGRESSEVENTSINK
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSICACHELISTENER
|
||||
NS_DECL_NSIRESUMABLECHANNEL
|
||||
|
||||
nsFtpChannel(nsIURI *uri, nsIProxyInfo *pi)
|
||||
: mProxyInfo(pi)
|
||||
, mStartPos(0)
|
||||
, mResumeRequested(PR_FALSE)
|
||||
{
|
||||
SetURI(uri);
|
||||
}
|
||||
// nsFTPChannel methods:
|
||||
nsFTPChannel();
|
||||
virtual ~nsFTPChannel();
|
||||
|
||||
// initializes the channel.
|
||||
nsresult Init(nsIURI* uri,
|
||||
nsIProxyInfo* proxyInfo,
|
||||
nsICacheSession* session);
|
||||
|
||||
nsIProxyInfo *ProxyInfo() {
|
||||
return mProxyInfo;
|
||||
}
|
||||
nsresult SetupState(PRUint64 startPos, const nsACString& entityID);
|
||||
nsresult GenerateCacheKey(nsACString &cacheKey);
|
||||
|
||||
nsresult AsyncOpenAt(nsIStreamListener *listener, nsISupports *ctxt,
|
||||
PRUint64 startPos, const nsACString& entityID);
|
||||
|
||||
// Were we asked to resume a download?
|
||||
PRBool ResumeRequested() { return mResumeRequested; }
|
||||
|
||||
// Download from this byte offset
|
||||
PRUint64 StartPos() { return mStartPos; }
|
||||
|
||||
// ID of the entity to resume downloading
|
||||
const nsCString &EntityID() {
|
||||
return mEntityID;
|
||||
}
|
||||
void SetEntityID(const nsCSubstring &entityID) {
|
||||
mEntityID = entityID;
|
||||
}
|
||||
|
||||
// Data stream to upload
|
||||
nsIInputStream *UploadStream() {
|
||||
return mUploadStream;
|
||||
// Helper function to simplify getting notification callbacks.
|
||||
template <class T>
|
||||
void GetCallback(nsCOMPtr<T> &aResult) {
|
||||
GetInterface(NS_GET_TEMPLATE_IID(T), getter_AddRefs(aResult));
|
||||
}
|
||||
|
||||
// Helper function for getting the nsIFTPEventSink.
|
||||
void GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult);
|
||||
|
||||
protected:
|
||||
virtual ~nsFtpChannel() {}
|
||||
virtual nsresult OpenContentStream(PRBool async, nsIInputStream **result);
|
||||
virtual PRBool GetStatusArg(nsresult status, nsString &statusArg);
|
||||
virtual void OnCallbacksChanged();
|
||||
void InitProgressSink();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIProxyInfo> mProxyInfo;
|
||||
nsCOMPtr<nsIFTPEventSink> mFTPEventSink;
|
||||
nsCOMPtr<nsIInputStream> mUploadStream;
|
||||
PRUint64 mStartPos;
|
||||
nsCString mEntityID;
|
||||
PRPackedBool mResumeRequested;
|
||||
protected:
|
||||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
nsCOMPtr<nsIURI> mURL;
|
||||
|
||||
nsCOMPtr<nsIInputStream> mUploadStream;
|
||||
|
||||
// various callback interfaces
|
||||
nsCOMPtr<nsIProgressEventSink> mProgressSink;
|
||||
nsCOMPtr<nsIFTPEventSink> mFTPEventSink;
|
||||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||
|
||||
PRBool mIsPending;
|
||||
PRUint32 mLoadFlags;
|
||||
|
||||
PRUint32 mSourceOffset;
|
||||
PRInt32 mAmount;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
nsCString mContentType;
|
||||
nsCString mContentCharset;
|
||||
PRInt32 mContentLength;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
|
||||
nsFtpState* mFTPState;
|
||||
|
||||
nsCOMPtr<nsISupports> mUserContext;
|
||||
nsresult mStatus;
|
||||
PRPackedBool mCanceled;
|
||||
|
||||
nsCOMPtr<nsIIOService> mIOService;
|
||||
|
||||
nsCOMPtr<nsICacheSession> mCacheSession;
|
||||
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
|
||||
nsCOMPtr<nsIProxyInfo> mProxyInfo;
|
||||
nsCString mEntityID;
|
||||
PRUint64 mStartPos;
|
||||
};
|
||||
|
||||
#endif /* nsFTPChannel_h___ */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -40,9 +40,6 @@
|
|||
#define __nsFtpState__h_
|
||||
|
||||
#include "ftpCore.h"
|
||||
#include "nsFTPChannel.h"
|
||||
#include "nsBaseContentStream.h"
|
||||
|
||||
#include "nsInt64.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
@ -50,14 +47,13 @@
|
|||
#include "nsISocketTransport.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsICacheListener.h"
|
||||
#include "nsIURI.h"
|
||||
#include "prtime.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIFTPChannel.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
@ -70,7 +66,6 @@
|
|||
#include "nsFtpControlConnection.h"
|
||||
|
||||
#include "nsICacheEntryDescriptor.h"
|
||||
#include "nsICacheListener.h"
|
||||
|
||||
// ftp server types
|
||||
#define FTP_GENERIC_TYPE 0
|
||||
|
@ -83,9 +78,6 @@
|
|||
typedef enum _FTP_STATE {
|
||||
///////////////////////
|
||||
//// Internal states
|
||||
FTP_INIT,
|
||||
FTP_WAIT_CACHE,
|
||||
FTP_READ_CACHE,
|
||||
FTP_COMMAND_CONNECT,
|
||||
FTP_READ_BUF,
|
||||
FTP_ERROR,
|
||||
|
@ -112,46 +104,38 @@ typedef enum _FTP_STATE {
|
|||
// higher level ftp actions
|
||||
typedef enum _FTP_ACTION {GET, PUT} FTP_ACTION;
|
||||
|
||||
class nsFtpChannel;
|
||||
class DataRequestForwarder;
|
||||
class nsFTPChannel;
|
||||
|
||||
// The nsFtpState object is the content stream for the channel. It implements
|
||||
// nsIInputStreamCallback, so it can read data from the control connection. It
|
||||
// implements nsITransportEventSink so it can mix status events from both the
|
||||
// control connection and the data connection.
|
||||
|
||||
class nsFtpState : public nsBaseContentStream,
|
||||
public nsIInputStreamCallback,
|
||||
public nsITransportEventSink,
|
||||
public nsICacheListener,
|
||||
public nsIRequestObserver,
|
||||
public nsFtpControlConnectionListener {
|
||||
class nsFtpState : public nsIStreamListener,
|
||||
public nsIRequest {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIINPUTSTREAMCALLBACK
|
||||
NS_DECL_NSITRANSPORTEVENTSINK
|
||||
NS_DECL_NSICACHELISTENER
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
// Override input stream methods:
|
||||
NS_IMETHOD CloseWithStatus(nsresult status);
|
||||
NS_IMETHOD Available(PRUint32 *result);
|
||||
NS_IMETHOD ReadSegments(nsWriteSegmentFun fun, void *closure,
|
||||
PRUint32 count, PRUint32 *result);
|
||||
|
||||
// nsFtpControlConnectionListener methods:
|
||||
virtual void OnControlDataAvailable(const char *data, PRUint32 dataLen);
|
||||
virtual void OnControlError(nsresult status);
|
||||
NS_DECL_NSIREQUEST
|
||||
|
||||
nsFtpState();
|
||||
nsresult Init(nsFtpChannel *channel);
|
||||
|
||||
protected:
|
||||
// Notification from nsBaseContentStream::AsyncWait
|
||||
virtual void OnCallbackPending();
|
||||
|
||||
private:
|
||||
virtual ~nsFtpState();
|
||||
|
||||
nsresult Init(nsFTPChannel *aChannel,
|
||||
nsICacheEntryDescriptor* cacheEntry,
|
||||
nsIProxyInfo* proxyInfo,
|
||||
PRUint64 startPos,
|
||||
const nsACString& entity);
|
||||
|
||||
// use this to provide a stream to be written to the server.
|
||||
nsresult SetWriteStream(nsIInputStream* aInStream);
|
||||
|
||||
nsresult GetEntityID(nsACString& aEntityID);
|
||||
|
||||
nsresult Connect();
|
||||
|
||||
// lets the data forwarder tell us when the the data pipe has been created
|
||||
// and when the data pipe has finished.
|
||||
void DataConnectionEstablished();
|
||||
void DataConnectionComplete();
|
||||
private:
|
||||
///////////////////////////////////
|
||||
// BEGIN: STATE METHODS
|
||||
nsresult S_user(); FTP_STATE R_user();
|
||||
|
@ -181,60 +165,13 @@ private:
|
|||
void KillControlConnection();
|
||||
nsresult StopProcessing();
|
||||
nsresult EstablishControlConnection();
|
||||
nsresult SendFTPCommand(const nsCSubstring& command);
|
||||
nsresult SendFTPCommand(nsCString& command);
|
||||
void ConvertFilespecToVMS(nsCString& fileSpec);
|
||||
void ConvertDirspecToVMS(nsCString& fileSpec);
|
||||
void ConvertDirspecFromVMS(nsCString& fileSpec);
|
||||
nsresult BuildStreamConverter(nsIStreamListener** convertStreamListener);
|
||||
nsresult SetContentType();
|
||||
|
||||
/**
|
||||
* This method is called to kick-off the FTP state machine. mState is
|
||||
* reset to FTP_COMMAND_CONNECT, and the FTP state machine progresses from
|
||||
* there. This method is initially called (indirectly) from the channel's
|
||||
* AsyncOpen implementation.
|
||||
*/
|
||||
void Connect();
|
||||
|
||||
/**
|
||||
* This method opens a cache entry for reading or writing depending on the
|
||||
* state of the channel and of the system (e.g., opened for reading if we
|
||||
* are offline). This method is responsible for setting mCacheEntry if
|
||||
* there is a cache entry that can be used. It returns true if it ends up
|
||||
* waiting (asynchronously) for access to the cache entry. In that case,
|
||||
* the nsFtpState's OnCacheEntryAvailable method will be called once the
|
||||
* cache entry is available or if an error occurs.
|
||||
*/
|
||||
PRBool CheckCache();
|
||||
|
||||
/**
|
||||
* This method returns true if the data for this URL can be read from the
|
||||
* cache. This method assumes that mCacheEntry is non-null.
|
||||
*/
|
||||
PRBool CanReadCacheEntry();
|
||||
|
||||
/**
|
||||
* This method causes the cache entry to be read. Data from the cache
|
||||
* entry will be fed to the channel's listener. This method returns true
|
||||
* if successfully reading from the cache. This method assumes that
|
||||
* mCacheEntry is non-null and opened with read access.
|
||||
*/
|
||||
PRBool ReadCacheEntry();
|
||||
|
||||
/**
|
||||
* This method configures mDataStream with an asynchronous input stream to
|
||||
* the cache entry. The cache entry is read on a background thread. This
|
||||
* method assumes that mCacheEntry is non-null and opened with read access.
|
||||
*/
|
||||
nsresult OpenCacheDataStream();
|
||||
|
||||
/**
|
||||
* This method inserts the cache entry's output stream into the stream
|
||||
* listener chain for the FTP channel. As a result, the cache entry
|
||||
* receives data as data is pushed to the channel's listener. This method
|
||||
* assumes that mCacheEntry is non-null and opened with write access.
|
||||
*/
|
||||
nsresult InstallCacheListener();
|
||||
PRBool CanReadEntry();
|
||||
|
||||
///////////////////////////////////
|
||||
// Private members
|
||||
|
@ -244,22 +181,27 @@ private:
|
|||
FTP_STATE mNextState; // the next state
|
||||
PRPackedBool mKeepRunning; // thread event loop boolean
|
||||
PRInt32 mResponseCode; // the last command response code
|
||||
nsCString mResponseMsg; // the last command response text
|
||||
nsCAutoString mResponseMsg; // the last command response text
|
||||
|
||||
// ****** channel/transport/stream vars
|
||||
nsRefPtr<nsFtpControlConnection> mControlConnection; // cacheable control connection (owns mCPipe)
|
||||
nsFtpControlConnection* mControlConnection; // cacheable control connection (owns mCPipe)
|
||||
PRPackedBool mReceivedControlData;
|
||||
PRPackedBool mTryingCachedControl; // retrying the password
|
||||
PRPackedBool mWaitingForDConn; // Are we wait for a data connection
|
||||
PRPackedBool mRETRFailed; // Did we already try a RETR and it failed?
|
||||
nsCOMPtr<nsISocketTransport> mDPipe; // the data transport
|
||||
nsCOMPtr<nsIRequest> mDPipeRequest;
|
||||
DataRequestForwarder* mDRequestForwarder;
|
||||
PRUint64 mFileSize;
|
||||
nsCString mModTime;
|
||||
|
||||
// ****** consumer vars
|
||||
nsRefPtr<nsFtpChannel> mChannel; // our owning FTP channel we pass through our events
|
||||
nsRefPtr<nsFTPChannel> mChannel; // our owning FTP channel we pass through our events
|
||||
nsCOMPtr<nsIProxyInfo> mProxyInfo;
|
||||
|
||||
// ****** connection cache vars
|
||||
PRInt32 mServerType; // What kind of server are we talking to
|
||||
PRPackedBool mList; // Use LIST instead of NLST
|
||||
|
||||
// ****** protocol interpretation related state vars
|
||||
nsString mUsername; // username
|
||||
|
@ -270,28 +212,35 @@ private:
|
|||
nsresult mInternalError; // represents internal state errors
|
||||
|
||||
// ****** URI vars
|
||||
nsCOMPtr<nsIURI> mURL; // the uri we're connecting to
|
||||
PRInt32 mPort; // the port to connect to
|
||||
nsString mFilename; // url filename (if any)
|
||||
nsCString mPath; // the url's path
|
||||
nsCString mPwd; // login Path
|
||||
|
||||
// ****** other vars
|
||||
nsCOMPtr<nsITransport> mDataTransport;
|
||||
nsCOMPtr<nsIAsyncInputStream> mDataStream;
|
||||
nsCOMPtr<nsIRequest> mUploadRequest;
|
||||
PRPackedBool mIPv6Checked;
|
||||
PRUint8 mSuspendCount;// number of times we've been suspended.
|
||||
PRUint32 mBufferSegmentSize;
|
||||
PRUint32 mBufferMaxSize;
|
||||
PRLock *mLock;
|
||||
nsCOMPtr<nsIInputStream> mWriteStream; // This stream is written to the server.
|
||||
PRUint32 mWriteCount;
|
||||
PRPackedBool mIPv6Checked;
|
||||
|
||||
static PRUint32 mSessionStartTime;
|
||||
|
||||
nsAutoArrayPtr<char> mIPv6ServerAddress; // Server IPv6 address; null if server not IPv6
|
||||
char *mIPv6ServerAddress; // Server IPv6 address; null if server not IPv6
|
||||
|
||||
// ***** control read gvars
|
||||
nsresult mControlStatus;
|
||||
nsCString mControlReadCarryOverBuf;
|
||||
nsCAutoString mControlReadCarryOverBuf;
|
||||
|
||||
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
|
||||
|
||||
nsUint64 mStartPos;
|
||||
nsCString mSuppliedEntityID;
|
||||
nsCString mEntityID;
|
||||
};
|
||||
|
||||
|
||||
#endif //__nsFtpState__h_
|
||||
|
|
|
@ -47,172 +47,130 @@
|
|||
#include "nsEventQueueUtils.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
extern PRLogModuleInfo* gFTPLog;
|
||||
#endif
|
||||
#define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
|
||||
#define LOG_ALWAYS(args) PR_LOG(gFTPLog, PR_LOG_ALWAYS, args)
|
||||
#else
|
||||
#define LOG(args)
|
||||
#define LOG_ALWAYS(args)
|
||||
#endif
|
||||
|
||||
|
||||
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
|
||||
|
||||
//
|
||||
// nsFtpControlConnection implementation ...
|
||||
//
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFtpControlConnection, nsIInputStreamCallback)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsFtpControlConnection,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFtpControlConnection::OnInputStreamReady(nsIAsyncInputStream *stream)
|
||||
nsFtpControlConnection::nsFtpControlConnection(const char* host, PRUint32 port)
|
||||
: mServerType(0), mPort(port)
|
||||
{
|
||||
char data[4096];
|
||||
LOG_ALWAYS(("(%x) nsFtpControlConnection created", this));
|
||||
|
||||
// Consume data whether we have a listener or not.
|
||||
PRUint32 avail;
|
||||
nsresult rv = stream->Available(&avail);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (avail > sizeof(data))
|
||||
avail = sizeof(data);
|
||||
|
||||
PRUint32 n;
|
||||
rv = stream->Read(data, avail, &n);
|
||||
if (NS_SUCCEEDED(rv) && n != avail)
|
||||
avail = n;
|
||||
}
|
||||
|
||||
// It's important that we null out mListener before calling one of its
|
||||
// methods as it may call WaitData, which would queue up another read.
|
||||
|
||||
nsRefPtr<nsFtpControlConnectionListener> listener;
|
||||
listener.swap(mListener);
|
||||
|
||||
if (!listener)
|
||||
return NS_OK;
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
listener->OnControlError(rv);
|
||||
} else {
|
||||
listener->OnControlDataAvailable(data, avail);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsFtpControlConnection::nsFtpControlConnection(const nsCSubstring& host, PRUint32 port)
|
||||
: mServerType(0), mHost(host), mPort(port)
|
||||
{
|
||||
LOG_ALWAYS(("FTP:CC created @%p", this));
|
||||
mHost.Assign(host);
|
||||
}
|
||||
|
||||
nsFtpControlConnection::~nsFtpControlConnection()
|
||||
{
|
||||
LOG_ALWAYS(("FTP:CC destroyed @%p", this));
|
||||
LOG_ALWAYS(("(%x) nsFtpControlConnection destroyed", this));
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsFtpControlConnection::IsAlive()
|
||||
{
|
||||
if (!mSocket)
|
||||
if (!mCPipe)
|
||||
return PR_FALSE;
|
||||
|
||||
PRBool isAlive = PR_FALSE;
|
||||
mSocket->IsAlive(&isAlive);
|
||||
mCPipe->IsAlive(&isAlive);
|
||||
return isAlive;
|
||||
}
|
||||
nsresult
|
||||
nsFtpControlConnection::Connect(nsIProxyInfo* proxyInfo,
|
||||
nsITransportEventSink* eventSink)
|
||||
{
|
||||
if (mSocket)
|
||||
return NS_OK;
|
||||
|
||||
// build our own
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISocketTransportService> sts =
|
||||
do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = sts->CreateTransport(nsnull, 0, mHost, mPort, proxyInfo,
|
||||
getter_AddRefs(mSocket)); // the command transport
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (!mCPipe) {
|
||||
// build our own
|
||||
nsCOMPtr<nsISocketTransportService> sts =
|
||||
do_GetService(kSocketTransportServiceCID, &rv);
|
||||
|
||||
// proxy transport events back to current thread
|
||||
if (eventSink) {
|
||||
nsCOMPtr<nsIEventQueue> eventQ;
|
||||
rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mSocket->SetEventSink(eventSink, eventQ);
|
||||
rv = sts->CreateTransport(nsnull, 0, mHost, mPort, proxyInfo,
|
||||
getter_AddRefs(mCPipe)); // the command transport
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// proxy transport events back to current thread
|
||||
if (eventSink) {
|
||||
nsCOMPtr<nsIEventQueue> eventQ;
|
||||
rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mCPipe->SetEventSink(eventSink, eventQ);
|
||||
}
|
||||
|
||||
// open buffered, blocking output stream to socket. so long as commands
|
||||
// do not exceed 1024 bytes in length, the writing thread (the main thread)
|
||||
// will not block. this should be OK.
|
||||
rv = mCPipe->OpenOutputStream(nsITransport::OPEN_BLOCKING, 1024, 1,
|
||||
getter_AddRefs(mOutStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// open buffered, non-blocking/asynchronous input stream to socket.
|
||||
nsCOMPtr<nsIInputStream> inStream;
|
||||
rv = mCPipe->OpenInputStream(0,
|
||||
FTP_COMMAND_CHANNEL_SEG_SIZE,
|
||||
FTP_COMMAND_CHANNEL_SEG_COUNT,
|
||||
getter_AddRefs(inStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIInputStreamPump> pump;
|
||||
rv = NS_NewInputStreamPump(getter_AddRefs(pump), inStream);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// get the ball rolling by reading on the control socket.
|
||||
rv = pump->AsyncRead(NS_STATIC_CAST(nsIStreamListener*, this), nsnull);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// cyclic reference!
|
||||
mReadRequest = pump;
|
||||
}
|
||||
|
||||
// open buffered, blocking output stream to socket. so long as commands
|
||||
// do not exceed 1024 bytes in length, the writing thread (the main thread)
|
||||
// will not block. this should be OK.
|
||||
rv = mSocket->OpenOutputStream(nsITransport::OPEN_BLOCKING, 1024, 1,
|
||||
getter_AddRefs(mSocketOutput));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// open buffered, non-blocking/asynchronous input stream to socket.
|
||||
nsCOMPtr<nsIInputStream> inStream;
|
||||
rv = mSocket->OpenInputStream(0,
|
||||
FTP_COMMAND_CHANNEL_SEG_SIZE,
|
||||
FTP_COMMAND_CHANNEL_SEG_COUNT,
|
||||
getter_AddRefs(inStream));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mSocketInput = do_QueryInterface(inStream);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFtpControlConnection::WaitData(nsFtpControlConnectionListener *listener)
|
||||
{
|
||||
LOG(("FTP:(%p) wait data [listener=%p]\n", this, listener));
|
||||
|
||||
// If listener is null, then simply disconnect the listener. Otherwise,
|
||||
// ensure that we are listening.
|
||||
if (!listener) {
|
||||
mListener = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ENSURE_STATE(mSocketInput);
|
||||
|
||||
nsCOMPtr<nsIEventQueue> eventQ;
|
||||
NS_GetCurrentEventQ(getter_AddRefs(eventQ));
|
||||
NS_ENSURE_STATE(eventQ);
|
||||
|
||||
mListener = listener;
|
||||
return mSocketInput->AsyncWait(this, 0, 0, eventQ);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFtpControlConnection::Disconnect(nsresult status)
|
||||
{
|
||||
if (!mSocket)
|
||||
return NS_OK; // already disconnected
|
||||
if (!mCPipe) return NS_ERROR_FAILURE;
|
||||
|
||||
LOG_ALWAYS(("FTP:(%p) CC disconnecting (%x)", this, status));
|
||||
LOG_ALWAYS(("(%x) nsFtpControlConnection disconnecting (%x)", this, status));
|
||||
|
||||
if (NS_FAILED(status)) {
|
||||
// break cyclic reference!
|
||||
mSocket->Close(status);
|
||||
mSocket = 0;
|
||||
mSocketInput->AsyncWait(nsnull, 0, 0, nsnull); // clear any observer
|
||||
mSocketInput = nsnull;
|
||||
mSocketOutput = nsnull;
|
||||
mOutStream = 0;
|
||||
mReadRequest->Cancel(status);
|
||||
mReadRequest = 0;
|
||||
mCPipe->Close(status);
|
||||
mCPipe = 0;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFtpControlConnection::Write(const nsCSubstring& command)
|
||||
nsFtpControlConnection::Write(nsCString& command, PRBool suspend)
|
||||
{
|
||||
NS_ENSURE_STATE(mSocketOutput);
|
||||
if (!mCPipe)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PRUint32 len = command.Length();
|
||||
PRUint32 cnt;
|
||||
nsresult rv = mSocketOutput->Write(command.Data(), len, &cnt);
|
||||
nsresult rv = mOutStream->Write(command.get(), len, &cnt);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
@ -220,5 +178,59 @@ nsFtpControlConnection::Write(const nsCSubstring& command)
|
|||
if (len != cnt)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (suspend)
|
||||
return NS_OK;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFtpControlConnection::OnStartRequest(nsIRequest *request, nsISupports *aContext)
|
||||
{
|
||||
if (!mCPipe)
|
||||
return NS_OK;
|
||||
|
||||
if (!mListener)
|
||||
return NS_OK;
|
||||
|
||||
// In case our listener tries to remove itself via SetStreamListener(nsnull),
|
||||
// we need to keep an extra reference to it on the stack.
|
||||
nsCOMPtr<nsIStreamListener> deathGrip = mListener;
|
||||
return mListener->OnStartRequest(request, aContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFtpControlConnection::OnStopRequest(nsIRequest *request, nsISupports *aContext,
|
||||
nsresult aStatus)
|
||||
{
|
||||
if (!mCPipe)
|
||||
return NS_OK;
|
||||
|
||||
if (!mListener)
|
||||
return NS_OK;
|
||||
|
||||
// In case our listener tries to remove itself via SetStreamListener(nsnull),
|
||||
// we need to keep an extra reference to it on the stack.
|
||||
nsCOMPtr<nsIStreamListener> deathGrip = mListener;
|
||||
return mListener->OnStopRequest(request, aContext, aStatus);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFtpControlConnection::OnDataAvailable(nsIRequest *request,
|
||||
nsISupports *aContext,
|
||||
nsIInputStream *aInStream,
|
||||
PRUint32 aOffset,
|
||||
PRUint32 aCount)
|
||||
{
|
||||
if (!mCPipe)
|
||||
return NS_OK;
|
||||
|
||||
if (!mListener)
|
||||
return NS_OK;
|
||||
|
||||
// In case our listener tries to remove itself via SetStreamListener(nsnull),
|
||||
// we need to keep an extra reference to it on the stack.
|
||||
nsCOMPtr<nsIStreamListener> deathGrip = mListener;
|
||||
return mListener->OnDataAvailable(request, aContext, aInStream,
|
||||
aOffset, aCount);
|
||||
}
|
||||
|
|
|
@ -46,57 +46,33 @@
|
|||
#include "nsIRequest.h"
|
||||
#include "nsISocketTransport.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIProxyInfo;
|
||||
class nsITransportEventSink;
|
||||
|
||||
class nsFtpControlConnectionListener : public nsISupports {
|
||||
public:
|
||||
/**
|
||||
* Called when a chunk of data arrives on the control connection.
|
||||
* @param data
|
||||
* The new data or null if an error occured.
|
||||
* @param dataLen
|
||||
* The data length in bytes.
|
||||
*/
|
||||
virtual void OnControlDataAvailable(const char *data, PRUint32 dataLen) = 0;
|
||||
|
||||
/**
|
||||
* Called when an error occurs on the control connection.
|
||||
* @param status
|
||||
* A failure code providing more info about the error.
|
||||
*/
|
||||
virtual void OnControlError(nsresult status) = 0;
|
||||
};
|
||||
|
||||
class nsFtpControlConnection : public nsIInputStreamCallback
|
||||
class nsFtpControlConnection : public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAMCALLBACK
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
nsFtpControlConnection(const nsCSubstring& host, PRUint32 port);
|
||||
nsFtpControlConnection(const char* host, PRUint32 port);
|
||||
~nsFtpControlConnection();
|
||||
|
||||
nsresult Connect(nsIProxyInfo* proxyInfo, nsITransportEventSink* eventSink);
|
||||
nsresult Disconnect(nsresult status);
|
||||
nsresult Write(const nsCSubstring& command);
|
||||
nsresult Write(nsCString& command, PRBool suspend);
|
||||
|
||||
PRBool IsAlive();
|
||||
|
||||
nsITransport *Transport() { return mSocket; }
|
||||
nsIRequest *ReadRequest() { return mReadRequest; }
|
||||
nsITransport *Transport() { return mCPipe; }
|
||||
|
||||
/**
|
||||
* Call this function to be notified asynchronously when there is data
|
||||
* available for the socket. The listener passed to this method replaces
|
||||
* any existing listener, and the listener can be null to disconnect the
|
||||
* previous listener.
|
||||
*/
|
||||
nsresult WaitData(nsFtpControlConnectionListener *listener);
|
||||
void SetStreamListener(nsIStreamListener *l) { mListener = l; }
|
||||
|
||||
PRUint32 mServerType; // what kind of server is it.
|
||||
nsString mPassword;
|
||||
|
@ -107,11 +83,10 @@ private:
|
|||
nsCString mHost;
|
||||
PRUint32 mPort;
|
||||
|
||||
nsCOMPtr<nsISocketTransport> mSocket;
|
||||
nsCOMPtr<nsIOutputStream> mSocketOutput;
|
||||
nsCOMPtr<nsIAsyncInputStream> mSocketInput;
|
||||
|
||||
nsRefPtr<nsFtpControlConnectionListener> mListener;
|
||||
nsCOMPtr<nsIRequest> mReadRequest;
|
||||
nsCOMPtr<nsISocketTransport> mCPipe;
|
||||
nsCOMPtr<nsIOutputStream> mOutStream;
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
//
|
||||
// To enable logging (see prlog.h for full details):
|
||||
//
|
||||
// set NSPR_LOG_MODULES=nsFtp:5
|
||||
// set NSPR_LOG_MODULES=nsFTPProtocol:5
|
||||
// set NSPR_LOG_FILE=nspr.log
|
||||
//
|
||||
// this enables PR_LOG_DEBUG level information and places all output in
|
||||
|
@ -86,7 +86,7 @@ PRLogModuleInfo* gFTPLog = nsnull;
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define IDLE_TIMEOUT_PREF "network.ftp.idleConnectionTimeout"
|
||||
#define IDLE_CONNECTION_LIMIT 8 /* TODO pref me */
|
||||
#define IDLE_CONNECTION_LIMIT 8 /* XXX pref me */
|
||||
|
||||
static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
|
||||
static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
|
||||
|
@ -99,17 +99,16 @@ nsFtpProtocolHandler::nsFtpProtocolHandler()
|
|||
: mIdleTimeout(-1)
|
||||
{
|
||||
#if defined(PR_LOGGING)
|
||||
if (!gFTPLog)
|
||||
gFTPLog = PR_NewLogModule("nsFtp");
|
||||
if (!gFTPLog) gFTPLog = PR_NewLogModule("nsFTPProtocol");
|
||||
#endif
|
||||
LOG(("FTP:creating handler @%x\n", this));
|
||||
LOG(("Creating nsFtpProtocolHandler @%x\n", this));
|
||||
|
||||
gFtpHandler = this;
|
||||
}
|
||||
|
||||
nsFtpProtocolHandler::~nsFtpProtocolHandler()
|
||||
{
|
||||
LOG(("FTP:destroying handler @%x\n", this));
|
||||
LOG(("Destroying nsFtpProtocolHandler @%x\n", this));
|
||||
|
||||
NS_ASSERTION(mRootConnectionList.Count() == 0, "why wasn't Observe called?");
|
||||
|
||||
|
@ -144,7 +143,7 @@ nsFtpProtocolHandler::Init()
|
|||
if (observerService)
|
||||
observerService->AddObserver(this,
|
||||
"network:offline-about-to-go-offline",
|
||||
PR_TRUE);
|
||||
PR_FALSE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -212,17 +211,27 @@ nsFtpProtocolHandler::NewChannel(nsIURI* url, nsIChannel* *result)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFtpProtocolHandler::NewProxiedChannel(nsIURI* uri, nsIProxyInfo* proxyInfo,
|
||||
nsIChannel* *result)
|
||||
nsFtpProtocolHandler::NewProxiedChannel(nsIURI* url, nsIProxyInfo* proxyInfo, nsIChannel* *result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(uri);
|
||||
nsFtpChannel *channel = new nsFtpChannel(uri, proxyInfo);
|
||||
NS_ENSURE_ARG_POINTER(url);
|
||||
nsFTPChannel *channel = new nsFTPChannel();
|
||||
if (!channel)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(channel);
|
||||
|
||||
nsresult rv = channel->Init();
|
||||
nsCOMPtr<nsICacheService> cache = do_GetService(kCacheServiceCID);
|
||||
if (cache) {
|
||||
cache->CreateSession("FTP",
|
||||
nsICache::STORE_ANYWHERE,
|
||||
nsICache::STREAM_BASED,
|
||||
getter_AddRefs(mCacheSession));
|
||||
if (mCacheSession)
|
||||
mCacheSession->SetDoomEntriesIfExpired(PR_FALSE);
|
||||
}
|
||||
|
||||
nsresult rv = channel->Init(url, proxyInfo, mCacheSession);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("nsFtpProtocolHandler::NewChannel() FAILED\n"));
|
||||
NS_RELEASE(channel);
|
||||
return rv;
|
||||
}
|
||||
|
@ -243,7 +252,7 @@ nsFtpProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retva
|
|||
void
|
||||
nsFtpProtocolHandler::Timeout(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
LOG(("FTP:timeout reached for %p\n", aClosure));
|
||||
LOG(("Timeout reached for %0x\n", aClosure));
|
||||
|
||||
PRBool found = gFtpHandler->mRootConnectionList.RemoveElement(aClosure);
|
||||
if (!found) {
|
||||
|
@ -266,7 +275,7 @@ nsFtpProtocolHandler::RemoveConnection(nsIURI *aKey, nsFtpControlConnection* *_r
|
|||
nsCAutoString spec;
|
||||
aKey->GetPrePath(spec);
|
||||
|
||||
LOG(("FTP:removing connection for %s\n", spec.get()));
|
||||
LOG(("Removing connection for %s\n", spec.get()));
|
||||
|
||||
timerStruct* ts = nsnull;
|
||||
PRInt32 i;
|
||||
|
@ -301,7 +310,7 @@ nsFtpProtocolHandler::InsertConnection(nsIURI *aKey, nsFtpControlConnection *aCo
|
|||
nsCAutoString spec;
|
||||
aKey->GetPrePath(spec);
|
||||
|
||||
LOG(("FTP:inserting connection for %s\n", spec.get()));
|
||||
LOG(("Inserting connection for %s\n", spec.get()));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
|
@ -364,7 +373,7 @@ nsFtpProtocolHandler::Observe(nsISupports *aSubject,
|
|||
const char *aTopic,
|
||||
const PRUnichar *aData)
|
||||
{
|
||||
LOG(("FTP:observing [%s]\n", aTopic));
|
||||
LOG(("nsFtpProtocolHandler::Observe [topic=%s]\n", aTopic));
|
||||
|
||||
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
||||
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(aSubject);
|
||||
|
@ -376,12 +385,14 @@ nsFtpProtocolHandler::Observe(nsISupports *aSubject,
|
|||
nsresult rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &timeout);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mIdleTimeout = timeout;
|
||||
} else if (!strcmp(aTopic, "network:offline-about-to-go-offline")) {
|
||||
}
|
||||
else if (!strcmp(aTopic, "network:offline-about-to-go-offline")) {
|
||||
PRInt32 i;
|
||||
for (i=0;i<mRootConnectionList.Count();++i)
|
||||
delete (timerStruct*)mRootConnectionList[i];
|
||||
mRootConnectionList.Clear();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
NS_NOTREACHED("unexpected topic");
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
#include "nsITXTToHTMLConv.h"
|
||||
#include "nsIPrompt.h"
|
||||
#include "nsEventQueueUtils.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -80,6 +79,8 @@ public:
|
|||
NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void *closure,
|
||||
PRUint32 count, PRUint32 *result);
|
||||
NS_IMETHOD CloseWithStatus(nsresult status);
|
||||
NS_IMETHOD AsyncWait(nsIInputStreamCallback *callback, PRUint32 flags,
|
||||
PRUint32 count, nsIEventTarget *target);
|
||||
|
||||
nsGopherContentStream(nsGopherChannel *channel)
|
||||
: nsBaseContentStream(PR_TRUE) // non-blocking
|
||||
|
@ -93,9 +94,6 @@ public:
|
|||
void UpdateContentType(char type);
|
||||
nsresult SendRequest();
|
||||
|
||||
protected:
|
||||
virtual void OnCallbackPending();
|
||||
|
||||
private:
|
||||
nsRefPtr<nsGopherChannel> mChannel;
|
||||
nsCOMPtr<nsISocketTransport> mSocket;
|
||||
|
@ -121,15 +119,14 @@ NS_IMETHODIMP
|
|||
nsGopherContentStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
|
||||
PRUint32 count, PRUint32 *result)
|
||||
{
|
||||
// Insert a thunk here so that the input stream passed to the writer is
|
||||
// this input stream instead of mSocketInput.
|
||||
if (mSocketInput) {
|
||||
nsWriteSegmentThunk thunk = { this, writer, closure };
|
||||
return mSocketInput->ReadSegments(NS_WriteSegmentThunk, &thunk, count,
|
||||
result);
|
||||
}
|
||||
// TODO: Insert a thunk here so that the input stream passed to the writer
|
||||
// is this input stream instead of mSocketInput. This thunk should be
|
||||
// some generic thunk available from nsStreamUtils.
|
||||
if (mSocketInput)
|
||||
return mSocketInput->ReadSegments(writer, closure, count, result);
|
||||
|
||||
return nsBaseContentStream::ReadSegments(writer, closure, count, result);
|
||||
// No data yet
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -144,6 +141,26 @@ nsGopherContentStream::CloseWithStatus(nsresult status)
|
|||
return nsBaseContentStream::CloseWithStatus(status);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGopherContentStream::AsyncWait(nsIInputStreamCallback *callback, PRUint32 flags,
|
||||
PRUint32 count, nsIEventTarget *target)
|
||||
{
|
||||
nsresult rv = nsBaseContentStream::AsyncWait(callback, flags, count, target);
|
||||
if (NS_FAILED(rv) && IsClosed())
|
||||
return rv;
|
||||
|
||||
// We have a callback, so failure means we should close the stream.
|
||||
if (!mSocket) {
|
||||
rv = OpenSocket(target);
|
||||
} else if (mSocketInput) {
|
||||
rv = mSocketInput->AsyncWait(this, 0, 0, target);
|
||||
}
|
||||
if (NS_FAILED(rv))
|
||||
CloseWithStatus(rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGopherContentStream::OnInputStreamReady(nsIAsyncInputStream *stream)
|
||||
{
|
||||
|
@ -166,22 +183,6 @@ nsGopherContentStream::OnOutputStreamReady(nsIAsyncOutputStream *stream)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsGopherContentStream::OnCallbackPending()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// We have a callback, so failure means we should close the stream.
|
||||
if (!mSocket) {
|
||||
rv = OpenSocket(CallbackTarget());
|
||||
} else if (mSocketInput) {
|
||||
rv = mSocketInput->AsyncWait(this, 0, 0, CallbackTarget());
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
CloseWithStatus(rv);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGopherContentStream::OpenSocket(nsIEventTarget *target)
|
||||
{
|
||||
|
|
|
@ -3646,7 +3646,7 @@ nsHttpChannel::SetUploadStream(nsIInputStream *stream, const nsACString &content
|
|||
mUploadStreamHasHeaders = PR_FALSE;
|
||||
mRequestHead.SetMethod(nsHttp::Get); // revert to GET request
|
||||
}
|
||||
mUploadStream = stream;
|
||||
mUploadStream = stream;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,12 +97,28 @@ NS_IMETHODIMP
|
|||
nsFTPDirListingConv::AsyncConvertData(const char *aFromType, const char *aToType,
|
||||
nsIStreamListener *aListener, nsISupports *aCtxt) {
|
||||
NS_ASSERTION(aListener && aFromType && aToType, "null pointer passed into FTP dir listing converter");
|
||||
nsresult rv;
|
||||
|
||||
// hook up our final listener. this guy gets the various On*() calls we want to throw
|
||||
// at him.
|
||||
mFinalListener = aListener;
|
||||
NS_ADDREF(mFinalListener);
|
||||
|
||||
// we need our own channel that represents the content-type of the
|
||||
// converted data.
|
||||
NS_ASSERTION(aCtxt, "FTP dir listing needs a context (the uri)");
|
||||
nsIURI *uri;
|
||||
rv = aCtxt->QueryInterface(NS_GET_IID(nsIURI), (void**)&uri);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// XXX this seems really wrong!!
|
||||
rv = NS_NewInputStreamChannel(&mPartChannel,
|
||||
uri,
|
||||
nsnull,
|
||||
NS_LITERAL_CSTRING(APPLICATION_HTTP_INDEX_FORMAT));
|
||||
NS_RELEASE(uri);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PR_LOG(gFTPDirListConvLog, PR_LOG_DEBUG,
|
||||
("nsFTPDirListingConv::AsyncConvertData() converting FROM raw, TO application/http-index-format\n"));
|
||||
|
||||
|
@ -196,7 +212,7 @@ nsFTPDirListingConv::OnDataAvailable(nsIRequest* request, nsISupports *ctxt,
|
|||
rv = NS_NewCStringInputStream(getter_AddRefs(inputData), indexFormat);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mFinalListener->OnDataAvailable(request, ctxt, inputData, 0, indexFormat.Length());
|
||||
rv = mFinalListener->OnDataAvailable(mPartChannel, ctxt, inputData, 0, indexFormat.Length());
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -207,7 +223,7 @@ NS_IMETHODIMP
|
|||
nsFTPDirListingConv::OnStartRequest(nsIRequest* request, nsISupports *ctxt) {
|
||||
// we don't care about start. move along... but start masqeurading
|
||||
// as the http-index channel now.
|
||||
return mFinalListener->OnStartRequest(request, ctxt);
|
||||
return mFinalListener->OnStartRequest(mPartChannel, ctxt);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -215,18 +231,33 @@ nsFTPDirListingConv::OnStopRequest(nsIRequest* request, nsISupports *ctxt,
|
|||
nsresult aStatus) {
|
||||
// we don't care about stop. move along...
|
||||
|
||||
return mFinalListener->OnStopRequest(request, ctxt, aStatus);
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadgroup;
|
||||
rv = channel->GetLoadGroup(getter_AddRefs(loadgroup));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (loadgroup)
|
||||
(void)loadgroup->RemoveRequest(mPartChannel, nsnull, aStatus);
|
||||
|
||||
return mFinalListener->OnStopRequest(mPartChannel, ctxt, aStatus);
|
||||
}
|
||||
|
||||
|
||||
// nsFTPDirListingConv methods
|
||||
nsFTPDirListingConv::nsFTPDirListingConv() {
|
||||
mFinalListener = nsnull;
|
||||
mPartChannel = nsnull;
|
||||
mSentHeading = PR_FALSE;
|
||||
}
|
||||
|
||||
nsFTPDirListingConv::~nsFTPDirListingConv() {
|
||||
NS_IF_RELEASE(mFinalListener);
|
||||
NS_IF_RELEASE(mPartChannel);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -81,6 +81,8 @@ private:
|
|||
PRBool mSentHeading; // have we sent 100, 101, 200, and 300 lines yet?
|
||||
|
||||
nsIStreamListener *mFinalListener; // this guy gets the converted data via his OnDataAvailable()
|
||||
nsIChannel *mPartChannel; // the channel for the given part we're processing.
|
||||
// one channel per part.
|
||||
};
|
||||
|
||||
#endif /* __nsftpdirlistingdconv__h__ */
|
||||
|
|
|
@ -129,7 +129,6 @@ void XXXNeverCalled()
|
|||
NS_CopySegmentToStream(nsnull, nsnull, nsnull, 0, 0, nsnull);
|
||||
NS_CopySegmentToBuffer(nsnull, nsnull, nsnull, 0, 0, nsnull);
|
||||
NS_DiscardSegment(nsnull, nsnull, nsnull, 0, 0, nsnull);
|
||||
NS_WriteSegmentThunk(nsnull, nsnull, nsnull, 0, 0, 0);
|
||||
NS_NewByteInputStream(nsnull, nsnull, 0, NS_ASSIGNMENT_COPY);
|
||||
NS_NewCStringInputStream(nsnull, nsCString());
|
||||
NS_NewStringInputStream(nsnull, nsString());
|
||||
|
|
|
@ -91,8 +91,7 @@ interface nsIAsyncInputStream : nsIInputStream
|
|||
* event will be dispatched when the stream becomes readable or closed.
|
||||
*
|
||||
* @param aCallback
|
||||
* This object is notified when the stream becomes ready. This
|
||||
* parameter may be null to clear an existing callback.
|
||||
* This object is notified when the stream becomes ready.
|
||||
* @param aFlags
|
||||
* This parameter specifies optional flags passed in to configure
|
||||
* the behavior of this method. Pass zero to specify no flags.
|
||||
|
|
|
@ -91,8 +91,7 @@ interface nsIAsyncOutputStream : nsIOutputStream
|
|||
* event will be dispatched when the stream becomes writable or closed.
|
||||
*
|
||||
* @param aCallback
|
||||
* This object is notified when the stream becomes ready. This
|
||||
* parameter may be null to clear an existing callback.
|
||||
* This object is notified when the stream becomes ready.
|
||||
* @param aFlags
|
||||
* This parameter specifies optional flags passed in to configure
|
||||
* the behavior of this method. Pass zero to specify no flags.
|
||||
|
|
|
@ -813,9 +813,6 @@ nsPipeInputStream::AsyncWait(nsIInputStreamCallback *callback,
|
|||
mCallback = 0;
|
||||
mCallbackFlags = 0;
|
||||
|
||||
if (!callback)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> proxy;
|
||||
if (target) {
|
||||
nsresult rv = NS_NewInputStreamReadyEvent(getter_AddRefs(proxy),
|
||||
|
@ -1187,9 +1184,6 @@ nsPipeOutputStream::AsyncWait(nsIOutputStreamCallback *callback,
|
|||
mCallback = 0;
|
||||
mCallbackFlags = 0;
|
||||
|
||||
if (!callback)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIOutputStreamCallback> proxy;
|
||||
if (target) {
|
||||
nsresult rv = NS_NewOutputStreamReadyEvent(getter_AddRefs(proxy),
|
||||
|
|
|
@ -721,18 +721,3 @@ NS_DiscardSegment(nsIInputStream *inStr,
|
|||
*countWritten = count;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_COM NS_METHOD
|
||||
NS_WriteSegmentThunk(nsIInputStream *inStr,
|
||||
void *closure,
|
||||
const char *buffer,
|
||||
PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 *countWritten)
|
||||
{
|
||||
nsWriteSegmentThunk *thunk = NS_STATIC_CAST(nsWriteSegmentThunk *, closure);
|
||||
return thunk->mFun(thunk->mStream, thunk->mClosure, buffer, offset, count,
|
||||
countWritten);
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
#define nsStreamUtils_h__
|
||||
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
class nsIInputStream;
|
||||
class nsIOutputStream;
|
||||
class nsIInputStreamCallback;
|
||||
class nsIOutputStreamCallback;
|
||||
|
@ -204,26 +204,4 @@ NS_DiscardSegment(nsIInputStream *aInputStream, void *aClosure,
|
|||
const char *aFromSegment, PRUint32 aToOffset,
|
||||
PRUint32 aCount, PRUint32 *aWriteCount);
|
||||
|
||||
/**
|
||||
* This function is intended to be passed to nsIInputStream::ReadSegments to
|
||||
* adjust the aInputStream parameter passed to a consumer's WriteSegmentFun.
|
||||
* The aClosure parameter must be a pointer to a nsWriteSegmentThunk object.
|
||||
* The mStream and mClosure members of that object will be passed to the mFun
|
||||
* function, with the remainder of the parameters being what are passed to
|
||||
* NS_WriteSegmentThunk.
|
||||
*
|
||||
* This function comes in handy when implementing ReadSegments in terms of an
|
||||
* inner stream's ReadSegments.
|
||||
*/
|
||||
extern NS_COM NS_METHOD
|
||||
NS_WriteSegmentThunk(nsIInputStream *aInputStream, void *aClosure,
|
||||
const char *aFromSegment, PRUint32 aToOffset,
|
||||
PRUint32 aCount, PRUint32 *aWriteCount);
|
||||
|
||||
struct nsWriteSegmentThunk {
|
||||
nsIInputStream *mStream;
|
||||
nsWriteSegmentFun mFun;
|
||||
void *mClosure;
|
||||
};
|
||||
|
||||
#endif // !nsStreamUtils_h__
|
||||
|
|
Загрузка…
Ссылка в новой задаче