Bug 792808 - use XMLHttpRequestBinding::STATE consts in the XHR subclasses and remove XMLHttpRequest::State enum class; r=baku
authorThomas Wisniewski <wisniewskit@gmail.com>
Sun, 19 Nov 2017 23:00:10 -0500
changeset 456653 88a0a583d4ca8965dc82f51796e1de4cd9fef28b
parent 456652 2c9c1b0ef8c305fac3407ad4d75a69374d894701
child 456654 560e1ce075054819e1d5c9ae98edbbe4f34c887d
push id8799
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 16:46:23 +0000
treeherdermozilla-beta@15334014dc67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs792808
milestone60.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 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;
   }