зеркало из https://github.com/mozilla/gecko-dev.git
Fixes bug 66493. nsSocketTransport changes broke in-process PSM.
r=bryner,gagan,brendan,dougt sr=mscott
This commit is contained in:
Родитель
2eccaab14e
Коммит
d4b4bf4bce
|
@ -65,7 +65,10 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsSocketInputStream()
|
||||
: mBytesRead(0), mSocketFD(nsnull) { NS_INIT_ISUPPORTS(); }
|
||||
: mBytesRead(0),
|
||||
mSocketFD(nsnull),
|
||||
mWouldBlock(PR_FALSE)
|
||||
{ NS_INIT_ISUPPORTS(); }
|
||||
virtual ~nsSocketInputStream() {}
|
||||
|
||||
void SetSocketFD(PRFileDesc *aSocketFD) {
|
||||
|
@ -77,6 +80,9 @@ public:
|
|||
void ZeroBytesRead() {
|
||||
mBytesRead = 0;
|
||||
}
|
||||
PRBool GotWouldBlock() {
|
||||
return mWouldBlock;
|
||||
}
|
||||
|
||||
//
|
||||
// nsIInputStream implementation...
|
||||
|
@ -98,11 +104,15 @@ public:
|
|||
NS_PRECONDITION(mSocketFD, "null socket fd");
|
||||
PRInt32 result = PR_Read(mSocketFD, aBuf, aCount);
|
||||
LOG(("nsSocketTransport: PR_Read(count=%u) returned %d\n", aCount, result));
|
||||
mWouldBlock = PR_FALSE;
|
||||
nsresult rv = NS_OK;
|
||||
if (result < 0) {
|
||||
PRErrorCode code = PR_GetError();
|
||||
if (PR_WOULD_BLOCK_ERROR == code)
|
||||
if (PR_WOULD_BLOCK_ERROR == code) {
|
||||
LOG(("nsSocketTransport: PR_Read() failed with PR_WOULD_BLOCK_ERROR\n"));
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
mWouldBlock = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
LOG(("nsSocketTransport: PR_Read() failed [error=%x, os_error=%x]\n",
|
||||
code, PR_GetOSError()));
|
||||
|
@ -133,6 +143,7 @@ public:
|
|||
protected:
|
||||
PRUint32 mBytesRead;
|
||||
PRFileDesc *mSocketFD;
|
||||
PRBool mWouldBlock;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsSocketInputStream, nsIInputStream)
|
||||
|
@ -148,7 +159,10 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsSocketOutputStream()
|
||||
: mBytesWritten(0), mSocketFD(nsnull) { NS_INIT_ISUPPORTS(); }
|
||||
: mBytesWritten(0),
|
||||
mSocketFD(nsnull),
|
||||
mWouldBlock(PR_FALSE)
|
||||
{ NS_INIT_ISUPPORTS(); }
|
||||
virtual ~nsSocketOutputStream() {}
|
||||
|
||||
void SetSocketFD(PRFileDesc *aSocketFD) {
|
||||
|
@ -160,6 +174,9 @@ public:
|
|||
void ZeroBytesWritten() {
|
||||
mBytesWritten = 0;
|
||||
}
|
||||
PRBool GotWouldBlock() {
|
||||
return mWouldBlock;
|
||||
}
|
||||
|
||||
//
|
||||
// nsIInputStream implementation...
|
||||
|
@ -174,12 +191,15 @@ public:
|
|||
NS_PRECONDITION(mSocketFD, "null socket fd");
|
||||
PRInt32 result = PR_Write(mSocketFD, aBuf, aCount);
|
||||
LOG(("nsSocketTransport: PR_Write(count=%u) returned %d\n", aCount, result));
|
||||
mWouldBlock = PR_FALSE;
|
||||
nsresult rv = NS_OK;
|
||||
if (result < 0) {
|
||||
PRErrorCode code = PR_GetError();
|
||||
if (PR_WOULD_BLOCK_ERROR == code)
|
||||
if (PR_WOULD_BLOCK_ERROR == code) {
|
||||
LOG(("nsSocketTransport: PR_Write() failed with PR_WOULD_BLOCK_ERROR\n"));
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
else {
|
||||
mWouldBlock = PR_TRUE;
|
||||
} else {
|
||||
LOG(("nsSocketTransport: PR_Write() failed [error=%x, os_error=%x]\n",
|
||||
code, PR_GetOSError()));
|
||||
rv = NS_ERROR_FAILURE;
|
||||
|
@ -216,6 +236,7 @@ public:
|
|||
protected:
|
||||
PRUint32 mBytesWritten;
|
||||
PRFileDesc *mSocketFD;
|
||||
PRBool mWouldBlock;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsSocketOutputStream, nsIOutputStream)
|
||||
|
@ -761,8 +782,9 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
|
|||
break;
|
||||
|
||||
case eSocketState_WaitReadWrite:
|
||||
LOG(("nsSocketTransport: Transport [host=%s:%d this=%x] is in WaitReadWrite state.\n",
|
||||
mHostName, mPort, this));
|
||||
LOG(("nsSocketTransport: Transport [host=%s:%d this=%x] "
|
||||
"is in WaitReadWrite state [readtype=%x writetype=%x status=%x].\n",
|
||||
mHostName, mPort, this, GetReadType(), GetWriteType(), mStatus));
|
||||
// Process the read request...
|
||||
if (GetReadType() != eSocketRead_None) {
|
||||
if (mBytesExpected == 0) {
|
||||
|
@ -1259,7 +1281,7 @@ nsresult nsSocketTransport::doReadAsync(PRInt16 aSelectFlags)
|
|||
//
|
||||
if (mSelectFlags & PR_POLL_WRITE) {
|
||||
LOG(("nsSocketTransport: READING [this=%x] busy waiting on read!\n", this));
|
||||
PR_Sleep(50); // Don't starve the other threads either!!
|
||||
PR_Sleep(10); // Don't starve the other threads either!!
|
||||
} else {
|
||||
LOG(("nsSocketTransport: READING [this=%x] listener would block; suspending self.\n", this));
|
||||
mSuspendCount++;
|
||||
|
@ -1276,7 +1298,7 @@ nsresult nsSocketTransport::doReadAsync(PRInt16 aSelectFlags)
|
|||
PRUint32 total = mSocketInputStream->GetBytesRead();
|
||||
mReadOffset += total;
|
||||
|
||||
if (0 == total) {
|
||||
if ((0 == total) && !mSocketInputStream->GotWouldBlock()) {
|
||||
LOG(("nsSocketTransport: READING [this=%x] done reading socket.\n", this));
|
||||
mSelectFlags &= ~PR_POLL_READ;
|
||||
}
|
||||
|
@ -1289,7 +1311,7 @@ nsresult nsSocketTransport::doReadAsync(PRInt16 aSelectFlags)
|
|||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
if (!(nsIChannel::LOAD_BACKGROUND & mLoadAttributes) && mEventSink)
|
||||
if (total && !(nsIChannel::LOAD_BACKGROUND & mLoadAttributes) && mEventSink)
|
||||
// we don't have content length info at the socket level
|
||||
// just pass 0 through.
|
||||
mEventSink->OnProgress(this, mReadContext, mReadOffset, 0);
|
||||
|
@ -1442,7 +1464,7 @@ nsresult nsSocketTransport::doWriteAsync(PRInt16 aSelectFlags)
|
|||
//
|
||||
if (mSelectFlags & PR_POLL_READ) {
|
||||
LOG(("nsSocketTransport: WRITING [this=%x] busy waiting on write!\n", this));
|
||||
PR_Sleep(50); // Don't starve the other threads either!!
|
||||
PR_Sleep(10); // Don't starve the other threads either!!
|
||||
} else {
|
||||
LOG(("nsSocketTransport: WRITING [this=%x] provider would block; suspending self.\n", this));
|
||||
mSuspendCount++;
|
||||
|
@ -1459,12 +1481,12 @@ nsresult nsSocketTransport::doWriteAsync(PRInt16 aSelectFlags)
|
|||
PRUint32 total = mSocketOutputStream->GetBytesWritten();
|
||||
mWriteOffset += total;
|
||||
|
||||
if (0 == total) {
|
||||
LOG(("nsSocketTransport: READING [this=%x] done writing to socket.\n", this));
|
||||
if ((0 == total) && !mSocketOutputStream->GotWouldBlock()) {
|
||||
LOG(("nsSocketTransport: WRITING [this=%x] done writing to socket.\n", this));
|
||||
mSelectFlags &= ~PR_POLL_WRITE;
|
||||
}
|
||||
else {
|
||||
LOG(("nsSocketTransport: READING [this=%x] wrote %u bytes [offset=%u]\n",
|
||||
LOG(("nsSocketTransport: WRITING [this=%x] wrote %u bytes [offset=%u]\n",
|
||||
this, total, mWriteOffset));
|
||||
//
|
||||
// Stay in the write state
|
||||
|
@ -1472,7 +1494,7 @@ nsresult nsSocketTransport::doWriteAsync(PRInt16 aSelectFlags)
|
|||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
if (!(nsIChannel::LOAD_BACKGROUND & mLoadAttributes) && mEventSink)
|
||||
if (total && !(nsIChannel::LOAD_BACKGROUND & mLoadAttributes) && mEventSink)
|
||||
// we don't have content length info at the socket level
|
||||
// just pass 0 through.
|
||||
mEventSink->OnProgress(this, mWriteContext, mWriteOffset, 0);
|
||||
|
|
|
@ -286,7 +286,7 @@ nsStreamListenerProxy::OnDataAvailable(nsIChannel *aChannel,
|
|||
}
|
||||
else if (bytesWritten == 0) {
|
||||
LOG(("nsStreamListenerProxy: Copied zero bytes; not posting an event [chan=%x]\n", aChannel));
|
||||
return NS_BASE_STREAM_CLOSED; // there was no more data to read!
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,14 +31,61 @@
|
|||
extern PRLogModuleInfo* gFTPLog;
|
||||
#endif /* PR_LOGGING */
|
||||
|
||||
//NS_IMPL_THREADSAFE_ISUPPORTS2(nsFtpControlConnection,
|
||||
// nsIStreamListener,
|
||||
// nsIStreamObserver);
|
||||
class nsFtpStreamProvider : public nsIStreamProvider {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsFtpStreamProvider() {}
|
||||
virtual ~nsFtpStreamProvider() {}
|
||||
|
||||
//
|
||||
// nsIStreamObserver implementation ...
|
||||
//
|
||||
NS_IMETHODIMP OnStartRequest(nsIChannel *chan, nsISupports *ctxt) { return NS_OK; }
|
||||
NS_IMETHODIMP OnStopRequest(nsIChannel *chan, nsISupports *ctxt, nsresult status, const PRUnichar *statusText) { return NS_OK; }
|
||||
|
||||
//
|
||||
// nsIStreamProvider implementation ...
|
||||
//
|
||||
NS_IMETHODIMP OnDataWritable(nsIChannel *aChannel, nsISupports *aContext,
|
||||
nsIOutputStream *aOutStream,
|
||||
PRUint32 aOffset, PRUint32 aCount)
|
||||
{
|
||||
NS_ASSERTION(mInStream, "not initialized");
|
||||
|
||||
nsresult rv;
|
||||
PRUint32 avail;
|
||||
|
||||
// Write whatever is available in the pipe. If the pipe is empty, then
|
||||
// return NS_BASE_STREAM_WOULD_BLOCK; we will resume the write when there
|
||||
// is more data.
|
||||
|
||||
rv = mInStream->Available(&avail);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (avail == 0) {
|
||||
NS_STATIC_CAST(nsFtpControlConnection*, aContext)->mSuspendedWrite = PR_TRUE;
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
PRUint32 bytesWritten;
|
||||
return aOutStream->WriteFrom(mInStream, PR_MIN(avail, aCount), &bytesWritten);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> mInStream;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsFtpStreamProvider,
|
||||
nsIStreamProvider,
|
||||
nsIStreamObserver)
|
||||
|
||||
|
||||
//
|
||||
// nsFtpControlConnection implementation ...
|
||||
//
|
||||
|
||||
NS_IMPL_THREADSAFE_QUERY_INTERFACE2(nsFtpControlConnection,
|
||||
nsIStreamListener,
|
||||
nsIStreamObserver);
|
||||
nsIStreamObserver)
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsFtpControlConnection);
|
||||
nsrefcnt nsFtpControlConnection::Release(void)
|
||||
|
@ -99,11 +146,15 @@ nsFtpControlConnection::Connect()
|
|||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// so that we can share the nsIStreamObserver implemention, we will be checking the context
|
||||
// to indicate between the read and the write transport. We will be passing the a non-null
|
||||
// context for the write, and a null context for the read.
|
||||
nsCOMPtr<nsIStreamProvider> provider;
|
||||
NS_NEWXPCOM(provider, nsFtpStreamProvider);
|
||||
if (!provider) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = NS_AsyncWriteFromStream(mCPipe, inStream, NS_STATIC_CAST(nsIStreamObserver*, this), NS_STATIC_CAST(nsISupports*, this));
|
||||
// setup the stream provider to get data from the pipe.
|
||||
NS_STATIC_CAST(nsFtpStreamProvider*,
|
||||
NS_STATIC_CAST(nsIStreamProvider*, provider))->mInStream = inStream;
|
||||
|
||||
rv = mCPipe->AsyncWrite(provider, NS_STATIC_CAST(nsISupports*, this));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// get the ball rolling by reading on the control socket.
|
||||
|
@ -139,8 +190,13 @@ nsFtpControlConnection::Write(nsCString& command)
|
|||
PRUint32 len = command.Length();
|
||||
PRUint32 cnt;
|
||||
nsresult rv = mOutStream->Write(command.GetBuffer(), len, &cnt);
|
||||
if (NS_SUCCEEDED(rv) && len==cnt)
|
||||
if (NS_SUCCEEDED(rv) && len==cnt) {
|
||||
if (mSuspendedWrite) {
|
||||
mSuspendedWrite = PR_FALSE;
|
||||
mCPipe->Resume();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ public:
|
|||
nsCAutoString mCwd; // what dir are we in
|
||||
PRBool mList; // are we sending LIST or NLST
|
||||
nsAutoString mPassword;
|
||||
PRBool mSuspendedWrite;
|
||||
|
||||
private:
|
||||
PRLock* mLock; // protects mListener.
|
||||
|
|
|
@ -693,6 +693,7 @@ nsPipe::nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
|
|||
rv = reader(this, closure, writeBuf, *writeCount, writeBufLen, &readCount);
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
NS_ASSERTION(readCount <= writeBufLen, "reader returned bad readCount");
|
||||
// XXX should not update counters if reader returned WOULD_BLOCK!!
|
||||
writeBuf += readCount;
|
||||
writeBufLen -= readCount;
|
||||
*writeCount += readCount;
|
||||
|
@ -703,8 +704,11 @@ nsPipe::nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
|
|||
// call flush to notify the guy downstream, hoping that he'll somehow
|
||||
// wake up the guy upstream to eventually produce more data for us.
|
||||
nsresult rv2 = Flush();
|
||||
if (/*rv2 == NS_BASE_STREAM_WOULD_BLOCK || */NS_FAILED(rv2))
|
||||
if (NS_FAILED(rv2)) {
|
||||
if (rv2 == NS_BASE_STREAM_WOULD_BLOCK)
|
||||
rv = pipe->mCondition;
|
||||
goto done;
|
||||
}
|
||||
// else we flushed, so go around again
|
||||
continue;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче