merge
authorTed Mielczarek <ted.mielczarek@gmail.com>
Mon, 21 Nov 2011 14:00:15 -0500
changeset 82229 15ce8c86aa562559b7521116c3da46dde19a5fe9
parent 82228 8dfc790e62e86449955c997a839c82b535775ae4 (current diff)
parent 82226 c531673c8d2f063b72c10bcae1f591a256c3f7e5 (diff)
child 82230 deed0cafecc729fb1b5aec84ee419128d6dff387
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1209,26 +1209,26 @@ nsXMLHttpRequest::Abort()
   PRUint32 responseLength = mResponseBody.Length();
   ResetResponse();
   mState |= XML_HTTP_REQUEST_ABORTED;
   
   if (!(mState & (XML_HTTP_REQUEST_UNSENT |
                   XML_HTTP_REQUEST_OPENED |
                   XML_HTTP_REQUEST_DONE))) {
     ChangeState(XML_HTTP_REQUEST_DONE, true);
-  }
-
-  if (!(mState & XML_HTTP_REQUEST_SYNCLOOPING)) {
-    NS_NAMED_LITERAL_STRING(abortStr, ABORT_STR);
-    DispatchProgressEvent(this, abortStr, mLoadLengthComputable, responseLength,
-                          mLoadTotal);
-    if (mUpload && !mUploadComplete) {
-      mUploadComplete = true;
-      DispatchProgressEvent(mUpload, abortStr, true, mUploadTransferred,
-                            mUploadTotal);
+
+    if (!(mState & XML_HTTP_REQUEST_SYNCLOOPING)) {
+      NS_NAMED_LITERAL_STRING(abortStr, ABORT_STR);
+      DispatchProgressEvent(this, abortStr, mLoadLengthComputable, responseLength,
+                            mLoadTotal);
+      if (mUpload && !mUploadComplete) {
+        mUploadComplete = true;
+        DispatchProgressEvent(mUpload, abortStr, true, mUploadTransferred,
+                              mUploadTotal);
+      }
     }
   }
 
   // The ChangeState call above calls onreadystatechange handlers which
   // if they load a new url will cause nsXMLHttpRequest::Open to clear
   // the abort state bit. If this occurs we're not uninitialized (bug 361773).
   if (mState & XML_HTTP_REQUEST_ABORTED) {
     ChangeState(XML_HTTP_REQUEST_UNSENT, false);  // IE seems to do it
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -523,16 +523,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug684671.html \
 		test_bug685798.html \
 		test_bug686449.xhtml \
 		test_bug690056.html \
 		test_bug692434.html \
 		file_bug692434.xml \
 		test_bug693875.html \
 		test_nodelist_holes.html \
+		test_xhr_abort_after_load.html \
 		$(NULL)
 
 _CHROME_FILES =	\
 		test_bug357450.js \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
--- a/content/base/test/test_bug482935.html
+++ b/content/base/test/test_bug482935.html
@@ -22,42 +22,39 @@ function clearCache() {
 // after it has reached state 4
 function testCancelInPhase4() {
 
   clearCache();
 
   // First request - should be loaded from server
   var xhr = new XMLHttpRequest();
   xhr.addEventListener("readystatechange", function(e) {
-    if (xhr.readyState >= 4) {
-      xhr.addEventListener("abort", function() {
-        setTimeout(function() {
-          // This request was cancelled, so the responseText should be empty string
-          is(xhr.responseText, "", "Expected empty response to cancelled request");
-
-          // Second request - should be found in cache
-          var xhr2 = new XMLHttpRequest();
+    if (xhr.readyState < xhr.DONE) return;
+    is(xhr.readyState, xhr.DONE, "wrong readyState");
+    xhr.abort();
+    SimpleTest.executeSoon(function() {
+      // This request was cancelled, so the responseText should be empty string
+      is(xhr.responseText, "", "Expected empty response to cancelled request");
 
-          xhr2.addEventListener("load", function() {
-            is(xhr2.responseText, "0", "Received fresh value for second request");
-            SimpleTest.finish();
-          }, false);
+      // Second request - should be found in cache
+      var xhr2 = new XMLHttpRequest();
 
-          xhr2.open("GET", url);
-          xhr2.setRequestHeader("X-Request", "1", false);
-
-          try { xhr2.send(); }
-          catch(e) {
-            is(xhr2.status, "200", "Exception!");
-          }
-        }, 0);
+      xhr2.addEventListener("load", function() {
+        is(xhr2.responseText, "0", "Received fresh value for second request");
+        SimpleTest.finish();
       }, false);
 
-      xhr.abort();
-    }
+      xhr2.open("GET", url);
+      xhr2.setRequestHeader("X-Request", "1", false);
+
+      try { xhr2.send(); }
+      catch(e) {
+        is(xhr2.status, "200", "Exception!");
+      }
+    });
   }, false);
 
   xhr.open("GET", url, true);
   xhr.setRequestHeader("X-Request", "0", false);
   try { xhr.send(); }
   catch(e) {
     is("Nothing", "Exception", "Boom: " + e);
   }
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_xhr_abort_after_load.html
@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test bug 482935</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="	/tests/SimpleTest/test.css" />
+</head>
+<body onload="onWindowLoad()">
+<script class="testbody" type="text/javascript">"use strict";
+SimpleTest.waitForExplicitFinish();
+
+var url = "file_XHR_pass1.xml";
+
+function onWindowLoad() {
+  runTest();
+}
+
+function runTest() {
+  var testFunctions = [
+    startTest1,
+    startTest2,
+    startTest3,
+  ];
+
+  function nextTest() {
+    if (testFunctions.length == 0) {
+      SimpleTest.finish();
+    }
+    (testFunctions.shift())();
+  }
+
+  nextTest();
+
+  var xhr;
+  function startTest1() {
+    xhr = new XMLHttpRequest();
+    xhr.onload = onLoad1;
+    xhr.open("GET", url);
+    xhr.send();
+  }
+
+  function onLoad1() {
+    is(xhr.readyState, xhr.DONE, "readyState should be DONE");
+    xhr.onabort = onAbort1;
+    xhr.abort();
+
+    function onAbort1(e) {
+      ok(false, e.type + " event should not be fired!");
+    }
+
+    is(xhr.readyState, xhr.UNSENT, "readyState should be UNSENT");
+    nextTest();
+  }
+
+  function startTest2() {
+    xhr = new XMLHttpRequest();
+    xhr.onloadstart = onAfterSend;
+    xhr.open("GET", url);
+    xhr.send();
+  }
+
+  function startTest3() {
+    xhr = new XMLHttpRequest();
+    xhr.open("GET", url);
+    xhr.send();
+    onAfterSend();
+  }
+
+  function onAfterSend() {
+    is(xhr.readyState, xhr.OPENED, "readyState should be OPENED");
+    var sent = false;
+    try {
+      xhr.send();
+    } catch (e) {
+      sent = true;
+    }
+    ok(sent, "send() flag should be set");
+    var aborted = false;
+    xhr.onabort = onAbort2;
+    xhr.abort();
+
+    function onAbort2() {
+      is(xhr.readyState, xhr.DONE, "readyState should be DONE");
+      aborted = true;
+    }
+
+    ok(aborted, "abort event should be fired");
+    is(xhr.readyState, xhr.UNSENT, "readyState should be UNSENT");
+    nextTest();
+  }
+}
+
+</script>
+</body>
+</html>
--- a/dom/workers/XMLHttpRequestPrivate.cpp
+++ b/dom/workers/XMLHttpRequestPrivate.cpp
@@ -561,16 +561,29 @@ public:
     else if (mType.EqualsASCII(sEventStrings[STRING_loadend])) {
       if (mUploadEvent) {
         mProxy->mSeenUploadLoadStart = false;
       }
       else {
         mProxy->mSeenLoadStart = false;
       }
     }
+    else if (mType.EqualsASCII(sEventStrings[STRING_abort])) {
+      if ((mUploadEvent && !mProxy->mSeenUploadLoadStart) ||
+          (!mUploadEvent && !mProxy->mSeenLoadStart)) {
+        // We've already dispatched premature abort events.
+        return true;
+      }
+    }
+    else if (mType.EqualsASCII(sEventStrings[STRING_readystatechange])) {
+      if (mReadyState == 4 && !mUploadEvent && !mProxy->mSeenLoadStart) {
+        // We've already dispatched premature abort events.
+        return true;
+      }
+    }
 
     if (mProgressEvent) {
       // Cache these for premature abort events.
       if (mUploadEvent) {
         mProxy->mLastUploadLengthComputable = mLengthComputable;
         mProxy->mLastUploadLoaded = mLoaded;
         mProxy->mLastUploadTotal = mTotal;
       }
@@ -1528,17 +1541,17 @@ XMLHttpRequestPrivate::Abort(JSContext* 
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   if (mCanceled) {
     return false;
   }
 
   if (mProxy) {
-    if (!MaybeDispatchPrematureAbortEvents(aCx, false)) {
+    if (!MaybeDispatchPrematureAbortEvents(aCx)) {
       return false;
     }
   }
   else {
     return true;
   }
 
   mProxy->mOuterChannelId++;
@@ -1614,17 +1627,17 @@ XMLHttpRequestPrivate::Open(JSContext* a
 
   nsDependentJSString method, url, user, password;
   if (!method.init(aCx, aMethod) || !url.init(aCx, aURL) ||
       !user.init(aCx, aUser) || !password.init(aCx, aPassword)) {
     return false;
   }
 
   if (mProxy) {
-    if (!MaybeDispatchPrematureAbortEvents(aCx, true)) {
+    if (!MaybeDispatchPrematureAbortEvents(aCx)) {
       return false;
     }
   }
   else {
     mProxy = new Proxy(this);
   }
 
   mProxy->mOuterChannelId++;
@@ -1826,18 +1839,17 @@ XMLHttpRequestPrivate::OverrideMimeType(
 
   nsRefPtr<OverrideMimeTypeRunnable> runnable =
     new OverrideMimeTypeRunnable(mWorkerPrivate, mProxy, 
                                  NS_ConvertUTF16toUTF8(mimeType));
   return runnable->Dispatch(aCx);
 }
 
 bool
-XMLHttpRequestPrivate::MaybeDispatchPrematureAbortEvents(JSContext* aCx,
-                                                         bool aFromOpen)
+XMLHttpRequestPrivate::MaybeDispatchPrematureAbortEvents(JSContext* aCx)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   NS_ASSERTION(mProxy, "Must have a proxy here!");
 
   xhr::StateData state = {
     JSVAL_VOID, JSVAL_VOID, JSVAL_VOID, INT_TO_JSVAL(4), JSVAL_VOID,
     false, false, false, false, false
   };
@@ -1860,21 +1872,19 @@ XMLHttpRequestPrivate::MaybeDispatchPrem
     NS_ASSERTION(target, "Must have a target!");
 
     if (!xhr::UpdateXHRState(aCx, target, false, state) ||
         !DispatchPrematureAbortEvent(aCx, target, STRING_readystatechange,
                                      false)) {
       return false;
     }
 
-    if (aFromOpen) {
-      if (!DispatchPrematureAbortEvent(aCx, target, STRING_abort, false) ||
-          !DispatchPrematureAbortEvent(aCx, target, STRING_loadend, false)) {
-        return false;
-      }
+    if (!DispatchPrematureAbortEvent(aCx, target, STRING_abort, false) ||
+        !DispatchPrematureAbortEvent(aCx, target, STRING_loadend, false)) {
+      return false;
     }
 
     mProxy->mSeenLoadStart = false;
   }
 
   return true;
 }
 
--- a/dom/workers/XMLHttpRequestPrivate.h
+++ b/dom/workers/XMLHttpRequestPrivate.h
@@ -150,17 +150,17 @@ public:
 private:
   void
   ReleaseProxy();
 
   bool
   RootJSObject(JSContext* aCx);
 
   bool
-  MaybeDispatchPrematureAbortEvents(JSContext* aCx, bool aFromOpen);
+  MaybeDispatchPrematureAbortEvents(JSContext* aCx);
 
   bool
   DispatchPrematureAbortEvent(JSContext* aCx, JSObject* aTarget,
                               PRUint64 aEventType, bool aUploadTarget);
 
   bool
   SendInProgress() const
   {
--- a/layout/base/nsImageLoader.cpp
+++ b/layout/base/nsImageLoader.cpp
@@ -101,20 +101,24 @@ nsImageLoader::Destroy()
     list = todestroy->mNextLoader;
     todestroy->mNextLoader = nsnull;
     todestroy->Destroy();
   }
 
   if (mRequest && mFrame) {
     nsLayoutUtils::DeregisterImageRequest(mFrame->PresContext(), mRequest,
                                           &mRequestRegistered);
+  }
+
+  mFrame = nsnull;
+
+  if (mRequest) {
     mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
   }
 
-  mFrame = nsnull;
   mRequest = nsnull;
 }
 
 nsresult
 nsImageLoader::Load(imgIRequest *aImage)
 {
   NS_ASSERTION(!mRequest, "can't reuse image loaders");
   NS_ASSERTION(mFrame, "not initialized");