Fix for link-click problem

git-svn-id: svn://10.0.0.236/branches/linkclickfix_tmp_branch@65508 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
ruslan%netscape.com
2000-04-07 21:54:37 +00:00
parent 953c538a6a
commit 0e08e3e2ee
12 changed files with 217 additions and 90 deletions

View File

@@ -27,6 +27,16 @@ interface nsISocketTransport : nsISupports
{
attribute boolean reuseConnection;
/**
* socket read/write timeout in seconds; 0 = no timeout
*/
attribute unsigned long socketTimeout;
/**
* socket connect timeout in seconds; 0 = no timeout
*/
attribute unsigned long socketConnectTimeout;
/**
* Is used to tell the channel to stop reading data after a certain point;
* needed by HTTP/1.1
@@ -39,7 +49,7 @@ interface nsISocketTransport : nsISupports
*
* @param seconds amount of time after which the socket is always deemed to be
* dead (no further checking is done in this case); seconds = 0
* will cause it not to do timeout checking at all
* will cause it not to do the timeout checking at all
*/
boolean isAlive (in unsigned long seconds);
};

View File

@@ -98,7 +98,6 @@ nsSocketState gStateTable[eSocketOperation_Max][eSocketState_Max] = {
#define CONNECT_TIMEOUT_IN_MS 20
static PRIntervalTime gConnectTimeout = PR_INTERVAL_NO_WAIT;
static PRIntervalTime gTimeoutInterval = PR_INTERVAL_NO_WAIT;
#if defined(PR_LOGGING)
//
@@ -143,7 +142,9 @@ nsSocketTransport::nsSocketTransport():
mWriteBufferIndex(0),
mWriteBufferLength(0),
mBufferSegmentSize(0),
mBufferMaxSize(0)
mBufferMaxSize(0),
mSocketTimeout (PR_INTERVAL_NO_TIMEOUT),
mSocketConnectTimeout (PR_MillisecondsToInterval (DEFAULT_SOCKET_CONNECT_TIMEOUT_IN_MS))
{
NS_INIT_REFCNT();
@@ -308,16 +309,17 @@ nsresult nsSocketTransport::CheckForTimeout (PRIntervalTime aCurrentTime)
idleInterval = aCurrentTime - mLastActiveTime;
//
// Only timeout if the transport is waiting to connect to the server
//
if ((mCurrentState == eSocketState_WaitConnect)
&& idleInterval >= gTimeoutInterval)
if (mSocketConnectTimeout != PR_INTERVAL_NO_TIMEOUT && mCurrentState == eSocketState_WaitConnect
&& idleInterval >= mSocketConnectTimeout
||
mSocketTimeout != PR_INTERVAL_NO_TIMEOUT && mCurrentState == eSocketState_WaitReadWrite
&& idleInterval >= mSocketTimeout)
{
PR_LOG(gSocketLog, PR_LOG_ERROR,
("nsSocketTransport::CheckForTimeout() [%s:%d %x].\t"
"TIMED OUT... Idle interval: %d\n",
mHostName, mPort, this, idleInterval));
PR_LOG (
gSocketLog, PR_LOG_ERROR, ("nsSocketTransport::CheckForTimeout() [%s:%d %x].\t"
"TIMED OUT... Idle interval: %d\n",
mHostName, mPort, this, idleInterval)
);
// Move the transport into the Timeout state...
mCurrentState = eSocketState_Timeout;
@@ -1254,12 +1256,6 @@ nsresult nsSocketTransport::CloseConnection(PRBool bNow)
}
void nsSocketTransport::SetSocketTimeout(PRIntervalTime aTimeInterval)
{
gTimeoutInterval = aTimeInterval;
}
//
// --------------------------------------------------------------------------
// nsISupports implementation...
@@ -2156,28 +2152,6 @@ nsSocketTransport::SetNotificationCallbacks(nsIInterfaceRequestor* aNotification
return NS_OK;
}
nsresult
nsSocketTransport::fireStatus(PRUint32 aCode)
{
// need to optimize this - TODO
nsXPIDLString tempmesg;
nsresult rv = GetSocketErrorString(aCode, getter_Copies(tempmesg));
nsAutoString mesg(tempmesg);
if (mPrintHost)
mesg.AppendWithConversion(mPrintHost);
else
mesg.AppendWithConversion(mHostName);
if (NS_FAILED(rv)) return rv;
return mEventSink ? mEventSink->OnStatus(this,
mReadContext,
mesg.GetUnicode()) // this gets freed elsewhere.
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsSocketTransport::IsAlive (PRUint32 seconds, PRBool *alive)
{
@@ -2197,11 +2171,11 @@ nsSocketTransport::IsAlive (PRUint32 seconds, PRBool *alive)
static char c;
PRInt32 rval = PR_Read (mSocketFD, &c, 0);
if (rval <= 0)
if (rval < 0)
{
PRErrorCode code = PR_GetError ();
if (rval < 0 && code != PR_WOULD_BLOCK_ERROR)
if (code != PR_WOULD_BLOCK_ERROR)
*alive = PR_FALSE;
}
}
@@ -2211,6 +2185,75 @@ nsSocketTransport::IsAlive (PRUint32 seconds, PRBool *alive)
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::GetSocketTimeout (PRUint32 * o_Seconds)
{
if (o_Seconds == NULL)
return NS_ERROR_NULL_POINTER;
if (mSocketTimeout == PR_INTERVAL_NO_TIMEOUT)
*o_Seconds = 0;
else
*o_Seconds = PR_IntervalToSeconds (mSocketTimeout);
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::SetSocketTimeout (PRUint32 a_Seconds)
{
if (a_Seconds == 0)
mSocketTimeout = PR_INTERVAL_NO_TIMEOUT;
else
mSocketTimeout = PR_SecondsToInterval (a_Seconds);
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::GetSocketConnectTimeout (PRUint32 * o_Seconds)
{
if (o_Seconds == NULL)
return NS_ERROR_NULL_POINTER;
if (mSocketConnectTimeout == PR_INTERVAL_NO_TIMEOUT)
*o_Seconds = 0;
else
*o_Seconds = PR_IntervalToSeconds (mSocketConnectTimeout);
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::SetSocketConnectTimeout (PRUint32 a_Seconds)
{
if (a_Seconds == 0)
mSocketConnectTimeout = PR_INTERVAL_NO_TIMEOUT;
else
mSocketConnectTimeout = PR_SecondsToInterval (a_Seconds);
return NS_OK;
}
nsresult
nsSocketTransport::fireStatus(PRUint32 aCode)
{
// need to optimize this - TODO
nsXPIDLString tempmesg;
nsresult rv = GetSocketErrorString(aCode, getter_Copies(tempmesg));
nsAutoString mesg(tempmesg);
if (mPrintHost)
mesg.AppendWithConversion(mPrintHost);
else
mesg.AppendWithConversion(mHostName);
if (NS_FAILED(rv)) return rv;
return mEventSink ? mEventSink->OnStatus(this,
mReadContext,
mesg.GetUnicode()) // this gets freed elsewhere.
: NS_ERROR_FAILURE;
}
//TODO l10n and i18n stuff here!
nsresult
nsSocketTransport::GetSocketErrorString(PRUint32 iCode,

View File

@@ -106,6 +106,12 @@ enum nsSocketReadWriteInfo {
eSocketDNS_Wait = 0x2020
};
//
// This is the default timeout value (in milliseconds) for sockets which have
// no activity...
//
#define DEFAULT_SOCKET_CONNECT_TIMEOUT_IN_MS 35*1000
// Forward declarations...
class nsSocketTransportService;
class nsIInterfaceRequestor;
@@ -137,7 +143,7 @@ public:
nsresult Process(PRInt16 aSelectFlags);
nsresult CheckForTimeout(PRIntervalTime aCurrentTime);
nsresult CheckForTimeout (PRIntervalTime aCurrentTime);
// Close this socket either right away or once done with the transaction.
nsresult CloseConnection(PRBool bNow=PR_TRUE);
@@ -149,8 +155,6 @@ public:
static nsSocketTransport* GetInstance(PRCList* qp) { return (nsSocketTransport*)((char*)qp - offsetof(nsSocketTransport, mListLink)); }
static void SetSocketTimeout(PRIntervalTime aTimeoutInterval);
PRBool CanBeReused(void) { return
(mCurrentState != eSocketState_Error) && !mCloseConnectionOnceDone;}
@@ -167,6 +171,9 @@ protected:
nsresult GetSocketErrorString(PRUint32 iCode, PRUnichar** oString) const;
private:
PRIntervalTime mSocketTimeout;
PRIntervalTime mSocketConnectTimeout;
// Access methods for manipulating the ReadWriteInfo...
inline void SetReadType(nsSocketReadWriteInfo aType) {
mReadWriteState = (mReadWriteState & ~eSocketRead_Type_Mask) | aType;

View File

@@ -49,8 +49,6 @@ nsSocketTransportService::nsSocketTransportService()
mActiveTransportList = nsnull;
mThreadRunning = PR_FALSE;
SetSocketTimeoutInterval(PR_MillisecondsToInterval(DEFAULT_SOCKET_TIMEOUT_IN_MS));
}
@@ -345,24 +343,6 @@ nsresult nsSocketTransportService::RemoveFromSelectList(nsSocketTransport* aTran
}
nsresult
nsSocketTransportService::GetSocketTimeoutInterval(PRIntervalTime* aResult)
{
*aResult = mSocketTimeoutInterval;
return NS_OK;
}
nsresult
nsSocketTransportService::SetSocketTimeoutInterval(PRIntervalTime aTime)
{
mSocketTimeoutInterval = aTime;
// Update the timeout value in the socket transport...
nsSocketTransport::SetSocketTimeout(aTime);
return NS_OK;
}
//
// --------------------------------------------------------------------------
// nsISupports implementation...
@@ -389,7 +369,7 @@ nsSocketTransportService::Run(void)
mSelectFDSet[0].fd = mThreadEvent;
mSelectFDSet[0].in_flags = PR_POLL_READ;
mSelectFDSetCount = 1;
pollTimeout = mSocketTimeoutInterval;
pollTimeout = PR_MillisecondsToInterval (DEFAULT_POLL_TIMEOUT_IN_MS);
#else
//
// For now, rather than breaking out of the call to PR_Poll(...) just set

View File

@@ -38,17 +38,12 @@
#define USE_POLLABLE_EVENT
#endif
//
// This is the default timeout value (in milliseconds) for sockets which have
// no activity...
//
#define DEFAULT_SOCKET_TIMEOUT_IN_MS 35*1000
//
// This is the Maximum number of Socket Transport instances that can be active
// at once...
//
#define MAX_OPEN_CONNECTIONS 50
#define DEFAULT_POLL_TIMEOUT_IN_MS 35*1000
// Forward declarations...
@@ -89,8 +84,6 @@ protected:
PRLock* mThreadLock;
PRBool mThreadRunning;
PRIntervalTime mSocketTimeoutInterval;
PRCList mWorkQ;
PRInt32 mSelectFDSetCount;

View File

@@ -97,7 +97,8 @@ nsHTTPChannel::nsHTTPChannel(nsIURI* i_URL, nsHTTPHandler* i_Handler):
mBufferSegmentSize(0),
mBufferMaxSize(0),
mStatus(NS_OK),
mPipeliningAllowed (PR_TRUE)
mPipeliningAllowed (PR_TRUE),
mPipelinedRequest (nsnull)
{
NS_INIT_REFCNT();
@@ -1327,17 +1328,24 @@ nsHTTPChannel::Open(void)
if (NS_ERROR_BUSY == rv)
{
mPipelinedRequest = pReq;
if (!mPipelinedRequest)
{
mPipelinedRequest = pReq;
NS_RELEASE (pReq);
}
mState = HS_WAITING_FOR_OPEN;
return NS_OK;
}
if (!mPipelinedRequest)
NS_RELEASE (pReq);
if (NS_FAILED (rv))
{
ResponseCompleted (mResponseDataListener, rv, nsnull);
return rv;
}
NS_RELEASE (pReq);
}
mState = HS_WAITING_FOR_RESPONSE;

View File

@@ -601,7 +601,9 @@ nsHTTPHandler::nsHTTPHandler():
mCapabilities (DEFAULT_ALLOWED_CAPABILITIES ),
mKeepAliveTimeout (DEFAULT_KEEP_ALIVE_TIMEOUT),
mMaxConnections (MAX_NUMBER_OF_OPEN_TRANSPORTS),
mReferrerLevel(0)
mReferrerLevel (0),
mRequestTimeout (DEFAULT_HTTP_REQUEST_TIMEOUT),
mConnectTimeout (DEFAULT_HTTP_CONNECT_TIMEOUT)
{
NS_INIT_REFCNT ();
SetAcceptEncodings (DEFAULT_ACCEPT_ENCODINGS);
@@ -970,13 +972,21 @@ nsresult nsHTTPHandler::CreateTransport(const char* host,
{
nsresult rv;
NS_WITH_SERVICE(nsISocketTransportService, sts,
kSocketTransportServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
NS_WITH_SERVICE (nsISocketTransportService, sts, kSocketTransportServiceCID, &rv);
if (NS_FAILED (rv))
return rv;
return sts->CreateTransport(host, port, aPrintHost,
bufferSegmentSize, bufferMaxSize,
o_pTrans);
rv = sts -> CreateTransport (host, port, aPrintHost, bufferSegmentSize, bufferMaxSize, o_pTrans);
if (NS_SUCCEEDED (rv))
{
nsCOMPtr<nsISocketTransport> trans = do_QueryInterface (*o_pTrans, &rv);
if (NS_SUCCEEDED (rv))
{
trans -> SetSocketTimeout (mRequestTimeout);
trans -> SetSocketConnectTimeout (mConnectTimeout);
}
}
return rv;
}
nsresult nsHTTPHandler::ReleaseTransport (nsIChannel* i_pTrans, PRUint32 aCapabilities)
@@ -1225,6 +1235,9 @@ nsHTTPHandler::PrefsChanged(const char* pref)
mCapabilities &= ~ALLOW_PROXY_PIPELINING;
}
mPrefs -> GetIntPref ("network.http.connect.timeout", &mConnectTimeout);
mPrefs -> GetIntPref ("network.http.request.timeout", &mRequestTimeout);
// Things read only during initialization...
if (bChangedAll) // intl.accept_languages
{

View File

@@ -61,6 +61,9 @@ class nsHTTPChannel;
// because of HTTP/1.1 is default now
#define DEFAULT_ALLOWED_CAPABILITIES (DEFAULT_PROXY_CAPABILITIES|DEFAULT_SERVER_CAPABILITIES)
#define DEFAULT_HTTP_REQUEST_TIMEOUT 30
#define DEFAULT_HTTP_CONNECT_TIMEOUT 30
class nsHTTPPipelinedRequest;
class nsIHTTPChannel;
@@ -155,6 +158,9 @@ protected:
private:
nsHashtable mCapTable;
PRInt32 mRequestTimeout;
PRInt32 mConnectTimeout;
PRUint32 getCapabilities (const char *host, PRInt32 port, PRUint32 cap);
void setCapabilities (nsIChannel* i_pTrans, PRUint32 aCapabilities);

View File

@@ -579,9 +579,12 @@ nsHTTPPipelinedRequest::WriteRequest ()
if (!mTransport)
{
PRUint32 tMode = mAttempts ? TRANSPORT_OPEN_ALWAYS : TRANSPORT_REUSE_ALIVE;
if (mPostDataStream)
tMode &= ~(TRANSPORT_REUSE_ALIVE);
rv = mHandler -> RequestTransport (req -> mURI, req -> mConnection, mBufferSegmentSize, mBufferMaxSize,
getter_AddRefs (mTransport),
mAttempts ? TRANSPORT_OPEN_ALWAYS : TRANSPORT_REUSE_ALIVE);
getter_AddRefs (mTransport), tMode);
if (NS_FAILED (rv))
{
@@ -669,10 +672,13 @@ nsHTTPPipelinedRequest::OnStopRequest (nsIChannel* channel, nsISupports* i_Conte
nsresult rv;
nsCOMPtr<nsISocketTransport> trans = do_QueryInterface (mTransport, &rv);
mOnStopDone = PR_TRUE;
nsHTTPRequest * req = (nsHTTPRequest *) mRequests -> ElementAt (0);
rv = iStatus;
PR_LOG (gHTTPLog, PR_LOG_DEBUG, ("\nnsHTTPRequest::OnStopRequest () [this=%x], iStatus=%u\n", this, iStatus));
if (NS_SUCCEEDED (rv))
{
PRBool isAlive = PR_TRUE;
@@ -715,7 +721,7 @@ nsHTTPPipelinedRequest::OnStopRequest (nsIChannel* channel, nsISupports* i_Conte
else
rv = NS_ERROR_OUT_OF_MEMORY;
}
mOnStopDone = PR_TRUE;
WriteRequest (); // write again to see if anything else is queued up
}
}
@@ -739,7 +745,7 @@ nsHTTPPipelinedRequest::OnStopRequest (nsIChannel* channel, nsISupports* i_Conte
//
if (NS_FAILED (rv))
{
if (mListener == nsnull)
if (mTotalProcessed == 0 && mAttempts == 0)
{
// the pipeline just started - we still can attempt to recover
@@ -755,7 +761,6 @@ nsHTTPPipelinedRequest::OnStopRequest (nsIChannel* channel, nsISupports* i_Conte
{
mAttempts++;
mTotalWritten = 0;
mOnStopDone = PR_TRUE;
rv = WriteRequest ();
@@ -766,6 +771,11 @@ nsHTTPPipelinedRequest::OnStopRequest (nsIChannel* channel, nsISupports* i_Conte
}
}
}
else
{
mHandler -> ReleaseTransport (mTransport, 0);
mTransport = null_nsCOMPtr ();
}
// Notify the HTTPChannel that the request has finished
nsCOMPtr<nsIStreamListener> consumer;
@@ -785,6 +795,43 @@ nsHTTPPipelinedRequest::OnStopRequest (nsIChannel* channel, nsISupports* i_Conte
return rv;
}
nsresult
nsHTTPPipelinedRequest::RestartRequest ()
{
nsresult rv = NS_ERROR_FAILURE;
PR_LOG (gHTTPLog, PR_LOG_DEBUG, ("\nnsHTTPPipelinedRequest::RestartRequest () [this=%x], mTotalProcessed=%u\n", this, mTotalProcessed));
if (mTotalProcessed == 0)
{
// the pipeline just started - we still can attempt to recover
nsCOMPtr<nsISocketTransport> trans = do_QueryInterface (mTransport, &rv);
PRUint32 wasKeptAlive = 0;
if (trans)
trans -> GetReuseCount (&wasKeptAlive);
if (wasKeptAlive && mAttempts == 0)
{
rv = NS_OK;
mListener = nsnull;
if (mOnStopDone)
{
mHandler -> ReleaseTransport (mTransport, 0);
mTransport = null_nsCOMPtr ();
mTotalWritten = 0;
mAttempts++;
rv = WriteRequest ();
}
}
}
return rv;
}
nsresult
nsHTTPPipelinedRequest::IsPending (PRBool *result)
{

View File

@@ -195,6 +195,7 @@ public:
nsresult GetCurrentRequest (nsHTTPRequest ** o_Req);
nsresult AdvanceToNextRequest ();
nsresult RestartRequest ();
nsresult IsPending (PRBool *result);
nsresult Cancel (nsresult status );

View File

@@ -220,7 +220,8 @@ nsHTTPServerListener::nsHTTPServerListener(nsHTTPChannel* aChannel, nsHTTPHandle
mCompressHeaderChecked (PR_FALSE),
mChunkHeaderEOF(PR_FALSE),
mChunkHeaderChecked (PR_FALSE),
mPipelinedRequest (request)
mPipelinedRequest (request),
mDataReceived (PR_FALSE)
{
nsHTTPRequest * req = nsnull;
mChannel -> mHTTPServerListener = this;
@@ -264,6 +265,9 @@ nsHTTPServerListener::OnDataAvailable(nsIChannel* channel,
"\tstream=%x. \toffset=%d. \tlength=%d.\n",
this, i_pStream, i_SourceOffset, i_Length));
if (i_Length > 0)
mDataReceived = PR_TRUE;
if (!mResponse)
{
mResponse = new nsHTTPResponse ();
@@ -486,6 +490,7 @@ nsHTTPServerListener::OnStartRequest (nsIChannel* channel, nsISupports* i_pConte
mCompressHeaderChecked = PR_FALSE;
mChunkHeaderEOF = PR_FALSE;
mChunkHeaderChecked = PR_FALSE;
mDataReceived = PR_FALSE;
mBytesReceived = 0;
mBodyBytesReceived = 0;
mHeaderBuffer.Truncate ();
@@ -523,6 +528,19 @@ nsHTTPServerListener::OnStopRequest (nsIChannel* channel, nsISupports* i_pContex
("nsHTTPServerListener::OnStopRequest [this=%x]."
"\tStatus = %x\n", this, i_Status));
if (!mDataReceived)
{
// no data has been received from the channel at all - must be due to the fact that the
// server has dropped the connection on keep-alive
if (mPipelinedRequest)
{
nsresult rv = mPipelinedRequest -> RestartRequest ();
if (NS_SUCCEEDED (rv))
return rv;
}
}
if (NS_SUCCEEDED(rv) && !mHeadersDone)
{
//

View File

@@ -122,6 +122,7 @@ protected:
PRBool mCompressHeaderChecked;
PRBool mChunkHeaderChecked;
PRBool mDataReceived;
PRBool mChunkHeaderEOF;
nsHTTPPipelinedRequest* mPipelinedRequest;
};