Bug 1245184 - CookieManager should remove cookies only if they match the userContextId, r=sicking
☠☠ backed out by f88f85b0de5f ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 19 Feb 2016 14:49:50 +0100
changeset 307837 27f3968ae8b29206f67a4a85671c88bb12ffbf18
parent 307836 78162b5666f91f750ae6c8af2cf16392be193e0a
child 307838 9163c83ed1a856315bbdaf69e871823cfbb531c5
push id9214
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:25:21 +0000
treeherdermozilla-aurora@8849dd1a4a79 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs1245184
milestone47.0a1
Bug 1245184 - CookieManager should remove cookies only if they match the userContextId, r=sicking
browser/base/content/sanitize.js
browser/components/preferences/cookies.js
dom/base/ChromeUtils.cpp
dom/base/ChromeUtils.h
dom/webidl/ChromeUtils.webidl
netwerk/cookie/nsCookieService.cpp
netwerk/cookie/nsICookieManager.idl
netwerk/test/TestCookie.cpp
netwerk/test/moz.build
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -236,17 +236,18 @@ Sanitizer.prototype = {
           if (range) {
             // Iterate through the cookies and delete any created after our cutoff.
             let cookiesEnum = cookieMgr.enumerator;
             while (cookiesEnum.hasMoreElements()) {
               let cookie = cookiesEnum.getNext().QueryInterface(Ci.nsICookie2);
 
               if (cookie.creationTime > range[0]) {
                 // This cookie was created after our cutoff, clear it
-                cookieMgr.remove(cookie.host, cookie.name, cookie.path, false);
+                cookieMgr.remove(cookie.host, cookie.name, cookie.path,
+                                 cookie.originAttributes, false);
 
                 if (++yieldCounter % YIELD_PERIOD == 0) {
                   yield new Promise(resolve => setTimeout(resolve, 0)); // Don't block the main thread too long
                 }
               }
             }
           }
           else {
--- a/browser/components/preferences/cookies.js
+++ b/browser/components/preferences/cookies.js
@@ -66,17 +66,19 @@ var gCookiesWindow = {
     this._updateRemoveAllButton();
 
     this._saveState();
   },
 
   _cookieEquals: function (aCookieA, aCookieB, aStrippedHost) {
     return aCookieA.rawHost == aStrippedHost &&
            aCookieA.name == aCookieB.name &&
-           aCookieA.path == aCookieB.path;
+           aCookieA.path == aCookieB.path &&
+           ChromeUtils.isOriginAttributesEqual(aCookieA.originAttributes,
+                                               aCookieB.originAttributes);
   },
 
   observe: function (aCookie, aTopic, aData) {
     if (aTopic != "cookie-changed")
       return;
 
     if (aCookie instanceof Components.interfaces.nsICookie) {
       var strippedHost = this._makeStrippedHost(aCookie.host);
@@ -271,25 +273,29 @@ var gCookiesWindow = {
         }
         this._filterSet.splice(aIndex, removeCount);
         return;
       }
 
       var item = this._getItemAtIndex(aIndex);
       if (!item) return;
       this._invalidateCache(aIndex - 1);
-      if (item.container)
+      if (item.container) {
         gCookiesWindow._hosts[item.rawHost] = null;
-      else {
+      } else {
         var parent = this._getItemAtIndex(item.parentIndex);
         for (var i = 0; i < parent.cookies.length; ++i) {
           var cookie = parent.cookies[i];
           if (item.rawHost == cookie.rawHost &&
-              item.name == cookie.name && item.path == cookie.path)
+              item.name == cookie.name &&
+              item.path == cookie.path &&
+              ChromeUtils.isOriginAttributesEqual(item.originAttributes,
+                                                  cookie.originAttributes)) {
             parent.cookies.splice(i, removeCount);
+          }
         }
       }
     },
 
     _invalidateCache: function (aIndex) {
       this._cacheValid = Math.min(this._cacheValid, aIndex);
     },
 
@@ -579,17 +585,18 @@ var gCookiesWindow = {
   performDeletion: function gCookiesWindow_performDeletion(deleteItems) {
     var psvc = Components.classes["@mozilla.org/preferences-service;1"]
                          .getService(Components.interfaces.nsIPrefBranch);
     var blockFutureCookies = false;
     if (psvc.prefHasUserValue("network.cookie.blockFutureCookies"))
       blockFutureCookies = psvc.getBoolPref("network.cookie.blockFutureCookies");
     for (var i = 0; i < deleteItems.length; ++i) {
       var item = deleteItems[i];
-      this._cm.remove(item.host, item.name, item.path, blockFutureCookies);
+      this._cm.remove(item.host, item.name, item.path,
+                      item.originAttributes, blockFutureCookies);
     }
   },
 
   deleteCookie: function () {
     // Selection Notes
     // - Selection always moves to *NEXT* adjacent item unless item
     //   is last child at a given level in which case it moves to *PREVIOUS*
     //   item
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -95,11 +95,22 @@ ChromeUtils::CreateOriginAttributesFromO
 /* static */ void
 ChromeUtils::CreateOriginAttributesFromDict(dom::GlobalObject& aGlobal,
                                  const dom::OriginAttributesDictionary& aAttrs,
                                  dom::OriginAttributesDictionary& aNewAttrs)
 {
   aNewAttrs = aAttrs;
 }
 
+/* static */ bool
+ChromeUtils::IsOriginAttributesEqual(dom::GlobalObject& aGlobal,
+                                     const dom::OriginAttributesDictionary& aA,
+                                     const dom::OriginAttributesDictionary& aB)
+{
+  return aA.mAddonId == aB.mAddonId &&
+         aA.mAppId == aB.mAppId &&
+         aA.mInBrowser == aB.mInBrowser &&
+         aA.mSignedPkg == aB.mSignedPkg &&
+         aA.mUserContextId == aB.mUserContextId;
+}
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -67,14 +67,19 @@ public:
                                    const nsAString& aOrigin,
                                    dom::OriginAttributesDictionary& aAttrs,
                                    ErrorResult& aRv);
 
   static void
   CreateOriginAttributesFromDict(dom::GlobalObject& aGlobal,
                                  const dom::OriginAttributesDictionary& aAttrs,
                                  dom::OriginAttributesDictionary& aNewAttrs);
+
+  static bool
+  IsOriginAttributesEqual(dom::GlobalObject& aGlobal,
+                          const dom::OriginAttributesDictionary& aA,
+                          const dom::OriginAttributesDictionary& aB);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ChromeUtils__
--- a/dom/webidl/ChromeUtils.webidl
+++ b/dom/webidl/ChromeUtils.webidl
@@ -58,16 +58,23 @@ interface ChromeUtils : ThreadSafeChrome
    *
    * @param originAttrs       The origin attributes to copy.
    * @returns                 An OriginAttributesDictionary copy of |originAttrs|
    *                          with unspecified attributes added and assigned 
    *                          default values.
    */
   static OriginAttributesDictionary
   createOriginAttributesFromDict(optional OriginAttributesDictionary originAttrs);
+
+  /**
+   * Returns true if the 2 OriginAttributes are equal.
+   */
+  static boolean
+  isOriginAttributesEqual(optional OriginAttributesDictionary aA,
+                          optional OriginAttributesDictionary aB);
 };
 
 /**
  * Used by principals and the script security manager to represent origin
  * attributes. The first dictionary is designed to contain the full set of
  * OriginAttributes, the second is used for pattern-matching (i.e. does this
  * OriginAttributesDictionary match the non-empty attributes in this pattern).
  *
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -2361,19 +2361,25 @@ nsCookieService::Remove(const nsACString
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCookieService::Remove(const nsACString &aHost,
                         const nsACString &aName,
                         const nsACString &aPath,
-                        bool             aBlocked)
+                        JS::HandleValue  aOriginAttributes,
+                        bool             aBlocked,
+                        JSContext*       aCx)
 {
   NeckoOriginAttributes attrs;
+  if (!attrs.Init(aCx, aOriginAttributes)) {
+    return NS_ERROR_FAILURE;
+  }
+
   return Remove(aHost, attrs, aName, aPath, aBlocked);
 }
 
 /******************************************************************************
  * nsCookieService impl:
  * private file I/O functions
  ******************************************************************************/
 
--- a/netwerk/cookie/nsICookieManager.idl
+++ b/netwerk/cookie/nsICookieManager.idl
@@ -34,16 +34,19 @@ interface nsICookieManager : nsISupports
    * directly from the desired nsICookie object.
    *
    * @param aHost The host or domain for which the cookie was set. @see
    *              nsICookieManager2::add for a description of acceptable host
    *              strings. If the target cookie is a domain cookie, a leading
    *              dot must be present.
    * @param aName The name specified in the cookie
    * @param aPath The path for which the cookie was set
+   * @param aOriginAttributes The originAttributes of this cookie
    * @param aBlocked Indicates if cookies from this host should be permanently blocked
    *
    */
-  void remove(in AUTF8String aHost,
-              in ACString    aName,
-              in AUTF8String aPath,
-              in boolean     aBlocked);
+  [implicit_jscontext]
+  void remove(in AUTF8String   aHost,
+              in ACString      aName,
+              in AUTF8String   aPath,
+              in jsval         aOriginAttributes,
+              in boolean       aBlocked);
 };
--- a/netwerk/test/TestCookie.cpp
+++ b/netwerk/test/TestCookie.cpp
@@ -670,17 +670,19 @@ main(int32_t argc, char *argv[])
               hostCookies == 2;
       // check CookieExists() using the third cookie
       bool found;
       rv[9] = NS_SUCCEEDED(cookieMgr2->CookieExists(newDomainCookie, &found)) && found;
       // remove the cookie, block it, and ensure it can't be added again
       rv[10] = NS_SUCCEEDED(cookieMgr->Remove(NS_LITERAL_CSTRING("new.domain"), // domain
                                               NS_LITERAL_CSTRING("test3"),      // name
                                               NS_LITERAL_CSTRING("/rabbit"),    // path
-                                              true));                        // is blocked
+                                              JS::NullHandleValue,              // originAttributes
+                                              true,                             // is blocked
+                                              nullptr));                        // JSContext
       rv[11] = NS_SUCCEEDED(cookieMgr2->CookieExists(newDomainCookie, &found)) && !found;
       rv[12] = NS_SUCCEEDED(cookieMgr2->Add(NS_LITERAL_CSTRING("new.domain"),     // domain
                                             NS_LITERAL_CSTRING("/rabbit"),        // path
                                             NS_LITERAL_CSTRING("test3"),          // name
                                             NS_LITERAL_CSTRING("yes"),            // value
                                             false,                             // is secure
                                             false,                             // is httponly
                                             true,                              // is session
--- a/netwerk/test/moz.build
+++ b/netwerk/test/moz.build
@@ -47,9 +47,11 @@ CppUnitTests([
     'TestUDPSocket',
 ])
 
 RESOURCE_FILES += [
     'urlparse.dat',
     'urlparse_unx.dat',
 ]
 
+USE_LIBS += ['static:js']
+
 CXXFLAGS += CONFIG['TK_CFLAGS']