Bug 792808 - use XMLHttpRequestBinding::STATE consts in the XHR subclasses and remove XMLHttpRequest::State enum class; r?baku draft
authorThomas Wisniewski <wisniewskit@gmail.com>
Sun, 19 Nov 2017 23:00:10 -0500
changeset 756158 3cb8e288742229061865a9bb224e7514a2364713
parent 756157 75903afe8064aeb0dcfe20a969f080d5263d63a1
push id99394
push userwisniewskit@gmail.com
push dateFri, 16 Feb 2018 14:37:01 +0000
reviewersbaku
bugs792808
milestone60.0a1
Bug 792808 - use XMLHttpRequestBinding::STATE consts in the XHR subclasses and remove XMLHttpRequest::State enum class; r?baku MozReview-Commit-ID: HcP9oEzOnub
dom/xhr/XMLHttpRequestMainThread.cpp
dom/xhr/XMLHttpRequestMainThread.h
dom/xhr/XMLHttpRequestWorker.cpp
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -193,17 +193,17 @@ static void AddLoadFlags(nsIRequest *req
 bool
 XMLHttpRequestMainThread::sDontWarnAboutSyncXHR = false;
 
 XMLHttpRequestMainThread::XMLHttpRequestMainThread()
   : mResponseBodyDecodedPos(0),
     mResponseCharset(nullptr),
     mResponseType(XMLHttpRequestResponseType::_empty),
     mRequestObserver(nullptr),
-    mState(State::unsent),
+    mState(XMLHttpRequestBinding::UNSENT),
     mStyleBackend(StyleBackendType::None),
     mFlagSynchronous(false), mFlagAborted(false), mFlagParseBody(false),
     mFlagSyncLooping(false), mFlagBackgroundRequest(false),
     mFlagHadUploadListenersOnSend(false), mFlagACwithCredentials(false),
     mFlagTimedOut(false), mFlagDeleted(false), mFlagSend(false),
     mUploadTransferred(0), mUploadTotal(0), mUploadComplete(true),
     mProgressSinceLastProgressEvent(false),
     mRequestSentTime(0), mTimeoutMilliseconds(0),
@@ -225,18 +225,18 @@ XMLHttpRequestMainThread::XMLHttpRequest
 {
   mozilla::HoldJSObjects(this);
 }
 
 XMLHttpRequestMainThread::~XMLHttpRequestMainThread()
 {
   mFlagDeleted = true;
 
-  if ((mState == State::opened && mFlagSend) ||
-      mState == State::loading) {
+  if ((mState == XMLHttpRequestBinding::OPENED && mFlagSend) ||
+      mState == XMLHttpRequestBinding::LOADING) {
     Abort();
   }
 
   mParseEndListener = nullptr;
 
   MOZ_ASSERT(!mFlagSyncLooping, "we rather crash than hang");
   mFlagSyncLooping = false;
 
@@ -450,17 +450,17 @@ XMLHttpRequestMainThread::GetResponseXML
       mResponseType != XMLHttpRequestResponseType::Document) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSEXML);
     return nullptr;
   }
   if (mWarnAboutSyncHtml) {
     mWarnAboutSyncHtml = false;
     LogMessage("HTMLSyncXHRWarning", GetOwner());
   }
-  if (mState != State::done) {
+  if (mState != XMLHttpRequestBinding::DONE) {
     return nullptr;
   }
   return mResponseXML;
 }
 
 /*
  * This piece copied from XMLDocument, we try to get the charset
  * from HTTP headers.
@@ -564,17 +564,18 @@ XMLHttpRequestMainThread::GetResponseTex
   aSnapshot.Reset();
 
   if (mResponseType != XMLHttpRequestResponseType::_empty &&
       mResponseType != XMLHttpRequestResponseType::Text) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSETEXT);
     return;
   }
 
-  if (mState != State::loading && mState != State::done) {
+  if (mState != XMLHttpRequestBinding::LOADING &&
+      mState != XMLHttpRequestBinding::DONE) {
     return;
   }
 
   // Main Fetch step 18 requires to ignore body for head/connect methods.
   if (mRequestMethod.EqualsLiteral("HEAD") ||
       mRequestMethod.EqualsLiteral("CONNECT")) {
     return;
   }
@@ -595,17 +596,17 @@ XMLHttpRequestMainThread::GetResponseTex
   aRv = AppendToResponseText(mResponseBody.get() + mResponseBodyDecodedPos,
                              mResponseBody.Length() - mResponseBodyDecodedPos);
   if (aRv.Failed()) {
     return;
   }
 
   mResponseBodyDecodedPos = mResponseBody.Length();
 
-  if (mState == State::done) {
+  if (mState == XMLHttpRequestBinding::DONE) {
     // Free memory buffer which we no longer need
     mResponseBody.Truncate();
     mResponseBodyDecodedPos = 0;
   }
 
   mResponseText.CreateSnapshot(aSnapshot);
 }
 
@@ -632,23 +633,25 @@ XMLHttpRequestMainThread::CreateResponse
 }
 
 void
 XMLHttpRequestMainThread::SetResponseType(XMLHttpRequestResponseType aResponseType,
                                           ErrorResult& aRv)
 {
   NOT_CALLABLE_IN_SYNC_SEND_RV
 
-  if (mState == State::loading || mState == State::done) {
+  if (mState == XMLHttpRequestBinding::LOADING ||
+      mState == XMLHttpRequestBinding::DONE) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_LOADING_OR_DONE);
     return;
   }
 
   // sync request is not allowed setting responseType in window context
-  if (HasOrHasHadOwner() && mState != State::unsent && mFlagSynchronous) {
+  if (HasOrHasHadOwner() &&
+      mState != XMLHttpRequestBinding::UNSENT && mFlagSynchronous) {
     LogMessage("ResponseTypeSyncXHRWarning", GetOwner());
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_XHR_TIMEOUT_AND_RESPONSETYPE_UNSUPPORTED_FOR_SYNC);
     return;
   }
 
   if (mFlagSynchronous &&
       aResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_CHUNKED_RESPONSETYPES_UNSUPPORTED_FOR_SYNC);
@@ -683,17 +686,17 @@ XMLHttpRequestMainThread::GetResponse(JS
     }
     return;
   }
 
   case XMLHttpRequestResponseType::Arraybuffer:
   case XMLHttpRequestResponseType::Moz_chunked_arraybuffer:
   {
     if (!(mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
-          mState == State::done) &&
+          mState == XMLHttpRequestBinding::DONE) &&
         !(mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer &&
           mInLoadProgressEvent)) {
       aResponse.setNull();
       return;
     }
 
     if (!mResultArrayBuffer) {
       mResultArrayBuffer = mArrayBufferBuilder.getArrayBuffer(aCx);
@@ -702,42 +705,42 @@ XMLHttpRequestMainThread::GetResponse(JS
         return;
       }
     }
     aResponse.setObject(*mResultArrayBuffer);
     return;
   }
   case XMLHttpRequestResponseType::Blob:
   {
-    if (mState != State::done) {
+    if (mState != XMLHttpRequestBinding::DONE) {
       aResponse.setNull();
       return;
     }
 
     if (!mResponseBlob) {
       aResponse.setNull();
       return;
     }
 
     GetOrCreateDOMReflector(aCx, mResponseBlob, aResponse);
     return;
   }
   case XMLHttpRequestResponseType::Document:
   {
-    if (!mResponseXML || mState != State::done) {
+    if (!mResponseXML || mState != XMLHttpRequestBinding::DONE) {
       aResponse.setNull();
       return;
     }
 
     aRv = nsContentUtils::WrapNative(aCx, mResponseXML, aResponse);
     return;
   }
   case XMLHttpRequestResponseType::Json:
   {
-    if (mState != State::done) {
+    if (mState != XMLHttpRequestBinding::DONE) {
       aResponse.setNull();
       return;
     }
 
     if (mResultJSON.isUndefined()) {
       aRv = CreateResponseParsedJSON(aCx);
       TruncateResponseText();
       if (aRv.Failed()) {
@@ -789,17 +792,18 @@ XMLHttpRequestMainThread::IsDeniedCrossS
   return false;
 }
 
 void
 XMLHttpRequestMainThread::GetResponseURL(nsAString& aUrl)
 {
   aUrl.Truncate();
 
-  if ((mState == State::unsent || mState == State::opened) || !mChannel) {
+  if ((mState == XMLHttpRequestBinding::UNSENT ||
+       mState == XMLHttpRequestBinding::OPENED) || !mChannel) {
     return;
   }
 
   // Make sure we don't leak responseURL information from denied cross-site
   // requests.
   if (IsDeniedCrossSiteCORSRequest()) {
     return;
   }
@@ -820,17 +824,18 @@ uint32_t
 XMLHttpRequestMainThread::GetStatus(ErrorResult& aRv)
 {
   // Make sure we don't leak status information from denied cross-site
   // requests.
   if (IsDeniedCrossSiteCORSRequest()) {
     return 0;
   }
 
-  if (mState == State::unsent || mState == State::opened) {
+  if (mState == XMLHttpRequestBinding::UNSENT ||
+      mState == XMLHttpRequestBinding::OPENED) {
     return 0;
   }
 
   if (mErrorLoad != ErrorType::eOK) {
     // Let's simulate the http protocol for jar/app requests:
     nsCOMPtr<nsIJARChannel> jarChannel = GetCurrentJARChannel();
     if (jarChannel) {
       nsresult status;
@@ -873,17 +878,18 @@ XMLHttpRequestMainThread::GetStatusText(
   if (IsDeniedCrossSiteCORSRequest()) {
     return;
   }
 
   // Check the current XHR state to see if it is valid to obtain the statusText
   // value.  This check is to prevent the status text for redirects from being
   // available before all the redirects have been followed and HTTP headers have
   // been received.
-  if (mState == State::unsent || mState == State::opened) {
+  if (mState == XMLHttpRequestBinding::UNSENT ||
+      mState == XMLHttpRequestBinding::OPENED) {
     return;
   }
 
   if (mErrorLoad != ErrorType::eOK) {
     return;
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
@@ -891,18 +897,19 @@ XMLHttpRequestMainThread::GetStatusText(
     Unused << httpChannel->GetResponseStatusText(aStatusText);
   } else {
     aStatusText.AssignLiteral("OK");
   }
 }
 
 void
 XMLHttpRequestMainThread::TerminateOngoingFetch() {
-  if ((mState == State::opened && mFlagSend) ||
-      mState == State::headers_received || mState == State::loading) {
+  if ((mState == XMLHttpRequestBinding::OPENED && mFlagSend) ||
+      mState == XMLHttpRequestBinding::HEADERS_RECEIVED ||
+      mState == XMLHttpRequestBinding::LOADING) {
     CloseRequest();
   }
 }
 
 void
 XMLHttpRequestMainThread::CloseRequest()
 {
   mWaitingForOnStopRequest = false;
@@ -923,47 +930,47 @@ XMLHttpRequestMainThread::CloseRequestWi
   ResetResponse();
 
   // If we're in the destructor, don't risk dispatching an event.
   if (mFlagDeleted) {
     mFlagSyncLooping = false;
     return;
   }
 
-  if (mState != State::unsent &&
-      !(mState == State::opened && !mFlagSend) &&
-      mState != State::done) {
-    ChangeState(State::done, true);
+  if (mState != XMLHttpRequestBinding::UNSENT &&
+      !(mState == XMLHttpRequestBinding::OPENED && !mFlagSend) &&
+      mState != XMLHttpRequestBinding::DONE) {
+    ChangeState(XMLHttpRequestBinding::DONE, true);
 
     if (!mFlagSyncLooping) {
       if (mUpload && !mUploadComplete) {
         mUploadComplete = true;
         DispatchProgressEvent(mUpload, aType, 0, -1);
       }
       DispatchProgressEvent(this, aType, 0, -1);
     }
   }
 
   // The ChangeState call above calls onreadystatechange handlers which
   // if they load a new url will cause XMLHttpRequestMainThread::Open to clear
   // the abort state bit. If this occurs we're not uninitialized (bug 361773).
   if (mFlagAborted) {
-    ChangeState(State::unsent, false);  // IE seems to do it
+    ChangeState(XMLHttpRequestBinding::UNSENT, false);  // IE seems to do it
   }
 
   mFlagSyncLooping = false;
 }
 
 void
 XMLHttpRequestMainThread::RequestErrorSteps(const ProgressEventType aEventType,
                                             const nsresult aOptionalException,
                                             ErrorResult& aRv)
 {
   // Step 1
-  mState = State::done;
+  mState = XMLHttpRequestBinding::DONE;
 
   StopProgressEventTimer();
 
   // Step 2
   mFlagSend = false;
 
   // Step 3
   ResetResponse();
@@ -1012,25 +1019,25 @@ void
 XMLHttpRequestMainThread::AbortInternal(ErrorResult& aRv)
 {
   mFlagAborted = true;
 
   // Step 1
   TerminateOngoingFetch();
 
   // Step 2
-  if ((mState == State::opened && mFlagSend) ||
-       mState == State::headers_received ||
-       mState == State::loading) {
+  if ((mState == XMLHttpRequestBinding::OPENED && mFlagSend) ||
+       mState == XMLHttpRequestBinding::HEADERS_RECEIVED ||
+       mState == XMLHttpRequestBinding::LOADING) {
     RequestErrorSteps(ProgressEventType::abort, NS_OK, aRv);
   }
 
   // Step 3
-  if (mState == State::done) {
-    ChangeState(State::unsent, false); // no ReadystateChange event
+  if (mState == XMLHttpRequestBinding::DONE) {
+    ChangeState(XMLHttpRequestBinding::UNSENT, false); // no ReadystateChange event
   }
 
   mFlagSyncLooping = false;
 }
 
 /*Method that checks if it is safe to expose a header value to the client.
 It is used to check what headers are exposed for CORS requests.*/
 bool
@@ -1093,17 +1100,18 @@ XMLHttpRequestMainThread::GetAllResponse
                                                 ErrorResult& aRv)
 {
   NOT_CALLABLE_IN_SYNC_SEND_RV
 
   aResponseHeaders.Truncate();
 
   // If the state is UNSENT or OPENED,
   // return the empty string and terminate these steps.
-  if (mState == State::unsent || mState == State::opened) {
+  if (mState == XMLHttpRequestBinding::UNSENT ||
+      mState == XMLHttpRequestBinding::OPENED) {
     return;
   }
 
   if (mErrorLoad != ErrorType::eOK) {
     return;
   }
 
   if (nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel()) {
@@ -1154,17 +1162,18 @@ XMLHttpRequestMainThread::GetResponseHea
 
   _retval.SetIsVoid(true);
 
   nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
 
   if (!httpChannel) {
     // If the state is UNSENT or OPENED,
     // return null and terminate these steps.
-    if (mState == State::unsent || mState == State::opened) {
+    if (mState == XMLHttpRequestBinding::UNSENT ||
+        mState == XMLHttpRequestBinding::OPENED) {
       return;
     }
 
     // Even non-http channels supply content type and content length.
     // Remember we don't leak header information from denied cross-site
     // requests.
     nsresult status;
     if (!mChannel ||
@@ -1231,17 +1240,17 @@ XMLHttpRequestMainThread::GetLoadGroup()
   }
 
   return nullptr;
 }
 
 nsresult
 XMLHttpRequestMainThread::FireReadystatechangeEvent()
 {
-  MOZ_ASSERT(mState != State::unsent);
+  MOZ_ASSERT(mState != XMLHttpRequestBinding::UNSENT);
   RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
   event->InitEvent(kLiteralString_readystatechange, false, false);
   // We assume anyone who managed to call CreateReadystatechangeEvent is trusted
   event->SetTrusted(true);
   DispatchOrStoreEvent(this, event);
   return NS_OK;
 }
 
@@ -1364,18 +1373,18 @@ bool
 XMLHttpRequestMainThread::IsSystemXHR() const
 {
   return mIsSystem || nsContentUtils::IsSystemPrincipal(mPrincipal);
 }
 
 bool
 XMLHttpRequestMainThread::InUploadPhase() const
 {
-  // We're in the upload phase while our state is State::opened.
-  return mState == State::opened;
+  // We're in the upload phase while our state is OPENED.
+  return mState == XMLHttpRequestBinding::OPENED;
 }
 
 // This case is hit when the async parameter is outright omitted, which
 // should set it to true (and the username and password to null).
 void
 XMLHttpRequestMainThread::Open(const nsACString& aMethod, const nsAString& aUrl,
                                ErrorResult& aRv)
 {
@@ -1513,28 +1522,28 @@ XMLHttpRequestMainThread::Open(const nsA
 
   // Per spec we should only create the channel on send(), but we have internal
   // code that relies on the channel being created now, and that code is not
   // always IsSystemXHR(). However, we're not supposed to throw channel-creation
   // errors during open(), so we silently ignore those here.
   CreateChannel();
 
   // Step 12
-  if (mState != State::opened) {
-    mState = State::opened;
+  if (mState != XMLHttpRequestBinding::OPENED) {
+    mState = XMLHttpRequestBinding::OPENED;
     FireReadystatechangeEvent();
   }
 
   return NS_OK;
 }
 
 void
 XMLHttpRequestMainThread::SetOriginAttributes(const OriginAttributesDictionary& aAttrs)
 {
-  MOZ_ASSERT((mState == State::opened) && !mFlagSend);
+  MOZ_ASSERT((mState == XMLHttpRequestBinding::OPENED) && !mFlagSend);
 
   OriginAttributes attrs(aAttrs);
 
   nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
   MOZ_ASSERT(loadInfo);
   if (loadInfo) {
     loadInfo->SetOriginAttributes(attrs);
   }
@@ -1729,17 +1738,17 @@ private:
 
 NS_IMPL_ISUPPORTS0(FileCreationHandler)
 
 } // namespace
 
 void
 XMLHttpRequestMainThread::LocalFileToBlobCompleted(Blob* aBlob)
 {
-  MOZ_ASSERT(mState != State::done);
+  MOZ_ASSERT(mState != XMLHttpRequestBinding::DONE);
 
   mResponseBlob = aBlob;
   mBlobStorage = nullptr;
   NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
 
   ChangeStateToDone();
 }
 
@@ -1772,33 +1781,33 @@ XMLHttpRequestMainThread::OnDataAvailabl
 
       // The nsIStreamListener contract mandates us to read from the stream
       // before returning.
       uint32_t totalRead;
       rv =
         inStr->ReadSegments(DummyStreamReaderFunc, nullptr, count, &totalRead);
       NS_ENSURE_SUCCESS(rv, rv);
 
-      ChangeState(State::loading);
+      ChangeState(XMLHttpRequestBinding::LOADING);
 
       // Cancel() must be called with an error. We use
       // NS_ERROR_FILE_ALREADY_EXISTS to know that we've aborted the operation
       // just because we can retrieve the File from the channel directly.
       return request->Cancel(NS_ERROR_FILE_ALREADY_EXISTS);
     }
   }
 
   uint32_t totalRead;
   rv = inStr->ReadSegments(XMLHttpRequestMainThread::StreamReaderFunc,
                            (void*)this, count, &totalRead);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Fire the first progress event/loading state change
-  if (mState == State::headers_received) {
-    ChangeState(State::loading);
+  if (mState == XMLHttpRequestBinding::HEADERS_RECEIVED) {
+    ChangeState(XMLHttpRequestBinding::LOADING);
     if (!mFlagSynchronous) {
       DispatchProgressEvent(this, ProgressEventType::progress,
                             mLoadTransferred, mLoadTotal);
     }
     mProgressSinceLastProgressEvent = false;
   }
 
   if (!mFlagSynchronous && !mProgressTimerIsActive) {
@@ -1820,21 +1829,21 @@ XMLHttpRequestMainThread::OnStartRequest
   }
 
   if (request != mChannel) {
     // Can this still happen?
     return NS_OK;
   }
 
   // Don't do anything if we have been aborted
-  if (mState == State::unsent) {
+  if (mState == XMLHttpRequestBinding::UNSENT) {
     return NS_OK;
   }
 
-  /* Apparently, Abort() should set State::unsent.  See bug 361773.
+  /* Apparently, Abort() should set UNSENT.  See bug 361773.
      XHR2 spec says this is correct. */
   if (mFlagAborted) {
     NS_ERROR("Ugh, still getting data on an aborted XMLHttpRequest!");
 
     return NS_ERROR_UNEXPECTED;
   }
 
   // Don't do anything if we have timed out.
@@ -1866,17 +1875,17 @@ XMLHttpRequestMainThread::OnStartRequest
 
     mUploadComplete = true;
     DispatchProgressEvent(mUpload, ProgressEventType::load,
                           mUploadTotal, mUploadTotal);
   }
 
   mContext = ctxt;
   mFlagParseBody = true;
-  ChangeState(State::headers_received);
+  ChangeState(XMLHttpRequestBinding::HEADERS_RECEIVED);
 
   ResetResponse();
 
   if (!mOverrideMimeType.IsEmpty()) {
     channel->SetContentType(NS_ConvertUTF16toUTF8(mOverrideMimeType));
   }
 
   // Fallback to 'application/octet-stream'
@@ -2096,18 +2105,18 @@ XMLHttpRequestMainThread::OnStopRequest(
   if (mRequestObserver) {
     NS_ASSERTION(mFirstStartRequestSeen, "Inconsistent state!");
     mFirstStartRequestSeen = false;
     mRequestObserver->OnStopRequest(request, ctxt, status);
   }
 
   // make sure to notify the listener if we were aborted
   // XXX in fact, why don't we do the cleanup below in this case??
-  // State::unsent is for abort calls.  See OnStartRequest above.
-  if (mState == State::unsent || mFlagTimedOut) {
+  // UNSENT is for abort calls.  See OnStartRequest above.
+  if (mState == XMLHttpRequestBinding::UNSENT || mFlagTimedOut) {
     if (mXMLParserStreamListener)
       (void) mXMLParserStreamListener->OnStopRequest(request, ctxt, status);
     return NS_OK;
   }
 
   // Is this good enough here?
   if (mXMLParserStreamListener && mFlagParseBody) {
     mXMLParserStreamListener->OnStopRequest(request, ctxt, status);
@@ -2206,17 +2215,18 @@ XMLHttpRequestMainThread::OnStopRequest(
 
     mErrorLoad = ErrorType::eUnreachable;
     mResponseXML = nullptr;
   }
 
   // If we're uninitialized at this point, we encountered an error
   // earlier and listeners have already been notified. Also we do
   // not want to do this if we already completed.
-  if (mState == State::unsent || mState == State::done) {
+  if (mState == XMLHttpRequestBinding::UNSENT ||
+      mState == XMLHttpRequestBinding::DONE) {
     return NS_OK;
   }
 
   if (!mResponseXML) {
     mFlagParseBody = false;
 
     //We postpone the 'done' until the creation of the Blob is completed.
     if (!waitingForBlobCreation) {
@@ -2292,17 +2302,17 @@ XMLHttpRequestMainThread::ChangeStateToD
   if (!mFlagSynchronous &&
       (!mLoadTransferred || mProgressSinceLastProgressEvent)) {
     DispatchProgressEvent(this, ProgressEventType::progress,
                           mLoadTransferred, mLoadTotal);
     mProgressSinceLastProgressEvent = false;
   }
 
   // Per spec, fire readystatechange=4/done before final error events.
-  ChangeState(State::done, true);
+  ChangeState(XMLHttpRequestBinding::DONE, true);
 
   // Per spec, if we failed in the upload phase, fire a final error
   // and loadend events for the upload after readystatechange=4/done.
   if (!mFlagSynchronous && mUpload && !mUploadComplete) {
     DispatchProgressEvent(mUpload, ProgressEventType::error, 0, -1);
   }
 
   // Per spec, fire download's load/error and loadend events after
@@ -2655,17 +2665,17 @@ XMLHttpRequestMainThread::InitiateFetch(
     // ref to us to be extra safe.
     mChannel->SetNotificationCallbacks(mNotificationCallbacks);
     mChannel = nullptr;
 
     mErrorLoad = ErrorType::eChannelOpen;
 
     // Per spec, we throw on sync errors, but not async.
     if (mFlagSynchronous) {
-      mState = State::done;
+      mState = XMLHttpRequestBinding::DONE;
       return NS_ERROR_DOM_NETWORK_ERR;
     }
   }
 
   return NS_OK;
 }
 
 void
@@ -2742,17 +2752,17 @@ XMLHttpRequestMainThread::Send(JSContext
   }
 }
 
 nsresult
 XMLHttpRequestMainThread::MaybeSilentSendFailure(nsresult aRv)
 {
   // Per spec, silently fail on async request failures; throw for sync.
   if (mFlagSynchronous) {
-    mState = State::done;
+    mState = XMLHttpRequestBinding::DONE;
     return NS_ERROR_DOM_NETWORK_ERR;
   }
 
   // Defer the actual sending of async events just in case listeners
   // are attached after the send() method is called.
   Unused << NS_WARN_IF(NS_FAILED(
     DispatchToMainThread(NewRunnableMethod<ProgressEventType>(
       "dom::XMLHttpRequestMainThread::CloseRequestWithError",
@@ -2765,17 +2775,17 @@ XMLHttpRequestMainThread::MaybeSilentSen
 nsresult
 XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
 
   // Step 1
-  if (mState != State::opened) {
+  if (mState != XMLHttpRequestBinding::OPENED) {
     return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_BE_OPENED;
   }
 
   // Step 2
   if (mFlagSend) {
     return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING;
   }
 
@@ -2986,17 +2996,17 @@ XMLHttpRequestMainThread::IsLowercaseRes
 void
 XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName,
                                            const nsACString& aValue,
                                            ErrorResult& aRv)
 {
   NOT_CALLABLE_IN_SYNC_SEND_RV
 
   // Step 1
-  if (mState != State::opened) {
+  if (mState != XMLHttpRequestBinding::OPENED) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_BE_OPENED);
     return;
   }
 
   // Step 2
   if (mFlagSend) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING);
     return;
@@ -3036,17 +3046,18 @@ XMLHttpRequestMainThread::SetRequestHead
   }
 }
 
 void
 XMLHttpRequestMainThread::SetTimeout(uint32_t aTimeout, ErrorResult& aRv)
 {
   NOT_CALLABLE_IN_SYNC_SEND_RV
 
-  if (mFlagSynchronous && mState != State::unsent && HasOrHasHadOwner()) {
+  if (mFlagSynchronous &&
+      mState != XMLHttpRequestBinding::UNSENT && HasOrHasHadOwner()) {
     /* Timeout is not supported for synchronous requests with an owning window,
        per XHR2 spec. */
     LogMessage("TimeoutSyncXHRWarning", GetOwner());
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_XHR_TIMEOUT_AND_RESPONSETYPE_UNSUPPORTED_FOR_SYNC);
     return;
   }
 
   mTimeoutMilliseconds = aTimeout;
@@ -3077,17 +3088,17 @@ XMLHttpRequestMainThread::DispatchToMain
   return NS_DispatchToMainThread(Move(aRunnable));
 }
 
 void
 XMLHttpRequestMainThread::StartTimeoutTimer()
 {
   MOZ_ASSERT(mRequestSentTime,
              "StartTimeoutTimer mustn't be called before the request was sent!");
-  if (mState == State::done) {
+  if (mState == XMLHttpRequestBinding::DONE) {
     // do nothing!
     return;
   }
 
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
   }
 
@@ -3106,26 +3117,27 @@ XMLHttpRequestMainThread::StartTimeoutTi
     mTimeoutMilliseconds > elapsed ? mTimeoutMilliseconds - elapsed : 0,
     nsITimer::TYPE_ONE_SHOT
   );
 }
 
 uint16_t
 XMLHttpRequestMainThread::ReadyState() const
 {
-  return static_cast<uint16_t>(mState);
+  return mState;
 }
 
 void
 XMLHttpRequestMainThread::OverrideMimeType(const nsAString& aMimeType,
                                            ErrorResult& aRv)
 {
   NOT_CALLABLE_IN_SYNC_SEND_RV
 
-  if (mState == State::loading || mState == State::done) {
+  if (mState == XMLHttpRequestBinding::LOADING ||
+      mState == XMLHttpRequestBinding::DONE) {
     ResetResponse();
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_LOADING_OR_DONE);
     return;
   }
 
   mOverrideMimeType = aMimeType;
 }
 
@@ -3137,17 +3149,17 @@ XMLHttpRequestMainThread::MozBackgroundR
 
 nsresult
 XMLHttpRequestMainThread::SetMozBackgroundRequest(bool aMozBackgroundRequest)
 {
   if (!IsSystemXHR()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  if (mState != State::unsent) {
+  if (mState != XMLHttpRequestBinding::UNSENT) {
     // Can't change this while we're in the middle of something.
     return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING;
   }
 
   mFlagBackgroundRequest = aMozBackgroundRequest;
 
   return NS_OK;
 }
@@ -3170,39 +3182,41 @@ void
 XMLHttpRequestMainThread::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv)
 {
   NOT_CALLABLE_IN_SYNC_SEND_RV
 
   // Return error if we're already processing a request.  Note that we can't use
   // ReadyState() here, because it can't differentiate between "opened" and
   // "sent", so we use mState directly.
 
-  if ((mState != State::unsent && mState != State::opened) ||
+  if ((mState != XMLHttpRequestBinding::UNSENT &&
+       mState != XMLHttpRequestBinding::OPENED) ||
       mFlagSend || mIsAnon) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING);
     return;
   }
 
   mFlagACwithCredentials = aWithCredentials;
 }
 
 nsresult
-XMLHttpRequestMainThread::ChangeState(State aState, bool aBroadcast)
+XMLHttpRequestMainThread::ChangeState(uint16_t aState, bool aBroadcast)
 {
   mState = aState;
   nsresult rv = NS_OK;
 
-  if (aState != State::headers_received && aState != State::loading) {
+  if (aState != XMLHttpRequestBinding::HEADERS_RECEIVED &&
+      aState != XMLHttpRequestBinding::LOADING) {
     StopProgressEventTimer();
   }
 
 
   if (aBroadcast && (!mFlagSynchronous ||
-                     aState == State::opened ||
-                     aState == State::done)) {
+                     aState == XMLHttpRequestBinding::OPENED ||
+                     aState == XMLHttpRequestBinding::DONE)) {
     rv = FireReadystatechangeEvent();
   }
 
   return rv;
 }
 
 /////////////////////////////////////////////////////
 // nsIChannelEventSink methods:
@@ -3425,17 +3439,17 @@ bool
 XMLHttpRequestMainThread::MozSystem() const
 {
   return IsSystemXHR();
 }
 
 void
 XMLHttpRequestMainThread::HandleTimeoutCallback()
 {
-  if (mState == State::done) {
+  if (mState == XMLHttpRequestBinding::DONE) {
     NS_NOTREACHED("XMLHttpRequestMainThread::HandleTimeoutCallback with completed request");
     // do nothing!
     return;
   }
 
   mFlagTimedOut = true;
   CloseRequestWithError(ProgressEventType::timeout);
 }
@@ -3667,17 +3681,17 @@ void
 XMLHttpRequestMainThread::BlobStoreCompleted(MutableBlobStorage* aBlobStorage,
                                              Blob* aBlob, nsresult aRv)
 {
   // Ok, the state is changed...
   if (mBlobStorage != aBlobStorage || NS_FAILED(aRv)) {
     return;
   }
 
-  MOZ_ASSERT(mState != State::done);
+  MOZ_ASSERT(mState != XMLHttpRequestBinding::DONE);
 
   mResponseBlob = aBlob;
   mBlobStorage = nullptr;
 
   ChangeStateToDone();
 }
 
 NS_IMETHODIMP
--- a/dom/xhr/XMLHttpRequestMainThread.h
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -504,38 +504,28 @@ public:
   void BlobStoreCompleted(MutableBlobStorage* aBlobStorage,
                           Blob* aBlob,
                           nsresult aResult) override;
 
   void
   LocalFileToBlobCompleted(Blob* aBlob);
 
 protected:
-  // XHR states are meant to mirror the XHR2 spec:
-  //   https://xhr.spec.whatwg.org/#states
-  enum class State : uint8_t {
-    unsent,           // object has been constructed.
-    opened,           // open() has been successfully invoked.
-    headers_received, // redirects followed and response headers received.
-    loading,          // response body is being received.
-    done,             // data transfer concluded, whether success or error.
-  };
-
   nsresult DetectCharset();
   nsresult AppendToResponseText(const char * aBuffer, uint32_t aBufferLen);
   static nsresult StreamReaderFunc(nsIInputStream* in,
                                    void* closure,
                                    const char* fromRawSegment,
                                    uint32_t toOffset,
                                    uint32_t count,
                                    uint32_t *writeCount);
   nsresult CreateResponseParsedJSON(JSContext* aCx);
   // Change the state of the object with this. The broadcast argument
   // determines if the onreadystatechange listener should be called.
-  nsresult ChangeState(State aState, bool aBroadcast = true);
+  nsresult ChangeState(uint16_t aState, bool aBroadcast = true);
   already_AddRefed<nsILoadGroup> GetLoadGroup() const;
   nsIURI *GetBaseURI();
 
   already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel();
   already_AddRefed<nsIJARChannel> GetCurrentJARChannel();
 
   void TruncateResponseText();
 
@@ -691,17 +681,17 @@ protected:
   nsIRequestObserver* mRequestObserver;
 
   nsCOMPtr<nsIURI> mBaseURI;
   nsCOMPtr<nsILoadGroup> mLoadGroup;
 
   Maybe<ClientInfo> mClientInfo;
   Maybe<ServiceWorkerDescriptor> mController;
 
-  State mState;
+  uint16_t mState;
 
   StyleBackendType mStyleBackend;
 
   bool mFlagSynchronous;
   bool mFlagAborted;
   bool mFlagParseBody;
   bool mFlagSyncLooping;
   bool mFlagBackgroundRequest;
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -2183,20 +2183,20 @@ XMLHttpRequestWorker::Abort(ErrorResult&
 
   if (!mProxy) {
     return;
   }
 
   // Set our status to 0 and statusText to "" if we
   // will be aborting an ongoing fetch, so the upcoming
   // abort events we dispatch have the correct info.
-  if ((mStateData.mReadyState == State::opened && mStateData.mFlagSend) ||
-      mStateData.mReadyState == State::headers_received ||
-      mStateData.mReadyState == State::loading ||
-      mStateData.mReadyState == State::done) {
+  if ((mStateData.mReadyState == XMLHttpRequestBinding::OPENED && mStateData.mFlagSend) ||
+      mStateData.mReadyState == XMLHttpRequestBinding::HEADERS_RECEIVED ||
+      mStateData.mReadyState == XMLHttpRequestBinding::LOADING ||
+      mStateData.mReadyState == XMLHttpRequestBinding::DONE) {
     mStateData.mStatus = 0;
     mStateData.mStatusText.Truncate();
   }
 
   MaybeDispatchPrematureAbortEvents(aRv);
   if (aRv.Failed()) {
     return;
   }