From ee15761a5073435d10aba49b3a11245e8331635d Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Thu, 15 Mar 2018 19:18:30 +0100 Subject: Bug 1311798: Align XMLHttpRequest abort() with the spec --- dom/xhr/XMLHttpRequestMainThread.cpp | 69 ++++++++++++++++++++++++++++++++++-- dom/xhr/XMLHttpRequestMainThread.h | 5 +++ dom/xhr/XMLHttpRequestWorker.cpp | 7 +++- dom/xhr/XMLHttpRequestWorker.h | 7 ++-- 4 files changed, 82 insertions(+), 6 deletions(-) (limited to 'dom/xhr') diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index a47a01aa0..4fd34a993 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -1081,10 +1081,75 @@ XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType) } 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 diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index c9bcddf99..68499874a 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -396,6 +396,11 @@ public: aRv = SendInternal(&body); } + void + RequestErrorSteps(const ProgressEventType aEventType, + const nsresult aOptionalException, + ErrorResult& aRv); + void Abort() { ErrorResult rv; diff --git a/dom/xhr/XMLHttpRequestWorker.cpp b/dom/xhr/XMLHttpRequestWorker.cpp index f61383baf..4869d0099 100644 --- a/dom/xhr/XMLHttpRequestWorker.cpp +++ b/dom/xhr/XMLHttpRequestWorker.cpp @@ -1669,7 +1669,9 @@ XMLHttpRequestWorker::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv) // 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; } @@ -1811,6 +1813,8 @@ XMLHttpRequestWorker::SendInternal(SendRunnable* aRunnable, 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. @@ -1837,6 +1841,7 @@ XMLHttpRequestWorker::SendInternal(SendRunnable* aRunnable, if (!autoSyncLoop->Run() && !aRv.Failed()) { aRv.Throw(NS_ERROR_FAILURE); } + mStateData.mFlagSend = false; } bool diff --git a/dom/xhr/XMLHttpRequestWorker.h b/dom/xhr/XMLHttpRequestWorker.h index 90232fe85..c6647f8f3 100644 --- a/dom/xhr/XMLHttpRequestWorker.h +++ b/dom/xhr/XMLHttpRequestWorker.h @@ -34,15 +34,16 @@ public: uint32_t mStatus; nsCString mStatusText; uint16_t mReadyState; + bool mFlagSend; JS::Heap 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); -- cgit v1.2.3