Fixes many ftp problems. Details in 72280. r=valeski@netscape.com

This commit is contained in:
dougt%netscape.com 2001-03-21 19:04:32 +00:00
parent 08ad4c34ba
commit 6a3a4a8997
6 changed files with 388 additions and 253 deletions

View File

@ -51,6 +51,7 @@ nsFTPChannel::nsFTPChannel()
mFTPState(nsnull),
mLock(nsnull),
mStatus(NS_OK),
mCanceled(PR_FALSE),
mProxyPort(-1),
mProxyTransparent(PR_FALSE)
{
@ -157,8 +158,20 @@ nsFTPChannel::GetStatus(nsresult *status)
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");
nsAutoLock lock(mLock);
if (mCanceled)
return NS_OK;
mCanceled = PR_TRUE;
mStatus = status;
if (mProxyChannel) {
return mProxyChannel->Cancel(status);
@ -170,6 +183,10 @@ nsFTPChannel::Cancel(nsresult status) {
NS_IMETHODIMP
nsFTPChannel::Suspend(void) {
PR_LOG(gFTPLog, PR_LOG_DEBUG,
("nsFTPChannel::Suspend() called [this=%x]\n", this));
nsAutoLock lock(mLock);
if (mProxyChannel) {
return mProxyChannel->Suspend();
@ -181,6 +198,10 @@ nsFTPChannel::Suspend(void) {
NS_IMETHODIMP
nsFTPChannel::Resume(void) {
PR_LOG(gFTPLog, PR_LOG_DEBUG,
("nsFTPChannel::Resume() called [this=%x]\n", this));
nsAutoLock lock(mLock);
if (mProxyChannel) {
return mProxyChannel->Resume();
@ -242,14 +263,7 @@ nsFTPChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
mListener = listener;
mUserContext = ctxt;
if (mEventSink) {
nsCOMPtr<nsIIOService> serv = do_GetService(kIOServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = mEventSink->OnStatus(this, ctxt, NS_NET_STATUS_BEGIN_FTP_TRANSACTION, nsnull);
if (NS_FAILED(rv)) return rv;
}
// Add this request to the load group
if (mLoadGroup) {
rv = mLoadGroup->AddRequest(this, nsnull);
if (NS_FAILED(rv)) return rv;
@ -269,10 +283,9 @@ nsFTPChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
rv = mFTPState->Init(this, mPrompter);
if (NS_FAILED(rv)) return rv;
rv = mFTPState->SetStreamListener(this, ctxt);
if (NS_FAILED(rv)) return rv;
return mFTPState->Connect();
rv = mFTPState->Connect();
return rv;
}
NS_IMETHODIMP
@ -379,8 +392,7 @@ nsFTPChannel::SetOwner(nsISupports* aOwner)
NS_IMETHODIMP
nsFTPChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
{
*aNotificationCallbacks = mCallbacks.get();
NS_IF_ADDREF(*aNotificationCallbacks);
NS_IF_ADDREF(*aNotificationCallbacks = mCallbacks);
return NS_OK;
}
@ -389,13 +401,15 @@ nsFTPChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallb
{
mCallbacks = aNotificationCallbacks;
// FIX these should be proxies!
if (mCallbacks) {
(void)mCallbacks->GetInterface(NS_GET_IID(nsIProgressEventSink),
getter_AddRefs(mEventSink));
(void)mCallbacks->GetInterface(NS_GET_IID(nsIPrompt),
getter_AddRefs(mPrompter));
NS_ASSERTION ( mPrompter, "Channel doesn't have a prompt!!!" );
}
return NS_OK;
}
@ -425,17 +439,26 @@ NS_IMETHODIMP
nsFTPChannel::OnStatus(nsIRequest *request, nsISupports *aContext,
nsresult aStatus, const PRUnichar* aStatusArg)
{
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.
NS_ASSERTION(mFTPState, "ftp state is null.");
(void) mFTPState->DataConnectionEstablished();
}
if (!mEventSink)
return NS_OK;
return mEventSink->OnStatus(this, aContext, aStatus,
return mEventSink->OnStatus(this, mUserContext, aStatus,
NS_ConvertASCIItoUCS2(mHost).get());
}
NS_IMETHODIMP
nsFTPChannel::OnProgress(nsIRequest *request, nsISupports* aContext,
PRUint32 aProgress, PRUint32 aProgressMax) {
return mEventSink ? mEventSink->OnProgress(this, aContext, aProgress, (PRUint32) mContentLength) : NS_OK;
return mEventSink ? mEventSink->OnProgress(this, mUserContext, aProgress, (PRUint32) mContentLength) : NS_OK;
}
@ -444,15 +467,15 @@ NS_IMETHODIMP
nsFTPChannel::OnStopRequest(nsIRequest *request, nsISupports* aContext,
nsresult aStatus, const PRUnichar* aStatusArg)
{
PR_LOG(gFTPLog,
PR_LOG_DEBUG,
("nsFTPChannel::OnStopRequest() called [this=%x, request=%x, aStatus=%x]\n",
this, request, aStatus));
nsresult rv = NS_OK;
if (mLoadGroup) {
rv = mLoadGroup->RemoveRequest(this, nsnull, aStatus, aStatusArg);
if (NS_FAILED(rv)) return rv;
}
if (mObserver) {
rv = mObserver->OnStopRequest(this, aContext, aStatus, aStatusArg);
rv = mObserver->OnStopRequest(this, mUserContext, aStatus, aStatusArg);
if (NS_FAILED(rv)) return rv;
}
@ -460,19 +483,29 @@ nsFTPChannel::OnStopRequest(nsIRequest *request, nsISupports* aContext,
rv = mListener->OnStopRequest(this, aContext, aStatus, aStatusArg);
if (NS_FAILED(rv)) return rv;
}
if (mLoadGroup) {
rv = mLoadGroup->RemoveRequest(this, nsnull, aStatus, aStatusArg);
if (NS_FAILED(rv)) return rv;
}
return rv;
}
NS_IMETHODIMP
nsFTPChannel::OnStartRequest(nsIRequest *request, nsISupports *aContext) {
nsFTPChannel::OnStartRequest(nsIRequest *request, nsISupports *aContext)
{
PR_LOG(gFTPLog,
PR_LOG_DEBUG,
("nsFTPChannel::OnStartRequest() called [this=%x, request=%x]\n",
this, request));
nsresult rv = NS_OK;
if (mObserver) {
rv = mObserver->OnStartRequest(this, aContext);
rv = mObserver->OnStartRequest(this, mUserContext);
if (NS_FAILED(rv)) return rv;
}
if (mListener) {
rv = mListener->OnStartRequest(this, aContext);
rv = mListener->OnStartRequest(this, mUserContext);
if (NS_FAILED(rv)) return rv;
}
return rv;
@ -484,7 +517,7 @@ NS_IMETHODIMP
nsFTPChannel::OnDataAvailable(nsIRequest *request, nsISupports* aContext,
nsIInputStream *aInputStream, PRUint32 aSourceOffset,
PRUint32 aLength) {
return mListener->OnDataAvailable(this, aContext, aInputStream, aSourceOffset, aLength);
return mListener->OnDataAvailable(this, mUserContext, aInputStream, aSourceOffset, aLength);
}
// nsIFTPChannel methods

View File

@ -84,7 +84,7 @@ public:
nsresult Init(nsIURI* uri);
nsresult SetProxyChannel(nsIChannel *aChannel);
protected:
nsCOMPtr<nsIURI> mOriginalURI;
nsCOMPtr<nsIURI> mURL;
@ -111,7 +111,8 @@ protected:
PRLock* mLock;
nsCOMPtr<nsISupports> mUserContext;
nsresult mStatus;
PRPackedBool mCanceled;
nsCOMPtr<nsIChannel> mProxyChannel; // a proxy channel
nsCAutoString mProxyHost;
PRInt32 mProxyPort;

View File

@ -59,14 +59,12 @@ extern PRLogModuleInfo* gFTPLog;
#endif /* PR_LOGGING */
class DataRequestForwarder : public nsIChannel, public nsIStreamListener
{
public:
DataRequestForwarder();
virtual ~DataRequestForwarder();
nsresult Init(nsIRequest *request, nsIStreamListener *listener);
nsresult Init(nsIRequest *request, nsIStreamListener *listener = nsnull);
#ifdef DOUGT_NEW_CACHE
nsresult SetCacheEntryDescriptor(nsICacheEntryDescriptor *desc);
@ -89,9 +87,16 @@ protected:
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsIStreamListener> mListener;
nsresult DelayedOnStartRequest(nsIRequest *request, nsISupports *ctxt);
PRBool mDelayedOnStartFired;
};
// The whole purpose of this class is to opaque
// the socket transport so that clients only see
// the same nsIChannel/nsIRequest that they started.
NS_IMPL_THREADSAFE_ISUPPORTS4(DataRequestForwarder,
nsIStreamListener,
nsIStreamObserver,
@ -101,6 +106,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS4(DataRequestForwarder,
DataRequestForwarder::DataRequestForwarder()
{
mDelayedOnStartFired = PR_FALSE;
NS_INIT_ISUPPORTS();
}
@ -122,7 +128,11 @@ DataRequestForwarder::Init(nsIRequest *request, nsIStreamListener *listener)
{
mRequest = request;
mChannel = do_QueryInterface(request);
mListener = listener;
if (listener == nsnull)
mListener = do_QueryInterface(request);
else
mListener = listener;
if (!mRequest || !mChannel || !mListener)
return NS_ERROR_FAILURE;
@ -131,8 +141,8 @@ DataRequestForwarder::Init(nsIRequest *request, nsIStreamListener *listener)
}
NS_IMETHODIMP
DataRequestForwarder::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
nsresult
DataRequestForwarder::DelayedOnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
#ifdef DOUGT_NEW_CACHE
@ -144,7 +154,7 @@ DataRequestForwarder::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
NS_ASSERTION(0, "Could not create cache transport.");
return rv;
}
rv = transport->OpenOutputStream(0, (PRUint32) -1, 0, getter_AddRefs(mCacheOutputStream));
rv = transport->OpenOutputStream(0, (PRUint32) ULONG_MAX, 0, getter_AddRefs(mCacheOutputStream));
if (NS_FAILED(rv)) {
NS_ASSERTION(0, "Could not create cache output stream.");
@ -156,9 +166,14 @@ DataRequestForwarder::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
}
NS_IMETHODIMP
DataRequestForwarder::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
return NS_OK;
}
NS_IMETHODIMP
DataRequestForwarder::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult statusCode, const PRUnichar *statusText)
{
#ifdef DOUGT_NEW_CACHE
if (mCacheWriteDescriptor) {
nsresult rv;
@ -177,12 +192,24 @@ DataRequestForwarder::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsre
}
}
#endif
return mListener->OnStopRequest(this, ctxt, statusCode, statusText);
return mListener->OnStopRequest(this, ctxt, statusCode, statusText);
}
NS_IMETHODIMP
DataRequestForwarder::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, nsIInputStream *input, PRUint32 offset, PRUint32 count)
{
nsresult rv;
// we want to delay firing the onStartRequest until we know that there is data
if (!mDelayedOnStartFired) {
rv = DelayedOnStartRequest(request, ctxt);
if (NS_FAILED(rv)) {
NS_ASSERTION(0, "Firing Ftp OnStart failed.");
return rv;
}
mDelayedOnStartFired = PR_TRUE;
}
#ifdef DOUGT_NEW_CACHE
if (mCacheWriteDescriptor) {
@ -199,8 +226,6 @@ DataRequestForwarder::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, ns
}
NS_IMPL_THREADSAFE_ISUPPORTS3(nsFtpState,
nsIStreamListener,
nsIStreamObserver,
@ -214,8 +239,8 @@ nsFtpState::nsFtpState() {
#ifdef DOUGT_NEW_CACHE
mReadingFromCache = PR_FALSE;
#endif
mCanceled = mList = mRetryPass = PR_FALSE;
mFireCallbacks = mBin = mKeepRunning = mAnonymous = PR_TRUE;
mTryingCachedControl = mList = mRetryPass = PR_FALSE;
mFireCallbacks = mKeepRunning = mAnonymous = PR_TRUE;
mAction = GET;
mState = FTP_COMMAND_CONNECT;
@ -228,6 +253,7 @@ nsFtpState::nsFtpState() {
mLastModified = LL_ZERO;
mWriteCount = 0;
mControlStatus = NS_OK;
mControlReadContinue = PR_FALSE;
mControlReadBrokenLine = PR_FALSE;
@ -388,11 +414,19 @@ NS_IMETHODIMP
nsFtpState::OnStopRequest(nsIRequest *request, nsISupports *aContext,
nsresult aStatus, const PRUnichar* aStatusArg)
{
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) nsFtpState::OnStopRequest() rv=%d\n", this, aStatus));
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) nsFtpState::OnStopRequest() rv=%x\n", this, aStatus));
mControlStatus = aStatus;
if (NS_FAILED(aStatus) || NS_FAILED(mInternalError)) {
StopProcessing();
}
// HACK. This may not always work. I am assuming that I can mask the OnStopRequest
// notification since I created it via the control connection.
if (mTryingCachedControl && NS_FAILED(aStatus) && NS_SUCCEEDED(mInternalError)) {
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) nsFtpState::OnStopRequest() cache connect failed. Reconnecting...\n", this, aStatus));
mTryingCachedControl = PR_FALSE;
Connect();
return NS_OK;
}
StopProcessing();
return NS_OK;
}
@ -400,31 +434,41 @@ nsresult
nsFtpState::EstablishControlConnection()
{
nsresult rv;
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) trying cached control\n", this));
nsISupports* connection;
(void) nsFtpProtocolHandler::RemoveConnection(mURL, &connection);
if (connection) {
mControlConnection = NS_STATIC_CAST(nsFtpControlConnection*, connection);
// set stream listener of the control connection to be us.
(void) mControlConnection->SetStreamListener(NS_STATIC_CAST(nsIStreamListener*, this));
// read cached variables into us.
mServerType = mControlConnection->mServerType;
mCwd = mControlConnection->mCwd;
mList = mControlConnection->mList;
mPassword = mControlConnection->mPassword;
// we're already connected to this server, skip login.
mState = FTP_S_PASV;
mResponseCode = 530; //assume the control connection was dropped.
// if we succeed, return. Otherwise, we need to
// create a transport
return NS_OK;
mControlConnection = NS_STATIC_CAST(nsFtpControlConnection*, (nsIStreamListener*)connection);
if (mControlConnection->IsAlive())
{
// set stream listener of the control connection to be us.
(void) mControlConnection->SetStreamListener(NS_STATIC_CAST(nsIStreamListener*, this));
// read cached variables into us.
mServerType = mControlConnection->mServerType;
mCwd = mControlConnection->mCwd;
mList = mControlConnection->mList;
mPassword = mControlConnection->mPassword;
mTryingCachedControl = PR_TRUE;
// we're already connected to this server, skip login.
mState = FTP_S_PASV;
mResponseCode = 530; //assume the control connection was dropped.
mControlStatus = NS_OK;
// if we succeed, return. Otherwise, we need to
// create a transport
return NS_OK;
}
#if defined(PR_LOGGING)
else
{
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) isAlive return false\n", this));
}
#endif
}
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) creating control\n", this));
@ -443,13 +487,16 @@ nsFtpState::EstablishControlConnection()
if (NS_FAILED(rv)) return rv;
mState = FTP_READ_BUF;
mNextState = FTP_S_USER;
mControlConnection = new nsFtpControlConnection(transport);
if (!mControlConnection) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mControlConnection);
mControlConnection->SetStreamListener(NS_STATIC_CAST(nsIStreamListener*, this));
// Must do it this way 'cuz the channel intercepts the progress notifications.
(void) mControlConnection->SetStreamListener(NS_STATIC_CAST(nsIStreamListener*, this));
return mControlConnection->Connect();
}
@ -459,9 +506,6 @@ nsFtpState::Process() {
nsresult rv = NS_OK;
PRBool processingRead = PR_TRUE;
if (mCanceled)
mState = FTP_COMPLETE;
while (mKeepRunning && processingRead) {
switch(mState) {
@ -484,7 +528,7 @@ nsFtpState::Process() {
break;
case FTP_READ_BUF:
{
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) Waiting for control data (%d)...", this, rv));
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) Waiting for control data (%x)...", this, rv));
processingRead = PR_FALSE;
break;
}
@ -492,7 +536,7 @@ nsFtpState::Process() {
case FTP_ERROR: // xx needs more work to handle dropped control connection cases
{
if (mResponseCode == 530 &&
if (mTryingCachedControl && mResponseCode == 530 &&
mInternalError == NS_ERROR_FTP_PASV) {
// The user was logged out during an pasv operation
// we want to restart this request with a new control
@ -783,9 +827,10 @@ nsFtpState::Process() {
case FTP_R_LIST:
{
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) R_LIST - ", this));
mState = R_list();
if (FTP_ERROR == mState) {
mInternalError = rv;
mInternalError = NS_ERROR_FAILURE;
mNextState = FTP_ERROR;
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) FAILED\n", this));
} else {
@ -859,7 +904,12 @@ nsFtpState::Process() {
//////////////////////////////
//// DATA CONNECTION STATES
//////////////////////////////
case FTP_S_PASV:
case FTP_WAIT_FOR_DCON:
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) Waiting for data connection...", this));
processingRead = PR_FALSE;
break;
case FTP_S_PASV:
{
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) S_PASV - ", this));
rv = S_pasv();
@ -978,22 +1028,6 @@ nsFtpState::Process() {
return rv;
}
nsresult
nsFtpState::SetStreamObserver(nsIStreamObserver* aObserver, nsISupports *aContext) {
nsresult rv = NS_OK;
NS_ASSERTION(aObserver, "null observer");
mObserver = aObserver;
mObserverContext = aContext;
return rv;
}
nsresult
nsFtpState::SetStreamListener(nsIStreamListener* aListener, nsISupports *aContext) {
mListener = aListener;
mListenerContext = aContext;
return NS_OK;
}
///////////////////////////////////
// STATE METHODS
///////////////////////////////////
@ -1033,7 +1067,7 @@ nsFtpState::S_user() {
}
usernameStr.Append(CRLF);
return ControlAsyncWrite(usernameStr);
return SendFTPCommand(usernameStr);
}
FTP_STATE
@ -1071,7 +1105,18 @@ nsFtpState::S_pass() {
mResponseMsg = "";
if (mAnonymous) {
passwordStr.Append("mozilla@");
char* anonPassword;
NS_WITH_SERVICE(nsIPref, pPref, kPrefCID, &rv);
if (NS_SUCCEEDED(rv) || pPref)
rv = pPref->CopyCharPref("network.ftp.anonymous_password", &anonPassword);
if (NS_SUCCEEDED(rv) && anonPassword && *anonPassword != '\0') {
passwordStr.Append(anonPassword);
nsMemory::Free(anonPassword);
}
else {
// default to
passwordStr.Append("mozilla@");
}
} else {
if (!mPassword.Length() || mRetryPass) {
if (!mPrompter) return NS_ERROR_NOT_INITIALIZED;
@ -1108,7 +1153,7 @@ nsFtpState::S_pass() {
}
passwordStr.Append(CRLF);
return ControlAsyncWrite(passwordStr);
return SendFTPCommand(passwordStr);
}
FTP_STATE
@ -1126,14 +1171,6 @@ nsFtpState::R_pass() {
return FTP_S_USER;
} else if (mResponseCode == 530) {
// user limit reached
if (!mPrompter) return FTP_ERROR;
nsresult rv;
nsAutoString title;
title.AssignWithConversion("Error"); // localization
nsAutoString text;
text.AssignWithConversion(mResponseMsg);
rv = mPrompter->Alert(title.GetUnicode(), text.GetUnicode());
return FTP_ERROR;
} else {
// kick back out to S_pass() and ask the user again.
@ -1157,7 +1194,7 @@ nsFtpState::R_pass() {
nsresult
nsFtpState::S_syst() {
nsCString systString( nsLiteralCString( "SYST" CRLF) );
return ControlAsyncWrite( systString );
return SendFTPCommand( systString );
}
FTP_STATE
@ -1187,7 +1224,7 @@ nsFtpState::R_syst() {
nsresult
nsFtpState::S_acct() {
nsCString acctString( nsLiteralCString( "ACCT noaccount" CRLF) );
return ControlAsyncWrite(acctString);
return SendFTPCommand(acctString);
}
FTP_STATE
@ -1201,7 +1238,7 @@ nsFtpState::R_acct() {
nsresult
nsFtpState::S_pwd() {
nsCString pwdString( nsLiteralCString("PWD" CRLF) );
return ControlAsyncWrite(pwdString);
return SendFTPCommand(pwdString);
}
@ -1248,14 +1285,26 @@ nsresult
nsFtpState::S_mode() {
char * string;
if ( mBin )
// we're connected figure out what type of transfer we're doing (ascii or binary)
nsXPIDLCString type;
nsresult rv = mChannel->GetContentType(getter_Copies(type));
nsCAutoString typeStr;
if (NS_FAILED(rv) || !type)
typeStr = "bin";
else
typeStr.Assign(type);
PRInt32 textType = typeStr.Find("text");
if ( textType != 0 )
string = "TYPE I" CRLF;
else
string = "TYPE A" CRLF;
nsCString type(string);
nsCString typeString(string);
return ControlAsyncWrite(type);
return SendFTPCommand(typeString);
}
FTP_STATE
@ -1279,7 +1328,7 @@ nsFtpState::S_cwd() {
cwdStr.Mid(mCwdAttempt, 4, cwdStr.Length() - 6);
return ControlAsyncWrite(cwdStr);
return SendFTPCommand(cwdStr);
}
FTP_STATE
@ -1319,7 +1368,7 @@ nsFtpState::S_size() {
sizeBuf.Append(mPath);
sizeBuf.Append(CRLF);
return ControlAsyncWrite(sizeBuf);
return SendFTPCommand(sizeBuf);
}
FTP_STATE
@ -1339,7 +1388,7 @@ nsFtpState::S_mdtm() {
mdtmStr.Append(mPath);
mdtmStr.Append(CRLF);
return ControlAsyncWrite(mdtmStr);
return SendFTPCommand(mdtmStr);
}
FTP_STATE
@ -1394,7 +1443,7 @@ nsFtpState::S_list() {
nsCString listString(string);
rv = ControlAsyncWrite(listString);
rv = SendFTPCommand(listString, PR_TRUE);
if (NS_FAILED(rv)) return rv;
#ifdef DOUGT_NEW_CACHE
@ -1405,6 +1454,7 @@ nsFtpState::S_list() {
// unconverted data of fromType, and the final listener in the chain (in this case
// the mListener).
nsCOMPtr<nsIStreamListener> converterListener;
nsCOMPtr<nsIStreamListener> listener = do_QueryInterface(mChannel);
NS_WITH_SERVICE(nsIStreamConverterService, streamConvService, kStreamConverterServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
@ -1427,7 +1477,7 @@ nsFtpState::S_list() {
if (mGenerateHTMLContent) {
rv = streamConvService->AsyncConvertData(fromStr.GetUnicode(), NS_LITERAL_STRING("text/html").get(),
mListener, mURL, getter_AddRefs(converterListener));
listener, mURL, getter_AddRefs(converterListener));
if (NS_FAILED(rv)){
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) streamConvService->AsyncConvertData failed (rv=%d)\n", this, rv));
@ -1436,16 +1486,24 @@ nsFtpState::S_list() {
} else {
rv = streamConvService->AsyncConvertData(fromStr.GetUnicode(),
NS_LITERAL_STRING("application/http-index-format").get(),
mListener, mURL, getter_AddRefs(converterListener));
listener, mURL, getter_AddRefs(converterListener));
}
mFireCallbacks = PR_FALSE; // listener callbacks will be handled by the transport.
if (NS_FAILED(rv)){
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) streamConvService->AsyncConvertData failed (rv=%x)\n", this, rv));
return rv;
}
DataRequestForwarder *forwarder = new DataRequestForwarder;
if (!forwarder) return NS_ERROR_FAILURE;
NS_ADDREF(forwarder);
forwarder->Init(mChannel, converterListener);
rv = forwarder->Init(mChannel, converterListener);
if (NS_FAILED(rv)){
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) forwarder->Init failed (rv=%x)\n", this, rv));
return rv;
}
#ifdef DOUGT_NEW_CACHE
if (mCacheEntry && mReadingFromCache)
@ -1461,16 +1519,13 @@ nsFtpState::S_list() {
NS_ASSERTION(0, "Could not create cache transport.");
return rv;
}
rv = transport->AsyncRead(forwarder, mListenerContext, 0, -1, 0, getter_AddRefs(mDPipeRequest));
NS_RELEASE(forwarder); // let the transport worry about this objects lifespan
rv = transport->AsyncRead(forwarder, nsnull, 0, ULONG_MAX, 0, getter_AddRefs(mDPipeRequest));
return rv;
}
(void) forwarder->SetCacheEntryDescriptor(mCacheEntry);
#endif
rv = mDPipe->AsyncRead(forwarder, mListenerContext, 0, -1, 0, getter_AddRefs(mDPipeRequest));
rv = mDPipe->AsyncRead(forwarder, nsnull, 0, ULONG_MAX, 0, getter_AddRefs(mDPipeRequest));
NS_RELEASE(forwarder); // let the transport worry about this objects lifespan
return rv;
}
@ -1491,19 +1546,21 @@ nsFtpState::S_retr() {
retrStr.Append(mPath);
retrStr.Append(CRLF);
rv = ControlAsyncWrite(retrStr);
rv = SendFTPCommand(retrStr, PR_TRUE);
if (NS_FAILED(rv)) return rv;
mFireCallbacks = PR_FALSE; // listener callbacks will be handled by the transport.
DataRequestForwarder *forwarder = new DataRequestForwarder;
if (!forwarder) return NS_ERROR_FAILURE;
NS_ADDREF(forwarder);
forwarder->Init(mChannel, mListener);
rv = mDPipe->AsyncRead(forwarder, mListenerContext, 0, -1, 0, getter_AddRefs(mDPipeRequest));
rv = forwarder->Init(mChannel);
if (NS_FAILED(rv)){
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) forwarder->Init failed (rv=%x)\n", this, rv));
return rv;
}
rv = mDPipe->AsyncRead(forwarder, nsnull, 0, ULONG_MAX, 0, getter_AddRefs(mDPipeRequest));
NS_RELEASE(forwarder); // let the transport worry about this objects lifespan
return rv;
}
@ -1541,17 +1598,18 @@ nsFtpState::S_stor() {
retrStr.Append(mPath);
retrStr.Append(CRLF);
rv = ControlAsyncWrite(retrStr);
rv = SendFTPCommand(retrStr, PR_TRUE);
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(mWriteStream, "we're trying to upload without any data");
if (NS_FAILED(rv)) return rv;
mFireCallbacks = PR_FALSE; // observer callbacks will be handled by the transport.
nsCOMPtr<nsIStreamObserver> observer = do_QueryInterface(mChannel, &rv);
if (NS_FAILED(rv)) return rv;
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) writing on Data Transport\n", this));
return NS_AsyncWriteFromStream(getter_AddRefs(mDPipeRequest), mDPipe, mWriteStream,
0, mWriteCount, 0, mObserver, mObserverContext);
0, mWriteCount, 0, observer, nsnull);
}
FTP_STATE
@ -1599,7 +1657,7 @@ nsFtpState::S_pasv() {
string = "PASV" CRLF;
nsCString pasvString(string);
return ControlAsyncWrite(pasvString);
return SendFTPCommand(pasvString);
}
@ -1690,7 +1748,7 @@ nsFtpState::R_pasv() {
getter_AddRefs(mDPipe)); // the data channel
if (NS_FAILED(rv)) return FTP_ERROR;
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) Created Data Transport (%s:%d)\n", this, hostStr, port));
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) Created Data Transport (%s:%x)\n", this, hostStr, port));
nsCOMPtr<nsISocketTransport> sTrans = do_QueryInterface(mDPipe, &rv);
if (NS_FAILED(rv)) return FTP_ERROR;
@ -1698,27 +1756,9 @@ nsFtpState::R_pasv() {
if (NS_FAILED(sTrans->SetReuseConnection(PR_FALSE))) return FTP_ERROR;
// hook ourself up as a proxy for progress notifications
nsCOMPtr<nsIInterfaceRequestor> callbacks;
mChannel->GetNotificationCallbacks(getter_AddRefs(callbacks));
nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(mChannel);
mDPipe->SetNotificationCallbacks(callbacks, PR_FALSE);
// we're connected figure out what type of transfer we're doing (ascii or binary)
nsXPIDLCString type;
rv = mChannel->GetContentType(getter_Copies(type));
nsCAutoString typeStr;
if (NS_FAILED(rv) || !type)
typeStr = "bin";
else
typeStr.Assign(type);
PRInt32 textType = typeStr.Find("text");
if (textType == 0)
// only send ascii for text type files
mBin = PR_FALSE;
else
// all others are bin
mBin = PR_TRUE;
return FTP_S_MODE;
}
@ -1728,7 +1768,7 @@ nsFtpState::S_del_file() {
delStr.Append(mPath);
delStr.Append(CRLF);
return ControlAsyncWrite(delStr);
return SendFTPCommand(delStr, PR_TRUE);
}
FTP_STATE
@ -1744,7 +1784,7 @@ nsFtpState::S_del_dir() {
delDirStr.Append(mPath);
delDirStr.Append(CRLF);
return ControlAsyncWrite(delDirStr);
return SendFTPCommand(delDirStr, PR_TRUE);
}
FTP_STATE
@ -1760,7 +1800,7 @@ nsFtpState::S_mkdir() {
mkdirStr.Append(mPath);
mkdirStr.Append(CRLF);
return ControlAsyncWrite(mkdirStr);
return SendFTPCommand(mkdirStr, PR_TRUE);
}
FTP_STATE
@ -1818,26 +1858,19 @@ NS_IMETHODIMP
nsFtpState::Cancel(nsresult status)
{
NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) nsFtpState::Cancel() rv=%d\n", this, status));
// We want to try to save the control connection during
// a cancel. We do not cancel the control socket, but just set
// a flag. When Process() is called (through OnData() or
// onStopRequest()), we will check this flag and set the
// mState accordingly. We can't set mState directly because
// cancel may be called out-of-band and I do not want to enter
// a critical section when manipulating mState.
mCanceled = PR_TRUE;
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) nsFtpState::Cancel() rv=%x\n", this, status));
// kill the data connection immediately.
if (mDPipeRequest) {
mDPipeRequest->Cancel(status);
mDPipeRequest = 0;
}
#ifdef DOUGT_NEW_CACHE
if (mCacheEntry)
mCacheEntry->Doom();
#endif
(void) StopProcessing();
return NS_OK;
}
@ -1904,7 +1937,6 @@ nsFtpState::Init(nsIFTPChannel* aChannel,
nsresult rv = NS_OK;
mKeepRunning = PR_TRUE;
mPrompter = aPrompter;
// parameter validation
@ -1955,13 +1987,20 @@ nsFtpState::Init(nsIFTPChannel* aChannel,
#ifdef DOUGT_NEW_CACHE
// if there is no cache, it is NOT an error.
static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
NS_WITH_SERVICE(nsICacheService, serv, kCacheServiceCID, &rv);
if (NS_SUCCEEDED(rv)) {
(void) serv->CreateSession("FTP Directory Listings",
nsICache::STORE_IN_MEMORY,
PR_TRUE,
getter_AddRefs(mCacheSession));
PRBool useCache = PR_TRUE;
NS_WITH_SERVICE(nsIPref, pPref, kPrefCID, &rv);
if (NS_SUCCEEDED(rv) || pPref)
pPref->GetBoolPref("network.ftp.useCache", &useCache);
if (useCache) {
static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
NS_WITH_SERVICE(nsICacheService, serv, kCacheServiceCID, &rv);
if (NS_SUCCEEDED(rv)) {
(void) serv->CreateSession("FTP Directory Listings",
nsICache::STORE_IN_MEMORY,
PR_TRUE,
getter_AddRefs(mCacheSession));
}
}
#endif
@ -1996,9 +2035,6 @@ nsFtpState::Connect()
PRUint32 aLoadAttributes;
mChannel->GetLoadAttributes(&aLoadAttributes);
// FIX we should be honoring the load attributes!
// aLoadAttributes & nsIChannel::FORCE_RELOAD
if (accessMode & nsICache::ACCESS_WRITE) {
// we said that we could validate, so here we do it.
mCacheEntry->MarkValid();
@ -2014,11 +2050,13 @@ nsFtpState::Connect()
#endif
mState = FTP_COMMAND_CONNECT;
mNextState = FTP_S_USER;
rv = Process();
// check for errors.
if (NS_FAILED(rv)) {
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("-- Connect() on Control Connect FAILED with rv = %d\n", rv));
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("-- Connect() on Control Connect FAILED with rv = %x\n", rv));
mInternalError = NS_ERROR_FAILURE;
mState = FTP_ERROR;
}
@ -2035,7 +2073,6 @@ nsFtpState::SetWriteStream(nsIInputStream* aInStream, PRUint32 aWriteCount) {
void
nsFtpState::KillControlConnnection() {
mCanceled = PR_FALSE;
mControlReadContinue = PR_FALSE;
mControlReadBrokenLine = PR_FALSE;
mControlReadCarryOverBuf.Truncate(0);
@ -2046,11 +2083,9 @@ nsFtpState::KillControlConnnection() {
mCPipe->Cancel(NS_BINDING_ABORTED);
#endif
// if the control goes away, the data socket goes away...
if (mDPipe) {
mDPipe->SetNotificationCallbacks(nsnull, PR_FALSE);
mDPipe = 0;
mDPipeRequest = 0;
}
mIPv6Checked = PR_FALSE;
@ -2067,11 +2102,11 @@ nsFtpState::KillControlConnnection() {
return;
// kill the reference to ourselves in the control connection.
mControlConnection->SetStreamListener(nsnull);
(void) mControlConnection->SetStreamListener(nsnull);
if (FTP_CACHE_CONTROL_CONNECTION &&
NS_SUCCEEDED(mInternalError) &&
mControlConnection->IsConnected()) {
mControlConnection->IsAlive()) {
PR_LOG(gFTPLog, PR_LOG_ALWAYS, ("(%x) nsFtpState caching control connection", this));
@ -2081,7 +2116,7 @@ nsFtpState::KillControlConnnection() {
mControlConnection->mList = mList;
mControlConnection->mPassword = mPassword;
nsresult rv = nsFtpProtocolHandler::InsertConnection(mURL,
NS_STATIC_CAST(nsISupports*, mControlConnection));
NS_STATIC_CAST(nsISupports*, (nsIStreamListener*)mControlConnection));
// Can't cache it? Kill it then.
if (NS_FAILED(rv))
mControlConnection->Disconnect();
@ -2099,53 +2134,49 @@ nsFtpState::StopProcessing() {
nsresult rv;
PR_LOG(gFTPLog, PR_LOG_ALWAYS, ("(%x) nsFtpState stopping", this));
// protect thy arse.
nsCOMPtr<nsIStreamListener> kungfoDeathGrip = NS_STATIC_CAST(nsIStreamListener*, this);
#ifdef DEBUG_dougt
printf("FTP Stopped: [response code %d] [response msg follows:]\n%s\n", mResponseCode, mResponseMsg.get());
#endif
// Lets mask the FTP error code so that a client does not have to parse it
nsresult broadcastErrorCode = NS_BINDING_ABORTED;
// did the protocol fail?
if ( NS_FAILED(mInternalError) )
{
// check to see if the control status is bad.
// web shell wont throw an alert. we better:
nsAutoString text;
text.AssignWithConversion(mResponseMsg);
NS_ASSERTION(mPrompter, "no prompter!");
if (mPrompter)
(void) mPrompter->Alert(nsnull, text.GetUnicode());
}
if ( NS_FAILED(mControlStatus) ) {
broadcastErrorCode = mControlStatus;
}
if (mFireCallbacks && mChannel) {
nsCOMPtr<nsIStreamListener> channelListener = do_QueryInterface(mChannel);
nsCOMPtr<nsIRequest> channelRequest = do_QueryInterface(mChannel);
nsCOMPtr<nsIStreamListener> asyncListener;
rv = NS_NewAsyncStreamListener(getter_AddRefs(asyncListener), channelListener, NS_UI_THREAD_EVENTQ);
if(NS_FAILED(rv)) return rv;
//(void) asyncListener->OnStartRequest(channelRequest, nsnull);
(void) asyncListener->OnStopRequest(channelRequest, nsnull, broadcastErrorCode, nsnull);
}
// Clean up the event loop
mKeepRunning = PR_FALSE;
nsCOMPtr<nsIRequest> request = do_QueryInterface(mChannel);
if (NS_FAILED(mInternalError) && mChannel && request) {
if (request)
request->Cancel(mInternalError);
}
KillControlConnnection();
//xxx do these have to be async?
if (mFireCallbacks) {
if (mObserver) {
nsCOMPtr<nsIStreamObserver> asyncObserver;
rv = NS_NewAsyncStreamObserver(getter_AddRefs(asyncObserver), mObserver, NS_UI_THREAD_EVENTQ);
if(NS_FAILED(rv)) return rv;
// we only want to fire OnStop. No OnStart has been fired, and
// we only want to propagate an error.
rv = asyncObserver->OnStopRequest(request, mObserverContext, mInternalError, nsnull);
if (NS_FAILED(rv)) return rv;
}
if (mListener) {
nsCOMPtr<nsIStreamListener> asyncListener;
rv = NS_NewAsyncStreamListener(getter_AddRefs(asyncListener), mListener, NS_UI_THREAD_EVENTQ);
if(NS_FAILED(rv)) return rv;
// we only want to fire OnStop. No OnStart has been fired, and
// we only want to propagate an error.
rv = asyncListener->OnStopRequest(request, mListenerContext, mInternalError, nsnull);
if (NS_FAILED(rv)) return rv;
}
}
// Release the Observers
mObserver = 0;
mObserverContext = 0;
mListener = 0;
mListenerContext = 0;
mWriteStream = 0;
mPrompter = 0;
@ -2196,6 +2227,23 @@ nsFtpState::SetDirMIMEType(nsString& aString) {
}
}
nsresult
nsFtpState::DataConnectionEstablished()
{
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("(%x) Data Connection established.", this));
mFireCallbacks = PR_FALSE; // observer callbacks will be handled by the transport.
#if 0
if (mControlConnection) {
nsCOMPtr<nsIRequest> writeRequest;
mControlConnection->GetWriteRequest(getter_AddRefs(writeRequest));
NS_ASSERTION(writeRequest, "null write request");
if (writeRequest)
writeRequest->Resume();
}
#endif
return NS_OK;
}
nsresult
nsFtpState::CreateTransport(const char * host, PRInt32 port, PRUint32 bufferSegmentSize, PRUint32 bufferMaxSize, nsITransport** o_pTrans)
{
@ -2243,14 +2291,14 @@ nsFtpState::CreateTransport(const char * host, PRInt32 port, PRUint32 bufferSegm
}
}
return sts->CreateTransport(host, port, nsnull, -1,
return sts->CreateTransport(host, port, nsnull, ULONG_MAX,
bufferSegmentSize,
bufferMaxSize,
o_pTrans);
}
nsresult
nsFtpState::ControlAsyncWrite(nsCString& command)
nsFtpState::SendFTPCommand(nsCString& command, PRBool waitForDataConn)
{
NS_ASSERTION(mControlConnection, "null control connection");
@ -2264,9 +2312,17 @@ nsFtpState::ControlAsyncWrite(nsCString& command)
#endif
#endif
if (mControlConnection)
if (mControlConnection) {
#if 0
if (waitForDataConn) {
nsCOMPtr<nsIRequest> writeRequest;
mControlConnection->GetWriteRequest(getter_AddRefs(writeRequest));
if (writeRequest)
writeRequest->Suspend();
}
#endif
return mControlConnection->Write(command);
}
return NS_ERROR_FAILURE;
}

View File

@ -85,7 +85,9 @@ typedef enum _FTP_STATE {
///////////////////////
//// Data channel connection setup states
FTP_S_PASV, FTP_R_PASV
FTP_WAIT_FOR_DCON,
FTP_S_PASV,
FTP_R_PASV
} FTP_STATE;
// higher level ftp actions
@ -104,17 +106,13 @@ public:
nsresult Init(nsIFTPChannel *aChannel, nsIPrompt *aPrompter);
// use this to set an observer.
nsresult SetStreamObserver(nsIStreamObserver *aObserver, nsISupports *aContext);
// use this to set a listener to receive data related On*() notifications
nsresult SetStreamListener(nsIStreamListener *aListener, nsISupports *aContext=nsnull);
// use this to provide a stream to be written to the server.
nsresult SetWriteStream(nsIInputStream* aInStream, PRUint32 aWriteCount);
nsresult Connect();
// lets the data forwarder tell us when the the data pipe has been created.
nsresult DataConnectionEstablished();
private:
///////////////////////////////////
// BEGIN: STATE METHODS
@ -154,8 +152,8 @@ private:
void KillControlConnnection();
nsresult StopProcessing();
nsresult EstablishControlConnection();
nsresult ControlAsyncWrite(nsCString& command);
nsresult SendFTPCommand(nsCString& command, PRBool waitForDataConn = PR_FALSE);
///////////////////////////////////
// Private members
@ -163,19 +161,15 @@ private:
FTP_STATE mState; // the current state
FTP_STATE mNextState; // the next state
PRPackedBool mKeepRunning; // thread event loop boolean
PRPackedBool mCanceled; // indicates channel being canceled.
PRInt32 mResponseCode; // the last command response code
nsCAutoString mResponseMsg; // the last command response text
// ****** channel/transport/stream vars
PRPackedBool mTryingCachedControl; // retrying the password
nsFtpControlConnection* mControlConnection;// cacheable control connection (owns mCPipe)
nsCOMPtr<nsITransport> mDPipe; // the data transport
nsCOMPtr<nsIRequest> mDPipeRequest;
// ****** consumer vars
nsCOMPtr<nsIStreamListener> mListener; // the consumer of our read events
nsCOMPtr<nsISupports> mListenerContext; // the context we pass through our read events
nsCOMPtr<nsIStreamObserver> mObserver; // the consumer of our open events
nsCOMPtr<nsISupports> mObserverContext; // the context we pass through our open events
nsCOMPtr<nsIFTPChannel> mChannel; // our owning FTP channel we pass through our events
// ****** connection cache vars
@ -188,7 +182,6 @@ private:
nsAutoString mUsername; // username
nsAutoString mPassword; // password
FTP_ACTION mAction; // the higher level action (GET/PUT)
PRPackedBool mBin; // transfer mode (ascii or binary)
PRPackedBool mAnonymous; // try connecting anonymous (default)
PRPackedBool mRetryPass; // retrying the password
nsresult mInternalError; // represents internal state errors
@ -207,13 +200,14 @@ private:
PRLock *mLock;
nsCOMPtr<nsIInputStream> mWriteStream; // This stream is written to the server.
PRUint32 mWriteCount; // The amount of data to write to the server.
PRPackedBool mFireCallbacks; // Fire the listener callbacks.
PRPackedBool mFireCallbacks; // Fire the listener callback.
PRBool mGenerateHTMLContent;
PRPackedBool mIPv6Checked;
nsCOMPtr<nsIPrompt> mPrompter;
char *mIPv6ServerAddress; // Server IPv6 address; null if server not IPv6
// ***** control read gvars
nsresult mControlStatus;
PRPackedBool mControlReadContinue;
PRPackedBool mControlReadBrokenLine;
nsCAutoString mControlReadCarryOverBuf;

View File

@ -26,6 +26,7 @@
#include "nsIPipe.h"
#include "nsIInputStream.h"
#include "nsIStreamProvider.h"
#include "nsISocketTransport.h"
#if defined(PR_LOGGING)
extern PRLogModuleInfo* gFTPLog;
@ -64,7 +65,7 @@ public:
if (NS_FAILED(rv)) return rv;
if (avail == 0) {
NS_STATIC_CAST(nsFtpControlConnection*, aContext)->mSuspendedWrite = 1;
NS_STATIC_CAST(nsFtpControlConnection*, (nsIStreamListener*)aContext)->mSuspendedWrite = 1;
return NS_BASE_STREAM_WOULD_BLOCK;
}
PRUint32 bytesWritten;
@ -83,9 +84,10 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(nsFtpStreamProvider,
// nsFtpControlConnection implementation ...
//
NS_IMPL_THREADSAFE_QUERY_INTERFACE2(nsFtpControlConnection,
NS_IMPL_THREADSAFE_QUERY_INTERFACE3(nsFtpControlConnection,
nsIStreamListener,
nsIStreamObserver);
nsIStreamObserver,
nsIProgressEventSink);
NS_IMPL_THREADSAFE_ADDREF(nsFtpControlConnection);
nsrefcnt nsFtpControlConnection::Release(void)
@ -128,6 +130,20 @@ nsFtpControlConnection::~nsFtpControlConnection()
PR_LOG(gFTPLog, PR_LOG_ALWAYS, ("(%x) nsFtpControlConnection destroyed", this));
}
PRBool
nsFtpControlConnection::IsAlive()
{
if (!mConnected)
return mConnected;
PRBool isAlive = PR_FALSE;
nsCOMPtr<nsISocketTransport> sTrans = do_QueryInterface(mCPipe);
if (!sTrans) return PR_FALSE;
sTrans->IsAlive(0, &isAlive);
return isAlive;
}
nsresult
nsFtpControlConnection::Connect()
{
@ -137,6 +153,13 @@ nsFtpControlConnection::Connect()
nsresult rv;
nsCOMPtr<nsIInputStream> inStream;
#ifdef DOUGT_IS_SICK
nsCOMPtr<nsISocketTransport> sTrans = do_QueryInterface(mCPipe);
if (!sTrans) return NS_ERROR_FAILURE;
rv = sTrans->SetSocketTimeout(25);
if (NS_FAILED(rv)) return rv;
#endif
rv = NS_NewPipe(getter_AddRefs(inStream),
getter_AddRefs(mOutStream),
64, // segmentSize
@ -155,7 +178,7 @@ nsFtpControlConnection::Connect()
NS_STATIC_CAST(nsIStreamProvider*, provider))->mInStream = inStream;
rv = mCPipe->AsyncWrite(provider,
NS_STATIC_CAST(nsISupports*, this),
NS_STATIC_CAST(nsISupports*, (nsIStreamListener*)this),
0, -1,
nsITransport::DONT_PROXY_STREAM_PROVIDER |
nsITransport::DONT_PROXY_STREAM_OBSERVER,
@ -220,6 +243,15 @@ nsFtpControlConnection::SetStreamListener(nsIStreamListener *aListener)
return NS_OK;
}
nsresult
nsFtpControlConnection::SetProgressEventSink(nsIProgressEventSink *eventSink)
{
nsAutoLock lock(mLock);
mEventSink = eventSink;
return NS_OK;
}
NS_IMETHODIMP
nsFtpControlConnection::OnStartRequest(nsIRequest *request, nsISupports *aContext)
{
@ -285,3 +317,17 @@ nsFtpControlConnection::OnDataAvailable(nsIRequest *request,
return myListener->OnDataAvailable(request, aContext, aInStream,
aOffset, aCount);
}
NS_IMETHODIMP
nsFtpControlConnection::OnProgress(nsIRequest *request, nsISupports *ctxt, PRUint32 aProgress, PRUint32 aProgressMax)
{
// Progress Means Nothing... At least not for the ftp control connection :-)
return NS_OK;
}
NS_IMETHODIMP nsFtpControlConnection::OnStatus(nsIRequest *request, nsISupports *ctxt, nsresult status, const PRUnichar *statusArg)
{
if (mEventSink)
mEventSink->OnStatus(request, ctxt, status, statusArg);
return NS_OK;
}

View File

@ -31,13 +31,15 @@
#include "nsString.h"
#include "nsIOutputStream.h"
#include "nsAutoLock.h"
#include "nsIProgressEventSink.h"
class nsFtpControlConnection : public nsIStreamListener
class nsFtpControlConnection : public nsIStreamListener, public nsIProgressEventSink
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSISTREAMOBSERVER
NS_DECL_NSIPROGRESSEVENTSINK
nsFtpControlConnection(nsITransport* socketTransport);
virtual ~nsFtpControlConnection();
@ -45,13 +47,15 @@ public:
nsresult Connect();
nsresult Disconnect();
nsresult Write(nsCString& command);
PRBool IsConnected() { return mConnected; }
void GetReadRequest(nsIRequest** request) { NS_ADDREF(*request=mReadRequest); }
void GetWriteRequest(nsIRequest** request) { NS_ADDREF(*request=mWriteRequest); }
void GetReadRequest(nsIRequest** request) { NS_IF_ADDREF(*request=mReadRequest); }
void GetWriteRequest(nsIRequest** request) { NS_IF_ADDREF(*request=mWriteRequest); }
PRBool IsAlive();
nsresult GetTransport(nsITransport** controlTransport);
nsresult SetStreamListener(nsIStreamListener *aListener);
nsresult SetProgressEventSink(nsIProgressEventSink *eventSink);
PRUint32 mServerType; // what kind of server is it.
nsCAutoString mCwd; // what dir are we in
@ -68,6 +72,7 @@ private:
nsCOMPtr<nsITransport> mCPipe;
nsCOMPtr<nsIOutputStream> mOutStream;
nsCOMPtr<nsIStreamListener> mListener;
nsCOMPtr<nsIProgressEventSink> mEventSink;
PRPackedBool mConnected;
PRPackedBool mWriteSuspened;
};