Bug 432391 part 1. Fix CancelAndForgetObserver to work correctly even if Cancel has been called. r=joe, a=dveditz
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 14 Oct 2011 16:15:56 -0400
changeset 35247 173bc943fe0d1dc8f7d9e6d0f293711efa26fa93
parent 35246 e04e018f9ae69c5dc383cbd823a6aa694b6472d4
child 35248 982f9c134751e6fe10f81c2319cd117533444229
child 35251 0219ac257e3c3f656fb7680db9c1d8af59197efc
push id2013
push userdveditz@mozilla.com
push dateTue, 24 Jan 2012 02:26:38 +0000
reviewersjoe, dveditz
bugs432391
milestone1.9.2.26pre
Bug 432391 part 1. Fix CancelAndForgetObserver to work correctly even if Cancel has been called. r=joe, a=dveditz
modules/libpr0n/src/imgRequest.cpp
modules/libpr0n/src/imgRequestProxy.cpp
--- a/modules/libpr0n/src/imgRequest.cpp
+++ b/modules/libpr0n/src/imgRequest.cpp
@@ -175,17 +175,20 @@ nsresult imgRequest::AddProxy(imgRequest
   return mObservers.AppendElementUnlessExists(proxy) ?
     NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, PRBool aNotify)
 {
   LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequest::RemoveProxy", "proxy", proxy);
 
-  mObservers.RemoveElement(proxy);
+  if (!mObservers.RemoveElement(proxy)) {
+    // Not one of our proxies; we're done
+    return NS_OK;
+  }
 
   /* Check mState below before we potentially call Cancel() below. Since
      Cancel() may result in OnStopRequest being called back before Cancel()
      returns, leaving mState in a different state then the one it was in at
      this point.
    */
 
   if (aNotify) {
--- a/modules/libpr0n/src/imgRequestProxy.cpp
+++ b/modules/libpr0n/src/imgRequestProxy.cpp
@@ -221,27 +221,36 @@ imgRequestProxy::DoCancel(nsresult statu
   mOwner->RemoveProxy(this, status, PR_FALSE);
 
   NullOutListener();
 }
 
 /* void cancelAndForgetObserver (in nsresult aStatus); */
 NS_IMETHODIMP imgRequestProxy::CancelAndForgetObserver(nsresult aStatus)
 {
-  if (mCanceled || !mOwner)
+  if (!mOwner)
+    return NS_ERROR_FAILURE;
+
+  // If mCanceled is true but mListener is non-null, that means
+  // someone called Cancel() on us but the imgCancelRunnable is still
+  // pending.  We still need to null out mListener before returning
+  // from this function in this case.  That means we want to do the
+  // RemoveProxy call right now, because we need to deliver the
+  // onStopRequest.
+  if (mCanceled && !mListener)
     return NS_ERROR_FAILURE;
 
   LOG_SCOPE(gImgLog, "imgRequestProxy::CancelAndForgetObserver");
 
   mCanceled = PR_TRUE;
 
   // Now cheat and make sure our removal from loadgroup happens async
   PRBool oldIsInLoadGroup = mIsInLoadGroup;
   mIsInLoadGroup = PR_FALSE;
-  
+
   // Passing false to aNotify means that mListener will still get
   // OnStopRequest, if needed.
   mOwner->RemoveProxy(this, aStatus, PR_FALSE);
 
   mIsInLoadGroup = oldIsInLoadGroup;
 
   if (mIsInLoadGroup) {
     nsCOMPtr<nsIRunnable> ev =