bug #21884 (r=mscott) bug #21459 (r=warren). I'm checking in the changes for 21459 again with an important fix for the image crashes :-)

This commit is contained in:
rpotts%netscape.com 1999-12-16 07:59:25 +00:00
parent 6fed82b2a1
commit b8fa07f3ff
5 changed files with 125 additions and 70 deletions

View File

@ -835,20 +835,22 @@ private:
NS_IMETHOD NS_IMETHOD
OnDataAvailable(nsIChannel *aChannel, nsISupports *aContext, OnDataAvailable(nsIChannel *aChannel, nsISupports *aContext,
nsIInputStream *aStream, PRUint32 aSourceOffset, PRUint32 aCount) { nsIInputStream *aStream, PRUint32 aSourceOffset,
return mListener->OnDataAvailable(aChannel, aContext, aStream, aSourceOffset, aCount); PRUint32 aCount)
{
return mListener->OnDataAvailable(mChannel, aContext,
aStream, aSourceOffset, aCount);
} }
NS_IMETHOD NS_IMETHOD
OnStartRequest(nsIChannel *aChannel, nsISupports *aContext) { OnStartRequest(nsIChannel *aChannel, nsISupports *aContext) {
return mListener->OnStartRequest(aChannel, aContext); return mListener->OnStartRequest(mChannel, aContext);
} }
NS_IMETHOD NS_IMETHOD
OnStopRequest(nsIChannel *aChannel, nsISupports *aContext, OnStopRequest(nsIChannel *aChannel, nsISupports *aContext,
nsresult aStatus, const PRUnichar *aErrorMsg) { nsresult aStatus, const PRUnichar *aErrorMsg) {
mChannel->ResponseCompleted(0, aStatus, aErrorMsg); return mChannel->ResponseCompleted(nsnull, mListener, aStatus, aErrorMsg);
return mListener->OnStopRequest(aChannel, aContext, aStatus, aErrorMsg);
} }
protected: protected:
@ -918,7 +920,7 @@ nsHTTPChannel::ReadFromCache(PRUint32 aStartPosition, PRInt32 aReadCount)
mResponseContext, listener); mResponseContext, listener);
NS_RELEASE(listener); NS_RELEASE(listener);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
ResponseCompleted(0, rv, 0); ResponseCompleted(0, nsnull, rv, 0);
} }
return rv; return rv;
} }
@ -1097,7 +1099,7 @@ nsHTTPChannel::Open(void)
} }
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
// Unable to create a transport... End the request... // Unable to create a transport... End the request...
(void) ResponseCompleted(nsnull, rv, nsnull); (void) ResponseCompleted(nsnull, mResponseDataListener, rv, nsnull);
return rv; return rv;
} }
@ -1105,7 +1107,7 @@ nsHTTPChannel::Open(void)
rv = transport->SetNotificationCallbacks(this); rv = transport->SetNotificationCallbacks(this);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
// Unable to create a transport... End the request... // Unable to create a transport... End the request...
(void) ResponseCompleted(nsnull, rv, nsnull); (void) ResponseCompleted(nsnull, mResponseDataListener, rv, nsnull);
return rv; return rv;
} }
@ -1242,11 +1244,47 @@ nsresult nsHTTPChannel::Redirect(const char *aNewLocation,
nsresult nsHTTPChannel::ResponseCompleted(nsIChannel* aTransport, nsresult nsHTTPChannel::ResponseCompleted(nsIChannel* aTransport,
nsIStreamListener *aListener,
nsresult aStatus, nsresult aStatus,
const PRUnichar* aMsg) const PRUnichar* aMsg)
{ {
nsresult rv = NS_OK; nsresult rv = NS_OK;
//
// First:
//
// Call the consumer OnStopRequest(...) to end the request...
if (aListener) {
rv = aListener->OnStopRequest(this, mResponseContext, aStatus, aMsg);
if (NS_FAILED(rv)) {
PR_LOG(gHTTPLog, PR_LOG_ERROR,
("nsHTTPChannel::OnStopRequest(...) [this=%x]."
"\tOnStopRequest to consumer failed! Status:%x\n",
this, rv));
}
}
// Release the transport...
if (aTransport) {
(void)mHandler->ReleaseTransport(aTransport);
}
//
// After the consumer has been notified, remove the channel from its
// load group... This will trigger an OnStopRequest from the load group.
//
if (mLoadGroup) {
(void)mLoadGroup->RemoveChannel(this, nsnull, aStatus, nsnull);
}
//
// Finally, notify the OpenObserver that the request has completed.
//
if (mOpenObserver) {
(void) mOpenObserver->OnStopRequest(this, mOpenContext, aStatus, aMsg);
}
// Null out pointers that are no longer needed... // Null out pointers that are no longer needed...
// rjc says: don't null out mResponseContext; // rjc says: don't null out mResponseContext;
@ -1256,21 +1294,6 @@ nsresult nsHTTPChannel::ResponseCompleted(nsIChannel* aTransport,
mResponseDataListener = 0; mResponseDataListener = 0;
NS_IF_RELEASE(mCachedResponse); NS_IF_RELEASE(mCachedResponse);
// Release the transport...
if (aTransport) {
(void)mHandler->ReleaseTransport(aTransport);
}
// Remove the channel from its load group...
if (mLoadGroup) {
(void)mLoadGroup->RemoveChannel(this, nsnull, aStatus, nsnull);
}
if (mOpenObserver) {
rv = mOpenObserver->OnStopRequest(this, mOpenContext, aStatus, aMsg);
if (NS_FAILED(rv)) return rv;
}
return rv; return rv;
} }
@ -1294,6 +1317,28 @@ nsresult nsHTTPChannel::GetResponseContext(nsISupports** aContext)
return NS_ERROR_NULL_POINTER; return NS_ERROR_NULL_POINTER;
} }
nsresult nsHTTPChannel::Abort()
{
// Disconnect the consumer from this response listener...
// This allows the entity that follows to be discarded
// without notifying the consumer...
if (mRawResponseListener) {
mRawResponseListener->Abort();
}
// Null out pointers that are no longer needed...
//
// This will prevent the OnStopRequest(...) notification from being fired
// for the original URL...
//
mResponseDataListener = 0;
mOpenObserver = 0;
return NS_OK;
}
nsresult nsHTTPChannel::OnHeadersAvailable() nsresult nsHTTPChannel::OnHeadersAvailable()
{ {
nsresult rv = NS_OK; nsresult rv = NS_OK;
@ -1582,8 +1627,9 @@ nsHTTPChannel::ProcessStatusCode(void)
if ((statusCode == 200) || (statusCode == 203)) { if ((statusCode == 200) || (statusCode == 203)) {
nsCOMPtr<nsIStreamListener> listener2; nsCOMPtr<nsIStreamListener> listener2;
CacheReceivedResponse(listener, getter_AddRefs(listener2)); CacheReceivedResponse(listener, getter_AddRefs(listener2));
if (listener2) if (listener2) {
listener = listener2; listener = listener2;
}
} }
break; break;
@ -1607,8 +1653,9 @@ nsHTTPChannel::ProcessStatusCode(void)
else if ((statusCode == 300) || (statusCode == 301)) { else if ((statusCode == 300) || (statusCode == 301)) {
nsCOMPtr<nsIStreamListener> listener2; nsCOMPtr<nsIStreamListener> listener2;
CacheReceivedResponse(listener, getter_AddRefs(listener2)); CacheReceivedResponse(listener, getter_AddRefs(listener2));
if (listener2) if (listener2) {
listener = listener2; listener = listener2;
}
} }
rv = ProcessRedirection(statusCode); rv = ProcessRedirection(statusCode);
@ -1645,9 +1692,12 @@ nsHTTPChannel::ProcessStatusCode(void)
break; break;
} }
if (mRawResponseListener) // If mResponseDataListener is null this means that the response has been
// aborted... So, do not update the response listener because this
// is being discarded...
if (mResponseDataListener && mRawResponseListener) {
mRawResponseListener->SetResponseDataListener(listener); mRawResponseListener->SetResponseDataListener(listener);
}
return rv; return rv;
} }
@ -1656,8 +1706,11 @@ nsHTTPChannel::ProcessNotModifiedResponse(nsIStreamListener *aListener)
{ {
nsresult rv; nsresult rv;
NS_ASSERTION(!mCachedContentIsValid, "We should never have cached a 304 response"); NS_ASSERTION(!mCachedContentIsValid, "We should never have cached a 304 response");
mRawResponseListener->Abort(); // Abort the current response... This will disconnect the consumer from
// the response listener... Thus allowing the entity that follows to
// be discarded without notifying the consumer...
Abort();
// Fake it so that HTTP headers come from cached versions // Fake it so that HTTP headers come from cached versions
SetResponse(mCachedResponse); SetResponse(mCachedResponse);
@ -1684,13 +1737,12 @@ nsHTTPChannel::ProcessRedirection(PRInt32 aStatusCode)
nsCOMPtr<nsIChannel> channel; nsCOMPtr<nsIChannel> channel;
rv = Redirect(location, getter_AddRefs(channel)); rv = Redirect(location, getter_AddRefs(channel));
if (NS_FAILED(rv)) return rv;
// Disconnect the consumer from this response listener... // Abort the current response... This will disconnect the consumer from
// This allows the entity that follows to be discarded // the response listener... Thus allowing the entity that follows to
// without notifying the consumer... // be discarded without notifying the consumer...
if (NS_SUCCEEDED(rv) && mRawResponseListener) { Abort();
mRawResponseListener->Abort();
}
} }
return rv; return rv;
} }
@ -1719,19 +1771,10 @@ nsHTTPChannel::ProcessAuthentication(PRInt32 aStatusCode)
if (NS_FAILED(rv = Authenticate(challenge, getter_AddRefs(channel)))) if (NS_FAILED(rv = Authenticate(challenge, getter_AddRefs(channel))))
return rv; return rv;
// Disconnect the consumer from this response listener... // Abort the current response... This will disconnect the consumer from
// This allows the entity that follows to be discarded // the response listener... Thus allowing the entity that follows to
// without notifying the consumer... // be discarded without notifying the consumer...
if (mRawResponseListener) Abort();
mRawResponseListener->Abort();
// Null out pointers that are no longer needed...
//
// This will prevent the OnStopRequest(...) notification from being fired
// for the original URL...
//
mResponseDataListener = 0;
mOpenObserver = 0;
return rv; return rv;
} }

View File

@ -86,9 +86,12 @@ public:
nsresult Open(); nsresult Open();
nsresult Redirect(const char *aURL, nsresult Redirect(const char *aURL,
nsIChannel **aResult); nsIChannel **aResult);
nsresult ResponseCompleted(nsIChannel* aTransport, nsresult ResponseCompleted(nsIChannel* aTransport,
nsIStreamListener* aListener,
nsresult aStatus, nsresult aStatus,
const PRUnichar* aMsg); const PRUnichar* aMsg);
nsresult SetResponse(nsHTTPResponse* i_pResp); nsresult SetResponse(nsHTTPResponse* i_pResp);
nsresult GetResponseContext(nsISupports** aContext); nsresult GetResponseContext(nsISupports** aContext);
nsresult CacheReceivedResponse(nsIStreamListener *aListener, nsresult CacheReceivedResponse(nsIStreamListener *aListener,
@ -101,6 +104,8 @@ public:
nsresult FinishedResponseHeaders(); nsresult FinishedResponseHeaders();
nsresult Abort();
protected: protected:
nsresult CheckCache(); nsresult CheckCache();
nsresult ReadFromCache(PRUint32 aStartPosition, PRInt32 aReadCount); nsresult ReadFromCache(PRUint32 aStartPosition, PRInt32 aReadCount);

View File

@ -498,7 +498,11 @@ nsHTTPRequest::OnStopRequest(nsIChannel* channel, nsISupports* i_Context,
this, iStatus)); this, iStatus));
// Notify the HTTPChannel that the request has finished // Notify the HTTPChannel that the request has finished
mConnection->ResponseCompleted(mTransport, iStatus, i_Msg); nsCOMPtr<nsIStreamListener> consumer;
mConnection->GetResponseDataListener(getter_AddRefs(consumer));
mConnection->ResponseCompleted(mTransport, consumer, iStatus, i_Msg);
mTransport = null_nsCOMPtr(); mTransport = null_nsCOMPtr();
rv = iStatus; rv = iStatus;

View File

@ -59,7 +59,6 @@ static const int kMAX_HEADER_SIZE = 60000;
nsHTTPResponseListener::nsHTTPResponseListener(nsHTTPChannel* aConnection): nsHTTPResponseListener::nsHTTPResponseListener(nsHTTPChannel* aConnection):
mFirstLineParsed(PR_FALSE), mFirstLineParsed(PR_FALSE),
mHeadersDone(PR_FALSE), mHeadersDone(PR_FALSE),
mAborted(PR_FALSE),
mResponse(nsnull), mResponse(nsnull),
mBytesReceived(0) mBytesReceived(0)
{ {
@ -178,7 +177,7 @@ nsHTTPResponseListener::OnDataAvailable(nsIChannel* channel,
// Abort the connection if the consumer has been released. This will // Abort the connection if the consumer has been released. This will
// happen if a redirect has been processed... // happen if a redirect has been processed...
// //
if (mAborted) { if (!mResponseDataListener) {
// XXX: What should the return code be? // XXX: What should the return code be?
rv = NS_BINDING_ABORTED; rv = NS_BINDING_ABORTED;
} }
@ -247,23 +246,13 @@ nsHTTPResponseListener::OnStopRequest(nsIChannel* channel,
// Notify the HTTPChannel that the response has completed... // Notify the HTTPChannel that the response has completed...
NS_ASSERTION(mChannel, "HTTPChannel is null."); NS_ASSERTION(mChannel, "HTTPChannel is null.");
if (mChannel) { if (mChannel) {
mChannel->ResponseCompleted(channel, i_Status, i_pMsg); mChannel->ResponseCompleted(channel, mResponseDataListener,
i_Status, i_pMsg);
// The HTTPChannel is no longer needed...
mChannel->mRawResponseListener = 0;
} }
// Call the consumer OnStopRequest(...) to end the request...
if (mResponseDataListener && !mAborted) {
rv = mResponseDataListener->OnStopRequest(mChannel, mChannel->mResponseContext, i_Status, i_pMsg);
if (NS_FAILED(rv)) {
PR_LOG(gHTTPLog, PR_LOG_ERROR,
("nsHTTPChannel::OnStopRequest(...) [this=%x]."
"\tOnStopRequest to consumer failed! Status:%x\n",
this, rv));
}
}
// The HTTPChannel is no longer needed...
mChannel->mRawResponseListener = 0;
NS_IF_RELEASE(mChannel); NS_IF_RELEASE(mChannel);
NS_IF_RELEASE(mResponse); NS_IF_RELEASE(mResponse);
@ -273,6 +262,21 @@ nsHTTPResponseListener::OnStopRequest(nsIChannel* channel,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// nsHTTPResponseListener methods: // nsHTTPResponseListener methods:
nsresult nsHTTPResponseListener::Abort()
{
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("nsHTTPResponseListener::Abort [this=%x].", this));
//
// Clearing the data consumer will cause the response to abort. This
// also prevents any more notifications from being passed out to the consumer.
//
mResponseDataListener = 0;
return NS_OK;
}
nsresult nsHTTPResponseListener::FireSingleOnData(nsIStreamListener *aListener, nsISupports *aContext) nsresult nsHTTPResponseListener::FireSingleOnData(nsIStreamListener *aListener, nsISupports *aContext)
{ {
nsresult rv; nsresult rv;
@ -281,7 +285,7 @@ nsresult nsHTTPResponseListener::FireSingleOnData(nsIStreamListener *aListener,
rv = FinishedResponseHeaders(); rv = FinishedResponseHeaders();
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
if (mBytesReceived) { if (mBytesReceived && mResponseDataListener) {
rv = mResponseDataListener->OnDataAvailable(mChannel, mChannel->mResponseContext, rv = mResponseDataListener->OnDataAvailable(mChannel, mChannel->mResponseContext,
mDataStream, 0, mBytesReceived); mDataStream, 0, mBytesReceived);
} }
@ -499,7 +503,7 @@ nsresult nsHTTPResponseListener::FinishedResponseHeaders(void)
// //
// Fire the OnStartRequest notification - now that user data is available // Fire the OnStartRequest notification - now that user data is available
// //
if (NS_SUCCEEDED(rv) && mResponseDataListener && !mAborted) { if (NS_SUCCEEDED(rv) && mResponseDataListener) {
rv = mResponseDataListener->OnStartRequest(mChannel, mChannel->mResponseContext); rv = mResponseDataListener->OnStartRequest(mChannel, mChannel->mResponseContext);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
PR_LOG(gHTTPLog, PR_LOG_ERROR, PR_LOG(gHTTPLog, PR_LOG_ERROR,

View File

@ -63,7 +63,7 @@ public:
NS_DECL_NSISTREAMLISTENER NS_DECL_NSISTREAMLISTENER
nsresult FireSingleOnData(nsIStreamListener *aListener, nsISupports *aContext); nsresult FireSingleOnData(nsIStreamListener *aListener, nsISupports *aContext);
void Abort() { mAborted = PR_TRUE; } nsresult Abort();
void SetResponseDataListener(nsIStreamListener *aListener) { void SetResponseDataListener(nsIStreamListener *aListener) {
mResponseDataListener = aListener; mResponseDataListener = aListener;
} }
@ -86,7 +86,6 @@ protected:
nsHTTPResponse* mResponse; nsHTTPResponse* mResponse;
PRBool mFirstLineParsed; PRBool mFirstLineParsed;
PRBool mHeadersDone; PRBool mHeadersDone;
PRBool mAborted;
nsCOMPtr<nsIInputStream> mDataStream; nsCOMPtr<nsIInputStream> mDataStream;
PRUint32 mBytesReceived; PRUint32 mBytesReceived;