Bug 1311798 - Align XMLHttpRequest.abort() with the spec. r=baku
authorThomas Wisniewski <wisniewskit@gmail.com>
Mon, 21 Nov 2016 01:30:00 -0500
changeset 368701 ca8475c0038cc2b90a9b71d8bc6e22c45c2e6818
parent 368700 21c25e0a134b72f5b5096050995e491074b41ff4
child 368702 6750f9bd442249d8f48cfb10c664ffcab4d5c144
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1311798
milestone53.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
Bug 1311798 - Align XMLHttpRequest.abort() with the spec. r=baku
dom/xhr/XMLHttpRequestMainThread.cpp
dom/xhr/XMLHttpRequestMainThread.h
dom/xhr/XMLHttpRequestWorker.cpp
dom/xhr/XMLHttpRequestWorker.h
testing/web-platform/meta/XMLHttpRequest/abort-during-open.htm.ini
testing/web-platform/meta/XMLHttpRequest/abort-during-open.worker.js.ini
testing/web-platform/meta/XMLHttpRequest/abort-event-abort.htm.ini
testing/web-platform/meta/XMLHttpRequest/send-data-unexpected-tostring.htm.ini
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -1059,20 +1059,85 @@ XMLHttpRequestMainThread::CloseRequestWi
   if (mFlagAborted) {
     ChangeState(State::unsent, false);  // IE seems to do it
   }
 
   mFlagSyncLooping = false;
 }
 
 void
-XMLHttpRequestMainThread::Abort(ErrorResult& arv)
+XMLHttpRequestMainThread::RequestErrorSteps(const ProgressEventType aEventType,
+                                            const nsresult aOptionalException,
+                                            ErrorResult& aRv)
+{
+  // Step 1
+  mState = State::done;
+
+  StopProgressEventTimer();
+
+  // Step 2
+  mFlagSend = false;
+
+  // Step 3
+  ResetResponse();
+
+  // If we're in the destructor, don't risk dispatching an event.
+  if (mFlagDeleted) {
+    mFlagSyncLooping = false;
+    return;
+  }
+
+  // Step 4
+  if (mFlagSynchronous && NS_FAILED(aOptionalException)) {
+    aRv.Throw(aOptionalException);
+    return;
+  }
+
+  // Step 5
+  FireReadystatechangeEvent();
+
+  // Step 6
+  if (mUpload && !mUploadComplete) {
+
+    // Step 6-1
+    mUploadComplete = true;
+
+    // Step 6-2
+    if (mFlagHadUploadListenersOnSend) {
+
+      // Steps 6-3, 6-4 (loadend is fired for us)
+      DispatchProgressEvent(mUpload, aEventType, 0, -1);
+    }
+  }
+
+  // Steps 7 and 8 (loadend is fired for us)
+  DispatchProgressEvent(this, aEventType, 0, -1);
+}
+
+void
+XMLHttpRequestMainThread::Abort(ErrorResult& aRv)
 {
   mFlagAborted = true;
-  CloseRequestWithError(ProgressEventType::abort);
+
+  // Step 1
+  CloseRequest();
+
+  // Step 2
+  if ((mState == State::opened && mFlagSend) ||
+       mState == State::headers_received ||
+       mState == State::loading) {
+    RequestErrorSteps(ProgressEventType::abort, NS_OK, aRv);
+  }
+
+  // Step 3
+  if (mState == State::done) {
+    ChangeState(State::unsent, false); // no ReadystateChange event
+  }
+
+  mFlagSyncLooping = false;
 }
 
 NS_IMETHODIMP
 XMLHttpRequestMainThread::SlowAbort()
 {
   Abort();
   return NS_OK;
 }
--- a/dom/xhr/XMLHttpRequestMainThread.h
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -391,16 +391,21 @@ public:
   Send(JSContext* aCx, nsIInputStream* aStream, ErrorResult& aRv) override
   {
     NS_ASSERTION(aStream, "Null should go to string version");
     RequestBody<nsIInputStream> body(aStream);
     aRv = SendInternal(&body);
   }
 
   void
+  RequestErrorSteps(const ProgressEventType aEventType,
+                    const nsresult aOptionalException,
+                    ErrorResult& aRv);
+
+  void
   Abort() {
     ErrorResult rv;
     Abort(rv);
     MOZ_ASSERT(!rv.Failed());
   }
 
   virtual void
   Abort(ErrorResult& aRv) override;
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -1664,17 +1664,19 @@ XMLHttpRequestWorker::MaybePin(ErrorResu
 void
 XMLHttpRequestWorker::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   MOZ_ASSERT(mProxy);
 
   // Only send readystatechange event when state changed.
   bool isStateChanged = false;
-  if (mStateData.mReadyState != 4) {
+  if ((mStateData.mReadyState == 1 && mStateData.mFlagSend) ||
+      mStateData.mReadyState == 2 ||
+      mStateData.mReadyState == 3) {
     isStateChanged = true;
     mStateData.mReadyState = 4;
   }
 
   if (mProxy->mSeenUploadLoadStart) {
     MOZ_ASSERT(mUpload);
 
     DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("abort"), true,
@@ -1806,16 +1808,18 @@ XMLHttpRequestWorker::SendInternal(SendR
     syncLoopTarget = autoSyncLoop->EventTarget();
   }
 
   mProxy->mOuterChannelId++;
 
   aRunnable->SetSyncLoopTarget(syncLoopTarget);
   aRunnable->SetHaveUploadListeners(hasUploadListeners);
 
+  mStateData.mFlagSend = true;
+
   aRunnable->Dispatch(aRv);
   if (aRv.Failed()) {
     // Dispatch() may have spun the event loop and we may have already unrooted.
     // If so we don't want autoUnpin to try again.
     if (!mRooted) {
       autoUnpin.Clear();
     }
     return;
@@ -1832,16 +1836,17 @@ XMLHttpRequestWorker::SendInternal(SendR
   // Don't clobber an existing exception that we may have thrown on aRv
   // already... though can there really be one?  In any case, it seems to me
   // that this autoSyncLoop->Run() can never fail, since the StopSyncLoop call
   // for it will come from ProxyCompleteRunnable and that always passes true for
   // the second arg.
   if (!autoSyncLoop->Run() && !aRv.Failed()) {
     aRv.Throw(NS_ERROR_FAILURE);
   }
+  mStateData.mFlagSend = false;
 }
 
 bool
 XMLHttpRequestWorker::Notify(Status aStatus)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   if (aStatus >= Canceling && !mCanceled) {
--- a/dom/xhr/XMLHttpRequestWorker.h
+++ b/dom/xhr/XMLHttpRequestWorker.h
@@ -28,25 +28,26 @@ class XMLHttpRequestWorker final : publi
 public:
   struct StateData
   {
     XMLHttpRequestStringSnapshot mResponseText;
     nsString mResponseURL;
     uint32_t mStatus;
     nsCString mStatusText;
     uint16_t mReadyState;
+    bool mFlagSend;
     JS::Heap<JS::Value> mResponse;
     nsresult mResponseTextResult;
     nsresult mStatusResult;
     nsresult mResponseResult;
 
     StateData()
-    : mStatus(0), mReadyState(0), mResponse(JS::UndefinedValue()),
-      mResponseTextResult(NS_OK), mStatusResult(NS_OK),
-      mResponseResult(NS_OK)
+    : mStatus(0), mReadyState(0), mFlagSend(false),
+      mResponse(JS::UndefinedValue()), mResponseTextResult(NS_OK),
+      mStatusResult(NS_OK), mResponseResult(NS_OK)
     { }
 
     void trace(JSTracer* trc);
   };
 
 private:
   RefPtr<XMLHttpRequestUpload> mUpload;
   workers::WorkerPrivate* mWorkerPrivate;
deleted file mode 100644
--- a/testing/web-platform/meta/XMLHttpRequest/abort-during-open.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[abort-during-open.htm]
-  type: testharness
-  [XMLHttpRequest: abort() during OPEN]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/XMLHttpRequest/abort-during-open.worker.js.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[abort-during-open.worker.html]
-  type: testharness
-  [Untitled]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/XMLHttpRequest/abort-event-abort.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[abort-event-abort.htm]
-  type: testharness
-  [XMLHttpRequest: The abort() method: do not fire abort event in OPENED state when send() flag is unset.]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/XMLHttpRequest/send-data-unexpected-tostring.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[send-data-unexpected-tostring.htm]
-  type: testharness
-  [abort() called from data stringification]
-    expected: FAIL
-