Bug 144795 - Move HTMLDocument.cookie getter/setter to Document; r=bzbarsky
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 18 Apr 2019 08:55:00 +0000
changeset 470076 ee03e8a4f6cd04cfc183a4ed2012c872cb021df0
parent 470075 24545a98e9e1a15b075bb27944a33353f385278a
child 470077 565279f288410f563f7871360a1d53d8e3f60dd9
push id112843
push useraiakab@mozilla.com
push dateFri, 19 Apr 2019 09:50:22 +0000
treeherdermozilla-inbound@c06f27cbfe40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs144795
milestone68.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 144795 - Move HTMLDocument.cookie getter/setter to Document; r=bzbarsky Differential Revision: https://phabricator.services.mozilla.com/D27931
dom/base/Document.cpp
dom/base/Document.h
dom/html/nsHTMLDocument.cpp
dom/html/nsHTMLDocument.h
dom/html/nsIHTMLDocument.h
dom/webidl/Document.webidl
dom/webidl/HTMLDocument.webidl
dom/xhr/XMLHttpRequestMainThread.cpp
testing/web-platform/meta/html/dom/interfaces.https.html.ini
testing/web-platform/meta/xhr/responsexml-document-properties.htm.ini
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -121,16 +121,17 @@
 #include "nsNetUtil.h"  // for NS_NewURI
 #include "nsIInputStreamChannel.h"
 #include "nsIAuthPrompt.h"
 #include "nsIAuthPrompt2.h"
 
 #include "nsIScriptSecurityManager.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
+#include "nsIPrivateBrowsingChannel.h"
 #include "ExpandedPrincipal.h"
 #include "mozilla/NullPrincipal.h"
 
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsFocusManager.h"
 #include "nsICookiePermission.h"
 #include "nsICookieService.h"
@@ -1232,16 +1233,17 @@ Document::Document(const char* aContentT
       mParserAborted(false),
       mReportedUseCounters(false),
       mHasReportedShadowDOMUsage(false),
       mDocTreeHadAudibleMedia(false),
       mDocTreeHadPlayRevoked(false),
       mHasDelayedRefreshEvent(false),
       mLoadEventFiring(false),
       mSkipLoadEventAfterClose(false),
+      mDisableCookieAccess(false),
       mPendingFullscreenRequests(0),
       mXMLDeclarationBits(0),
       mOnloadBlockCount(0),
       mAsyncOnloadBlockCount(0),
       mCompatMode(eCompatibility_FullStandards),
       mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
       mAncestorIsLoading(false),
 #ifdef MOZILLA_INTERNAL_API
@@ -3377,16 +3379,179 @@ void Document::SetLastFocusTime(const Ti
 
 void Document::GetReferrer(nsAString& aReferrer) const {
   if (mIsSrcdocDocument && mParentDocument)
     mParentDocument->GetReferrer(aReferrer);
   else
     CopyUTF8toUTF16(mReferrer, aReferrer);
 }
 
+void Document::GetCookie(nsAString& aCookie, ErrorResult& rv) {
+  aCookie.Truncate();  // clear current cookie in case service fails;
+                       // no cookie isn't an error condition.
+
+  if (mDisableCookieAccess) {
+    return;
+  }
+
+  // If the document's sandboxed origin flag is set, access to read cookies
+  // is prohibited.
+  if (mSandboxFlags & SANDBOXED_ORIGIN) {
+    rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  nsContentUtils::StorageAccess storageAccess =
+      nsContentUtils::StorageAllowedForDocument(this);
+  if (storageAccess == nsContentUtils::StorageAccess::eDeny) {
+    return;
+  }
+
+  if (storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
+      !StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
+    return;
+  }
+
+  // If the document is a cookie-averse Document... return the empty string.
+  if (IsCookieAverse()) {
+    return;
+  }
+
+  // not having a cookie service isn't an error
+  nsCOMPtr<nsICookieService> service =
+      do_GetService(NS_COOKIESERVICE_CONTRACTID);
+  if (service) {
+    // Get a URI from the document principal. We use the original
+    // codebase in case the codebase was changed by SetDomain
+    nsCOMPtr<nsIURI> codebaseURI;
+    NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
+
+    if (!codebaseURI) {
+      // Document's principal is not a codebase (may be system), so
+      // can't set cookies
+
+      return;
+    }
+
+    nsCOMPtr<nsIChannel> channel(mChannel);
+    if (!channel) {
+      channel = CreateDummyChannelForCookies(codebaseURI);
+      if (!channel) {
+        return;
+      }
+    }
+
+    nsCString cookie;
+    service->GetCookieString(codebaseURI, channel, getter_Copies(cookie));
+    // CopyUTF8toUTF16 doesn't handle error
+    // because it assumes that the input is valid.
+    UTF_8_ENCODING->DecodeWithoutBOMHandling(cookie, aCookie);
+  }
+}
+
+void Document::SetCookie(const nsAString& aCookie, ErrorResult& rv) {
+  if (mDisableCookieAccess) {
+    return;
+  }
+
+  // If the document's sandboxed origin flag is set, access to write cookies
+  // is prohibited.
+  if (mSandboxFlags & SANDBOXED_ORIGIN) {
+    rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  nsContentUtils::StorageAccess storageAccess =
+      nsContentUtils::StorageAllowedForDocument(this);
+  if (storageAccess == nsContentUtils::StorageAccess::eDeny) {
+    return;
+  }
+
+  if (storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
+      !StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
+    return;
+  }
+
+  // If the document is a cookie-averse Document... do nothing.
+  if (IsCookieAverse()) {
+    return;
+  }
+
+  // not having a cookie service isn't an error
+  nsCOMPtr<nsICookieService> service =
+      do_GetService(NS_COOKIESERVICE_CONTRACTID);
+  if (service && mDocumentURI) {
+    // The code for getting the URI matches Navigator::CookieEnabled
+    nsCOMPtr<nsIURI> codebaseURI;
+    NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
+
+    if (!codebaseURI) {
+      // Document's principal is not a codebase (may be system), so
+      // can't set cookies
+
+      return;
+    }
+
+    nsCOMPtr<nsIChannel> channel(mChannel);
+    if (!channel) {
+      channel = CreateDummyChannelForCookies(codebaseURI);
+      if (!channel) {
+        return;
+      }
+    }
+
+    NS_ConvertUTF16toUTF8 cookie(aCookie);
+    service->SetCookieString(codebaseURI, nullptr, cookie.get(), channel);
+  }
+}
+
+already_AddRefed<nsIChannel> Document::CreateDummyChannelForCookies(
+    nsIURI* aCodebaseURI) {
+  // The cookie service reads the privacy status of the channel we pass to it in
+  // order to determine which cookie database to query.  In some cases we don't
+  // have a proper channel to hand it to the cookie service though.  This
+  // function creates a dummy channel that is not used to load anything, for the
+  // sole purpose of handing it to the cookie service.  DO NOT USE THIS CHANNEL
+  // FOR ANY OTHER PURPOSE.
+  MOZ_ASSERT(!mChannel);
+
+  // The following channel is never openend, so it does not matter what
+  // securityFlags we pass; let's follow the principle of least privilege.
+  nsCOMPtr<nsIChannel> channel;
+  NS_NewChannel(getter_AddRefs(channel), aCodebaseURI, this,
+                nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
+                nsIContentPolicy::TYPE_INVALID);
+  nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
+  nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
+  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
+  if (!pbChannel || !loadContext) {
+    return nullptr;
+  }
+  pbChannel->SetPrivate(loadContext->UsePrivateBrowsing());
+
+  nsCOMPtr<nsIHttpChannel> docHTTPChannel = do_QueryInterface(GetChannel());
+  if (docHTTPChannel) {
+    bool isTracking = docHTTPChannel->IsTrackingResource();
+    if (isTracking) {
+      // If our document channel is from a tracking resource, we must
+      // override our channel's tracking status.
+      nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
+      MOZ_ASSERT(httpChannel,
+                 "How come we're coming from an HTTP doc but "
+                 "we don't have an HTTP channel here?");
+      if (httpChannel) {
+        httpChannel->OverrideTrackingFlagsForDocumentCookieAccessor(
+            docHTTPChannel);
+      }
+    }
+  }
+
+  return channel.forget();
+}
+
 mozilla::net::ReferrerPolicy Document::GetReferrerPolicy() const {
   if (mIsSrcdocDocument && mParentDocument &&
       mReferrerPolicy == mozilla::net::RP_Unset) {
     return mParentDocument->GetReferrerPolicy();
   }
   return mReferrerPolicy;
 }
 
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -1234,16 +1234,22 @@ class Document : public nsINode,
 
   /**
    * Called when the document was decoded as UTF-8 and decoder encountered no
    * errors.
    */
   void EnableEncodingMenu() { mEncodingMenuDisabled = false; }
 
   /**
+   * Called to disable client access to cookies through the document.cookie API
+   * from user JavaScript code.
+   */
+  void DisableCookieAccess() { mDisableCookieAccess = true; }
+
+  /**
    * Access HTTP header data (this may also get set from other
    * sources, like HTML META tags).
    */
   void GetHeaderData(nsAtom* aHeaderField, nsAString& aData) const;
   void SetHeaderData(nsAtom* aheaderField, const nsAString& aData);
 
   /**
    * Create a new presentation shell that will use aContext for its
@@ -3236,16 +3242,18 @@ class Document : public nsINode,
                                                     ErrorResult& rv);
   already_AddRefed<Attr> CreateAttribute(const nsAString& aName,
                                          ErrorResult& rv);
   already_AddRefed<Attr> CreateAttributeNS(const nsAString& aNamespaceURI,
                                            const nsAString& aQualifiedName,
                                            ErrorResult& rv);
   void GetInputEncoding(nsAString& aInputEncoding) const;
   already_AddRefed<Location> GetLocation() const;
+  void GetCookie(nsAString& aCookie, mozilla::ErrorResult& rv);
+  void SetCookie(const nsAString& aCookie, mozilla::ErrorResult& rv);
   void GetReferrer(nsAString& aReferrer) const;
   void GetLastModified(nsAString& aLastModified) const;
   void GetReadyState(nsAString& aReadyState) const;
 
   void GetTitle(nsAString& aTitle);
   void SetTitle(const nsAString& aTitle, ErrorResult& rv);
   void GetDir(nsAString& aDirection) const;
   void SetDir(const nsAString& aDirection);
@@ -3915,16 +3923,20 @@ class Document : public nsINode,
 
   // Helpers for GetElementsByName.
   static bool MatchNameAttribute(Element* aElement, int32_t aNamespaceID,
                                  nsAtom* aAtom, void* aData);
   static void* UseExistingNameString(nsINode* aRootNode, const nsString* aName);
 
   void MaybeResolveReadyForIdle();
 
+  // This should *ONLY* be used in GetCookie/SetCookie.
+  already_AddRefed<nsIChannel> CreateDummyChannelForCookies(
+      nsIURI* aCodebaseURI);
+
   nsCString mReferrer;
   nsString mLastModified;
 
   nsCOMPtr<nsIURI> mDocumentURI;
   nsCOMPtr<nsIURI> mOriginalURI;
   nsCOMPtr<nsIURI> mChromeXHRDocURI;
   nsCOMPtr<nsIURI> mDocumentBaseURI;
   nsCOMPtr<nsIURI> mChromeXHRDocBaseURI;
@@ -4292,16 +4304,19 @@ class Document : public nsINode,
   // The HTML spec has a "mute iframe load" flag, but that doesn't seem to have
   // the right semantics.  See <https://github.com/whatwg/html/issues/4292>.
   // What we have instead is a flag that is set if completion of our document
   // via document.close() should skip firing the load event.  Note that this
   // flag is only relevant for HTML documents, but lives here for reasons that
   // are documented above on SkipLoadEventAfterClose().
   bool mSkipLoadEventAfterClose : 1;
 
+  // When false, the .cookies property is completely disabled
+  bool mDisableCookieAccess : 1;
+
   uint8_t mPendingFullscreenRequests;
 
   uint8_t mXMLDeclarationBits;
 
   // Currently active onload blockers.
   uint32_t mOnloadBlockCount;
 
   // Onload blockers which haven't been activated yet.
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -28,35 +28,32 @@
 #include "nsPresContext.h"
 #include "nsPIDOMWindow.h"
 #include "nsDOMString.h"
 #include "nsIStreamListener.h"
 #include "nsIURI.h"
 #include "nsIURIMutator.h"
 #include "nsIIOService.h"
 #include "nsNetUtil.h"
-#include "nsIPrivateBrowsingChannel.h"
 #include "nsIContentViewer.h"
 #include "nsDocShell.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsIWebNavigation.h"
 #include "nsIBaseWindow.h"
 #include "nsIScriptContext.h"
 #include "nsIXPConnect.h"
 #include "nsContentList.h"
 #include "nsError.h"
 #include "nsIPrincipal.h"
 #include "nsJSPrincipals.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsAttrName.h"
 #include "nsNodeUtils.h"
 
 #include "nsNetCID.h"
-#include "nsICookieService.h"
-
 #include "nsIServiceManager.h"
 #include "nsIConsoleService.h"
 #include "nsIComponentManager.h"
 #include "nsParserCIID.h"
 #include "mozilla/parser/PrototypeDocumentParser.h"
 #include "mozilla/dom/PrototypeDocumentContentSink.h"
 #include "nsNameSpaceManager.h"
 #include "nsGenericHTMLElement.h"
@@ -175,17 +172,16 @@ nsHTMLDocument::nsHTMLDocument()
       mNumForms(0),
       mWriteLevel(0),
       mLoadFlags(0),
       mTooDeepWriteRecursion(false),
       mDisableDocWrite(false),
       mWarnedWidthHeight(false),
       mContentEditableCount(0),
       mEditingState(EditingState::eOff),
-      mDisableCookieAccess(false),
       mPendingMaybeEditingStateChanged(false),
       mHasBeenEditable(false),
       mIsPlainText(false) {
   mType = eHTML;
   mDefaultElementType = kNameSpaceID_XHTML;
   mCompatMode = eCompatibility_NavQuirks;
 }
 
@@ -964,179 +960,16 @@ void nsHTMLDocument::SetDomain(const nsA
     // Error: illegal domain
     rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   rv = NodePrincipal()->SetDomain(newURI);
 }
 
-already_AddRefed<nsIChannel> nsHTMLDocument::CreateDummyChannelForCookies(
-    nsIURI* aCodebaseURI) {
-  // The cookie service reads the privacy status of the channel we pass to it in
-  // order to determine which cookie database to query.  In some cases we don't
-  // have a proper channel to hand it to the cookie service though.  This
-  // function creates a dummy channel that is not used to load anything, for the
-  // sole purpose of handing it to the cookie service.  DO NOT USE THIS CHANNEL
-  // FOR ANY OTHER PURPOSE.
-  MOZ_ASSERT(!mChannel);
-
-  // The following channel is never openend, so it does not matter what
-  // securityFlags we pass; let's follow the principle of least privilege.
-  nsCOMPtr<nsIChannel> channel;
-  NS_NewChannel(getter_AddRefs(channel), aCodebaseURI, this,
-                nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
-                nsIContentPolicy::TYPE_INVALID);
-  nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
-  nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
-  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
-  if (!pbChannel || !loadContext) {
-    return nullptr;
-  }
-  pbChannel->SetPrivate(loadContext->UsePrivateBrowsing());
-
-  nsCOMPtr<nsIHttpChannel> docHTTPChannel = do_QueryInterface(GetChannel());
-  if (docHTTPChannel) {
-    bool isTracking = docHTTPChannel->IsTrackingResource();
-    if (isTracking) {
-      // If our document channel is from a tracking resource, we must
-      // override our channel's tracking status.
-      nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
-      MOZ_ASSERT(httpChannel,
-                 "How come we're coming from an HTTP doc but "
-                 "we don't have an HTTP channel here?");
-      if (httpChannel) {
-        httpChannel->OverrideTrackingFlagsForDocumentCookieAccessor(
-            docHTTPChannel);
-      }
-    }
-  }
-
-  return channel.forget();
-}
-
-void nsHTMLDocument::GetCookie(nsAString& aCookie, ErrorResult& rv) {
-  aCookie.Truncate();  // clear current cookie in case service fails;
-                       // no cookie isn't an error condition.
-
-  if (mDisableCookieAccess) {
-    return;
-  }
-
-  // If the document's sandboxed origin flag is set, access to read cookies
-  // is prohibited.
-  if (mSandboxFlags & SANDBOXED_ORIGIN) {
-    rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-    return;
-  }
-
-  nsContentUtils::StorageAccess storageAccess =
-      nsContentUtils::StorageAllowedForDocument(this);
-  if (storageAccess == nsContentUtils::StorageAccess::eDeny) {
-    return;
-  }
-
-  if (storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
-      !StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
-    return;
-  }
-
-  // If the document is a cookie-averse Document... return the empty string.
-  if (IsCookieAverse()) {
-    return;
-  }
-
-  // not having a cookie service isn't an error
-  nsCOMPtr<nsICookieService> service =
-      do_GetService(NS_COOKIESERVICE_CONTRACTID);
-  if (service) {
-    // Get a URI from the document principal. We use the original
-    // codebase in case the codebase was changed by SetDomain
-    nsCOMPtr<nsIURI> codebaseURI;
-    NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
-
-    if (!codebaseURI) {
-      // Document's principal is not a codebase (may be system), so
-      // can't set cookies
-
-      return;
-    }
-
-    nsCOMPtr<nsIChannel> channel(mChannel);
-    if (!channel) {
-      channel = CreateDummyChannelForCookies(codebaseURI);
-      if (!channel) {
-        return;
-      }
-    }
-
-    nsCString cookie;
-    service->GetCookieString(codebaseURI, channel, getter_Copies(cookie));
-    // CopyUTF8toUTF16 doesn't handle error
-    // because it assumes that the input is valid.
-    UTF_8_ENCODING->DecodeWithoutBOMHandling(cookie, aCookie);
-  }
-}
-
-void nsHTMLDocument::SetCookie(const nsAString& aCookie, ErrorResult& rv) {
-  if (mDisableCookieAccess) {
-    return;
-  }
-
-  // If the document's sandboxed origin flag is set, access to write cookies
-  // is prohibited.
-  if (mSandboxFlags & SANDBOXED_ORIGIN) {
-    rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-    return;
-  }
-
-  nsContentUtils::StorageAccess storageAccess =
-      nsContentUtils::StorageAllowedForDocument(this);
-  if (storageAccess == nsContentUtils::StorageAccess::eDeny) {
-    return;
-  }
-
-  if (storageAccess == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
-      !StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
-    return;
-  }
-
-  // If the document is a cookie-averse Document... do nothing.
-  if (IsCookieAverse()) {
-    return;
-  }
-
-  // not having a cookie service isn't an error
-  nsCOMPtr<nsICookieService> service =
-      do_GetService(NS_COOKIESERVICE_CONTRACTID);
-  if (service && mDocumentURI) {
-    // The for getting the URI matches nsNavigator::GetCookieEnabled
-    nsCOMPtr<nsIURI> codebaseURI;
-    NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
-
-    if (!codebaseURI) {
-      // Document's principal is not a codebase (may be system), so
-      // can't set cookies
-
-      return;
-    }
-
-    nsCOMPtr<nsIChannel> channel(mChannel);
-    if (!channel) {
-      channel = CreateDummyChannelForCookies(codebaseURI);
-      if (!channel) {
-        return;
-      }
-    }
-
-    NS_ConvertUTF16toUTF8 cookie(aCookie);
-    service->SetCookieString(codebaseURI, nullptr, cookie.get(), channel);
-  }
-}
-
 mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> nsHTMLDocument::Open(
     const nsAString& aURL, const nsAString& aName, const nsAString& aFeatures,
     bool aReplace, ErrorResult& rv) {
   MOZ_ASSERT(nsContentUtils::CanCallerAccess(this),
              "XOW should have caught this!");
 
   nsCOMPtr<nsPIDOMWindowInner> window = GetInnerWindow();
   if (!window) {
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -101,18 +101,16 @@ class nsHTMLDocument : public mozilla::d
   }
 
   nsresult ChangeContentEditableCount(nsIContent* aElement,
                                       int32_t aChange) override;
   void DeferredContentEditableCountChange(nsIContent* aElement);
 
   virtual EditingState GetEditingState() override { return mEditingState; }
 
-  virtual void DisableCookieAccess() override { mDisableCookieAccess = true; }
-
   class nsAutoEditingState {
    public:
     nsAutoEditingState(nsHTMLDocument* aDoc, EditingState aState)
         : mDoc(aDoc), mSavedState(aDoc->mEditingState) {
       aDoc->mEditingState = aState;
     }
     ~nsAutoEditingState() { mDoc->mEditingState = mSavedState; }
 
@@ -142,18 +140,16 @@ class nsHTMLDocument : public mozilla::d
 
   // WebIDL API
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aGivenProto) override;
   void GetDomain(nsAString& aDomain);
   void SetDomain(const nsAString& aDomain, mozilla::ErrorResult& rv);
   bool IsRegistrableDomainSuffixOfOrEqualTo(const nsAString& aHostSuffixString,
                                             const nsACString& aOrigHost);
-  void GetCookie(nsAString& aCookie, mozilla::ErrorResult& rv);
-  void SetCookie(const nsAString& aCookie, mozilla::ErrorResult& rv);
   void NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound,
                    JS::MutableHandle<JSObject*> aRetval,
                    mozilla::ErrorResult& rv) {
     JS::Rooted<JS::Value> v(cx);
     if ((aFound = ResolveName(cx, aName, &v, rv))) {
       aRetval.set(v.toObjectOrNull());
     }
   }
@@ -235,20 +231,16 @@ class nsHTMLDocument : public mozilla::d
       const nsAString& aHostSuffixString, nsIURI* aOrigHost);
 
   void WriteCommon(const nsAString& aText, bool aNewlineTerminate,
                    mozilla::ErrorResult& aRv);
   // A version of WriteCommon used by WebIDL bindings
   void WriteCommon(const mozilla::dom::Sequence<nsString>& aText,
                    bool aNewlineTerminate, mozilla::ErrorResult& rv);
 
-  // This should *ONLY* be used in GetCookie/SetCookie.
-  already_AddRefed<nsIChannel> CreateDummyChannelForCookies(
-      nsIURI* aCodebaseURI);
-
   /**
    * Like IsEditingOn(), but will flush as needed first.
    */
   bool IsEditingOnAfterFlush();
 
   void* GenerateParserKey(void);
 
   // A helper class to keep nsContentList objects alive for a short period of
@@ -331,19 +323,16 @@ class nsHTMLDocument : public mozilla::d
   // of places, and I'm pretty sure the exact ExecCommand call it
   // makes cannot actually run script.
   MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult EditingStateChanged();
   void MaybeEditingStateChanged();
 
   uint32_t mContentEditableCount;
   EditingState mEditingState;
 
-  // When false, the .cookies property is completely disabled
-  bool mDisableCookieAccess;
-
   /**
    * Temporary flag that is set in EndUpdate() to ignore
    * MaybeEditingStateChanged() script runners from a nested scope.
    */
   bool mPendingMaybeEditingStateChanged;
 
   // mHasBeenEditable is set to true when mEditingState is firstly set to
   // eDesignMode or eContentEditable.
--- a/dom/html/nsIHTMLDocument.h
+++ b/dom/html/nsIHTMLDocument.h
@@ -89,21 +89,16 @@ class nsIHTMLDocument : public nsISuppor
   /**
    * Set the editing state of the document. Don't use this if you want
    * to enable/disable editing, call EditingStateChanged() or
    * SetDesignMode().
    */
   virtual nsresult SetEditingState(EditingState aState) = 0;
 
   /**
-   * Disables getting and setting cookies
-   */
-  virtual void DisableCookieAccess() = 0;
-
-  /**
    * Called when this nsIHTMLDocument's editor is destroyed.
    */
   virtual void TearingDownEditor() = 0;
 
   virtual void SetIsXHTML(bool aXHTML) = 0;
 
   virtual void SetDocWriteDisabled(bool aDisabled) = 0;
 };
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -113,17 +113,17 @@ interface Document : Node {
   Attr createAttributeNS(DOMString? namespace, DOMString name);
 };
 
 // https://html.spec.whatwg.org/multipage/dom.html#the-document-object
 partial interface Document {
   [PutForwards=href, Unforgeable] readonly attribute Location? location;
   //(HTML only)         attribute DOMString domain;
   readonly attribute DOMString referrer;
-  //(HTML only)         attribute DOMString cookie;
+  [Throws] attribute DOMString cookie;
   readonly attribute DOMString lastModified;
   readonly attribute DOMString readyState;
 
   // DOM tree accessors
   //(Not proxy yet)getter object (DOMString name);
   [CEReactions, SetterThrows, Pure]
            attribute DOMString title;
   [CEReactions, Pure]
--- a/dom/webidl/HTMLDocument.webidl
+++ b/dom/webidl/HTMLDocument.webidl
@@ -3,18 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 [OverrideBuiltins]
 interface HTMLDocument : Document {
            [SetterThrows]
            attribute DOMString domain;
-           [Throws]
-           attribute DOMString cookie;
   // DOM tree accessors
   [Throws]
   getter object (DOMString name);
 
   // dynamic markup insertion
   [CEReactions, Throws]
   Document open(optional DOMString type, optional DOMString replace = ""); // type is ignored
   [CEReactions, Throws]
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -1978,20 +1978,17 @@ XMLHttpRequestMainThread::OnStartRequest
       mResponseXML->ForceEnableXULXBL();
     }
 
     nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
     bool isCrossSite = false;
     isCrossSite = loadInfo->GetTainting() != LoadTainting::Basic;
 
     if (isCrossSite) {
-      nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mResponseXML);
-      if (htmlDoc) {
-        htmlDoc->DisableCookieAccess();
-      }
+      mResponseXML->DisableCookieAccess();
     }
 
     nsCOMPtr<nsIStreamListener> listener;
     nsCOMPtr<nsILoadGroup> loadGroup;
     channel->GetLoadGroup(getter_AddRefs(loadGroup));
 
     // suppress <parsererror> nodes on XML document parse failure, but only
     // for non-privileged code (including Web Extensions). See bug 289714.
--- a/testing/web-platform/meta/html/dom/interfaces.https.html.ini
+++ b/testing/web-platform/meta/html/dom/interfaces.https.html.ini
@@ -1,16 +1,13 @@
 prefs: [dom.security.featurePolicy.enabled:true]
 [interfaces.https.html?include=(Document|Window)]
   [Document interface: attribute domain]
     expected: FAIL
 
-  [Document interface: attribute cookie]
-    expected: FAIL
-
   [Document interface: operation open(DOMString, DOMString)]
     expected: FAIL
 
   [Document interface: operation open(USVString, DOMString, DOMString)]
     expected: FAIL
 
   [Document interface: operation close()]
     expected: FAIL
@@ -91,19 +88,16 @@ prefs: [dom.security.featurePolicy.enabl
     expected: FAIL
 
   [Document interface: iframe.contentDocument must inherit property "onsecuritypolicyviolation" with the proper type]
     expected: FAIL
 
   [Document interface: new Document() must inherit property "domain" with the proper type]
     expected: FAIL
 
-  [Document interface: new Document() must inherit property "cookie" with the proper type]
-    expected: FAIL
-
   [Document interface: new Document() must inherit property "open(DOMString, DOMString)" with the proper type]
     expected: FAIL
 
   [Document interface: calling open(DOMString, DOMString) on new Document() with too few arguments must throw TypeError]
     expected: FAIL
 
   [Document interface: new Document() must inherit property "open(USVString, DOMString, DOMString)" with the proper type]
     expected: FAIL
@@ -199,19 +193,16 @@ prefs: [dom.security.featurePolicy.enabl
     expected: FAIL
 
   [Document interface: new Document() must inherit property "onsecuritypolicyviolation" with the proper type]
     expected: FAIL
 
   [Document interface: document.implementation.createDocument(null, "", null) must inherit property "domain" with the proper type]
     expected: FAIL
 
-  [Document interface: document.implementation.createDocument(null, "", null) must inherit property "cookie" with the proper type]
-    expected: FAIL
-
   [Document interface: document.implementation.createDocument(null, "", null) must inherit property "open(DOMString, DOMString)" with the proper type]
     expected: FAIL
 
   [Document interface: calling open(DOMString, DOMString) on document.implementation.createDocument(null, "", null) with too few arguments must throw TypeError]
     expected: FAIL
 
   [Document interface: document.implementation.createDocument(null, "", null) must inherit property "open(USVString, DOMString, DOMString)" with the proper type]
     expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/xhr/responsexml-document-properties.htm.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[responsexml-document-properties.htm]
-  [cookie]
-    expected: FAIL
-
-  [cookie (after setting it)]
-    expected: FAIL
-