Index: browser/base/content/browser.js
===================================================================
RCS file: /cvsroot/mozilla/browser/base/content/browser.js,v
retrieving revision 1.783
diff -p -U 8 -r1.783 browser.js
--- browser/base/content/browser.js	13 May 2007 15:47:05 -0000	1.783
+++ browser/base/content/browser.js	14 May 2007 09:20:59 -0000
@@ -778,16 +778,19 @@ function BrowserStartup()
   var uriToLoad = null;
   // Check for window.arguments[0]. If present, use that for uriToLoad.
   if ("arguments" in window && window.arguments[0])
     uriToLoad = window.arguments[0];
 
   gIsLoadingBlank = uriToLoad == "about:blank";
 
   prepareForStartup();
+  
+  if (uriToLoad && window.arguments.length >= 6 && window.arguments[5].cookieContainer)
+    getBrowser().docShell.QueryInterface(Components.interfaces.nsICookieCollector).cookieContainer = window.arguments[5].cookieContainer;
 
 #ifdef ENABLE_PAGE_CYCLER
   appCore.startPageCycler();
 #else
 # only load url passed in when we're not page cycling
   if (uriToLoad && !gIsLoadingBlank) {
     if (window.arguments.length >= 3)
       loadURI(uriToLoad, window.arguments[2], window.arguments[3] || null,
@@ -1845,17 +1848,17 @@ function openLocation()
 function openLocationCallback()
 {
   // make sure the DOM is ready
   setTimeout(function() { this.openLocation(); }, 0);
 }
 
 function BrowserOpenTab()
 {
-  gBrowser.loadOneTab("about:blank", null, null, null, false, false);
+  gBrowser.loadOneTab("about:blank", null, null, null, false, false, null);
   if (gURLBar)
     setTimeout(function() { gURLBar.focus(); }, 0);
 }
 
 /* Called from the openLocation dialog. This allows that dialog to instruct
    its opener to open a new window and then step completely out of the way.
    Anything less byzantine is causing horrible crashes, rather believably,
    though oddly only on Linux. */
@@ -1868,17 +1871,17 @@ function delayedOpenWindow(chrome, flags
   // window.arguments[1] be an integer instead of null.
   setTimeout(function() { openDialog(chrome, "_blank", flags, href, null, null, postData); }, 10);
 }
 
 /* Required because the tab needs time to set up its content viewers and get the load of
    the URI kicked off before becoming the active content area. */
 function delayedOpenTab(aUrl, aReferrer, aCharset, aPostData, aAllowThirdPartyFixup)
 {
-  gBrowser.loadOneTab(aUrl, aReferrer, aCharset, aPostData, false, aAllowThirdPartyFixup);
+  gBrowser.loadOneTab(aUrl, aReferrer, aCharset, aPostData, false, aAllowThirdPartyFixup, null);
 }
 
 function BrowserOpenFileWindow()
 {
   // Get filepicker component.
   try {
     const nsIFilePicker = Components.interfaces.nsIFilePicker;
     var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
@@ -1979,17 +1982,18 @@ function BrowserLoadURL(aTriggeringEvent
                true /* allow third party fixup */, aPostData);
     return;
   }
 
   if (aTriggeringEvent && aTriggeringEvent.altKey) {
     handleURLBarRevert();
     content.focus();
     gBrowser.loadOneTab(url, null, null, aPostData, false,
-                        true /* allow third party fixup */);
+                        true, /* allow third party fixup */
+                        null);
     aTriggeringEvent.preventDefault();
     aTriggeringEvent.stopPropagation();
   }
   else
     loadURI(url, null, aPostData, true /* allow third party fixup */);
 
   focusElement(content);
 }
@@ -3143,17 +3147,17 @@ const BrowserSearch = {
     // with a text/html response type.  This is unlikely (since
     // SearchService._addEngineToStore() should fail for such an engine),
     // but let's be on the safe side.
     if (!submission)
       return;
   
     if (useNewTab) {
       getBrowser().loadOneTab(submission.uri.spec, null, null,
-                              submission.postData, null, false);
+                              submission.postData, null, false, null);
     } else
       loadURI(submission.uri.spec, null, submission.postData, false);
   },
 
   /**
    * Returns the search bar element if it is present in the toolbar and not
    * hidden, null otherwise.
    */
@@ -4123,17 +4127,17 @@ nsBrowserAccess.prototype =
     }
     var url = aURI ? aURI.spec : "about:blank";
     switch(aWhere) {
       case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW :
         newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url);
         break;
       case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB :
         var loadInBackground = gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground");
-        var newTab = gBrowser.loadOneTab("about:blank", null, null, null, loadInBackground, false);
+        var newTab = gBrowser.loadOneTab("about:blank", null, null, null, loadInBackground, false, null);
         newWindow = gBrowser.getBrowserForTab(newTab).docShell
                             .QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindow);
         try {
           if (aOpener) {
             location = aOpener.location;
             referrer =
                     Components.classes["@mozilla.org/network/io-service;1"]
Index: browser/base/content/utilityOverlay.js
===================================================================
RCS file: /cvsroot/mozilla/browser/base/content/utilityOverlay.js,v
retrieving revision 1.50
diff -p -U 8 -r1.50 utilityOverlay.js
--- browser/base/content/utilityOverlay.js	7 Mar 2007 20:09:19 -0000	1.50
+++ browser/base/content/utilityOverlay.js	14 May 2007 09:21:00 -0000
@@ -219,17 +219,17 @@ function openUILinkIn( url, where, allow
     w.loadURI(url, referrerUrl, postData, allowThirdPartyFixup);
     break;
   case "tabshifted":
     loadInBackground = !loadInBackground;
     // fall through
   case "tab":
     var browser = w.getBrowser();
     browser.loadOneTab(url, referrerUrl, null, postData, loadInBackground,
-                       allowThirdPartyFixup || false);
+                       allowThirdPartyFixup || false, null);
     break;
   }
 
   // Call focusElement(w.content) instead of w.content.focus() to make sure
   // that we don't raise the old window, since the URI we just loaded may have
   // resulted in a new frontmost window (e.g. "javascript:window.open('');").
   focusElement(w.content);
 }
@@ -551,18 +551,24 @@ function openNewTabWith(aURL, aDocument,
   var wintype = document.documentElement.getAttribute("windowtype");
   var originCharset;
   if (wintype == "navigator:browser")
     originCharset = window.content.document.characterSet;
 
   // open link in new tab
   var referrerURI = aDocument ? aDocument.documentURIObject : null;
   var browser = top.document.getElementById("content");
+  
+  var inheritOptions = { };
+  // get current cookie container
+  browser.docShell.QueryInterface(Components.interfaces.nsICookieCollector);
+  inheritOptions.cookieContainer = browser.docShell.cookieContainer;
+  
   browser.loadOneTab(aURL, referrerURI, originCharset, aPostData,
-                     loadInBackground, aAllowThirdPartyFixup || false);
+                     loadInBackground, aAllowThirdPartyFixup || false, inheritOptions);
 }
 
 function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup)
 {
   if (aDocument)
     urlSecurityCheck(aURL, aDocument.nodePrincipal);
 
   // if and only if the current window is a browser window and it has a
@@ -570,12 +576,19 @@ function openNewWindowWith(aURL, aDocume
   // setting from the current document and use it to initialize the new browser
   // window...
   var charsetArg = null;
   var wintype = document.documentElement.getAttribute("windowtype");
   if (wintype == "navigator:browser")
     charsetArg = "charset=" + window.content.document.characterSet;
 
   var referrerURI = aDocument ? aDocument.documentURIObject : null;
+  var browser = top.document.getElementById("content");
+  
+  var inheritOptions = { };
+  // get current cookie container
+  browser.docShell.QueryInterface(Components.interfaces.nsICookieCollector);
+  inheritOptions.cookieContainer = browser.docShell.cookieContainer;
+  
   window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no",
                     aURL, charsetArg, referrerURI, aPostData,
-                    aAllowThirdPartyFixup);
+                    aAllowThirdPartyFixup, inheritOptions);
 }
Index: browser/components/preferences/cookies.js
===================================================================
RCS file: /cvsroot/mozilla/browser/components/preferences/cookies.js,v
retrieving revision 1.15
diff -p -U 8 -r1.15 cookies.js
--- browser/components/preferences/cookies.js	15 Sep 2006 21:28:47 -0000	1.15
+++ browser/components/preferences/cookies.js	14 May 2007 09:21:03 -0000
@@ -53,16 +53,20 @@ var gCookiesWindow = {
     var os = Components.classes["@mozilla.org/observer-service;1"]
                        .getService(Components.interfaces.nsIObserverService);
     os.addObserver(this, "cookie-changed", false);
     os.addObserver(this, "perm-changed", false);
     
     this._bundle = document.getElementById("bundlePreferences");
     this._tree = document.getElementById("cookiesList");
     
+    // check if a containerId was passed when opening this window
+    if (window.arguments && window.arguments[0])
+      this._cm = Components.classes["@mozilla.org/cookieService;1"].getService(Components.interfaces.nsICookieService).getContainer(window.arguments[0]).QueryInterface(Components.interfaces.nsICookieManager);
+    
     this._loadCookies();
     this._tree.treeBoxObject.view = this._view;
     this.sort("rawHost");
     if (this._view.rowCount > 0) 
       this._tree.view.selection.select(0);
       
     document.getElementById("filter").focus();
   },
Index: browser/components/sessionstore/src/nsSessionStore.js
===================================================================
RCS file: /cvsroot/mozilla/browser/components/sessionstore/src/nsSessionStore.js,v
retrieving revision 1.60
diff -p -U 8 -r1.60 nsSessionStore.js
--- browser/components/sessionstore/src/nsSessionStore.js	12 Feb 2007 03:07:54 -0000	1.60
+++ browser/components/sessionstore/src/nsSessionStore.js	14 May 2007 09:21:09 -0000
@@ -15,16 +15,17 @@
  *
  * The Initial Developer of the Original Code is
  * Simon Bünzli <zeniko@gmail.com>
  * Portions created by the Initial Developer are Copyright (C) 2006
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Dietrich Ayala <autonome@gmail.com>
+ *   Loune Lam <lpgcritter at nasquan dot com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -793,16 +794,18 @@ SessionStoreService.prototype = {
       }
       tabData.zoom = browser.markupDocumentViewer.textZoom;
       
       var disallow = CAPABILITIES.filter(function(aCapability) {
         return !browser.docShell["allow" + aCapability];
       });
       tabData.disallow = disallow.join(",");
       
+      tabData.cookieContainer = browser.docShell.QueryInterface(Ci.nsICookieCollector).cookieContainer.containerId;
+      
       var _this = this;
       var xulattr = Array.filter(tabbrowser.mTabs[i].attributes, function(aAttr) {
         return (_this.xulAttributes.indexOf(aAttr.name) > -1);
       }).map(function(aAttr) {
         return aAttr.name + "=" + encodeURI(aAttr.value);
       });
       tabData.xultab = xulattr.join(" ");
       
@@ -985,84 +988,108 @@ SessionStoreService.prototype = {
   },
 
   /**
    * store all hosts for a URL
    * @param aWindow
    *        Window reference
    */
   _updateCookieHosts: function sss_updateCookieHosts(aWindow) {
-    var hosts = this._windows[aWindow.__SSi]._hosts = {};
+    var hosts = this._windows[aWindow.__SSi]._containerHosts = {};
+    var currentContainer;
     
     // get all possible subdomain levels for a given URL
     var _this = this;
     function extractHosts(aEntry) {
       if (/^https?:\/\/(?:[^@\/\s]+@)?([\w.-]+)/.test(aEntry.url) &&
-        !hosts[RegExp.$1] && _this._checkPrivacyLevel(_this._getURIFromString(aEntry.url).schemeIs("https"))) {
+        !hosts[currentContainer][RegExp.$1] && _this._checkPrivacyLevel(_this._getURIFromString(aEntry.url).schemeIs("https"))) {
         var host = RegExp.$1;
         var ix;
         for (ix = host.indexOf(".") + 1; ix; ix = host.indexOf(".", ix) + 1) {
-          hosts[host.substr(ix)] = true;
+          hosts[currentContainer][host.substr(ix)] = true;
         }
-        hosts[host] = true;
+        hosts[currentContainer][host] = true;
       }
       if (aEntry.children) {
         aEntry.children.forEach(extractHosts);
       }
     }
     
-    this._windows[aWindow.__SSi].tabs.forEach(function(aTabData) { aTabData.entries.forEach(extractHosts); });
+    this._windows[aWindow.__SSi].tabs.forEach(function(aTabData) {
+      currentContainer = aTabData.cookieContainer;
+      if (!hosts[currentContainer])
+        hosts[currentContainer] = {};
+      aTabData.entries.forEach(extractHosts);
+    });
   },
 
   /**
    * Serialize cookie data
    * @param aWindows
    *        array of Window references
    */
   _updateCookies: function sss_updateCookies(aWindows) {
-    var cookiesEnum = Cc["@mozilla.org/cookiemanager;1"].
-                      getService(Ci.nsICookieManager).enumerator;
+    var cookieSvc = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService);
     // collect the cookies per window
     for (var i = 0; i < aWindows.length; i++) {
-      aWindows[i].cookies = { count: 0 };
+      aWindows[i].cookieContainers = { };
     }
     
-    var _this = this;
-    while (cookiesEnum.hasMoreElements()) {
-      var cookie = cookiesEnum.getNext().QueryInterface(Ci.nsICookie2);
-      if (cookie.isSession && cookie.host) {
-        var url = "", value = "";
-        aWindows.forEach(function(aWindow) {
-          if (aWindow._hosts && aWindow._hosts[cookie.rawHost]) {
-            // make sure to construct URL and value only once per cookie
-            if (!url) {
-              var url = "http" + (cookie.isSecure ? "s" : "") + "://" + cookie.host + (cookie.path || "").replace(/^(?!\/)/, "/");
-              if (_this._checkPrivacyLevel(cookie.isSecure)) {
-                value = (cookie.name || "name") + "=" + (cookie.value || "") + ";";
-                value += cookie.isDomain ? "domain=" + cookie.rawHost + ";" : "";
-                value += cookie.path ? "path=" + cookie.path + ";" : "";
-                value += cookie.isSecure ? "secure;" : "";
-              }
-            }
-            if (value) {
-              // in order to not unnecessarily bloat the session file,
-              // all window cookies are saved into one JS object
-              var cookies = aWindow.cookies;
-              cookies["domain" + ++cookies.count] = url;
-              cookies["value" + cookies.count] = value;
-            }
-          }
-        });
+    var _this = this;
+    var containers = [];
+    // for each window, retrieve the associated container
+    aWindows.forEach(function(aWindow) {
+      for (var cookieContainerId in aWindow._containerHosts) {
+	    var container = cookieSvc.getContainer(cookieContainerId);
+	    if (containers.indexOf(container) == -1)
+          containers.push(container);
+      }
+    });
+    
+    containers.forEach(function(aContainer) {
+      var containerId = aContainer.containerId;
+      dump("CCCCCCCCCCC PROCESSING "+containerId+"\n");
+      var cookiesEnum = aContainer.QueryInterface(Ci.nsICookieManager).enumerator;
+      while (cookiesEnum.hasMoreElements()) {
+        var cookie = cookiesEnum.getNext().QueryInterface(Ci.nsICookie2);
+        if (cookie.isSession && cookie.host) {
+          var url = "", value = "";
+          aWindows.forEach(function(aWindow) {
+            if (aWindow._containerHosts[containerId] && aWindow._containerHosts[containerId][cookie.rawHost]) {
+              // make sure to construct URL and value only once per cookie
+              if (!url) {
+                var url = "http" + (cookie.isSecure ? "s" : "") + "://" + cookie.host + (cookie.path || "").replace(/^(?!\/)/, "/");
+                if (_this._checkPrivacyLevel(cookie.isSecure)) {
+                  value = (cookie.name || "name") + "=" + (cookie.value || "") + ";";
+                  value += cookie.isDomain ? "domain=" + cookie.rawHost + ";" : "";
+                  value += cookie.path ? "path=" + cookie.path + ";" : "";
+                  value += cookie.isSecure ? "secure;" : "";
+                  value += cookie.httpOnly ? "HttpOnly;" : "";
+                }
+              }
+              if (value) {
+                // in order to not unnecessarily bloat the session file,
+                // all window cookies are saved into one JS object
+                var cookies = aWindow.cookieContainers;
+                if (!cookies[containerId])
+                  cookies[containerId] = { count: 0 };
+                cookies[containerId]["domain" + ++cookies[containerId].count] = url;
+                cookies[containerId]["value" + cookies[containerId].count] = value;
+              }
+              dump("CCCCCCCCCCC ADD "+cookie.host+" "+cookie.name+"\n");
+            }
+          });
+        }
       }
-    }
+    });
     
     // don't include empty cookie sections
     for (i = 0; i < aWindows.length; i++) {
-      if (aWindows[i].cookies.count == 0) {
-        delete aWindows[i].cookies;
+      if (aWindows[i].cookieContainers.count == 0) {
+        delete aWindows[i].cookieContainers;
       }
     }
   },
 
   /**
    * Store window dimensions, visibility, sidebar
    * @param aWindow
    *        Window reference
@@ -1209,18 +1236,18 @@ SessionStoreService.prototype = {
     // when overwriting tabs, remove all superflous ones
     for (t = openTabCount - 1; t >= newTabCount; t--) {
       tabbrowser.removeTab(tabbrowser.mTabs[t]);
     }
     
     if (aOverwriteTabs) {
       this.restoreWindowFeatures(aWindow, winData, root.opener || null);
     }
-    if (winData.cookies) {
-      this.restoreCookies(winData.cookies);
+    if (winData.cookieContainers) {
+      this.restoreCookies(winData.cookieContainers);
     }
     if (winData.extData) {
       if (!this._windows[aWindow.__SSi].extData) {
         this._windows[aWindow.__SSi].extData = {}
       }
       for (var key in winData.extData) {
         this._windows[aWindow.__SSi].extData[key] = winData.extData[key];
       }
@@ -1339,16 +1366,21 @@ SessionStoreService.prototype = {
     if (tabData.xultab) {
       tabData.xultab.split(" ").forEach(function(aAttr) {
         if (/^([^\s=]+)=(.*)/.test(aAttr)) {
           tab.setAttribute(RegExp.$1, decodeURI(RegExp.$2));
         }
       });
     }
     
+    if (tabData.cookieContainer) {
+      var cookieSvc = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService);
+      browser.docShell.QueryInterface(Ci.nsICookieCollector).cookieContainer = cookieSvc.getContainer(tabData.cookieContainer);
+    }
+    
     // notify the tabbrowser that the tab chrome has been restored
     var event = aWindow.document.createEvent("Events");
     event.initEvent("SSTabRestoring", true, false);
     tab.dispatchEvent(event);
     
     var activeIndex = (tabData.index || tabData.entries.length) - 1;
     try {
       browser.webNavigation.gotoIndex(activeIndex);
@@ -1561,21 +1593,25 @@ SessionStoreService.prototype = {
    *        Array of cookie data
    */
   restoreCookies: function sss_restoreCookies(aCookies) {
     var cookieService = Cc["@mozilla.org/cookieService;1"].
                         getService(Ci.nsICookieService);
     var ioService = Cc["@mozilla.org/network/io-service;1"].
                     getService(Ci.nsIIOService);
     
-    for (var i = 1; i <= aCookies.count; i++) {
-      try {
-        cookieService.setCookieString(ioService.newURI(aCookies["domain" + i], null, null), null, aCookies["value" + i] + "expires=0;", null);
+    for (let [cookieContainerId, cookies] in aCookies) {
+      var cookieContainer = cookieService.getContainer(cookieContainerId);
+      for (var i = 1; i <= cookies.count; i++) {
+        try {
+          cookieService.setCookieString(cookieContainer, ioService.newURI(cookies["domain" + i], null, null),
+                                        null, cookies["value" + i] + "expires=0;", null);
+        }
+        catch (ex) { debug(ex); } // don't let a single cookie stop recovering (might happen if a user tried to edit the session file)
       }
-      catch (ex) { debug(ex); } // don't let a single cookie stop recovering (might happen if a user tried to edit the session file)
     }
   },
 
   /**
    * Restart incomplete downloads
    * @param aWindow
    *        Window reference
    */
Index: content/base/public/nsIDocument.h
===================================================================
RCS file: /cvsroot/mozilla/content/base/public/nsIDocument.h,v
retrieving revision 3.264
diff -p -U 8 -r3.264 nsIDocument.h
--- content/base/public/nsIDocument.h	10 May 2007 20:21:12 -0000	3.264
+++ content/base/public/nsIDocument.h	14 May 2007 09:21:13 -0000
@@ -113,16 +113,17 @@ public:
 #ifdef MOZILLA_INTERNAL_API
   nsIDocument()
     : nsINode(nsnull),
       mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
       mBindingManager(nsnull),
       mNodeInfoManager(nsnull),
       mCompatMode(eCompatibility_FullStandards),
       mIsInitialDocumentInWindow(PR_FALSE),
+      mDocumentContainer(nsnull),
       mPartID(0)
   {
     mParentPtrBits |= PARENT_BIT_INDOCUMENT;
   }
 #endif
   
   /**
    * Let the document know that we're starting to load data into it.
Index: content/base/src/nsContentSink.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/base/src/nsContentSink.cpp,v
retrieving revision 1.75
diff -p -U 8 -r1.75 nsContentSink.cpp
--- content/base/src/nsContentSink.cpp	14 May 2007 03:52:49 -0000	1.75
+++ content/base/src/nsContentSink.cpp	14 May 2007 09:21:15 -0000
@@ -81,16 +81,18 @@
 #include "nsTimer.h"
 #include "nsIAppShell.h"
 #include "nsWidgetsCID.h"
 #include "nsIDOMNSDocument.h"
 #include "nsIRequest.h"
 #include "nsNodeUtils.h"
 #include "nsIDOMNode.h"
 #include "nsThreadUtils.h"
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
 
 PRLogModuleInfo* gContentSinkLogModuleInfo;
 
 class nsScriptLoaderObserverProxy : public nsIScriptLoaderObserver
 {
 public:
   nsScriptLoaderObserverProxy(nsIScriptLoaderObserver* aInner)
     : mInner(do_GetWeakReference(aInner))
@@ -427,17 +429,24 @@ nsContentSink::ProcessHeaderData(nsIAtom
       window->GetPrompter(getter_AddRefs(prompt));
     }
 
     nsCOMPtr<nsIChannel> channel;
     if (mParser) {
       mParser->GetChannel(getter_AddRefs(channel));
     }
 
-    rv = cookieServ->SetCookieString(codebaseURI,
+    // find the cookie container
+    nsCOMPtr<nsISupports> docShell = mDocument->GetContainer();
+    nsCOMPtr<nsICookieCollector> cookieCollector = do_QueryInterface(docShell);
+    nsCOMPtr<nsICookieContainer> cookieContainer;
+    cookieCollector->GetCookieContainer(getter_AddRefs(cookieContainer));
+
+    rv = cookieServ->SetCookieString(cookieContainer,
+                                     codebaseURI,
                                      prompt,
                                      NS_ConvertUTF16toUTF8(aValue).get(),
                                      channel);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
   else if (aHeader == nsGkAtoms::link) {
Index: content/base/src/nsDocument.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/base/src/nsDocument.cpp,v
retrieving revision 3.732
diff -p -U 8 -r3.732 nsDocument.cpp
--- content/base/src/nsDocument.cpp	12 May 2007 15:36:28 -0000	3.732
+++ content/base/src/nsDocument.cpp	14 May 2007 09:21:21 -0000
@@ -133,16 +133,19 @@ static NS_DEFINE_CID(kDOMEventGroupCID, 
 
 #include "nsIScriptContext.h"
 #include "nsBindingManager.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIRequest.h"
 #include "nsILink.h"
 
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
+
 #include "nsICharsetAlias.h"
 #include "nsIParser.h"
 #include "nsIContentSink.h"
 
 #include "nsDateTimeFormatCID.h"
 #include "nsIDateTimeFormat.h"
 #include "nsEventDispatcher.h"
 #include "nsMutationEvent.h"
@@ -901,16 +904,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
   NS_INTERFACE_MAP_ENTRY(nsPIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsIDOM3Node)
   NS_INTERFACE_MAP_ENTRY(nsIDOM3Document)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
   NS_INTERFACE_MAP_ENTRY(nsINode)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocument)
   if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) ||
       aIID.Equals(NS_GET_IID(nsIXPathEvaluatorInternal))) {
     if (!mXPathEvaluatorTearoff) {
       nsresult rv;
       mXPathEvaluatorTearoff =
         do_CreateInstance(NS_XPATH_EVALUATOR_CONTRACTID,
                           NS_STATIC_CAST(nsIDocument *, this), &rv);
@@ -5870,8 +5874,38 @@ nsDocument::GetScriptTypeID(PRUint32 *aS
 }
 
 NS_IMETHODIMP
 nsDocument::SetScriptTypeID(PRUint32 aScriptType)
 {
     NS_ERROR("Can't change default script type for a document");
     return NS_ERROR_NOT_IMPLEMENTED;
 }
+
+NS_IMETHODIMP
+nsDocument::GetInterface(const nsIID & aIID, void **aSink)
+{
+    NS_ENSURE_ARG_POINTER(aSink);
+    *aSink = nsnull;
+    nsresult rv;
+
+    if (aIID.Equals(NS_GET_IID(nsICookieCollector))) {
+        *aSink = mDocumentContainer;
+    }
+    else if (aIID.Equals(NS_GET_IID(nsICookieContainer))) {
+        nsCOMPtr<nsICookieCollector> cookieCollector = do_QueryReferent(mDocumentContainer);
+        nsCOMPtr<nsICookieContainer> cookieContainer = nsnull;
+        if (cookieCollector) {
+            cookieCollector->GetCookieContainer(getter_AddRefs(cookieContainer));
+        }
+        if (!cookieContainer)
+            return NS_NOINTERFACE;
+        *aSink = cookieContainer;
+    }
+
+    if (*aSink) {
+        NS_IF_ADDREF(((nsISupports *) * aSink));
+        return NS_OK;
+    }
+    else
+        return QueryInterface(aIID, aSink);
+}
+
Index: content/base/src/nsDocument.h
===================================================================
RCS file: /cvsroot/mozilla/content/base/src/nsDocument.h,v
retrieving revision 3.340
diff -p -U 8 -r3.340 nsDocument.h
--- content/base/src/nsDocument.h	12 May 2007 15:36:28 -0000	3.340
+++ content/base/src/nsDocument.h	14 May 2007 09:21:24 -0000
@@ -87,16 +87,17 @@
 #include "nsIScriptEventManager.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIRequest.h"
 #include "nsILoadGroup.h"
 #include "nsTObserverArray.h"
 #include "nsStubMutationObserver.h"
 #include "nsIChannel.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsIInterfaceRequestor.h"
 
 // Put these here so all document impls get them automatically
 #include "nsHTMLStyleSheet.h"
 #include "nsIHTMLCSSStyleSheet.h"
 
 #include "nsStyleSet.h"
 #include "nsXMLEventsManager.h"
 #include "pldhash.h"
@@ -288,17 +289,18 @@ class nsDocument : public nsIDocument,
                    public nsIDOMDocumentXBL,
                    public nsIDOM3Document,
                    public nsSupportsWeakReference,
                    public nsIDOMEventReceiver,
                    public nsIDOM3EventTarget,
                    public nsIDOMNSEventTarget,
                    public nsIScriptObjectPrincipal,
                    public nsIRadioGroupContainer,
-                   public nsStubMutationObserver
+                   public nsStubMutationObserver,
+                   public nsIInterfaceRequestor
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup);
   virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
                           nsIPrincipal* aPrincipal);
 
@@ -615,16 +617,19 @@ public:
   NS_DECL_NSIDOMEVENTTARGET
 
   // nsIDOM3EventTarget
   NS_DECL_NSIDOM3EVENTTARGET
 
   // nsIDOMNSEventTarget
   NS_DECL_NSIDOMNSEVENTTARGET
 
+  // nsIInterfaceRequestor
+  NS_DECL_NSIINTERFACEREQUESTOR
+
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal();
 
   virtual nsresult Init();
   
   virtual nsresult AddXMLEventsContent(nsIContent * aXMLEventsElement);
 
   virtual nsresult CreateElem(nsIAtom *aName, nsIAtom *aPrefix,
Index: content/base/src/nsObjectLoadingContent.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/base/src/nsObjectLoadingContent.cpp,v
retrieving revision 1.40
diff -p -U 8 -r1.40 nsObjectLoadingContent.cpp
--- content/base/src/nsObjectLoadingContent.cpp	1 May 2007 22:24:20 -0000	1.40
+++ content/base/src/nsObjectLoadingContent.cpp	14 May 2007 09:21:27 -0000
@@ -55,16 +55,18 @@
 #include "nsIPresShell.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIStreamConverterService.h"
 #include "nsIURILoader.h"
 #include "nsIURL.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebNavigationInfo.h"
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
 
 #include "nsPluginError.h"
 
 // Util headers
 #include "prlog.h"
 
 #include "nsAutoPtr.h"
 #include "nsCURILoader.h"
@@ -970,16 +972,23 @@ nsObjectLoadingContent::LoadObject(nsIUR
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Referrer
   nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
   if (httpChan) {
     httpChan->SetReferrer(doc->GetDocumentURI());
   }
 
+  // set the cookie container of the channel to that of the doc's
+  nsCOMPtr<nsICookieCollector> cookieCollector(do_QueryInterface(chan));
+  if (cookieCollector) {
+    nsCOMPtr<nsICookieContainer> container(do_GetInterface(doc));
+    cookieCollector->SetCookieContainer(container);
+  }
+
   // MIME Type hint
   if (!aTypeHint.IsEmpty()) {
     chan->SetContentType(aTypeHint);
   }
 
   // AsyncOpen can fail if a file does not exist.
   // Show fallback content in that case.
   rv = chan->AsyncOpen(this, nsnull);
Index: content/base/src/nsScriptLoader.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/base/src/nsScriptLoader.cpp,v
retrieving revision 1.104
diff -p -U 8 -r1.104 nsScriptLoader.cpp
--- content/base/src/nsScriptLoader.cpp	11 Apr 2007 20:18:11 -0000	1.104
+++ content/base/src/nsScriptLoader.cpp	14 May 2007 09:21:29 -0000
@@ -64,16 +64,18 @@
 #include "jscntxt.h"
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsAutoPtr.h"
 #include "nsIXPConnect.h"
 #include "nsContentErrors.h"
 #include "nsIParser.h"
 #include "nsThreadUtils.h"
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
 
 //////////////////////////////////////////////////////////////
 //
 //////////////////////////////////////////////////////////////
 
 // If aMaybeCertPrincipal is a cert principal and aNewPrincipal is not the same
 // as aMaybeCertPrincipal, downgrade aMaybeCertPrincipal to a codebase
 // principal.  Return the downgraded principal, or aMaybeCertPrincipal if no
@@ -463,16 +465,23 @@ nsScriptLoader::ProcessScriptElement(nsI
     if (httpChannel) {
       // HTTP content negotation has little value in this context.
       httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                     NS_LITERAL_CSTRING("*/*"),
                                     PR_FALSE);
       httpChannel->SetReferrer(mDocument->GetDocumentURI());
     }
 
+    // set the cookie container of the channel to that of the doc's
+    nsCOMPtr<nsICookieCollector> cookieCollector(do_QueryInterface(channel));
+    if (cookieCollector) {
+      nsCOMPtr<nsICookieContainer> container(do_GetInterface(mDocument));
+      cookieCollector->SetCookieContainer(container);
+    }
+
     rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = channel->AsyncOpen(loader, request);
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     request->mLoading = PR_FALSE;
     request->mIsInline = PR_TRUE;
Index: content/base/src/nsXMLHttpRequest.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/base/src/nsXMLHttpRequest.cpp,v
retrieving revision 1.179
diff -p -U 8 -r1.179 nsXMLHttpRequest.cpp
--- content/base/src/nsXMLHttpRequest.cpp	13 May 2007 16:41:46 -0000	1.179
+++ content/base/src/nsXMLHttpRequest.cpp	14 May 2007 09:21:36 -0000
@@ -77,16 +77,18 @@
 #include "nsDOMJSUtils.h"
 #include "nsCOMArray.h"
 #include "nsDOMClassInfo.h"
 #include "nsIScriptableUConv.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentErrors.h"
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
 
 #define LOAD_STR "load"
 #define ERROR_STR "error"
 #define PROGRESS_STR "progress"
 #define UPLOADPROGRESS_STR "uploadprogress"
 #define READYSTATE_STR "readystatechange"
 
 // CIDs
@@ -1090,16 +1092,25 @@ nsXMLHttpRequest::OpenRequest(const nsAC
   if (NS_FAILED(rv)) return rv;
 
   //mChannel->SetAuthTriedWithPrehost(authp);
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
   if (httpChannel) {
     rv = httpChannel->SetRequestMethod(method);
   }
+  if (NS_FAILED(rv)) return rv;
+
+  // set the http request cookie container to that of the parent document
+  nsCOMPtr<nsICookieCollector> cookieCollector(do_QueryInterface(mChannel));
+  if (cookieCollector && doc) {
+    // find the cookie container
+    nsCOMPtr<nsICookieContainer> cookieContainer = do_GetInterface(doc);
+    cookieCollector->SetCookieContainer(cookieContainer);
+  }
 
   ChangeState(XML_HTTP_REQUEST_OPENED);
 
   return rv;
 }
 
 /* void open (in AUTF8String method, in AUTF8String url); */
 NS_IMETHODIMP
Index: content/html/document/src/nsHTMLDocument.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/html/document/src/nsHTMLDocument.cpp,v
retrieving revision 3.720
diff -p -U 8 -r3.720 nsHTMLDocument.cpp
--- content/html/document/src/nsHTMLDocument.cpp	9 May 2007 02:47:58 -0000	3.720
+++ content/html/document/src/nsHTMLDocument.cpp	14 May 2007 09:21:44 -0000
@@ -123,16 +123,19 @@
 #include "nsIDocumentViewer.h"
 #include "nsIWyciwygChannel.h"
 #include "nsIScriptElement.h"
 #include "nsIScriptError.h"
 #include "nsIMutableArray.h"
 #include "nsArrayUtils.h"
 #include "nsIEffectiveTLDService.h"
 
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
+
 #include "nsIPrompt.h"
 //AHMED 12-2
 #include "nsBidiUtils.h"
 
 #include "nsIEditingSession.h"
 #include "nsIEditor.h"
 #include "nsNodeInfoManager.h"
 
@@ -1962,19 +1965,24 @@ nsHTMLDocument::GetCookie(nsAString& aCo
     NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
 
     if (!codebaseURI) {
       // Document's principal is not a codebase (may be system), so
       // can't set cookies
 
       return NS_OK;
     }
+	
+    // find the cookie container
+    nsCOMPtr<nsICookieCollector> cookieCollector = do_QueryReferent(mDocumentContainer);
+    nsCOMPtr<nsICookieContainer> cookieContainer;
+    cookieCollector->GetCookieContainer(getter_AddRefs(cookieContainer));
 
     nsXPIDLCString cookie;
-    service->GetCookieString(codebaseURI, mChannel, getter_Copies(cookie));
+    service->GetCookieString(cookieContainer, codebaseURI, mChannel, getter_Copies(cookie));
     CopyASCIItoUTF16(cookie, aCookie);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::SetCookie(const nsAString& aCookie)
@@ -1993,18 +2001,23 @@ nsHTMLDocument::SetCookie(const nsAStrin
 
     if (!codebaseURI) {
       // Document's principal is not a codebase (may be system), so
       // can't set cookies
 
       return NS_OK;
     }
 
+	// find the cookie container
+    nsCOMPtr<nsICookieCollector> cookieCollector = do_QueryReferent(mDocumentContainer);
+    nsCOMPtr<nsICookieContainer> cookieContainer;
+    cookieCollector->GetCookieContainer(getter_AddRefs(cookieContainer));
+
     NS_LossyConvertUTF16toASCII cookie(aCookie);
-    service->SetCookieString(codebaseURI, prompt, cookie.get(), mChannel);
+    service->SetCookieString(cookieContainer, codebaseURI, prompt, cookie.get(), mChannel);
   }
 
   return NS_OK;
 }
 
 // XXX TBI: accepting arguments to the open method.
 nsresult
 nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
@@ -2101,16 +2114,23 @@ nsHTMLDocument::OpenCommon(const nsACStr
   nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup);
 
   rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, group);
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
+  nsCOMPtr<nsICookieCollector> cookieCollector(do_QueryInterface(channel));
+  if (cookieCollector) {
+    nsCOMPtr<nsICookieCollector> cookieCollector = do_QueryReferent(mDocumentContainer);
+    nsCOMPtr<nsICookieContainer> cookieContainer;
+    cookieCollector->GetCookieContainer(getter_AddRefs(cookieContainer));
+  }
+
   // Set the caller principal, if any, on the channel so that we'll
   // make sure to use it when we reset.
   rv = channel->SetOwner(callerPrincipal);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Before we reset the doc notify the globalwindow of the change,
   // but only if we still have a window (i.e. our window object the
   // current inner window in our outer window).
Index: content/xbl/src/nsXBLService.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/xbl/src/nsXBLService.cpp,v
retrieving revision 1.235
diff -p -U 8 -r1.235 nsXBLService.cpp
--- content/xbl/src/nsXBLService.cpp	11 May 2007 13:34:07 -0000	1.235
+++ content/xbl/src/nsXBLService.cpp	14 May 2007 09:21:48 -0000
@@ -70,16 +70,19 @@
 #include "nsXBLPrototypeBinding.h"
 #include "nsIXBLDocumentInfo.h"
 #include "nsCRT.h"
 #include "nsContentUtils.h"
 #include "nsSyncLoadService.h"
 #include "nsIDOM3Node.h"
 #include "nsContentPolicyUtils.h"
 
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
+
 #include "nsIPresShell.h"
 #include "nsIDocumentObserver.h"
 #include "nsFrameManager.h"
 #include "nsStyleContext.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptError.h"
 
 #ifdef MOZ_XUL
@@ -1126,16 +1129,23 @@ nsXBLService::FetchBindingDocument(nsICo
   rv = NS_NewXBLContentSink(getter_AddRefs(xblSink), doc, aDocumentURI, nsnull);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Open channel
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel), aDocumentURI, nsnull, loadGroup);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // set the cookie container of the channel to that of the doc's
+  nsCOMPtr<nsICookieCollector> cookieCollector(do_QueryInterface(channel));
+  if (cookieCollector) {
+    nsCOMPtr<nsICookieContainer> container(do_GetInterface(aBoundDocument));
+    cookieCollector->SetCookieContainer(container);
+  }
+
   nsCOMPtr<nsIStreamListener> listener;
   rv = doc->StartDocumentLoad("loadAsInteractiveData",
                               channel,
                               loadGroup,
                               nsnull,
                               getter_AddRefs(listener),
                               PR_TRUE,
                               xblSink);
Index: content/xml/document/src/nsXMLContentSink.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/xml/document/src/nsXMLContentSink.cpp,v
retrieving revision 1.413
diff -p -U 8 -r1.413 nsXMLContentSink.cpp
--- content/xml/document/src/nsXMLContentSink.cpp	1 May 2007 22:24:21 -0000	1.413
+++ content/xml/document/src/nsXMLContentSink.cpp	14 May 2007 09:21:51 -0000
@@ -675,18 +675,17 @@ nsXMLContentSink::LoadXSLStyleSheet(nsIU
   mXSLTProcessor->SetTransformObserver(this);
 
   nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
   if (!loadGroup) {
     mXSLTProcessor = nsnull;
     return NS_ERROR_FAILURE;
   }
 
-  return mXSLTProcessor->LoadStyleSheet(aUrl, loadGroup,
-                                        mDocument->NodePrincipal());
+  return mXSLTProcessor->LoadStyleSheet(aUrl, loadGroup, mDocument);
 }
 
 nsresult
 nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
                                    const nsSubstring& aHref,
                                    PRBool aAlternate,
                                    const nsSubstring& aTitle,
                                    const nsSubstring& aType,
Index: content/xml/document/src/nsXMLDocument.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/xml/document/src/nsXMLDocument.cpp,v
retrieving revision 1.256
diff -p -U 8 -r1.256 nsXMLDocument.cpp
--- content/xml/document/src/nsXMLDocument.cpp	25 Apr 2007 16:35:28 -0000	1.256
+++ content/xml/document/src/nsXMLDocument.cpp	14 May 2007 09:21:52 -0000
@@ -86,16 +86,18 @@
 #include "nsIWindowWatcher.h"
 #include "nsIAuthPrompt.h"
 #include "nsIScriptGlobalObjectOwner.h"
 #include "nsIJSContextStack.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsEventDispatcher.h"
 #include "nsNodeUtils.h"
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
 
 
 // ==================================================================
 // =
 // ==================================================================
 
 
 nsresult
@@ -194,17 +196,16 @@ nsXMLDocument::~nsXMLDocument()
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLDocument)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLDocument, nsDocument)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 // QueryInterface implementation for nsXMLDocument
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLDocument)
-  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
   NS_INTERFACE_MAP_ENTRY(nsIDOMXMLDocument)
   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XMLDocument)
 NS_INTERFACE_MAP_END_INHERITING(nsDocument)
 
 
 NS_IMPL_ADDREF_INHERITED(nsXMLDocument, nsDocument)
 NS_IMPL_RELEASE_INHERITED(nsXMLDocument, nsDocument)
@@ -241,38 +242,41 @@ nsXMLDocument::ResetToURI(nsIURI *aURI, 
 }
 
 /////////////////////////////////////////////////////
 // nsIInterfaceRequestor methods:
 //
 NS_IMETHODIMP
 nsXMLDocument::GetInterface(const nsIID& aIID, void** aSink)
 {
-  if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
-    NS_ENSURE_ARG_POINTER(aSink);
-    *aSink = nsnull;
+  NS_ENSURE_ARG_POINTER(aSink);
+  *aSink = nsnull;
+  nsresult rv;
 
-    nsresult rv;
+  if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
     nsCOMPtr<nsIWindowWatcher> ww(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
     if (NS_FAILED(rv))
       return rv;
 
     nsCOMPtr<nsIAuthPrompt> prompt;
     rv = ww->GetNewAuthPrompter(nsnull, getter_AddRefs(prompt));
     if (NS_FAILED(rv))
       return rv;
 
     nsIAuthPrompt *p = prompt.get();
     NS_ADDREF(p);
     *aSink = p;
     return NS_OK;
   }
 
-
-  return QueryInterface(aIID, aSink);
+  rv = nsDocument::GetInterface(aIID, aSink);
+  if (NS_FAILED(rv))
+    return QueryInterface(aIID, aSink);
+  else
+    return NS_OK;
 }
 
 // nsIChannelEventSink
 NS_IMETHODIMP
 nsXMLDocument::OnChannelRedirect(nsIChannel *aOldChannel,
                                  nsIChannel *aNewChannel,
                                  PRUint32 aFlags)
 {
@@ -481,16 +485,25 @@ nsXMLDocument::Load(const nsAString& aUr
   // nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active,
   // which in turn keeps STOP button from becoming active  
   rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, loadGroup, this, 
                      nsIRequest::LOAD_BACKGROUND);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
+  // set the cookie container of the channel to that of the doc's
+  nsCOMPtr<nsICookieCollector> cookieCollector(do_QueryInterface(channel));
+  if (cookieCollector) {
+    nsCOMPtr<nsICookieContainer> cookieContainer;
+    nsCOMPtr<nsICookieCollector> parentCollector = do_QueryReferent(mDocumentContainer);
+    parentCollector->GetCookieContainer(getter_AddRefs(cookieContainer));
+    cookieCollector->SetCookieContainer(cookieContainer);
+  }
+
   // Set a principal for this document
   // XXXbz StartDocumentLoad should handle that.... And we shouldn't be calling
   // StartDocumentLoad until we get an OnStartRequest from this channel!
   nsCOMPtr<nsISupports> channelOwner;
   rv = channel->GetOwner(getter_AddRefs(channelOwner));
 
   // We don't care if GetOwner() succeeded here, if it failed,
   // channelOwner will be null, which is what we want in that case.
Index: content/xml/document/src/nsXMLDocument.h
===================================================================
RCS file: /cvsroot/mozilla/content/xml/document/src/nsXMLDocument.h,v
retrieving revision 1.86
diff -p -U 8 -r1.86 nsXMLDocument.h
--- content/xml/document/src/nsXMLDocument.h	8 Mar 2007 11:17:13 -0000	1.86
+++ content/xml/document/src/nsXMLDocument.h	14 May 2007 09:21:52 -0000
@@ -48,17 +48,16 @@
 #include "nsIHTMLCSSStyleSheet.h"
 
 class nsIParser;
 class nsIDOMNode;
 class nsIURI;
 class nsIChannel;
 
 class nsXMLDocument : public nsDocument,
-                      public nsIInterfaceRequestor,
                       public nsIChannelEventSink
 {
 public:
   nsXMLDocument(const char* aContentType = "application/xml");
   virtual ~nsXMLDocument();
 
   NS_DECL_ISUPPORTS_INHERITED
 
Index: content/xslt/public/nsIDocumentTransformer.h
===================================================================
RCS file: /cvsroot/mozilla/content/xslt/public/nsIDocumentTransformer.h,v
retrieving revision 1.7
diff -p -U 8 -r1.7 nsIDocumentTransformer.h
--- content/xslt/public/nsIDocumentTransformer.h	3 Oct 2006 02:22:22 -0000	1.7
+++ content/xslt/public/nsIDocumentTransformer.h	14 May 2007 09:21:53 -0000
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
  
 #ifndef nsIDocumentTransformer_h__
 #define nsIDocumentTransformer_h__
 
 #include "nsISupports.h"
 
 class nsIDOMDocument;
+class nsIDocument;
 class nsIDOMNode;
 class nsILoadGroup;
 class nsIURI;
 class nsIPrincipal;
 class nsString;
 
 #define NS_ITRANSFORMOBSERVER_IID \
 { 0x04b2d17c, 0xe98d, 0x45f5, \
@@ -73,17 +74,17 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsITransfo
 class nsIDocumentTransformer : public nsISupports
 {
 public: 
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENTTRANSFORMER_IID)
 
   NS_IMETHOD SetTransformObserver(nsITransformObserver* aObserver) = 0;
   NS_IMETHOD LoadStyleSheet(nsIURI* aUri, nsILoadGroup* aLoadGroup,
-                            nsIPrincipal* aCallerPrincipal) = 0;
+                            nsIDocument* aCallerDocument) = 0;
   NS_IMETHOD SetSourceContentModel(nsIDOMNode* aSource) = 0;
   NS_IMETHOD CancelLoads() = 0;
 
   NS_IMETHOD AddXSLTParamNamespace(const nsString& aPrefix,
                                    const nsString& aNamespace) = 0;
   NS_IMETHOD AddXSLTParam(const nsString& aName,
                           const nsString& aNamespace,
                           const nsString& aValue,
Index: content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp,v
retrieving revision 1.48
diff -p -U 8 -r1.48 txMozillaStylesheetCompiler.cpp
--- content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp	30 Jan 2007 21:21:04 -0000	1.48
+++ content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp	14 May 2007 09:21:56 -0000
@@ -64,16 +64,19 @@
 #include "txAtoms.h"
 #include "txLog.h"
 #include "txMozillaXSLTProcessor.h"
 #include "txStylesheetCompiler.h"
 #include "txXMLUtils.h"
 #include "nsAttrName.h"
 #include "nsIScriptError.h"
 
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
+
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
 static void
 getSpec(nsIChannel* aChannel, nsAString& aSpec)
 {
     if (!aChannel) {
         return;
     }
@@ -466,17 +469,17 @@ class txCompileObserver : public txAComp
 public:
     txCompileObserver(txMozillaXSLTProcessor* aProcessor,
                       nsILoadGroup* aLoadGroup);
     virtual ~txCompileObserver();
 
     TX_DECL_ACOMPILEOBSERVER;
 
     nsresult startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
-                       nsIURI* aReferrerURI);
+                       nsIURI* aReferrerURI, nsICookieContainer* aCookieContainer);
 
 protected:
     nsAutoRefCnt mRefCnt;
 
 private:
     nsRefPtr<txMozillaXSLTProcessor> mProcessor;
     nsCOMPtr<nsILoadGroup> mLoadGroup;
 
@@ -529,17 +532,17 @@ txCompileObserver::loadURI(const nsAStri
     nsCOMPtr<nsIURI> referrerUri;
     rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Do security check.
     rv = CheckLoadURI(uri, referrerUri, nsnull, nsnull);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    return startLoad(uri, aCompiler, referrerUri);
+    return startLoad(uri, aCompiler, referrerUri, nsnull);
 }
 
 void
 txCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler,
                                    nsresult aResult,
                                    const PRUnichar *aErrorText,
                                    const PRUnichar *aParam)
 {
@@ -548,17 +551,17 @@ txCompileObserver::onDoneCompiling(txSty
     }
     else {
         mProcessor->reportError(aResult, aErrorText, aParam);
     }
 }
 
 nsresult
 txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
-                             nsIURI* aReferrerURI)
+                             nsIURI* aReferrerURI, nsICookieContainer* aCookieContainer)
 {
     nsCOMPtr<nsIChannel> channel;
     nsresult rv = NS_NewChannel(getter_AddRefs(channel), aUri);
     NS_ENSURE_SUCCESS(rv, rv);
 
     channel->SetLoadGroup(mLoadGroup);
 
     channel->SetContentType(NS_LITERAL_CSTRING("text/xml"));
@@ -568,16 +571,20 @@ txCompileObserver::startLoad(nsIURI* aUr
         httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                       NS_LITERAL_CSTRING("text/xml,application/xml,application/xhtml+xml,*/*;q=0.1"),
                                       PR_FALSE);
 
         if (aReferrerURI) {
             httpChannel->SetReferrer(aReferrerURI);
         }
     }
+    nsCOMPtr<nsICookieCollector> cookieCollector = do_QueryInterface(channel);
+    if (cookieCollector) {
+        cookieCollector->SetCookieContainer(aCookieContainer);
+    }
 
     nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsRefPtr<txStylesheetSink> sink = new txStylesheetSink(aCompiler, parser);
     NS_ENSURE_TRUE(sink, NS_ERROR_OUT_OF_MEMORY);
 
     channel->SetNotificationCallbacks(sink);
@@ -586,40 +593,45 @@ txCompileObserver::startLoad(nsIURI* aUr
     parser->SetContentSink(sink);
     parser->Parse(aUri);
 
     return channel->AsyncOpen(sink, parser);
 }
 
 nsresult
 TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor,
-             nsILoadGroup* aLoadGroup, nsIPrincipal* aCallerPrincipal)
+             nsILoadGroup* aLoadGroup, nsIDocument* aCallerDocument)
 {
     nsCAutoString spec;
     aUri->GetSpec(spec);
     PR_LOG(txLog::xslt, PR_LOG_ALWAYS, ("TX_LoadSheet: %s\n", spec.get()));
 
+    nsCOMPtr<nsIPrincipal> callerPrincipal = aCallerDocument->NodePrincipal();
+
     nsCOMPtr<nsIURI> referrerURI;
-    aCallerPrincipal->GetURI(getter_AddRefs(referrerURI));
+    callerPrincipal->GetURI(getter_AddRefs(referrerURI));
     NS_ASSERTION(referrerURI, "Caller principal must have a URI!");
 
+    nsCOMPtr<nsICookieContainer> cookieContainer;
+    cookieContainer = do_GetInterface(callerPrincipal);
+
     // Pass source document as the context
-    nsresult rv = CheckLoadURI(aUri, referrerURI, aCallerPrincipal,
+    nsresult rv = CheckLoadURI(aUri, referrerURI, callerPrincipal,
                                aProcessor->GetSourceContentModel());
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsRefPtr<txCompileObserver> observer =
         new txCompileObserver(aProcessor, aLoadGroup);
     NS_ENSURE_TRUE(observer, NS_ERROR_OUT_OF_MEMORY);
 
     nsRefPtr<txStylesheetCompiler> compiler =
         new txStylesheetCompiler(NS_ConvertUTF8toUTF16(spec), observer);
     NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
 
-    return observer->startLoad(aUri, compiler, referrerURI);
+    return observer->startLoad(aUri, compiler, referrerURI, cookieContainer);
 }
 
 /**
  * handling DOM->txStylesheet
  * Observer needs to do synchronous loads.
  */
 static nsresult
 handleNode(nsIDOMNode* aNode, txStylesheetCompiler* aCompiler)
Index: content/xslt/src/xslt/txMozillaXSLTProcessor.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp,v
retrieving revision 1.65
diff -p -U 8 -r1.65 txMozillaXSLTProcessor.cpp
--- content/xslt/src/xslt/txMozillaXSLTProcessor.cpp	22 Dec 2006 17:22:18 -0000	1.65
+++ content/xslt/src/xslt/txMozillaXSLTProcessor.cpp	14 May 2007 09:21:58 -0000
@@ -1017,19 +1017,19 @@ txMozillaXSLTProcessor::GetFlags(PRUint3
 
     *aFlags = mFlags;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 txMozillaXSLTProcessor::LoadStyleSheet(nsIURI* aUri, nsILoadGroup* aLoadGroup,
-                                       nsIPrincipal* aCallerPrincipal)
+                                       nsIDocument* aCallerDocument)
 {
-    nsresult rv = TX_LoadSheet(aUri, this, aLoadGroup, aCallerPrincipal);
+    nsresult rv = TX_LoadSheet(aUri, this, aLoadGroup, aCallerDocument);
     if (NS_FAILED(rv) && mObserver) {
         // This is most likely a network or security error, just
         // use the uri as context.
         nsCAutoString spec;
         aUri->GetSpec(spec);
         CopyUTF8toUTF16(spec, mSourceText);
         nsresult status = NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_XSLT ? rv :
                           NS_ERROR_XSLT_NETWORK_ERROR;
Index: content/xslt/src/xslt/txMozillaXSLTProcessor.h
===================================================================
RCS file: /cvsroot/mozilla/content/xslt/src/xslt/txMozillaXSLTProcessor.h,v
retrieving revision 1.26
diff -p -U 8 -r1.26 txMozillaXSLTProcessor.h
--- content/xslt/src/xslt/txMozillaXSLTProcessor.h	23 Apr 2007 14:21:54 -0000	1.26
+++ content/xslt/src/xslt/txMozillaXSLTProcessor.h	14 May 2007 09:21:58 -0000
@@ -95,17 +95,17 @@ public:
     NS_DECL_NSIXSLTPROCESSOROBSOLETE
 
     // nsIXSLTProcessorPrivate interface
     NS_DECL_NSIXSLTPROCESSORPRIVATE
 
     // nsIDocumentTransformer interface
     NS_IMETHOD SetTransformObserver(nsITransformObserver* aObserver);
     NS_IMETHOD LoadStyleSheet(nsIURI* aUri, nsILoadGroup* aLoadGroup,
-                              nsIPrincipal* aCallerPrincipal);
+                              nsIDocument* aCallerDocument);
     NS_IMETHOD SetSourceContentModel(nsIDOMNode* aSource);
     NS_IMETHOD CancelLoads() {return NS_OK;}
     NS_IMETHOD AddXSLTParamNamespace(const nsString& aPrefix,
                                      const nsString& aNamespace);
     NS_IMETHOD AddXSLTParam(const nsString& aName,
                             const nsString& aNamespace,
                             const nsString& aSelect,
                             const nsString& aValue,
@@ -157,15 +157,15 @@ private:
     txNamespaceMap mParamNamespaceMap;
     nsRefPtr<txResultRecycler> mRecycler;
 
     PRUint32 mFlags;
 };
 
 extern nsresult TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor,
                              nsILoadGroup* aLoadGroup,
-                             nsIPrincipal* aCallerPrincipal);
+                             nsIDocument* aCallerDocument);
 
 extern nsresult TX_CompileStylesheet(nsIDOMNode* aNode,
                                      txMozillaXSLTProcessor* aProcessor,
                                      txStylesheet** aStylesheet);
 
 #endif
Index: docshell/base/nsDocShell.cpp
===================================================================
RCS file: /cvsroot/mozilla/docshell/base/nsDocShell.cpp,v
retrieving revision 1.833
diff -p -U 8 -r1.833 nsDocShell.cpp
--- docshell/base/nsDocShell.cpp	6 May 2007 21:06:27 -0000	1.833
+++ docshell/base/nsDocShell.cpp	14 May 2007 09:22:19 -0000
@@ -133,16 +133,17 @@
 #include "nsIHistoryEntry.h"
 #include "nsISHistoryListener.h"
 #include "nsIWindowWatcher.h"
 #include "nsIPromptFactory.h"
 #include "nsIObserver.h"
 #include "nsINestedURI.h"
 #include "nsITransportSecurityInfo.h"
 #include "nsINSSErrorsService.h"
+#include "nsICookieService.h"
 
 // Editor-related
 #include "nsIEditingSession.h"
 
 #include "nsPIDOMWindow.h"
 #include "nsIDOMDocument.h"
 #include "nsICachingChannel.h"
 #include "nsICacheVisitor.h"
@@ -295,17 +296,18 @@ nsDocShell::nsDocShell():
     mMarginWidth(0),
     mMarginHeight(0),
     mItemType(typeContent),
     mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
     mPreviousTransIndex(-1),
     mLoadedTransIndex(-1),
     mEditorData(nsnull),
     mTreeOwner(nsnull),
-    mChromeEventHandler(nsnull)
+    mChromeEventHandler(nsnull),
+    mCookieContainer(nsnull)
 {
     if (gDocShellCount++ == 0) {
         NS_ASSERTION(sURIFixup == nsnull,
                      "Huh, sURIFixup not null in first nsDocShell ctor!");
 
         CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
     }
 
@@ -361,16 +363,24 @@ nsDocShell::Init()
     nsCOMPtr<InterfaceRequestorProxy> proxy =
         new InterfaceRequestorProxy(NS_STATIC_CAST(nsIInterfaceRequestor*,
                                                    this));
     NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
     mLoadGroup->SetNotificationCallbacks(proxy);
 
     rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
     NS_ENSURE_SUCCESS(rv, rv);
+
+
+    // set to the default cookieContainer
+    nsCOMPtr<nsICookieService> csvc = do_GetService(NS_COOKIESERVICE_CONTRACTID);
+    nsCOMPtr<nsICookieContainer> container;
+    csvc->GetDefaultContainer(getter_AddRefs(container));
+    SetCookieContainer(container);
+
     
     // Add as |this| a progress listener to itself.  A little weird, but
     // simpler than reproducing all the listener-notification logic in
     // overrides of the various methods via which nsDocLoader can be
     // notified.   Note that this holds an nsWeakPtr to ourselves, so it's ok.
     return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
                                      nsIWebProgress::NOTIFY_STATE_NETWORK);
     
@@ -414,16 +424,17 @@ NS_INTERFACE_MAP_BEGIN(nsDocShell)
     NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
     NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
     NS_INTERFACE_MAP_ENTRY(nsIEditorDocShell)
     NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
     NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
     NS_INTERFACE_MAP_ENTRY(nsIObserver)
+    NS_INTERFACE_MAP_ENTRY(nsICookieCollector)
 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
 
 ///*****************************************************************************
 // nsDocShell::nsIInterfaceRequestor
 //*****************************************************************************   
 NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
 {
     NS_PRECONDITION(aSink, "null out param");
@@ -1744,16 +1755,25 @@ nsDocShell::SetDocLoaderParent(nsDocLoad
             SetAllowSubframes(value);
         }
         if (NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value)))
         {
             SetAllowImages(value);
         }
     }
 
+    // if parent is nsICookieCollector, inherit cookie container
+    nsCOMPtr<nsICookieCollector> parentAsCookieCollector(do_QueryInterface(parent));
+    if (parentAsCookieCollector)
+    {
+        nsCOMPtr<nsICookieContainer> container;
+        if (NS_SUCCEEDED(parentAsCookieCollector->GetCookieContainer(getter_AddRefs(container))))
+            SetCookieContainer(container);
+    }
+
     nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
     if (parentURIListener)
         mContentListener->SetParentContentListener(parentURIListener);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem ** aParent)
@@ -6896,16 +6916,22 @@ nsDocShell::DoURILoad(nsIURI * aURI,
     if (httpChannelInternal) {
       if (aFirstParty) {
         httpChannelInternal->SetDocumentURI(aURI);
       } else {
         httpChannelInternal->SetDocumentURI(aReferrerURI);
       }
     }
 
+    // set the http request cookie container to that of the parent docshell
+    nsCOMPtr<nsICookieCollector> cookieCollector(do_QueryInterface(channel));
+    if (cookieCollector) {
+      cookieCollector->SetCookieContainer(mCookieContainer);
+    }
+
     nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
     if (props)
     {
       // save true referrer for those who need it (e.g. xpinstall whitelisting)
       // Currently only http and ftp channels support this.
       props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
                                     aReferrerURI);
     }
@@ -8906,9 +8932,30 @@ nsDocShell::IsAboutBlank(nsIURI* aURI)
     if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
         return PR_FALSE;
     }
     
     nsCAutoString str;
     aURI->GetSpec(str);
     return str.EqualsLiteral("about:blank");
 }
-                                     
+
+
+//*****************************************************************************
+// nsDocShell::nsICookieCollector
+//*****************************************************************************
+/* attribute nsICookieContainer cookieContainer; */
+NS_IMETHODIMP
+nsDocShell::GetCookieContainer(nsICookieContainer * *aCookieContainer)
+{
+    NS_ENSURE_ARG_POINTER(aCookieContainer);
+    *aCookieContainer = mCookieContainer;
+    NS_IF_ADDREF(*aCookieContainer);
+    return NS_OK;
+}
+NS_IMETHODIMP
+nsDocShell::SetCookieContainer(nsICookieContainer * aCookieContainer)
+{
+    mCookieContainer = aCookieContainer;
+    NS_ENSURE_ARG_POINTER(aCookieContainer);
+    return NS_OK;
+}
+
Index: docshell/base/nsDocShell.h
===================================================================
RCS file: /cvsroot/mozilla/docshell/base/nsDocShell.h,v
retrieving revision 1.211
diff -p -U 8 -r1.211 nsDocShell.h
--- docshell/base/nsDocShell.h	6 May 2007 21:06:27 -0000	1.211
+++ docshell/base/nsDocShell.h	14 May 2007 09:22:21 -0000
@@ -100,16 +100,18 @@
 #include "nsIWebBrowserFind.h"
 #include "nsIHttpChannel.h"
 #include "nsDocShellTransferableHooks.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsISecureBrowserUI.h"
 #include "nsIObserver.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsPIDOMEventTarget.h"
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
 
 class nsIScrollableView;
 
 /* load commands were moved to nsIDocShell.h */
 /* load types were moved to nsDocShellLoadTypes.h */
 
 /* internally used ViewMode types */
 enum ViewMode {
@@ -156,17 +158,18 @@ class nsDocShell : public nsDocLoader,
                    public nsIDocCharset, 
                    public nsIContentViewerContainer,
                    public nsIScriptGlobalObjectOwner,
                    public nsIRefreshURI,
                    public nsIWebProgressListener,
                    public nsIEditorDocShell,
                    public nsIWebPageDescriptor,
                    public nsIAuthPromptProvider,
-                   public nsIObserver
+                   public nsIObserver,
+                   public nsICookieCollector
 {
 friend class nsDSURIContentListener;
 
 public:
     // Object Management
     nsDocShell();
 
     virtual nsresult Init();
@@ -185,16 +188,17 @@ public:
     NS_DECL_NSIINTERFACEREQUESTOR
     NS_DECL_NSIWEBPROGRESSLISTENER
     NS_DECL_NSIREFRESHURI
     NS_DECL_NSICONTENTVIEWERCONTAINER
     NS_DECL_NSIEDITORDOCSHELL
     NS_DECL_NSIWEBPAGEDESCRIPTOR
     NS_DECL_NSIAUTHPROMPTPROVIDER
     NS_DECL_NSIOBSERVER
+    NS_DECL_NSICOOKIECOLLECTOR
 
     NS_IMETHOD Stop() {
         // Need this here because otherwise nsIWebNavigation::Stop
         // overrides the docloader's Stop()
         return nsDocLoader::Stop();
     }
 
     // Need to implement (and forward) nsISecurityEventSink, because
@@ -594,16 +598,18 @@ protected:
     nsDocShellEditorData*      mEditorData;          // editor data, if any
 
     // Transferable hooks/callbacks
     nsCOMPtr<nsIClipboardDragDropHookList>  mTransferableHookData;
 
     // Secure browser UI object
     nsCOMPtr<nsISecureBrowserUI> mSecurityUI;
 
+    nsCOMPtr<nsICookieContainer> mCookieContainer;
+
     // WEAK REFERENCES BELOW HERE.
     // Note these are intentionally not addrefd.  Doing so will create a cycle.
     // For that reasons don't use nsCOMPtr.
 
     nsIDocShellTreeOwner *     mTreeOwner; // Weak Reference
     nsPIDOMEventTarget *       mChromeEventHandler; //Weak Reference
 
     static nsIURIFixup *sURIFixup;
Index: docshell/base/nsWebShell.cpp
===================================================================
RCS file: /cvsroot/mozilla/docshell/base/nsWebShell.cpp,v
retrieving revision 1.684
diff -p -U 8 -r1.684 nsWebShell.cpp
--- docshell/base/nsWebShell.cpp	18 Feb 2007 04:24:05 -0000	1.684
+++ docshell/base/nsWebShell.cpp	14 May 2007 09:22:24 -0000
@@ -108,16 +108,19 @@
 #include "nsILocaleService.h"
 #include "nsIStringBundle.h"
 
 #include "nsICachingChannel.h"
 
 #include "nsIDocument.h"
 #include "nsITextToSubURI.h"
 
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
+
 #include "nsIExternalProtocolService.h"
 #include "nsCExternalHandlerService.h"
 
 #include "nsIIDNService.h"
 
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsITimer.h"
@@ -439,16 +442,25 @@ SendPing(void *closure, nsIContent *cont
   if (!httpChan)
     return;
 
   // This is needed in order for 3rd-party cookie blocking to work.
   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(httpChan);
   if (httpInternal)
     httpInternal->SetDocumentURI(doc->GetDocumentURI());
 
+  // set the cookie container of the channel to that of the doc's
+  nsCOMPtr<nsICookieCollector> cookieCollector(do_QueryInterface(chan));
+  if (cookieCollector) {
+    nsCOMPtr<nsICookieContainer> cookieContainer;
+    nsCOMPtr<nsICookieCollector> parentCollector = do_GetInterface(doc);
+    parentCollector->GetCookieContainer(getter_AddRefs(cookieContainer));
+    cookieCollector->SetCookieContainer(cookieContainer);
+  }
+
   if (info->referrer)
     httpChan->SetReferrer(info->referrer);
 
   httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
 
   // Remove extraneous request headers (to reduce request size)
   httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
                              EmptyCString(), PR_FALSE);
Index: dom/src/base/nsGlobalWindow.cpp
===================================================================
RCS file: /cvsroot/mozilla/dom/src/base/nsGlobalWindow.cpp,v
retrieving revision 1.932
diff -p -U 8 -r1.932 nsGlobalWindow.cpp
--- dom/src/base/nsGlobalWindow.cpp	11 May 2007 13:34:08 -0000	1.932
+++ dom/src/base/nsGlobalWindow.cpp	14 May 2007 09:22:40 -0000
@@ -151,16 +151,18 @@
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsCSSProps.h"
 #include "nsIURIFixup.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsEventDispatcher.h"
 #include "nsIObserverService.h"
 #include "nsNetUtil.h"
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
 
 #include "plbase64.h"
 
 #ifdef NS_PRINTING
 #include "nsIPrintSettings.h"
 #include "nsIPrintSettingsService.h"
 #include "nsIWebBrowserPrint.h"
 #endif
Index: embedding/components/windowwatcher/src/nsWindowWatcher.cpp
===================================================================
RCS file: /cvsroot/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp,v
retrieving revision 1.129
diff -p -U 8 -r1.129 nsWindowWatcher.cpp
--- embedding/components/windowwatcher/src/nsWindowWatcher.cpp	24 Oct 2006 21:42:18 -0000	1.129
+++ embedding/components/windowwatcher/src/nsWindowWatcher.cpp	14 May 2007 09:22:57 -0000
@@ -78,16 +78,18 @@
 #include "nsIXPConnect.h"
 #include "nsPIDOMWindow.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsIContentViewer.h"
 #include "nsIDocumentViewer.h"
 #include "nsIWindowProvider.h"
 #include "nsIMutableArray.h"
 #include "nsISupportsArray.h"
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
 
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 
 #include "jsinterp.h" // for js_AllocStack() and js_FreeStack()
 
 #ifdef USEWEAKREFS
 #include "nsIWeakReference.h"
@@ -825,16 +827,26 @@ nsWindowWatcher::OpenWindowJSInternal(ns
 #ifdef DEBUG
     nsCOMPtr<nsPIDOMWindow> newDebugWindow = do_GetInterface(newDocShell);
     NS_ASSERTION(newWindow == newDebugWindow, "Different windows??");
 #endif
     if (newWindow) {
       newWindow->SetOpenerScriptPrincipal(newWindowPrincipal);
     }
   }
+  
+  // new docShell inherits cookie container from old docShell
+  if (newDocShell && aParent) {
+    nsCOMPtr<nsPIDOMWindow> parent = do_QueryInterface(aParent);
+    nsCOMPtr<nsICookieCollector> parentCollector = do_QueryInterface(parent->GetDocShell());
+    nsCOMPtr<nsICookieContainer> container; 
+    parentCollector->GetCookieContainer(getter_AddRefs(container));
+    nsCOMPtr<nsICookieCollector> collector = do_QueryInterface(newDocShell);
+    collector->SetCookieContainer(container);
+  }
 
   if (uriToLoad) { // get the script principal and pass it to docshell
     JSContextAutoPopper contextGuard;
 
     cx = GetJSContextFromCallStack();
 
     // get the security manager
     if (!cx)
Index: layout/style/nsCSSLoader.cpp
===================================================================
RCS file: /cvsroot/mozilla/layout/style/nsCSSLoader.cpp,v
retrieving revision 3.227
diff -p -U 8 -r3.227 nsCSSLoader.cpp
--- layout/style/nsCSSLoader.cpp	3 May 2007 01:15:53 -0000	3.227
+++ layout/style/nsCSSLoader.cpp	14 May 2007 09:23:41 -0000
@@ -74,16 +74,18 @@
 #include "nsICSSStyleSheet.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsICSSLoaderObserver.h"
 #include "nsICSSLoader.h"
 #include "nsICSSParser.h"
 #include "nsICSSImportRule.h"
 #include "nsThreadUtils.h"
 #include "nsGkAtoms.h"
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPrototypeCache.h"
 #endif
 
 #include "nsIMediaList.h"
 #include "nsIDOMStyleSheet.h"
 #include "nsIDOMCSSStyleSheet.h"
@@ -1424,16 +1426,22 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* 
     // send a minimal Accept header for text/css
     httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                   NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
                                   PR_FALSE);
     nsCOMPtr<nsIURI> referrerURI = aLoadData->GetReferrerURI();
     if (referrerURI)
       httpChannel->SetReferrer(referrerURI);
   }
+  // set the cookie container of the channel to that of the doc's
+  nsCOMPtr<nsICookieCollector> cookieCollector(do_QueryInterface(channel));
+  if (cookieCollector) {
+    nsCOMPtr<nsICookieContainer> container(do_GetInterface(mDocument));
+    cookieCollector->SetCookieContainer(container);
+  }
 
   // Now tell the channel we expect text/css data back....  We do
   // this before opening it, so it's only treated as a hint.
   channel->SetContentType(NS_LITERAL_CSTRING("text/css"));
 
   if (aLoadData->mLoaderPrincipal) {
     PRBool inherit;
     rv = NS_URIChainHasFlags(aLoadData->mURI,
Index: modules/libpr0n/src/imgLoader.cpp
===================================================================
RCS file: /cvsroot/mozilla/modules/libpr0n/src/imgLoader.cpp,v
retrieving revision 1.93
diff -p -U 8 -r1.93 imgLoader.cpp
--- modules/libpr0n/src/imgLoader.cpp	1 Jun 2006 18:35:20 -0000	1.93
+++ modules/libpr0n/src/imgLoader.cpp	14 May 2007 09:23:45 -0000
@@ -56,16 +56,20 @@
 #include "imgRequest.h"
 #include "imgRequestProxy.h"
 
 #include "ImageErrors.h"
 #include "ImageLogging.h"
 
 #include "nsIComponentRegistrar.h"
 
+// required for cookie container
+#include "nsICookieContainer.h"
+#include "nsICookieCollector.h"
+
 // we want to explore making the document own the load group
 // so we can associate the document URI with the load group.
 // until this point, we have an evil hack:
 #include "nsIHttpChannelInternal.h"  
 
 #if defined(DEBUG_pavlov) || defined(DEBUG_timeless)
 #include "nsISimpleEnumerator.h"
 #include "nsXPCOM.h"
@@ -172,17 +176,18 @@ static PRBool RevalidateEntry(nsICacheEn
 }
 
 
 static nsresult NewImageChannel(nsIChannel **aResult,
                                 nsIURI *aURI,
                                 nsIURI *aInitialDocumentURI,
                                 nsIURI *aReferringURI,
                                 nsILoadGroup *aLoadGroup,
-                                nsLoadFlags aLoadFlags)
+                                nsLoadFlags aLoadFlags,
+                                nsICookieContainer *aCookieContainer)
 {
   nsresult rv;
   nsCOMPtr<nsIChannel> newChannel;
   nsCOMPtr<nsIHttpChannel> newHttpChannel;
  
   nsCOMPtr<nsIInterfaceRequestor> callbacks;
 
   if (aLoadGroup) {
@@ -218,16 +223,20 @@ static nsresult NewImageChannel(nsIChann
                                      NS_LITERAL_CSTRING("image/png,*/*;q=0.5"),
                                      PR_FALSE);
 
     nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal = do_QueryInterface(newHttpChannel);
     NS_ENSURE_TRUE(httpChannelInternal, NS_ERROR_UNEXPECTED);
     httpChannelInternal->SetDocumentURI(aInitialDocumentURI);
     newHttpChannel->SetReferrer(aReferringURI);
   }
+  nsCOMPtr<nsICookieCollector> cookieCollector = do_QueryInterface(*aResult);
+  if (cookieCollector) {
+    cookieCollector->SetCookieContainer(aCookieContainer);
+  }
 
   // Image channels are loaded by default with reduced priority.
   nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(*aResult);
   if (p) {
     PRUint32 priority = nsISupportsPriority::PRIORITY_LOW;
 
     if (aLoadFlags & nsIRequest::LOAD_BACKGROUND)
       ++priority; // further reduce priority for background loads
@@ -375,16 +384,23 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIUR
             "imgRequest [request=%p]\n", this, request));
 
     entry = nsnull;
     NS_RELEASE(request);
 
     bCanCacheRequest = PR_FALSE;
   }
 
+  // find the document's cookie container
+  nsCOMPtr<nsICookieContainer> cookieContainer = nsnull;
+  if (aCX) {
+    // aCX is nsIDocument
+    cookieContainer = do_GetInterface(aCX);
+  }
+
   //
   // Time to load the request... There are 3 possible cases:
   // =======================================================
   //   1. There is no cached request (ie. nothing was found in the cache).
   //
   //   2. There is a cached request that must be validated.
   //
   //   3. There is a valid cached request.
@@ -409,17 +425,18 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIUR
 
     } else {
       nsCOMPtr<nsIChannel> newChannel;
       rv = NewImageChannel(getter_AddRefs(newChannel),
                            aURI,
                            aInitialDocumentURI,
                            aReferrerURI,
                            aLoadGroup,
-                           requestFlags);
+                           requestFlags,
+                           cookieContainer);
       if (NS_FAILED(rv)) {
         NS_RELEASE(request);
         return NS_ERROR_FAILURE;
       }
 
       nsCOMPtr<nsICachingChannel> cacheChan(do_QueryInterface(newChannel));
 
       if (cacheChan) {
@@ -465,17 +482,18 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIUR
     LOG_SCOPE(gImgLog, "imgLoader::LoadImage |cache miss|");
 
     nsCOMPtr<nsIChannel> newChannel;
     rv = NewImageChannel(getter_AddRefs(newChannel),
                          aURI,
                          aInitialDocumentURI,
                          aReferrerURI,
                          aLoadGroup,
-                         requestFlags);
+                         requestFlags,
+                         cookieContainer);
     if (NS_FAILED(rv))
       return NS_ERROR_FAILURE;
 
     NS_NEWXPCOM(request, imgRequest);
     if (!request) return NS_ERROR_OUT_OF_MEMORY;
 
     NS_ADDREF(request);
 
Index: modules/plugin/base/src/nsPluginHostImpl.cpp
===================================================================
RCS file: /cvsroot/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp,v
retrieving revision 1.572
diff -p -U 8 -r1.572 nsPluginHostImpl.cpp
--- modules/plugin/base/src/nsPluginHostImpl.cpp	1 May 2007 22:24:24 -0000	1.572
+++ modules/plugin/base/src/nsPluginHostImpl.cpp	14 May 2007 09:24:03 -0000
@@ -168,16 +168,19 @@
 #include "nsISupportsArray.h"
 #include "nsIDocShell.h"
 #include "nsPluginNativeWindow.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentErrors.h"
 
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
+
 #ifdef XP_UNIX
 #if defined (MOZ_WIDGET_GTK2)
 #include <gdk/gdkx.h> // for GDK_DISPLAY()
 #elif defined(MOZ_WIDGET_QT)
 #include <qwindowdefs.h> // for qt_xdisplay()
 #endif
 #endif
 
@@ -6190,17 +6193,21 @@ NS_IMETHODIMP nsPluginHostImpl::GetCooki
   }
 
   // make an nsURI from the argument url
   rv = ioService->NewURI(nsDependentCString(inCookieURL), nsnull, nsnull, getter_AddRefs(uriIn));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  rv = cookieService->GetCookieString(uriIn, nsnull, getter_Copies(cookieString));
+  // get the default cookie container
+  nsCOMPtr<nsICookieContainer> container;
+  cookieService->GetDefaultContainer(getter_AddRefs(container));
+
+  rv = cookieService->GetCookieString(container, uriIn, nsnull, getter_Copies(cookieString));
 
   if (NS_FAILED(rv) || (!cookieString) ||
       (inOutCookieSize <= (cookieStringLen = PL_strlen(cookieString.get())))) {
     return NS_ERROR_FAILURE;
   }
 
   PL_strcpy((char *) inOutCookieBuffer, cookieString.get());
   inOutCookieSize = cookieStringLen;
@@ -6234,24 +6241,28 @@ NS_IMETHODIMP nsPluginHostImpl::SetCooki
     return NS_ERROR_FAILURE;
   }
 
   // make an nsURI from the argument url
   rv = ioService->NewURI(nsDependentCString(inCookieURL), nsnull, nsnull, getter_AddRefs(uriIn));
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
   }
+  
+  // get the default cookie container
+  nsCOMPtr<nsICookieContainer> container;
+  cookieService->GetDefaultContainer(getter_AddRefs(container));
 
   nsCOMPtr<nsIPrompt> prompt;
   GetPrompt(nsnull, getter_AddRefs(prompt));
 
   char * cookie = (char *)inCookieBuffer;
   char c = cookie[inCookieSize];
   cookie[inCookieSize] = '\0';
-  rv = cookieService->SetCookieString(uriIn, prompt, cookie, nsnull);
+  rv = cookieService->SetCookieString(container, uriIn, prompt, cookie, nsnull);
   cookie[inCookieSize] = c;
 
   return rv;
 }
 
 
 ////////////////////////////////////////////////////////////////////////
 NS_IMETHODIMP nsPluginHostImpl::Observe(nsISupports *aSubject,
Index: netwerk/build/nsNetCID.h
===================================================================
RCS file: /cvsroot/mozilla/netwerk/build/nsNetCID.h,v
retrieving revision 1.65
diff -p -U 8 -r1.65 nsNetCID.h
--- netwerk/build/nsNetCID.h	17 Feb 2007 03:47:27 -0000	1.65
+++ netwerk/build/nsNetCID.h	14 May 2007 09:24:07 -0000
@@ -748,16 +748,29 @@
 #define NS_COOKIESERVICE_CID                           \
 { /* c375fa80-150f-11d6-a618-0010a401eb10 */           \
     0xc375fa80,                                        \
     0x150f,                                            \
     0x11d6,                                            \
     { 0xa6, 0x18, 0x00, 0x10, 0xa4, 0x01, 0xeb, 0x10 } \
 }
 
+// the cookie container
+#define NS_COOKIECONTAINER_CLASSNAME \
+    "CookieContainer"
+#define NS_COOKIECONTAINER_CONTRACTID \
+    "@mozilla.org/cookie-container;1"
+#define NS_COOKIECONTAINER_CID                         \
+{ /* f3a95abb-65f8-4203-acdb-3f309752433a */           \
+    0xf3a95abb,                                        \
+    0x65f8,                                            \
+    0x4203,                                            \
+    { 0xac, 0xdb, 0x3f, 0x30, 0x97, 0x52, 0x43, 0x3a } \
+}
+
 /******************************************************************************
  * netwerk/streamconv classes
  */
 
 // service implementing nsIStreamConverterService
 #define NS_STREAMCONVERTERSERVICE_CONTRACTID \
     "@mozilla.org/streamConverters;1"
 #define NS_STREAMCONVERTERSERVICE_CID                \
Index: netwerk/build/nsNetModule.cpp
===================================================================
RCS file: /cvsroot/mozilla/netwerk/build/nsNetModule.cpp,v
retrieving revision 1.140
diff -p -U 8 -r1.140 nsNetModule.cpp
--- netwerk/build/nsNetModule.cpp	15 Nov 2006 21:38:47 -0000	1.140
+++ netwerk/build/nsNetModule.cpp	14 May 2007 09:24:10 -0000
@@ -157,17 +157,19 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDirInde
 
 #include "nsStreamListenerTee.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsStreamListenerTee)
 
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifdef NECKO_COOKIES
 #include "nsCookieService.h"
+#include "nsCookieContainer.h"
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsCookieService, nsCookieService::GetSingleton)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsCookieContainer)
 #endif
 
 ///////////////////////////////////////////////////////////////////////////////
 // protocols
 ///////////////////////////////////////////////////////////////////////////////
 
 // about:blank is mandatory
 #include "nsAboutProtocolHandler.h"
@@ -1029,24 +1031,30 @@ static const nsModuleComponentInfo gNetM
        NS_CACHESERVICE_CONTRACTID,
        nsCacheService::Create
     },
 
 #ifdef NECKO_COOKIES
     { NS_COOKIEMANAGER_CLASSNAME,
       NS_COOKIEMANAGER_CID,
       NS_COOKIEMANAGER_CONTRACTID,
-      nsCookieServiceConstructor
+      nsCookieService::GetDefaultContainer
     },
 
     { NS_COOKIESERVICE_CLASSNAME,
       NS_COOKIESERVICE_CID,
       NS_COOKIESERVICE_CONTRACTID,
       nsCookieServiceConstructor
     },
+
+    { NS_COOKIECONTAINER_CLASSNAME,
+      NS_COOKIECONTAINER_CID,
+      NS_COOKIECONTAINER_CONTRACTID,
+      nsCookieContainerConstructor
+    },
 #endif
 
 #ifdef NECKO_PROTOCOL_gopher
     //gopher:
     { "The Gopher Protocol Handler", 
       NS_GOPHERHANDLER_CID,
       NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "gopher",
       nsGopherHandlerConstructor
Index: netwerk/cookie/public/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/netwerk/cookie/public/Makefile.in,v
retrieving revision 1.10
diff -p -U 8 -r1.10 Makefile.in
--- netwerk/cookie/public/Makefile.in	15 Sep 2005 11:03:08 -0000	1.10
+++ netwerk/cookie/public/Makefile.in	14 May 2007 09:24:10 -0000
@@ -48,18 +48,19 @@ GRE_MODULE	= 1
 
 SDK_XPIDLSRCS   = \
 		nsICookieManager.idl \
 		nsICookie.idl \
 		$(NULL)
 
 XPIDLSRCS	= \
 		nsICookieService.idl \
-		nsICookieServiceInternal.idl \
 		nsICookie2.idl \
 		nsICookieConsent.idl \
 		nsICookieManager2.idl \
 		nsICookiePermission.idl \
+		nsICookieContainer.idl \
+		nsICookieCollector.idl \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DIMPL_NS_NET
Index: netwerk/cookie/public/nsICookieCollector.idl
===================================================================
RCS file: netwerk/cookie/public/nsICookieCollector.idl
diff -N netwerk/cookie/public/nsICookieCollector.idl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ netwerk/cookie/public/nsICookieCollector.idl	14 May 2007 09:24:10 -0000
@@ -0,0 +1,50 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Cookie Containers Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Loune Lam <lpgcritter at nasquan dot com>.
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Loune Lam <lpgcritter at nasquan dot com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsICookieContainer;
+
+[scriptable, uuid(95D62733-7B16-42db-B795-FE385F44930A)]
+interface nsICookieCollector : nsISupports
+{
+	/**
+	 * The container this cookie collector holds
+	 */
+	attribute nsICookieContainer cookieContainer;
+};
Index: netwerk/cookie/public/nsICookieContainer.idl
===================================================================
RCS file: netwerk/cookie/public/nsICookieContainer.idl
diff -N netwerk/cookie/public/nsICookieContainer.idl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ netwerk/cookie/public/nsICookieContainer.idl	14 May 2007 09:24:11 -0000
@@ -0,0 +1,64 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Cookie Containers Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Loune Lam <lpgcritter at nasquan dot com>.
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Loune Lam <lpgcritter at nasquan dot com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIURI;
+interface nsICookie;
+interface nsIArray;
+
+[scriptable, uuid(a5556dc0-1ca9-46e2-a30c-303d70976a7e)]
+interface nsICookieContainer : nsISupports
+{
+
+    void init(in string aContainerId);
+
+    //
+    // An unique identifier for the container, mainly used by session restore to save the container
+    // must be in form of contractID
+    readonly attribute string containerId;
+
+    // set a single cookie to the container
+    // will be responsible for notifying observers (ie cookie-changed)
+    void setCookie(in nsIURI aHostURI, in nsICookie cookie);
+	
+    // called by getCookie functions to retrieve the cookies satifsfying the criteria
+    nsIArray getCookieList(in nsIURI aHostURI, in string aName, in boolean aHttpBound);
+
+
+};
Index: netwerk/cookie/public/nsICookieService.idl
===================================================================
RCS file: /cvsroot/mozilla/netwerk/cookie/public/nsICookieService.idl,v
retrieving revision 1.9
diff -p -U 8 -r1.9 nsICookieService.idl
--- netwerk/cookie/public/nsICookieService.idl	14 Mar 2007 17:22:01 -0000	1.9
+++ netwerk/cookie/public/nsICookieService.idl	14 May 2007 09:24:11 -0000
@@ -15,16 +15,17 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Loune Lam <lpgcritter at nasquan dot com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -35,16 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIURI;
 interface nsIPrompt;
 interface nsIChannel;
+interface nsICookieContainer;
 
 /**
  * nsICookieService
  *
  * Provides methods for setting and getting cookies in the context of a
  * page load.  See nsICookieManager for methods to manipulate the cookie
  * database directly.  This separation of interface is mainly historical.
  *
@@ -75,72 +77,80 @@ interface nsIChannel;
  * data   : none.
  */
 [scriptable, uuid(011C3190-1434-11d6-A618-0010A401EB10)]
 interface nsICookieService : nsISupports
 {
   /*
    * Get the complete cookie string associated with the URI.
    *
+   * @param aContainer
+   *        the container the cookie should be retrieved from
    * @param aURI
    *        the URI of the document for which cookies are being queried.
    * @param aChannel
    *        the channel used to load the document.  this parameter may be null,
    *        but it is strongly recommended that a non-null value be provided to
    *        ensure that the cookie privacy preferences are honored.
    *
    * @return the resulting cookie string
    */
-  string getCookieString(in nsIURI aURI, in nsIChannel aChannel);
+  string getCookieString(in nsICookieContainer aContainer, in nsIURI aURI, in nsIChannel aChannel);
 
   /*
    * Get the complete cookie string associated with the URI.
    *
    * This function is NOT redundant with getCookieString, as the result
    * will be different based on httponly (see bug 178993)
    *
+   * @param aContainer
+   *        the container the cookie should be retrieved from
    * @param aURI
    *        the URI of the document for which cookies are being queried.
    * @param aFirstURI
    *        the URI that the user originally typed in or clicked on to initiate
    *        the load of the document referenced by aURI.
    * @param aChannel
    *        the channel used to load the document.  this parameter may be null,
    *        but it is strongly recommended that a non-null value be provided to
    *        ensure that the cookie privacy preferences are honored.
    *
    * @return the resulting cookie string
    */
-  string getCookieStringFromHttp(in nsIURI aURI, in nsIURI aFirstURI, in nsIChannel aChannel);
+  string getCookieStringFromHttp(in nsICookieContainer aContainer, in nsIURI aURI, in nsIURI aFirstURI, in nsIChannel aChannel);
 
   /*
    * Set the cookie string associated with the URI.
    *
+   * @param aContainer
+   *        the container the cookie should be put into
    * @param aURI
    *        the URI of the document for which cookies are being set.
    * @param aPrompt
    *        the prompt to use for all user-level cookie notifications.
    * @param aCookie
    *        the cookie string to set.
    * @param aChannel
    *        the channel used to load the document.  this parameter may be null,
    *        but it is strongly recommended that a non-null value be provided to
    *        ensure that the cookie privacy preferences are honored.
    *
    * XXX should be able to allow null aPrompt, since nsIPrompt can be queryied
    * from aChannel.
    */
-  void setCookieString(in nsIURI aURI, in nsIPrompt aPrompt, in string aCookie, in nsIChannel aChannel);
+  void setCookieString(in nsICookieContainer aContainer, in nsIURI aURI, in nsIPrompt aPrompt, in string aCookie, in nsIChannel aChannel);
 
   /*
    * Set the cookie string and expires associated with the URI.
    *
    * This function is NOT redundant with setCookieString, as the result
    * will be different based on httponly (see bug 178993)
    *
+   * @param aContainer
+   *        the container the cookie should be put into
    * @param aURI
    *        the URI of the document for which cookies are being set.
    * @param aFirstURI
    *        the URI that the user originally typed in or clicked on to initiate
    *        the load of the document referenced by aURI.
    * @param aPrompt
    *        the prompt to use for all user-level cookie notifications.
    * @param aCookie
@@ -148,17 +158,37 @@ interface nsICookieService : nsISupports
    * @param aServerTime
    *        the expiry information of the cookie (the Date header from the HTTP
    *        response).
    * @param aChannel
    *        the channel used to load the document.  this parameter may be null,
    *        but it is strongly recommended that a non-null value be provided to
    *        ensure that the cookie privacy preferences are honored.
    */
-  void setCookieStringFromHttp(in nsIURI aURI, in nsIURI aFirstURI, in nsIPrompt aPrompt, in string aCookie, in string aServerTime, in nsIChannel aChannel);
+  void setCookieStringFromHttp(in nsICookieContainer aContainer, in nsIURI aURI, in nsIURI aFirstURI, in nsIPrompt aPrompt, in string aCookie, in string aServerTime, in nsIChannel aChannel);
 
   /**
    * This attribute really doesn't belong on this interface.  CVS blame will
    * tell you why it is here.  It remains until we can find a better home for
    * it.  Read the source if you want to know what it does :-(
    */
   readonly attribute boolean cookieIconIsVisible;
+
+  /**
+   * The default container that newly created channels and docshells use
+   */
+  attribute nsICookieContainer defaultContainer;
+
+  /**
+   * Get the container from the list of active containers by the aContainerId specified.
+   * 
+   * If container not found in the list, the container is created from getting the nsICookieContainer contractId from the aContainerId. It'll then be added to the list of active containers
+   * 
+   * This function is mainly used by session restore to get the correct container when restoring the cookies of the session.
+   * 
+   * @param aContainerId
+   *        The containerId which is in the form of contractId (of component)
+   *        concatenated with hash and the name of the container instance
+   *        eg. @mozilla.org/cookie-container;1#mycookiejar
+   */
+  nsICookieContainer getContainer(in string aContainerId);
+
 };
Index: netwerk/cookie/src/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/netwerk/cookie/src/Makefile.in,v
retrieving revision 1.5
diff -p -U 8 -r1.5 Makefile.in
--- netwerk/cookie/src/Makefile.in	5 Apr 2005 17:40:21 -0000	1.5
+++ netwerk/cookie/src/Makefile.in	14 May 2007 09:24:11 -0000
@@ -50,13 +50,14 @@ REQUIRES	= \
 		xpcom \
 		string \
 		pref \
 		$(NULL)
 
 CPPSRCS		= \
 		nsCookie.cpp \
 		nsCookieService.cpp \
+		nsCookieContainer.cpp \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DIMPL_NS_NET
Index: netwerk/cookie/src/nsCookieContainer.cpp
===================================================================
RCS file: netwerk/cookie/src/nsCookieContainer.cpp
diff -N netwerk/cookie/src/nsCookieContainer.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ netwerk/cookie/src/nsCookieContainer.cpp	14 May 2007 09:24:14 -0000
@@ -0,0 +1,1268 @@
+// vim:ts=2:sw=2:et:
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Witte <dwitte@stanford.edu>
+ *   Michiel van Leeuwen <mvl@exedo.nl>
+ *   Loune Lam <lpgcritter at nasquan dot com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsCookieContainer.h"
+#include "nsIServiceManager.h"
+
+#include "nsIIOService.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefBranch2.h"
+#include "nsIPrefService.h"
+#include "nsICookieConsent.h"
+#include "nsICookiePermission.h"
+#include "nsIURI.h"
+#include "nsIURL.h"
+#include "nsIChannel.h"
+#include "nsIHttpChannel.h"
+#include "nsIHttpChannelInternal.h" // evil hack!
+#include "nsIPrompt.h"
+#include "nsITimer.h"
+#include "nsIFile.h"
+#include "nsIObserverService.h"
+#include "nsILineInputStream.h"
+
+#include "nsCOMArray.h"
+#include "nsArrayEnumerator.h"
+#include "nsAutoPtr.h"
+#include "nsReadableUtils.h"
+#include "nsCRT.h"
+#include "prtime.h"
+#include "prprf.h"
+#include "prnetdb.h"
+#include "nsNetUtil.h"
+#include "nsNetCID.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsIArray.h"
+#include "nsIMutableArray.h"
+#include "nsArrayUtils.h"
+
+/******************************************************************************
+ * nsCookieService impl:
+ * useful types & constants
+ ******************************************************************************/
+
+// XXX_hack. See bug 178993.
+// This is a hack to hide HttpOnly cookies from older browsers
+//
+static const char kHttpOnlyPrefix[] = "#HttpOnly_";
+
+static const char kCookieFileNamePrefix[] = "cookies";
+static const char kCookieFileNameExt[] = ".txt";
+
+static const PRUint32 kLazyWriteTimeout = 5000; //msec
+
+#undef  LIMIT
+#define LIMIT(x, low, high, default) ((x) >= (low) && (x) <= (high) ? (x) : (default))
+
+// default limits for the cookie list. these can be tuned by the
+// network.cookie.maxNumber and network.cookie.maxPerHost prefs respectively.
+static const PRUint32 kMaxNumberOfCookies = 1000;
+static const PRUint32 kMaxCookiesPerHost  = 50;
+
+// XXX these casts and constructs are horrible, but our nsInt64/nsTime
+// classes are lacking so we need them for now. see bug 198694.
+#define USEC_PER_SEC   (nsInt64(1000000))
+#define NOW_IN_SECONDS (nsInt64(PR_Now()) / USEC_PER_SEC)
+
+// pref string constants
+static const char kPrefCookiesPermissions[] = "network.cookie.cookieBehavior";
+static const char kPrefMaxNumberOfCookies[] = "network.cookie.maxNumber";
+static const char kPrefMaxCookiesPerHost[]  = "network.cookie.maxPerHost";
+static const char kInitialCookieContainerId[] = "@mozilla.org/cookie-container;1#MAIN";
+
+
+// stores linked list iteration state, and provides a rudimentary
+// list traversal method
+struct nsListIter
+{
+  nsListIter() {}
+
+  nsListIter(nsCookieEntry *aEntry)
+   : entry(aEntry)
+   , prev(nsnull)
+   , current(aEntry ? aEntry->Head() : nsnull) {}
+
+  nsListIter(nsCookieEntry *aEntry,
+             nsCookie      *aPrev,
+             nsCookie      *aCurrent)
+   : entry(aEntry)
+   , prev(aPrev)
+   , current(aCurrent) {}
+
+  nsListIter& operator++() { prev = current; current = current->Next(); return *this; }
+
+  nsCookieEntry *entry;
+  nsCookie      *prev;
+  nsCookie      *current;
+};
+
+// stores temporary data for enumerating over the hash entries,
+// since enumeration is done using callback functions
+struct nsEnumerationData
+{
+  nsEnumerationData(nsInt64 aCurrentTime,
+                    PRInt64 aOldestTime)
+   : currentTime(aCurrentTime)
+   , oldestTime(aOldestTime)
+   , iter(nsnull, nsnull, nsnull) {}
+
+  // the current time
+  nsInt64 currentTime;
+
+  // oldest lastAccessed time in the cookie list. use aOldestTime = LL_MAXINT
+  // to enable this search, LL_MININT to disable it.
+  nsInt64 oldestTime;
+
+  // an iterator object that points to the desired cookie
+  nsListIter iter;
+};
+
+/******************************************************************************
+ * Cookie logging handlers
+ * used for logging in nsCookieService
+ ******************************************************************************/
+
+// logging handlers
+#ifdef MOZ_LOGGING
+// in order to do logging, the following environment variables need to be set:
+//
+//    set NSPR_LOG_MODULES=cookie:3 -- shows rejected cookies
+//    set NSPR_LOG_MODULES=cookie:4 -- shows accepted and rejected cookies
+//    set NSPR_LOG_FILE=cookie.log
+//
+// this next define has to appear before the include of prlog.h
+#define FORCE_PR_LOG // Allow logging in the release build
+#include "prlog.h"
+#endif
+
+// define logging macros for convenience
+#define SET_COOKIE PR_TRUE
+#define GET_COOKIE PR_FALSE
+
+#ifdef PR_LOGGING
+static PRLogModuleInfo *sCookieLog = PR_NewLogModule("cookie");
+
+#define COOKIE_LOGFAILURE(a, b, c, d) LogFailure(a, b, c, d)
+#define COOKIE_LOGSUCCESS(a, b, c, d) LogSuccess(a, b, c, d)
+
+static void
+LogFailure(PRBool aSetCookie, nsIURI *aHostURI, const char *aCookieString, const char *aReason)
+{
+  // if logging isn't enabled, return now to save cycles
+  if (!PR_LOG_TEST(sCookieLog, PR_LOG_WARNING)) {
+    return;
+  }
+
+  nsCAutoString spec;
+  if (aHostURI)
+    aHostURI->GetAsciiSpec(spec);
+
+  PR_LOG(sCookieLog, PR_LOG_WARNING,
+    ("%s%s%s\n", "===== ", aSetCookie ? "COOKIE NOT ACCEPTED" : "COOKIE NOT SENT", " ====="));
+  PR_LOG(sCookieLog, PR_LOG_WARNING,("request URL: %s\n", spec.get()));
+  if (aSetCookie) {
+    PR_LOG(sCookieLog, PR_LOG_WARNING,("cookie string: %s\n", aCookieString));
+  }
+
+  PRExplodedTime explodedTime;
+  PR_ExplodeTime(PR_Now(), PR_GMTParameters, &explodedTime);
+  char timeString[40];
+  PR_FormatTimeUSEnglish(timeString, 40, "%c GMT", &explodedTime);
+
+  PR_LOG(sCookieLog, PR_LOG_WARNING,("current time: %s", timeString));
+  PR_LOG(sCookieLog, PR_LOG_WARNING,("rejected because %s\n", aReason));
+  PR_LOG(sCookieLog, PR_LOG_WARNING,("\n"));
+}
+
+static void
+LogSuccess(PRBool aSetCookie, nsIURI *aHostURI, const char *aCookieString, nsCookie *aCookie)
+{
+  // if logging isn't enabled, return now to save cycles
+  if (!PR_LOG_TEST(sCookieLog, PR_LOG_DEBUG)) {
+    return;
+  }
+
+  nsCAutoString spec;
+  aHostURI->GetAsciiSpec(spec);
+
+  PR_LOG(sCookieLog, PR_LOG_DEBUG,
+    ("%s%s%s\n", "===== ", aSetCookie ? "COOKIE ACCEPTED" : "COOKIE SENT", " ====="));
+  PR_LOG(sCookieLog, PR_LOG_DEBUG,("request URL: %s\n", spec.get()));
+  PR_LOG(sCookieLog, PR_LOG_DEBUG,("cookie string: %s\n", aCookieString));
+
+  PRExplodedTime explodedTime;
+  PR_ExplodeTime(PR_Now(), PR_GMTParameters, &explodedTime);
+  char timeString[40];
+  PR_FormatTimeUSEnglish(timeString, 40, "%c GMT", &explodedTime);
+
+  PR_LOG(sCookieLog, PR_LOG_DEBUG,("current time: %s", timeString));
+
+  if (aSetCookie) {
+    PR_LOG(sCookieLog, PR_LOG_DEBUG,("----------------\n"));
+    PR_LOG(sCookieLog, PR_LOG_DEBUG,("name: %s\n", aCookie->Name().get()));
+    PR_LOG(sCookieLog, PR_LOG_DEBUG,("value: %s\n", aCookie->Value().get()));
+    PR_LOG(sCookieLog, PR_LOG_DEBUG,("%s: %s\n", aCookie->IsDomain() ? "domain" : "host", aCookie->Host().get()));
+    PR_LOG(sCookieLog, PR_LOG_DEBUG,("path: %s\n", aCookie->Path().get()));
+
+    if (!aCookie->IsSession()) {
+      PR_ExplodeTime(aCookie->Expiry() * USEC_PER_SEC, PR_GMTParameters, &explodedTime);
+      PR_FormatTimeUSEnglish(timeString, 40, "%c GMT", &explodedTime);
+    }
+
+    PR_LOG(sCookieLog, PR_LOG_DEBUG,
+      ("expires: %s", aCookie->IsSession() ? "at end of session" : timeString));
+    PR_LOG(sCookieLog, PR_LOG_DEBUG,("is secure: %s\n", aCookie->IsSecure() ? "true" : "false"));
+  }
+  PR_LOG(sCookieLog, PR_LOG_DEBUG,("\n"));
+}
+
+// inline wrappers to make passing in nsAFlatCStrings easier
+static inline void
+LogFailure(PRBool aSetCookie, nsIURI *aHostURI, const nsAFlatCString &aCookieString, const char *aReason)
+{
+  LogFailure(aSetCookie, aHostURI, aCookieString.get(), aReason);
+}
+
+static inline void
+LogSuccess(PRBool aSetCookie, nsIURI *aHostURI, const nsAFlatCString &aCookieString, nsCookie *aCookie)
+{
+  LogSuccess(aSetCookie, aHostURI, aCookieString.get(), aCookie);
+}
+
+#else
+#define COOKIE_LOGFAILURE(a, b, c, d) /* nothing */
+#define COOKIE_LOGSUCCESS(a, b, c, d) /* nothing */
+#endif
+
+/******************************************************************************
+ * nsCookieService impl:
+ * private list sorting callbacks
+ *
+ * these functions return:
+ *   < 0 if the first element should come before the second element,
+ *     0 if the first element may come before or after the second element,
+ *   > 0 if the first element should come after the second element.
+ ******************************************************************************/
+
+// comparison function for sorting cookies before sending to a server.
+PR_STATIC_CALLBACK(int)
+compareCookiesForSending(const void *aElement1,
+                         const void *aElement2,
+                         void       *aData)
+{
+  const nsCookie *cookie1 = NS_STATIC_CAST(const nsCookie*, aElement1);
+  const nsCookie *cookie2 = NS_STATIC_CAST(const nsCookie*, aElement2);
+
+  // compare by cookie path length in accordance with RFC2109
+  int rv = cookie2->Path().Length() - cookie1->Path().Length();
+  if (rv == 0) {
+    // when path lengths match, older cookies should be listed first.  this is
+    // required for backwards compatibility since some websites erroneously
+    // depend on receiving cookies in the order in which they were sent to the
+    // browser!  see bug 236772.
+    rv = cookie1->CreationTime() - cookie2->CreationTime();
+  }
+  return rv;
+}
+
+// comparison function for sorting cookies by lastAccessed time, with most-
+// recently-used cookies listed first.
+PR_STATIC_CALLBACK(int)
+compareCookiesForWriting(const void *aElement1,
+                         const void *aElement2,
+                         void       *aData)
+{
+  const nsCookie *cookie1 = NS_STATIC_CAST(const nsCookie*, aElement1);
+  const nsCookie *cookie2 = NS_STATIC_CAST(const nsCookie*, aElement2);
+
+  // we may have overflow problems returning the result directly, so we need branches
+  nsInt64 difference = cookie2->LastAccessed() - cookie1->LastAccessed();
+  return (difference > nsInt64(0)) ? 1 : (difference < nsInt64(0)) ? -1 : 0;
+}
+
+/******************************************************************************
+ * nsCookieService impl:
+ * public methods
+ ******************************************************************************/
+
+NS_IMPL_ISUPPORTS5(nsCookieContainer,
+                   nsICookieContainer,
+                   nsICookieManager,
+                   nsICookieManager2,
+                   nsIObserver,
+                   nsISupportsWeakReference)
+
+nsCookieContainer::nsCookieContainer()
+ : mCookieCount(0)
+ , mCookieChanged(PR_FALSE)
+ , mMaxNumberOfCookies(kMaxNumberOfCookies)
+ , mMaxCookiesPerHost(kMaxCookiesPerHost)
+ , mSessionOnly(PR_FALSE)
+ , mCookieFile(nsnull)
+{
+}
+
+nsCookieContainer::~nsCookieContainer()
+{
+  if (mWriteTimer)
+    mWriteTimer->Cancel();
+}
+
+
+NS_IMETHODIMP
+nsCookieContainer::Init(const char *aContainerId)
+{
+  // check containerId
+  const char* z = aContainerId;
+  while (*z != 0 && *z != '#') z++;
+  if (*z == 0)
+    return NS_ERROR_INVALID_ARG;
+
+  if (*++z == '+') {
+    // has + prefix, which means session container, ie don't save
+    mSessionOnly = PR_TRUE;
+  }
+
+  mContainerId.Assign(aContainerId);
+
+  mObserverService = do_GetService("@mozilla.org/observer-service;1");
+
+  if (!mHostTable.Init()) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  // trigger initialization code in profile-do-change
+  Observe(nsnull, "profile-do-change", nsnull);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCookieContainer::Observe(nsISupports     *aSubject,
+                         const char      *aTopic,
+                         const PRUnichar *aData)
+{
+  // check the topic
+  if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
+    // The profile is about to change,
+    // or is going away because the application is shutting down.
+    if (mWriteTimer) {
+      mWriteTimer->Cancel();
+      mWriteTimer = 0;
+    }
+
+    if (!nsCRT::strcmp(aData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
+      RemoveAllFromMemory();
+      // delete the cookie file
+      if (mCookieFile) {
+        mCookieFile->Remove(PR_FALSE);
+      }
+    } else {
+      if (!mSessionOnly)
+        Write();
+      RemoveAllFromMemory();
+    }
+
+  } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
+    // The profile has already changed.
+    // Now just read them from the new profile location.
+    // we also need to update the cached cookie file location
+    if (mSessionOnly)
+      return NS_OK;
+    nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mCookieFile));
+    if (NS_SUCCEEDED(rv)) {
+      nsCAutoString cookieFileName(kCookieFileNamePrefix);
+      // we have a special name for the initial/main container (ie just cookies.txt)
+      if (!mContainerId.Equals(kInitialCookieContainerId)) {
+        cookieFileName.Append("_");
+        // get the portion of the container id after the # as part of the filename
+        char* z = (char *)mContainerId.get();
+        while (*z != 0 && *z != '#') z++;
+        z++;
+        cookieFileName.Append(z);
+      }
+      cookieFileName.Append(kCookieFileNameExt);
+      mCookieFile->AppendNative(cookieFileName);
+    }
+    Read();
+
+  } else if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
+    nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
+    if (prefBranch)
+      PrefChanged(prefBranch);
+  }
+
+  return NS_OK;
+}
+
+// helper function for GetCookieList
+static inline PRBool ispathdelimiter(char c) { return c == '/' || c == '?' || c == '#' || c == ';'; }
+
+NS_IMETHODIMP
+nsCookieContainer::GetCookieList(nsIURI           *aHostURI,
+                               const char       *aName,
+                               PRBool           aHttpBound,
+                               nsIArray         **aResult
+							   /*nsAutoVoidArray  &aResult*/)
+{
+  if (!aHostURI) {
+    COOKIE_LOGFAILURE(GET_COOKIE, nsnull, nsnull, "host URI is null");
+    return NS_OK;
+  }
+
+  nsAutoVoidArray result;
+
+  // get host and path from the nsIURI
+  // note: there was a "check if host has embedded whitespace" here.
+  // it was removed since this check was added into the nsIURI impl (bug 146094).
+  nsCAutoString hostFromURI, pathFromURI;
+  if (NS_FAILED(aHostURI->GetAsciiHost(hostFromURI)) ||
+      NS_FAILED(aHostURI->GetPath(pathFromURI))) {
+    COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, nsnull, "couldn't get host/path from URI");
+    return NS_OK;
+  }
+  // trim trailing dots
+  hostFromURI.Trim(".");
+  // insert a leading dot, so we begin the hash lookup with the
+  // equivalent domain cookie host
+  hostFromURI.Insert(NS_LITERAL_CSTRING("."), 0);
+  ToLowerCase(hostFromURI);
+
+  // check if aHostURI is using an https secure protocol.
+  // if it isn't, then we can't send a secure cookie over the connection.
+  // if SchemeIs fails, assume an insecure connection, to be on the safe side
+  PRBool isSecure;
+  if (NS_FAILED(aHostURI->SchemeIs("https", &isSecure))) {
+    isSecure = PR_FALSE;
+  }
+
+  nsCookie *cookie;
+  nsInt64 currentTime = NOW_IN_SECONDS;
+  const char *currentDot = hostFromURI.get();
+  const char *nextDot = currentDot + 1;
+
+  // begin hash lookup, walking up the subdomain levels.
+  // we use nextDot to force a lookup of the original host (without leading dot).
+  do {
+    nsCookieEntry *entry = mHostTable.GetEntry(currentDot);
+    cookie = entry ? entry->Head() : nsnull;
+    for (; cookie; cookie = cookie->Next()) {
+      // check the cookie name, if appropriate
+      if (aName && *aName != 0 && !cookie->Name().Equals(aName)) {
+        continue;
+      }
+
+      // if the cookie is secure and the host scheme isn't, we can't send it
+      if (cookie->IsSecure() && !isSecure) {
+        continue;
+      }
+
+      // if the cookie is httpOnly and it's not going directly to the HTTP
+      // connection, don't send it
+      if (cookie->IsHttpOnly() && !aHttpBound) {
+        continue;
+      }
+
+      // calculate cookie path length, excluding trailing '/'
+      PRUint32 cookiePathLen = cookie->Path().Length();
+      if (cookiePathLen > 0 && cookie->Path().Last() == '/') {
+        --cookiePathLen;
+      }
+
+      // if the nsIURI path is shorter than the cookie path, don't send it back
+      if (!StringBeginsWith(pathFromURI, Substring(cookie->Path(), 0, cookiePathLen))) {
+        continue;
+      }
+
+      if (pathFromURI.Length() > cookiePathLen &&
+          !ispathdelimiter(pathFromURI.CharAt(cookiePathLen))) {
+        /*
+         * |ispathdelimiter| tests four cases: '/', '?', '#', and ';'.
+         * '/' is the "standard" case; the '?' test allows a site at host/abc?def
+         * to receive a cookie that has a path attribute of abc.  this seems
+         * strange but at least one major site (citibank, bug 156725) depends
+         * on it.  The test for # and ; are put in to proactively avoid problems
+         * with other sites - these are the only other chars allowed in the path.
+         */
+        continue;
+      }
+
+      // check if the cookie has expired
+      if (cookie->Expiry() <= currentTime) {
+        continue;
+      }
+
+      // all checks passed - add to list and update lastAccessed stamp of cookie
+      result.AppendElement(cookie);
+      cookie->SetLastAccessed(currentTime);
+    }
+
+    currentDot = nextDot;
+    if (currentDot)
+      nextDot = strchr(currentDot + 1, '.');
+
+  } while (currentDot);
+
+  // return cookies in order of path length; longest to shortest.
+  // this is required per RFC2109.  if cookies match in length,
+  // then sort by creation time (see bug 236772).
+  result.Sort(compareCookiesForSending, nsnull);
+
+  // because nsIArray doesn't have sort() we used nsAutoVoidArray above
+  // now we need to copy it into our nsIArray
+  nsCOMPtr<nsIMutableArray> iarray = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  for (int i = 0; i < result.Count(); i++)
+    iarray->AppendElement(NS_STATIC_CAST(nsICookie*, result[i]), PR_FALSE);
+
+  *aResult = iarray;
+  NS_IF_ADDREF(*aResult);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCookieContainer::SetCookie(nsIURI *aHostURI,
+						   nsICookie *cookie)
+{
+    AddInternal(NS_STATIC_CAST(nsCookie*, cookie), NOW_IN_SECONDS, aHostURI, nsnull);
+    
+    // write out the cookie file
+    if (!mSessionOnly)
+      LazyWrite();
+    
+    return NS_OK;
+}
+
+/* readonly attribute string containerId; */
+NS_IMETHODIMP
+nsCookieContainer::GetContainerId(char * *aContainerId)
+{
+    *aContainerId = (char *)nsMemory::Alloc((mContainerId.Length()+1) * sizeof(char));
+    memcpy(*aContainerId, mContainerId.get(), (mContainerId.Length()+1) * sizeof(char));
+    return NS_OK;
+}
+
+void
+nsCookieContainer::LazyWrite()
+{
+  if (mWriteTimer) {
+    mWriteTimer->SetDelay(kLazyWriteTimeout);
+  } else {
+    mWriteTimer = do_CreateInstance("@mozilla.org/timer;1");
+    if (mWriteTimer) {
+      mWriteTimer->InitWithFuncCallback(DoLazyWrite, this, kLazyWriteTimeout,
+                                        nsITimer::TYPE_ONE_SHOT);
+    }
+  }
+}
+
+void
+nsCookieContainer::DoLazyWrite(nsITimer *aTimer,
+                             void     *aClosure)
+{
+  nsCookieContainer *container = NS_REINTERPRET_CAST(nsCookieContainer*, aClosure);
+  container->Write();
+  container->mWriteTimer = 0;
+}
+
+// notify observers that the cookie list changed. there are four possible
+// values for aData:
+// "deleted" means a cookie was deleted. aCookie is the deleted cookie.
+// "added"   means a cookie was added. aCookie is the added cookie.
+// "changed" means a cookie was altered. aCookie is the new cookie.
+// "cleared" means the entire cookie list was cleared. aCookie is null.
+void
+nsCookieContainer::NotifyChanged(nsICookie2      *aCookie,
+                                 const PRUnichar *aData)
+{
+  mCookieChanged = PR_TRUE;
+
+  if (mObserverService)
+    mObserverService->NotifyObservers(aCookie, "cookie-changed", aData);
+
+}
+
+/******************************************************************************
+ * nsCookieService:
+ * pref observer impl
+ ******************************************************************************/
+
+void
+nsCookieContainer::PrefChanged(nsIPrefBranch *aPrefBranch)
+{
+  PRInt32 val;
+
+  mMaxNumberOfCookies = kMaxNumberOfCookies;
+  mMaxCookiesPerHost = kMaxCookiesPerHost;
+
+  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxNumberOfCookies, &val)))
+    mMaxNumberOfCookies = LIMIT(val, 0, 0xFFFF, 0xFFFF);
+
+  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxCookiesPerHost, &val)))
+    mMaxCookiesPerHost = LIMIT(val, 0, 0xFFFF, 0xFFFF);
+}
+
+/******************************************************************************
+ * nsICookieManager impl:
+ * nsICookieManager
+ ******************************************************************************/
+
+NS_IMETHODIMP
+nsCookieContainer::RemoveAll()
+{
+  RemoveAllFromMemory();
+  NotifyChanged(nsnull, NS_LITERAL_STRING("cleared").get());
+  if (!mSessionOnly)
+    Write();
+  return NS_OK;
+}
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+COMArrayCallback(nsCookieEntry *aEntry,
+                 void          *aArg)
+{
+  for (nsCookie *cookie = aEntry->Head(); cookie; cookie = cookie->Next()) {
+    NS_STATIC_CAST(nsCOMArray<nsICookie>*, aArg)->AppendObject(cookie);
+  }
+  return PL_DHASH_NEXT;
+}
+
+NS_IMETHODIMP
+nsCookieContainer::GetEnumerator(nsISimpleEnumerator **aEnumerator)
+{
+  RemoveExpiredCookies(NOW_IN_SECONDS);
+
+  nsCOMArray<nsICookie> cookieList(mCookieCount);
+  mHostTable.EnumerateEntries(COMArrayCallback, &cookieList);
+
+  return NS_NewArrayEnumerator(aEnumerator, cookieList);
+}
+
+NS_IMETHODIMP
+nsCookieContainer::Add(const nsACString &aDomain,
+                       const nsACString &aPath,
+                       const nsACString &aName,
+                       const nsACString &aValue,
+                       PRBool            aIsSecure,
+                       PRBool            aIsSession,
+                       PRInt64           aExpiry)
+{
+  nsInt64 currentTime = NOW_IN_SECONDS;
+
+  nsRefPtr<nsCookie> cookie =
+    nsCookie::Create(aName, aValue, aDomain, aPath,
+                     nsInt64(aExpiry),
+                     currentTime,
+                     aIsSession,
+                     aIsSecure,
+                     PR_FALSE,
+                     nsICookie::STATUS_UNKNOWN,
+                     nsICookie::POLICY_UNKNOWN);
+  if (!cookie) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  AddInternal(cookie, currentTime, nsnull, nsnull);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCookieContainer::Remove(const nsACString &aHost,
+                          const nsACString &aName,
+                          const nsACString &aPath,
+                          PRBool           aBlocked)
+{
+  nsListIter matchIter;
+  if (FindCookie(PromiseFlatCString(aHost),
+                 PromiseFlatCString(aName),
+                 PromiseFlatCString(aPath),
+                 matchIter)) {
+    nsRefPtr<nsCookie> cookie = matchIter.current;
+    RemoveCookieFromList(matchIter);
+    NotifyChanged(cookie, NS_LITERAL_STRING("deleted").get());
+
+    // check if we need to add the host to the permissions blacklist.
+    if (aBlocked) {
+      nsCOMPtr<nsICookiePermission> permissionService = do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
+      if (permissionService) {
+        nsCAutoString host(NS_LITERAL_CSTRING("http://") + cookie->RawHost());
+        nsCOMPtr<nsIURI> uri;
+        NS_NewURI(getter_AddRefs(uri), host);
+
+        if (uri)
+          permissionService->SetAccess(uri, nsICookiePermission::ACCESS_DENY);
+      }
+    }
+    if (!mSessionOnly)
+      LazyWrite();
+  }
+  return NS_OK;
+}
+
+/******************************************************************************
+ * nsCookieContainer impl:
+ * private file I/O functions
+ ******************************************************************************/
+
+nsresult
+nsCookieContainer::Read()
+{
+  nsresult rv;
+  nsCOMPtr<nsIInputStream> fileInputStream;
+  rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), mCookieFile);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  static const char kTrue[] = "TRUE";
+
+  nsCAutoString buffer;
+  PRBool isMore = PR_TRUE;
+  PRInt32 hostIndex, isDomainIndex, pathIndex, secureIndex, expiresIndex, nameIndex, cookieIndex;
+  nsASingleFragmentCString::char_iterator iter;
+  PRInt32 numInts;
+  PRInt64 expires;
+  PRBool isDomain, isHttpOnly = PR_FALSE;
+  nsInt64 currentTime = NOW_IN_SECONDS;
+  // we use lastAccessedCounter to keep cookies in recently-used order,
+  // so we start by initializing to currentTime (somewhat arbitrary)
+  nsInt64 lastAccessedCounter = currentTime;
+  nsCookie *newCookie;
+
+  /* file format is:
+   *
+   * host \t isDomain \t path \t secure \t expires \t name \t cookie
+   *
+   * if this format isn't respected we move onto the next line in the file.
+   * isDomain is "TRUE" or "FALSE" (default to "FALSE")
+   * isSecure is "TRUE" or "FALSE" (default to "TRUE")
+   * expires is a PRInt64 integer
+   * note 1: cookie can contain tabs.
+   * note 2: cookies are written in order of lastAccessed time:
+   *         most-recently used come first; least-recently-used come last.
+   */
+
+  /*
+   * ...but due to bug 178933, we hide HttpOnly cookies from older code
+   * in a comment, so they don't expose HttpOnly cookies to JS.
+   *
+   * The format for HttpOnly cookies is
+   *
+   * #HttpOnly_host \t isDomain \t path \t secure \t expires \t name \t cookie
+   *
+   */
+
+  while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
+    if (StringBeginsWith(buffer, NS_LITERAL_CSTRING(kHttpOnlyPrefix))) {
+      isHttpOnly = PR_TRUE;
+      hostIndex = sizeof(kHttpOnlyPrefix) - 1;
+    } else if (buffer.IsEmpty() || buffer.First() == '#') {
+      continue;
+    } else {
+      isHttpOnly = PR_FALSE;
+      hostIndex = 0;
+    }
+
+    // this is a cheap, cheesy way of parsing a tab-delimited line into
+    // string indexes, which can be lopped off into substrings. just for
+    // purposes of obfuscation, it also checks that each token was found.
+    // todo: use iterators?
+    if ((isDomainIndex = buffer.FindChar('\t', hostIndex)     + 1) == 0 ||
+        (pathIndex     = buffer.FindChar('\t', isDomainIndex) + 1) == 0 ||
+        (secureIndex   = buffer.FindChar('\t', pathIndex)     + 1) == 0 ||
+        (expiresIndex  = buffer.FindChar('\t', secureIndex)   + 1) == 0 ||
+        (nameIndex     = buffer.FindChar('\t', expiresIndex)  + 1) == 0 ||
+        (cookieIndex   = buffer.FindChar('\t', nameIndex)     + 1) == 0) {
+      continue;
+    }
+
+    // check the expirytime first - if it's expired, ignore
+    // nullstomp the trailing tab, to avoid copying the string
+    buffer.BeginWriting(iter);
+    *(iter += nameIndex - 1) = char(0);
+    numInts = PR_sscanf(buffer.get() + expiresIndex, "%lld", &expires);
+    if (numInts != 1 || nsInt64(expires) < currentTime) {
+      continue;
+    }
+
+    isDomain = Substring(buffer, isDomainIndex, pathIndex - isDomainIndex - 1)
+               .EqualsLiteral(kTrue);
+    const nsASingleFragmentCString &host = Substring(buffer, hostIndex, isDomainIndex - hostIndex - 1);
+    // check for bad legacy cookies (domain not starting with a dot, or containing a port),
+    // and discard
+    if (isDomain && !host.IsEmpty() && host.First() != '.' ||
+        host.FindChar(':') != kNotFound) {
+      continue;
+    }
+
+    // create a new nsCookie and assign the data.
+    newCookie =
+      nsCookie::Create(Substring(buffer, nameIndex, cookieIndex - nameIndex - 1),
+                       Substring(buffer, cookieIndex, buffer.Length() - cookieIndex),
+                       host,
+                       Substring(buffer, pathIndex, secureIndex - pathIndex - 1),
+                       nsInt64(expires),
+                       lastAccessedCounter,
+                       PR_FALSE,
+                       Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).EqualsLiteral(kTrue),
+                       isHttpOnly,
+                       nsICookie::STATUS_UNKNOWN,
+                       nsICookie::POLICY_UNKNOWN);
+    if (!newCookie) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    // trick: keep the cookies in most-recently-used order,
+    // by successively decrementing the lastAccessed time
+    lastAccessedCounter -= nsInt64(1);
+
+    if (!AddCookieToList(newCookie)) {
+      // It is purpose that created us; purpose that connects us;
+      // purpose that pulls us; that guides us; that drives us.
+      // It is purpose that defines us; purpose that binds us.
+      // When a cookie no longer has purpose, it has a choice:
+      // it can return to the source to be deleted, or it can go
+      // into exile, and stay hidden inside the Matrix.
+      // Let's choose deletion.
+      delete newCookie;
+    }
+  }
+
+  mCookieChanged = PR_FALSE;
+  return NS_OK;
+}
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+cookieListCallback(nsCookieEntry *aEntry,
+                   void          *aArg)
+{
+  for (nsCookie *cookie = aEntry->Head(); cookie; cookie = cookie->Next()) {
+    NS_STATIC_CAST(nsVoidArray*, aArg)->AppendElement(cookie);
+  }
+  return PL_DHASH_NEXT;
+}
+
+nsresult
+nsCookieContainer::Write()
+{
+  if (!mCookieChanged) {
+    return NS_OK;
+  }
+
+  if (!mCookieFile) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsIOutputStream> fileOutputStream;
+  rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
+                                       mCookieFile,
+                                       -1,
+                                       0600);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("failed to open cookies.txt for writing");
+    return rv;
+  }
+
+  // get a buffered output stream 4096 bytes big, to optimize writes
+  nsCOMPtr<nsIOutputStream> bufferedOutputStream;
+  rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), fileOutputStream, 4096);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  static const char kHeader[] =
+      "# HTTP Cookie File\n"
+      "# http://wp.netscape.com/newsref/std/cookie_spec.html\n"
+      "# This is a generated file!  Do not edit.\n"
+      "# To delete cookies, use the Cookie Manager.\n\n";
+  // note: kTrue and kFalse have leading/trailing tabs already added
+  static const char kTrue[] = "\tTRUE\t";
+  static const char kFalse[] = "\tFALSE\t";
+  static const char kTab[] = "\t";
+  static const char kNew[] = "\n";
+
+  // create a new nsVoidArray to hold the cookie list, and sort it
+  // such that least-recently-used cookies come last
+  nsVoidArray sortedCookieList(mCookieCount);
+  mHostTable.EnumerateEntries(cookieListCallback, &sortedCookieList);
+  sortedCookieList.Sort(compareCookiesForWriting, nsnull);
+
+  bufferedOutputStream->Write(kHeader, sizeof(kHeader) - 1, &rv);
+
+  /* file format is:
+   *
+   * host \t isDomain \t path \t secure \t expires \t name \t cookie
+   *
+   * isDomain is "TRUE" or "FALSE"
+   * isSecure is "TRUE" or "FALSE"
+   * expires is a PRInt64 integer
+   * note 1: cookie can contain tabs.
+   * note 2: cookies are written in order of lastAccessed time:
+   *         most-recently used come first; least-recently-used come last.
+   */
+
+  /*
+   * XXX but see above in ::Read for the HttpOnly hack
+   */
+   
+  nsCookie *cookie;
+  nsInt64 currentTime = NOW_IN_SECONDS;
+  char dateString[22];
+  PRUint32 dateLen;
+  for (PRUint32 i = 0; i < mCookieCount; ++i) {
+    cookie = NS_STATIC_CAST(nsCookie*, sortedCookieList.ElementAt(i));
+
+    // don't write entry if cookie has expired, or is a session cookie
+    if (cookie->IsSession() || cookie->Expiry() <= currentTime) {
+      continue;
+    }
+
+    // XXX hack for HttpOnly. see bug 178993.
+    if (cookie->IsHttpOnly()) {
+      bufferedOutputStream->Write(kHttpOnlyPrefix, sizeof(kHttpOnlyPrefix) - 1, &rv);
+    }
+    bufferedOutputStream->Write(cookie->Host().get(), cookie->Host().Length(), &rv);
+    if (cookie->IsDomain()) {
+      bufferedOutputStream->Write(kTrue, sizeof(kTrue) - 1, &rv);
+    } else {
+      bufferedOutputStream->Write(kFalse, sizeof(kFalse) - 1, &rv);
+    }
+    bufferedOutputStream->Write(cookie->Path().get(), cookie->Path().Length(), &rv);
+    if (cookie->IsSecure()) {
+      bufferedOutputStream->Write(kTrue, sizeof(kTrue) - 1, &rv);
+    } else {
+      bufferedOutputStream->Write(kFalse, sizeof(kFalse) - 1, &rv);
+    }
+    dateLen = PR_snprintf(dateString, sizeof(dateString), "%lld", PRInt64(cookie->Expiry()));
+    bufferedOutputStream->Write(dateString, dateLen, &rv);
+    bufferedOutputStream->Write(kTab, sizeof(kTab) - 1, &rv);
+    bufferedOutputStream->Write(cookie->Name().get(), cookie->Name().Length(), &rv);
+    bufferedOutputStream->Write(kTab, sizeof(kTab) - 1, &rv);
+    bufferedOutputStream->Write(cookie->Value().get(), cookie->Value().Length(), &rv);
+    bufferedOutputStream->Write(kNew, sizeof(kNew) - 1, &rv);
+  }
+
+  // All went ok. Maybe except for problems in Write(), but the stream detects
+  // that for us
+  nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOutputStream);
+  NS_ASSERTION(safeStream, "expected a safe output stream!");
+  if (safeStream) {
+    rv = safeStream->Finish();
+    if (NS_FAILED(rv)) {
+      NS_WARNING("failed to save cookie file! possible dataloss");
+      return rv;
+    }
+  }
+
+  mCookieChanged = PR_FALSE;
+  return NS_OK;
+}
+
+// this is a backend function for adding a cookie to the list, via SetCookie.
+// also used in the cookie manager, for profile migration from IE.
+// it either replaces an existing cookie; or adds the cookie to the hashtable,
+// and deletes a cookie (if maximum number of cookies has been
+// reached). also performs list maintenance by removing expired cookies.
+void
+nsCookieContainer::AddInternal(nsCookie  *aCookie,
+                               nsInt64    aCurrentTime,
+                               nsIURI     *aHostURI,
+                               const char *aCookieHeader)
+{
+  nsListIter matchIter;
+  const PRBool foundCookie =
+    FindCookie(aCookie->Host(), aCookie->Name(), aCookie->Path(), matchIter);
+
+  nsRefPtr<nsCookie> oldCookie;
+  if (foundCookie) {
+    oldCookie = matchIter.current;
+    RemoveCookieFromList(matchIter);
+
+    // check if the cookie has expired
+    if (aCookie->Expiry() <= aCurrentTime) {
+      COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "previously stored cookie was deleted");
+      NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
+      return;
+    }
+
+    // preserve creation time of cookie
+    if (oldCookie) {
+      aCookie->SetCreationTime(oldCookie->CreationTime());
+    }
+
+  } else {
+    // check if cookie has already expired
+    if (aCookie->Expiry() <= aCurrentTime) {
+      COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "cookie has already expired");
+      return;
+    }
+
+    // check if we have to delete an old cookie.
+    nsEnumerationData data(aCurrentTime, LL_MAXINT);
+    if (CountCookiesFromHostInternal(aCookie->RawHost(), data) >= mMaxCookiesPerHost) {
+      // remove the oldest cookie from host
+      oldCookie = data.iter.current;
+      RemoveCookieFromList(data.iter);
+
+    } else if (mCookieCount >= mMaxNumberOfCookies) {
+      // try to make room, by removing expired cookies
+      RemoveExpiredCookies(aCurrentTime);
+
+      // check if we still have to get rid of something
+      if (mCookieCount >= mMaxNumberOfCookies) {
+        // find the position of the oldest cookie, and remove it
+        data.oldestTime = LL_MAXINT;
+        FindOldestCookie(data);
+        oldCookie = data.iter.current;
+        RemoveCookieFromList(data.iter);
+      }
+    }
+
+    // if we deleted an old cookie, notify consumers
+    if (oldCookie)
+      NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
+  }
+
+  // add the cookie to head of list
+  AddCookieToList(aCookie);
+  NotifyChanged(aCookie, foundCookie ? NS_LITERAL_STRING("changed").get()
+                                     : NS_LITERAL_STRING("added").get());
+
+  COOKIE_LOGSUCCESS(SET_COOKIE, aHostURI, aCookieHeader, aCookie);
+}
+
+/******************************************************************************
+ * nsCookieService impl:
+ * private cookielist management functions
+ ******************************************************************************/
+
+void
+nsCookieContainer::RemoveAllFromMemory()
+{
+  // clearing the hashtable will call each nsCookieEntry's dtor,
+  // which releases all their respective children.
+  mHostTable.Clear();
+  mCookieCount = 0;
+  mCookieChanged = PR_TRUE;
+}
+
+PLDHashOperator PR_CALLBACK
+removeExpiredCallback(nsCookieEntry *aEntry,
+                      void          *aArg)
+{
+  nsCookieContainer* container = NS_REINTERPRET_CAST(nsCookieContainer*, ((void**)aArg)[0]);
+  const nsInt64 &currentTime = *NS_STATIC_CAST(nsInt64*, ((void**)aArg)[1]);
+  for (nsListIter iter(aEntry, nsnull, aEntry->Head()); iter.current; ) {
+    if (iter.current->Expiry() <= currentTime)
+      // remove from list. this takes care of updating the iterator for us
+      container->RemoveCookieFromList(iter);
+    else
+      ++iter;
+  }
+  return PL_DHASH_NEXT;
+}
+
+// removes any expired cookies from memory
+void
+nsCookieContainer::RemoveExpiredCookies(nsInt64 aCurrentTime)
+{
+  void* args[2];
+  args[0] = this;
+  args[1] = &aCurrentTime;
+  mHostTable.EnumerateEntries(removeExpiredCallback, &args);
+}
+
+// find whether a given cookie has been previously set. this is provided by the
+// nsICookieManager2 interface.
+NS_IMETHODIMP
+nsCookieContainer::CookieExists(nsICookie2 *aCookie,
+                                PRBool     *aFoundCookie)
+{
+  NS_ENSURE_ARG_POINTER(aCookie);
+
+  // just a placeholder
+  nsEnumerationData data(NOW_IN_SECONDS, LL_MININT);
+  nsCookie *cookie = NS_STATIC_CAST(nsCookie*, aCookie);
+
+  *aFoundCookie = FindCookie(cookie->Host(), cookie->Name(), cookie->Path(), data.iter);
+  return NS_OK;
+}
+
+// count the number of cookies from a given host, and simultaneously find the
+// oldest cookie from the host.
+PRUint32
+nsCookieContainer::CountCookiesFromHostInternal(const nsACString  &aHost,
+                                              nsEnumerationData &aData)
+{
+  PRUint32 countFromHost = 0;
+
+  nsCAutoString hostWithDot(NS_LITERAL_CSTRING(".") + aHost);
+
+  const char *currentDot = hostWithDot.get();
+  const char *nextDot = currentDot + 1;
+  do {
+    nsCookieEntry *entry = mHostTable.GetEntry(currentDot);
+    for (nsListIter iter(entry); iter.current; ++iter) {
+      // only count non-expired cookies
+      if (iter.current->Expiry() > aData.currentTime) {
+        ++countFromHost;
+
+        // check if we've found the oldest cookie so far
+        if (aData.oldestTime > iter.current->LastAccessed()) {
+          aData.oldestTime = iter.current->LastAccessed();
+          aData.iter = iter;
+        }
+      }
+    }
+
+    currentDot = nextDot;
+    if (currentDot)
+      nextDot = strchr(currentDot + 1, '.');
+
+  } while (currentDot);
+
+  return countFromHost;
+}
+
+// count the number of cookies stored by a particular host. this is provided by the
+// nsICookieManager2 interface.
+NS_IMETHODIMP
+nsCookieContainer::CountCookiesFromHost(const nsACString &aHost,
+                                      PRUint32         *aCountFromHost)
+{
+  // we don't care about finding the oldest cookie here, so disable the search
+  nsEnumerationData data(NOW_IN_SECONDS, LL_MININT);
+  
+  *aCountFromHost = CountCookiesFromHostInternal(aHost, data);
+  return NS_OK;
+}
+
+// find an exact previous match.
+PRBool
+nsCookieContainer::FindCookie(const nsAFlatCString &aHost,
+                            const nsAFlatCString &aName,
+                            const nsAFlatCString &aPath,
+                            nsListIter           &aIter)
+{
+  nsCookieEntry *entry = mHostTable.GetEntry(aHost.get());
+  for (aIter = nsListIter(entry); aIter.current; ++aIter) {
+    if (aPath.Equals(aIter.current->Path()) &&
+        aName.Equals(aIter.current->Name())) {
+      return PR_TRUE;
+    }
+  }
+
+  return PR_FALSE;
+}
+
+// removes a cookie from the hashtable, and update the iterator state.
+void
+nsCookieContainer::RemoveCookieFromList(nsListIter &aIter)
+{
+  if (!aIter.prev && !aIter.current->Next()) {
+    // we're removing the last element in the list - so just remove the entry
+    // from the hash. note that the entryclass' dtor will take care of
+    // releasing this last element for us!
+    mHostTable.RawRemoveEntry(aIter.entry);
+    aIter.current = nsnull;
+
+  } else {
+    // just remove the element from the list, and increment the iterator
+    nsCookie *next = aIter.current->Next();
+    NS_RELEASE(aIter.current);
+    if (aIter.prev) {
+      // element to remove is not the head
+      aIter.current = aIter.prev->Next() = next;
+    } else {
+      // element to remove is the head
+      aIter.current = aIter.entry->Head() = next;
+    }
+  }
+
+  --mCookieCount;
+  mCookieChanged = PR_TRUE;
+}
+
+PRBool
+nsCookieContainer::AddCookieToList(nsCookie *aCookie)
+{
+  nsCookieEntry *entry = mHostTable.PutEntry(aCookie->Host().get());
+
+  if (!entry) {
+    NS_ERROR("can't insert element into a null entry!");
+    return PR_FALSE;
+  }
+
+  NS_ADDREF(aCookie);
+
+  aCookie->Next() = entry->Head();
+  entry->Head() = aCookie;
+  ++mCookieCount;
+  mCookieChanged = PR_TRUE;
+
+  return PR_TRUE;
+}
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+findOldestCallback(nsCookieEntry *aEntry,
+                   void          *aArg)
+{
+  nsEnumerationData *data = NS_STATIC_CAST(nsEnumerationData*, aArg);
+  for (nsListIter iter(aEntry, nsnull, aEntry->Head()); iter.current; ++iter) {
+    // check if we've found the oldest cookie so far
+    if (data->oldestTime > iter.current->LastAccessed()) {
+      data->oldestTime = iter.current->LastAccessed();
+      data->iter = iter;
+    }
+  }
+  return PL_DHASH_NEXT;
+}
+
+void
+nsCookieContainer::FindOldestCookie(nsEnumerationData &aData)
+{
+  mHostTable.EnumerateEntries(findOldestCallback, &aData);
+}
Index: netwerk/cookie/src/nsCookieContainer.h
===================================================================
RCS file: netwerk/cookie/src/nsCookieContainer.h
diff -N netwerk/cookie/src/nsCookieContainer.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ netwerk/cookie/src/nsCookieContainer.h	14 May 2007 09:24:17 -0000
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Witte <dwitte@stanford.edu>
+ *   Michiel van Leeuwen <mvl@exedo.nl>
+ *   Loune Lam <lpgcritter at nasquan dot com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsCookieContainer_h__
+#define nsCookieContainer_h__
+
+#include "nsICookieManager.h"
+#include "nsICookieManager2.h"
+#include "nsICookieContainer.h"
+#include "nsICookieService.h"
+#include "nsIObserver.h"
+#include "nsWeakReference.h"
+
+#include "nsCookie.h"
+#include "nsString.h"
+#include "nsTHashtable.h"
+#include "nsInterfaceHashtable.h"
+#include "nsHashKeys.h"
+
+#include "nsInt64.h"
+
+struct nsCookieAttributes;
+struct nsListIter;
+struct nsEnumerationData;
+
+class nsAutoVoidArray;
+
+class nsIPrefBranch;
+class nsICookieConsent;
+class nsICookiePermission;
+class nsIPrefBranch;
+class nsIObserverService;
+class nsIURI;
+class nsIChannel;
+class nsITimer;
+class nsIFile;
+
+// hash entry class
+class nsCookieEntry : public PLDHashEntryHdr
+{
+  public:
+    // Hash methods
+    typedef const char* KeyType;
+    typedef const char* KeyTypePointer;
+
+    // do nothing with aHost - we require mHead to be set before we're live!
+    nsCookieEntry(KeyTypePointer aHost)
+     : mHead(nsnull)
+    {
+    }
+
+    nsCookieEntry(const nsCookieEntry& toCopy)
+    {
+      // if we end up here, things will break. nsTHashtable shouldn't
+      // allow this, since we set ALLOW_MEMMOVE to true.
+      NS_NOTREACHED("nsCookieEntry copy constructor is forbidden!");
+    }
+
+    ~nsCookieEntry()
+    {
+      // walk the linked list, and de-link everything by releasing & nulling.
+      // this allows the parent host entry to be deleted by the hashtable.
+      // note: we know mHead cannot be null here - we always set mHead to a
+      // valid nsCookie (if it were null, the hashtable wouldn't be able to find
+      // this entry, because the key string is provided by mHead).
+      nsCookie *current = mHead, *next;
+      do {
+        next = current->Next();
+        NS_RELEASE(current);
+      } while ((current = next));
+    }
+
+    KeyType GetKey() const
+    {
+      return HostPtr();
+    }
+
+    PRBool KeyEquals(KeyTypePointer aKey) const
+    {
+      return !strcmp(HostPtr(), aKey);
+    }
+
+    static KeyTypePointer KeyToPointer(KeyType aKey)
+    {
+      return aKey;
+    }
+
+    static PLDHashNumber HashKey(KeyTypePointer aKey)
+    {
+      // PL_DHashStringKey doesn't use the table parameter, so we can safely
+      // pass nsnull
+      return PL_DHashStringKey(nsnull, aKey);
+    }
+
+    enum { ALLOW_MEMMOVE = PR_TRUE };
+
+    // get methods
+    inline const nsDependentCString Host() const { return mHead->Host(); }
+
+    // linked list management helper
+    inline nsCookie*& Head() { return mHead; }
+
+    inline KeyTypePointer HostPtr() const
+    {
+      return mHead->Host().get();
+    }
+
+  private:
+    nsCookie *mHead;
+};
+
+/******************************************************************************
+ * nsCookieContainer:
+ * class declaration
+ ******************************************************************************/
+
+class nsCookieContainer : public nsICookieContainer
+                        , public nsICookieManager2
+                        , public nsIObserver
+                        , public nsSupportsWeakReference
+{
+  public:
+    // nsISupports
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIOBSERVER
+    NS_DECL_NSICOOKIECONTAINER
+    NS_DECL_NSICOOKIEMANAGER
+    NS_DECL_NSICOOKIEMANAGER2
+
+    nsCookieContainer();
+    virtual ~nsCookieContainer();
+
+  protected:
+    void                          PrefChanged(nsIPrefBranch *aPrefBranch);
+    nsresult                      Read();
+    nsresult                      Write();
+    void                          AddInternal(nsCookie *aCookie, nsInt64 aCurrentTime, nsIURI *aHostURI, const char *aCookieHeader);
+    void                          RemoveCookieFromList(nsListIter &aIter);
+    PRBool                        AddCookieToList(nsCookie *aCookie);
+    void                          RemoveAllFromMemory();
+    void                          RemoveExpiredCookies(nsInt64 aCurrentTime);
+    PRBool                        FindCookie(const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter);
+    void                          FindOldestCookie(nsEnumerationData &aData);
+    PRUint32                      CountCookiesFromHostInternal(const nsACString &aHost, nsEnumerationData &aData);
+    void                          NotifyChanged(nsICookie2 *aCookie, const PRUnichar *aData);
+
+    // Use LazyWrite to save the cookies file on a timer. It will write
+    // the file only once if repeatedly hammered quickly.
+    void                          LazyWrite();
+    static void                   DoLazyWrite(nsITimer *aTimer, void *aClosure);
+
+  protected:
+    // cached members
+    nsCOMPtr<nsIFile>             mCookieFile;
+    nsCOMPtr<nsIObserverService>  mObserverService;
+
+    // impl members
+    nsCOMPtr<nsITimer>            mWriteTimer;
+    nsTHashtable<nsCookieEntry>   mHostTable;
+    PRUint32                      mCookieCount;
+    PRPackedBool                  mCookieChanged;
+
+	nsCString                     mContainerId;
+	PRBool                        mSessionOnly;
+
+    // cached prefs
+    PRUint8                       mCookiesPermissions;   // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT, P3P}
+    PRUint16                      mMaxNumberOfCookies;
+    PRUint16                      mMaxCookiesPerHost;
+
+    // this callback needs access to member functions
+    friend PLDHashOperator PR_CALLBACK removeExpiredCallback(nsCookieEntry *aEntry, void *aArg);
+};
+
+#endif // nsCookieContainer_h__
Index: netwerk/cookie/src/nsCookieService.cpp
===================================================================
RCS file: /cvsroot/mozilla/netwerk/cookie/src/nsCookieService.cpp,v
retrieving revision 1.57
diff -p -U 8 -r1.57 nsCookieService.cpp
--- netwerk/cookie/src/nsCookieService.cpp	7 May 2007 11:14:01 -0000	1.57
+++ netwerk/cookie/src/nsCookieService.cpp	14 May 2007 09:24:21 -0000
@@ -18,16 +18,17 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2003
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Daniel Witte (dwitte@stanford.edu)
  *   Michiel van Leeuwen (mvl@exedo.nl)
+ *   Loune Lam (lpgcritter at nasquan dot com)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -64,38 +65,30 @@
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 #include "prtime.h"
 #include "prprf.h"
 #include "prnetdb.h"
 #include "nsNetUtil.h"
 #include "nsNetCID.h"
 #include "nsAppDirectoryServiceDefs.h"
+#include "nsIArray.h"
+#include "nsIMutableArray.h"
+#include "nsArrayUtils.h"
 
 /******************************************************************************
  * nsCookieService impl:
  * useful types & constants
  ******************************************************************************/
 
-// XXX_hack. See bug 178993.
-// This is a hack to hide HttpOnly cookies from older browsers
-//
-static const char kHttpOnlyPrefix[] = "#HttpOnly_";
-
-static const char kCookieFileName[] = "cookies.txt";
-
-static const PRUint32 kLazyWriteTimeout = 5000; //msec
-
 #undef  LIMIT
 #define LIMIT(x, low, high, default) ((x) >= (low) && (x) <= (high) ? (x) : (default))
 
 // default limits for the cookie list. these can be tuned by the
 // network.cookie.maxNumber and network.cookie.maxPerHost prefs respectively.
-static const PRUint32 kMaxNumberOfCookies = 1000;
-static const PRUint32 kMaxCookiesPerHost  = 50;
 static const PRUint32 kMaxBytesPerCookie  = 4096;
 static const PRUint32 kMaxBytesPerPath    = 1024;
 
 // this constant augments those defined on nsICookie, and indicates
 // the cookie should be rejected because of an error (rather than
 // something the user can control). this is used for notifying about
 // rejected cookies, since we only want to notify of rejections where
 // the user can do something about it (e.g. whitelist the site).
@@ -111,78 +104,33 @@ static const PRUint32 BEHAVIOR_ACCEPT   
 static const PRUint32 BEHAVIOR_REJECTFOREIGN = 1;
 static const PRUint32 BEHAVIOR_REJECT        = 2;
 static const PRUint32 BEHAVIOR_P3P           = 3;
 
 // pref string constants
 static const char kPrefCookiesPermissions[] = "network.cookie.cookieBehavior";
 static const char kPrefMaxNumberOfCookies[] = "network.cookie.maxNumber";
 static const char kPrefMaxCookiesPerHost[]  = "network.cookie.maxPerHost";
+static const char kInitialCookieContainerId[] = "@mozilla.org/cookie-container;1#MAIN";
 
 // struct for temporarily storing cookie attributes during header parsing
 struct nsCookieAttributes
 {
   nsCAutoString name;
   nsCAutoString value;
   nsCAutoString host;
   nsCAutoString path;
   nsCAutoString expires;
   nsCAutoString maxage;
   nsInt64 expiryTime;
   PRBool isSession;
   PRBool isSecure;
   PRBool isHttpOnly;
 };
 
-// stores linked list iteration state, and provides a rudimentary
-// list traversal method
-struct nsListIter
-{
-  nsListIter() {}
-
-  nsListIter(nsCookieEntry *aEntry)
-   : entry(aEntry)
-   , prev(nsnull)
-   , current(aEntry ? aEntry->Head() : nsnull) {}
-
-  nsListIter(nsCookieEntry *aEntry,
-             nsCookie      *aPrev,
-             nsCookie      *aCurrent)
-   : entry(aEntry)
-   , prev(aPrev)
-   , current(aCurrent) {}
-
-  nsListIter& operator++() { prev = current; current = current->Next(); return *this; }
-
-  nsCookieEntry *entry;
-  nsCookie      *prev;
-  nsCookie      *current;
-};
-
-// stores temporary data for enumerating over the hash entries,
-// since enumeration is done using callback functions
-struct nsEnumerationData
-{
-  nsEnumerationData(nsInt64 aCurrentTime,
-                    PRInt64 aOldestTime)
-   : currentTime(aCurrentTime)
-   , oldestTime(aOldestTime)
-   , iter(nsnull, nsnull, nsnull) {}
-
-  // the current time
-  nsInt64 currentTime;
-
-  // oldest lastAccessed time in the cookie list. use aOldestTime = LL_MAXINT
-  // to enable this search, LL_MININT to disable it.
-  nsInt64 oldestTime;
-
-  // an iterator object that points to the desired cookie
-  nsListIter iter;
-};
-
 /******************************************************************************
  * Cookie logging handlers
  * used for logging in nsCookieService
  ******************************************************************************/
 
 // logging handlers
 #ifdef MOZ_LOGGING
 // in order to do logging, the following environment variables need to be set:
@@ -368,440 +316,364 @@ nsCookieService::GetSingleton()
     if (NS_FAILED(gCookieService->Init())) {
       NS_RELEASE(gCookieService);
     }
   }
 
   return gCookieService;
 }
 
+NS_METHOD
+nsCookieService::GetDefaultContainer(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
+{
+  nsresult rv;
+  
+  if (aOuter != nsnull)
+    return NS_ERROR_NO_AGGREGATION;
+
+  nsCookieService *svc = GetSingleton(); // ref added in the getter
+
+  nsCOMPtr<nsICookieContainer> container;
+  rv = svc->GetDefaultContainer(getter_AddRefs(container));
+  if (NS_FAILED(rv)) return rv;;
+  NS_RELEASE(svc);
+
+  rv = container->QueryInterface(aIID, aResult);
+
+  return rv;
+}
+
 /******************************************************************************
  * nsCookieService impl:
  * public methods
  ******************************************************************************/
 
-NS_IMPL_ISUPPORTS6(nsCookieService,
+NS_IMPL_ISUPPORTS3(nsCookieService,
                    nsICookieService,
-                   nsICookieServiceInternal,
-                   nsICookieManager,
-                   nsICookieManager2,
                    nsIObserver,
                    nsISupportsWeakReference)
 
 nsCookieService::nsCookieService()
- : mCookieCount(0)
- , mCookieChanged(PR_FALSE)
- , mCookieIconVisible(PR_FALSE)
+ : mCookieIconVisible(PR_FALSE)
  , mCookiesPermissions(BEHAVIOR_ACCEPT)
- , mMaxNumberOfCookies(kMaxNumberOfCookies)
- , mMaxCookiesPerHost(kMaxCookiesPerHost)
+ , mDefaultContainerId(kInitialCookieContainerId)
 {
 }
 
 nsresult
 nsCookieService::Init()
 {
-  if (!mHostTable.Init()) {
+  if (!mContainerTable.Init()) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // init our pref and observer
   nsCOMPtr<nsIPrefBranch2> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefBranch) {
     prefBranch->AddObserver(kPrefCookiesPermissions, this, PR_TRUE);
     prefBranch->AddObserver(kPrefMaxNumberOfCookies, this, PR_TRUE);
     prefBranch->AddObserver(kPrefMaxCookiesPerHost,  this, PR_TRUE);
-    PrefChanged(prefBranch);
-  }
-
-  // cache mCookieFile
-  NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mCookieFile));
-  if (mCookieFile) {
-    mCookieFile->AppendNative(NS_LITERAL_CSTRING(kCookieFileName));
+    Observe(prefBranch, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, nsnull);
   }
 
-  Read();
-
   mObserverService = do_GetService("@mozilla.org/observer-service;1");
   if (mObserverService) {
     mObserverService->AddObserver(this, "profile-before-change", PR_TRUE);
     mObserverService->AddObserver(this, "profile-do-change", PR_TRUE);
     mObserverService->AddObserver(this, "cookieIcon", PR_TRUE);
+    mObserverService->AddObserver(this, "cookie-changed", PR_TRUE);
   }
 
   mPermissionService = do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
 
+  // create initial cookie container
+  nsCOMPtr<nsICookieContainer> container;
+  GetDefaultContainer(getter_AddRefs(container));
+
   return NS_OK;
 }
 
 nsCookieService::~nsCookieService()
 {
   gCookieService = nsnull;
+}
 
-  if (mWriteTimer)
-    mWriteTimer->Cancel();
+PR_STATIC_CALLBACK(PLDHashOperator)
+containersNotifyCallback(const char* aKey, nsICookieContainer* aData, void* userArg)
+{
+  nsCOMPtr<nsIObserver> observer = do_QueryInterface(aData);
+  if (observer) {
+    observer->Observe(NS_REINTERPRET_CAST(nsISupports*, ((void**)userArg)[0]), 
+        NS_REINTERPRET_CAST(const char*, ((void**)userArg)[1]),
+        NS_REINTERPRET_CAST(const PRUnichar *, ((void**)userArg)[2]));
+  }
+  return PL_DHASH_NEXT;
 }
 
 NS_IMETHODIMP
 nsCookieService::Observe(nsISupports     *aSubject,
                          const char      *aTopic,
                          const PRUnichar *aData)
 {
   // check the topic
-  if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
-    // The profile is about to change,
-    // or is going away because the application is shutting down.
-    if (mWriteTimer) {
-      mWriteTimer->Cancel();
-      mWriteTimer = 0;
-    }
-
-    if (!nsCRT::strcmp(aData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
-      RemoveAllFromMemory();
-      // delete the cookie file
-      if (mCookieFile) {
-        mCookieFile->Remove(PR_FALSE);
-      }
-    } else {
-      Write();
-      RemoveAllFromMemory();
-    }
-
-  } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
-    // The profile has already changed.    
-    // Now just read them from the new profile location.
-    // we also need to update the cached cookie file location
-    nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mCookieFile));
-    if (NS_SUCCEEDED(rv)) {
-      mCookieFile->AppendNative(NS_LITERAL_CSTRING(kCookieFileName));
-    }
-    Read();
-
-  } else if (!nsCRT::strcmp(aTopic, "cookieIcon")) {
+  if (!nsCRT::strcmp(aTopic, "cookieIcon")) {
     // this is an evil trick to avoid the blatant inefficiency of
     // (!nsCRT::strcmp(aData, NS_LITERAL_STRING("on").get()))
     mCookieIconVisible = (aData[0] == 'o' && aData[1] == 'n' && aData[2] == '\0');
 
-  } else if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
-    nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
-    if (prefBranch)
-      PrefChanged(prefBranch);
+  } else if (!nsCRT::strcmp(aTopic, "profile-before-change") ||
+      !nsCRT::strcmp(aTopic, "profile-do-change") ||
+      !nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
+
+    if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
+      // prefs changed, update default permissions
+      nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
+      if (prefBranch) {
+        mCookiesPermissions = BEHAVIOR_ACCEPT; // default
+        PRInt32 val;
+        if (NS_SUCCEEDED(prefBranch->GetIntPref(kPrefCookiesPermissions, &val)))
+          mCookiesPermissions = LIMIT(val, 0, 3, 0);
+      }
+    }
+    // relay notification to containers
+    void* args[3];
+    args[0] = aSubject;
+    args[1] = (void *)aTopic;
+    args[2] = (void *)aData;
+    mContainerTable.EnumerateRead(containersNotifyCallback, &args);
+
+  } else if (!nsCRT::strcmp(aTopic, "cookie-changed")) {
+    // legacy code originally in NotifyChanged()
+
+    // fire a cookieIcon notification if the cookie was downgraded or flagged
+    // by p3p. the cookieIcon notification is now deprecated, but we still need
+    // this until consumers can be fixed. to see if cookies have been
+    // downgraded or flagged, listen to cookie-changed directly.
+    nsCOMPtr<nsICookie2> cookie = do_QueryInterface(aSubject);
+    if (mCookiesPermissions == BEHAVIOR_P3P &&
+        (!nsCRT::strcmp(aData, NS_LITERAL_STRING("added").get()) ||
+         !nsCRT::strcmp(aData, NS_LITERAL_STRING("changed").get()))) {
+      nsCookieStatus status;
+      cookie->GetStatus(&status);
+      if (status == nsICookie::STATUS_DOWNGRADED ||
+          status == nsICookie::STATUS_FLAGGED) {
+        mCookieIconVisible = PR_TRUE;
+        if (mObserverService)
+          mObserverService->NotifyObservers(nsnull, "cookieIcon", NS_LITERAL_STRING("on").get());
+      }
+    }
   }
 
   return NS_OK;
 }
 
-// helper function for GetCookieList
-static inline PRBool ispathdelimiter(char c) { return c == '/' || c == '?' || c == '#' || c == ';'; }
 
-void
-nsCookieService::GetCookieList(nsIURI           *aHostURI,
-                               nsIURI           *aFirstURI,
-                               nsIChannel       *aChannel,
-                               const nsACString *aName,
-                               PRBool           aHttpBound,
-                               nsAutoVoidArray  &aResult)
+/* attribute string containerId; */
+NS_IMETHODIMP
+nsCookieService::SetDefaultContainer(nsICookieContainer *aContainer)
 {
-  if (!aHostURI) {
-    COOKIE_LOGFAILURE(GET_COOKIE, nsnull, nsnull, "host URI is null");
-    return;
-  }
-
-  // check default prefs
-  nsCookiePolicy cookiePolicy; // we don't use this here... just a placeholder
-  nsCookieStatus cookieStatus = CheckPrefs(aHostURI, aFirstURI, aChannel, nsnull, cookiePolicy);
-  // for GetCookie(), we don't fire rejection notifications.
-  switch (cookieStatus) {
-  case nsICookie::STATUS_REJECTED:
-  case STATUS_REJECTED_WITH_ERROR:
-    return;
-  }
-
-  // get host and path from the nsIURI
-  // note: there was a "check if host has embedded whitespace" here.
-  // it was removed since this check was added into the nsIURI impl (bug 146094).
-  nsCAutoString hostFromURI, pathFromURI;
-  if (NS_FAILED(aHostURI->GetAsciiHost(hostFromURI)) ||
-      NS_FAILED(aHostURI->GetPath(pathFromURI))) {
-    COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, nsnull, "couldn't get host/path from URI");
-    return;
-  }
-  // trim trailing dots
-  hostFromURI.Trim(".");
-  // insert a leading dot, so we begin the hash lookup with the
-  // equivalent domain cookie host
-  hostFromURI.Insert(NS_LITERAL_CSTRING("."), 0);
-  ToLowerCase(hostFromURI);
-
-  // check if aHostURI is using an https secure protocol.
-  // if it isn't, then we can't send a secure cookie over the connection.
-  // if SchemeIs fails, assume an insecure connection, to be on the safe side
-  PRBool isSecure;
-  if (NS_FAILED(aHostURI->SchemeIs("https", &isSecure))) {
-    isSecure = PR_FALSE;
-  }
-
-  nsCookie *cookie;
-  nsInt64 currentTime = NOW_IN_SECONDS;
-  const char *currentDot = hostFromURI.get();
-  const char *nextDot = currentDot + 1;
-
-  // begin hash lookup, walking up the subdomain levels.
-  // we use nextDot to force a lookup of the original host (without leading dot).
-  do {
-    nsCookieEntry *entry = mHostTable.GetEntry(currentDot);
-    cookie = entry ? entry->Head() : nsnull;
-    for (; cookie; cookie = cookie->Next()) {
-      // check the cookie name, if appropriate
-      if (aName && !aName->Equals(cookie->Name())) {
-        continue;
-      }
-
-      // if the cookie is secure and the host scheme isn't, we can't send it
-      if (cookie->IsSecure() && !isSecure) {
-        continue;
-      }
-
-      // if the cookie is httpOnly and it's not going directly to the HTTP
-      // connection, don't send it
-      if (cookie->IsHttpOnly() && !aHttpBound) {
-        continue;
-      }
-
-      // calculate cookie path length, excluding trailing '/'
-      PRUint32 cookiePathLen = cookie->Path().Length();
-      if (cookiePathLen > 0 && cookie->Path().Last() == '/') {
-        --cookiePathLen;
-      }
-
-      // if the nsIURI path is shorter than the cookie path, don't send it back
-      if (!StringBeginsWith(pathFromURI, Substring(cookie->Path(), 0, cookiePathLen))) {
-        continue;
-      }
-
-      if (pathFromURI.Length() > cookiePathLen &&
-          !ispathdelimiter(pathFromURI.CharAt(cookiePathLen))) {
-        /*
-         * |ispathdelimiter| tests four cases: '/', '?', '#', and ';'.
-         * '/' is the "standard" case; the '?' test allows a site at host/abc?def
-         * to receive a cookie that has a path attribute of abc.  this seems
-         * strange but at least one major site (citibank, bug 156725) depends
-         * on it.  The test for # and ; are put in to proactively avoid problems
-         * with other sites - these are the only other chars allowed in the path.
-         */
-        continue;
-      }
-
-      // check if the cookie has expired
-      if (cookie->Expiry() <= currentTime) {
-        continue;
-      }
-
-      // all checks passed - add to list and update lastAccessed stamp of cookie
-      aResult.AppendElement(cookie);
-      cookie->SetLastAccessed(currentTime);
+    if (!aContainer) {
+        mDefaultContainerId.Assign("");
+    } else {
+        char* id;
+        aContainer->GetContainerId(&id);
+        mDefaultContainerId.Assign(id);
+        nsMemory::Free(id);
     }
-
-    currentDot = nextDot;
-    if (currentDot)
-      nextDot = strchr(currentDot + 1, '.');
-
-  } while (currentDot);
-
-  // return cookies in order of path length; longest to shortest.
-  // this is required per RFC2109.  if cookies match in length,
-  // then sort by creation time (see bug 236772).
-  aResult.Sort(compareCookiesForSending, nsnull);
+    return NS_OK;
 }
-
 NS_IMETHODIMP
-nsCookieService::GetCookieValue(nsIURI *aHostURI,
-				nsIChannel *aChannel,
-                                const nsACString& aName,
-				nsACString& aResult)
+nsCookieService::GetDefaultContainer(nsICookieContainer **_retval)
 {
-  aResult.Truncate();
-
-  // try to determine first party URI
-  nsCOMPtr<nsIURI> firstURI;
-  if (aChannel) {
-    nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(aChannel);
-    if (httpInternal)
-      httpInternal->GetDocumentURI(getter_AddRefs(firstURI));
-  }
+    return GetContainer(mDefaultContainerId.get(), _retval);
+}
 
-  nsAutoVoidArray foundCookieList;
-  GetCookieList(aHostURI, firstURI, aChannel, &aName, PR_FALSE,
-                foundCookieList);
 
-  if (!foundCookieList.Count())
-    return NS_ERROR_NOT_AVAILABLE;
+/* nsICookieContainer getContainer (in string aContainerId); */
+NS_IMETHODIMP
+nsCookieService::GetContainer(const char *aContainerId,
+							  nsICookieContainer **_retval)
+{
+    nsresult rv;
 
-  nsCookie *cookie = NS_STATIC_CAST(nsCookie*, foundCookieList[0]);
+    nsCOMPtr<nsICookieContainer> container;
+    // find and get the container. If not found, create as a new container
+    if (!mContainerTable.Get(aContainerId, getter_AddRefs(container))) {
+        // extract the contractId from container id (everything up to the #)
+        char *contractId = (char *)nsMemory::Alloc(strlen(aContainerId) +1 * sizeof(char));
+        PRInt32 i;
+        for (i = 0; aContainerId[i] != 0 && aContainerId[i] != '#'; i++) {
+            contractId[i] = aContainerId[i];
+        }
+        contractId[i] = 0;
+        container = do_CreateInstance(contractId);
+        nsMemory::Free(contractId);
+        if (!container)
+            return NS_ERROR_FAILURE;
+
+        rv = container->Init(aContainerId);
+        NS_ENSURE_SUCCESS(rv, rv);
+        mContainerTable.Put(aContainerId, container);
+    }
+    *_retval = container;
+    NS_IF_ADDREF(*_retval);
 
-  aResult.Assign(cookie->Value());
-  return NS_OK;
+    return NS_OK;
 }
 
+
 NS_IMETHODIMP
-nsCookieService::GetCookieString(nsIURI     *aHostURI,
+nsCookieService::GetCookieString(nsICookieContainer *aContainer, 
+								 nsIURI     *aHostURI,
                                  nsIChannel *aChannel,
                                  char       **aCookie)
 {
   // try to determine first party URI
   nsCOMPtr<nsIURI> firstURI;
   if (aChannel) {
     nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(aChannel);
     if (httpInternal)
       httpInternal->GetDocumentURI(getter_AddRefs(firstURI));
   }
 
-  nsAutoVoidArray foundCookieList;
-  GetCookieList(aHostURI, firstURI, aChannel, nsnull, PR_FALSE,
-                foundCookieList);
+  // check default prefs
+  nsCOMPtr<nsICookiePermission> permissionService = do_QueryInterface(aContainer);
+  if (!permissionService)
+    permissionService = mPermissionService;
+  nsCookiePolicy cookiePolicy; // we don't use this here... just a placeholder
+  nsCookieStatus cookieStatus = CheckPrefs(permissionService, aHostURI, firstURI, aChannel, nsnull, cookiePolicy);
+  // for GetCookie(), we don't fire rejection notifications.
+  switch (cookieStatus) {
+  case nsICookie::STATUS_REJECTED:
+  case STATUS_REJECTED_WITH_ERROR:
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIArray> foundCookieList;
+  aContainer->GetCookieList(aHostURI, nsnull, PR_FALSE,
+                getter_AddRefs(foundCookieList));
   *aCookie = CookieStringFromArray(foundCookieList, aHostURI);
   
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCookieService::GetCookieStringFromHttp(nsIURI     *aHostURI,
+nsCookieService::GetCookieStringFromHttp(nsICookieContainer *aContainer, 
+										 nsIURI     *aHostURI,
                                          nsIURI     *aFirstURI,
                                          nsIChannel *aChannel,
                                          char       **aCookie)
 {
-  nsAutoVoidArray foundCookieList;
-  GetCookieList(aHostURI, aFirstURI, aChannel, nsnull, PR_TRUE,
-                foundCookieList);
+  // check default prefs
+  nsCOMPtr<nsICookiePermission> permissionService = do_QueryInterface(aContainer);
+  if (!permissionService)
+    permissionService = mPermissionService;
+  nsCookiePolicy cookiePolicy; // we don't use this here... just a placeholder
+  nsCookieStatus cookieStatus = CheckPrefs(permissionService, aHostURI, aFirstURI, aChannel, nsnull, cookiePolicy);
+  // for GetCookie(), we don't fire rejection notifications.
+  switch (cookieStatus) {
+  case nsICookie::STATUS_REJECTED:
+  case STATUS_REJECTED_WITH_ERROR:
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIArray> foundCookieList;
+  aContainer->GetCookieList(aHostURI, nsnull, PR_TRUE,
+                getter_AddRefs(foundCookieList));
   *aCookie = CookieStringFromArray(foundCookieList, aHostURI);
 
   return NS_OK;
 }
 
 char*
-nsCookieService::CookieStringFromArray(const nsAutoVoidArray& aCookieList,
+nsCookieService::CookieStringFromArray(nsIArray *aCookieList,
                                        nsIURI *aHostURI)
 {
-  nsCAutoString cookieData;
-  PRInt32 count = aCookieList.Count();
-  for (PRInt32 i = 0; i < count; ++i) {
-    nsCookie *cookie = NS_STATIC_CAST(nsCookie*, aCookieList.ElementAt(i));
+  nsCAutoString cookieData, cookieName, cookieValue;
+  PRUint32 count = 0;
+  aCookieList->GetLength(&count);
+  for (PRUint32 i = 0; i < count; ++i) {
+    nsCOMPtr<nsCookie> cookie = do_QueryElementAt(aCookieList, i);
+    cookie->GetName(cookieName);
+    cookie->GetValue(cookieValue);
 
     // check if we have anything to write
-    if (!cookie->Name().IsEmpty() || !cookie->Value().IsEmpty()) {
+    if (!cookieName.IsEmpty() || !cookieValue.IsEmpty()) {
       // if we've already added a cookie to the return list, append a "; " so
       // that subsequent cookies are delimited in the final list.
       if (!cookieData.IsEmpty()) {
         cookieData.AppendLiteral("; ");
       }
 
-      if (!cookie->Name().IsEmpty()) {
+      if (!cookieName.IsEmpty()) {
         // we have a name and value - write both
-        cookieData += cookie->Name() + NS_LITERAL_CSTRING("=") + cookie->Value();
+        cookieData += cookieName + NS_LITERAL_CSTRING("=") + cookieValue;
       } else {
         // just write value
-        cookieData += cookie->Value();
+        cookieData += cookieValue;
       }
     }
   }
 
   // it's wasteful to alloc a new string; but we have no other choice, until we
   // fix the callers to use nsACStrings.
   if (!cookieData.IsEmpty()) {
     COOKIE_LOGSUCCESS(GET_COOKIE, aHostURI, cookieData, nsnull);
     return ToNewCString(cookieData);
   }
   
   return nsnull;
 }
 
 NS_IMETHODIMP
-nsCookieService::SetCookieValue(nsIURI *aHostURI,
-                                nsIChannel *aChannel,
-                                const nsACString& aDomain,
-                                const nsACString& aPath,
-                                const nsACString& aName,
-                                const nsACString& aValue,
-                                PRBool aIsSession,
-                                PRInt64 aExpiry)
-{
-  // try to determine first party URI
-  nsCOMPtr<nsIURI> firstURI;
-
-  if (aChannel) {
-    nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(aChannel);
-    if (httpInternal)
-      httpInternal->GetDocumentURI(getter_AddRefs(firstURI));
-  }
-
-  // check default prefs
-  nsCookiePolicy cookiePolicy = nsICookie::POLICY_UNKNOWN;
-  nsCookieStatus cookieStatus = CheckPrefs(aHostURI, firstURI, aChannel, "", cookiePolicy);
-  // fire a notification if cookie was rejected (but not if there was an error)
-  switch (cookieStatus) {
-  case nsICookie::STATUS_REJECTED:
-    NotifyRejected(aHostURI);
-  case STATUS_REJECTED_WITH_ERROR:
-    return NS_OK;
-  }
-
-  nsCookieAttributes attributes;
-  attributes.name = aName;
-  attributes.value = aValue;
-  attributes.host = aDomain;
-  attributes.path = aPath;
-  attributes.expiryTime = aExpiry;
-  attributes.isSession = aIsSession;
-
-  attributes.isSecure = PR_FALSE;
-  aHostURI->SchemeIs("https", &attributes.isSecure);
-
-  CheckAndAdd(aHostURI, aChannel, attributes,
-              cookieStatus, cookiePolicy, EmptyCString());
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsCookieService::SetCookieString(nsIURI     *aHostURI,
+nsCookieService::SetCookieString(nsICookieContainer *aContainer, 
+								 nsIURI     *aHostURI,
                                  nsIPrompt  *aPrompt,
                                  const char *aCookieHeader,
                                  nsIChannel *aChannel)
 {
   // try to determine first party URI
   nsCOMPtr<nsIURI> firstURI;
 
   if (aChannel) {
     nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(aChannel);
     if (httpInternal)
       httpInternal->GetDocumentURI(getter_AddRefs(firstURI));
   }
 
-  return SetCookieStringFromHttp(aHostURI, firstURI, aPrompt, aCookieHeader, nsnull, aChannel);
+  return SetCookieStringFromHttp(aContainer, aHostURI, firstURI, aPrompt, aCookieHeader, nsnull, aChannel);
 }
 
 NS_IMETHODIMP
-nsCookieService::SetCookieStringFromHttp(nsIURI     *aHostURI,
+nsCookieService::SetCookieStringFromHttp(nsICookieContainer *aContainer, 
+										 nsIURI     *aHostURI,
                                          nsIURI     *aFirstURI,
                                          nsIPrompt  *aPrompt,
                                          const char *aCookieHeader,
                                          const char *aServerTime,
                                          nsIChannel *aChannel) 
 {
   if (!aHostURI) {
     COOKIE_LOGFAILURE(SET_COOKIE, nsnull, aCookieHeader, "host URI is null");
     return NS_OK;
   }
 
   // check default prefs
+  nsCOMPtr<nsICookiePermission> permissionService = do_QueryInterface(aContainer);
+  if (!permissionService)
+    permissionService = mPermissionService;
   nsCookiePolicy cookiePolicy = nsICookie::POLICY_UNKNOWN;
-  nsCookieStatus cookieStatus = CheckPrefs(aHostURI, aFirstURI, aChannel, aCookieHeader, cookiePolicy);
+  nsCookieStatus cookieStatus = CheckPrefs(permissionService, aHostURI, aFirstURI, aChannel, aCookieHeader, cookiePolicy);
   // fire a notification if cookie was rejected (but not if there was an error)
   switch (cookieStatus) {
   case nsICookie::STATUS_REJECTED:
-    NotifyRejected(aHostURI);
+    char *cid;
+    aContainer->GetContainerId(&cid);
+    NotifyRejected(aHostURI, NS_ConvertASCIItoUTF16(cid).get());
+    nsMemory::Free(cid);
   case STATUS_REJECTED_WITH_ERROR:
     return NS_OK;
   }
 
   // parse server local time. this is not just done here for efficiency
   // reasons - if there's an error parsing it, and we need to default it
   // to the current time, we must do it here since the current time in
   // SetCookieInternal() will change for each cookie processed (e.g. if the
@@ -811,483 +683,41 @@ nsCookieService::SetCookieStringFromHttp
   if (aServerTime && PR_ParseTimeString(aServerTime, PR_TRUE, &tempServerTime) == PR_SUCCESS) {
     serverTime = nsInt64(tempServerTime) / USEC_PER_SEC;
   } else {
     serverTime = NOW_IN_SECONDS;
   }
 
   // switch to a nice string type now, and process each cookie in the header
   nsDependentCString cookieHeader(aCookieHeader);
-  while (SetCookieInternal(aHostURI, aChannel,
+  while (SetCookieInternal(aContainer, aHostURI, aChannel,
                            cookieHeader, serverTime,
                            cookieStatus, cookiePolicy));
 
-  // write out the cookie file
-  LazyWrite();
   return NS_OK;
 }
 
-void
-nsCookieService::LazyWrite()
-{
-  if (mWriteTimer) {
-    mWriteTimer->SetDelay(kLazyWriteTimeout);
-  } else {
-    mWriteTimer = do_CreateInstance("@mozilla.org/timer;1");
-    if (mWriteTimer) {
-      mWriteTimer->InitWithFuncCallback(DoLazyWrite, this, kLazyWriteTimeout,
-                                        nsITimer::TYPE_ONE_SHOT);
-    }
-  }
-}
-
-void
-nsCookieService::DoLazyWrite(nsITimer *aTimer,
-                             void     *aClosure)
-{
-  nsCookieService *service = NS_REINTERPRET_CAST(nsCookieService*, aClosure);
-  service->Write();
-  service->mWriteTimer = 0;
-}
-
-// notify observers that a cookie was rejected due to the users' prefs.
-void
-nsCookieService::NotifyRejected(nsIURI *aHostURI)
-{
-  if (mObserverService)
-    mObserverService->NotifyObservers(aHostURI, "cookie-rejected", nsnull);
-}
-
-// notify observers that the cookie list changed. there are four possible
-// values for aData:
-// "deleted" means a cookie was deleted. aCookie is the deleted cookie.
-// "added"   means a cookie was added. aCookie is the added cookie.
-// "changed" means a cookie was altered. aCookie is the new cookie.
-// "cleared" means the entire cookie list was cleared. aCookie is null.
-void
-nsCookieService::NotifyChanged(nsICookie2      *aCookie,
-                               const PRUnichar *aData)
-{
-  mCookieChanged = PR_TRUE;
-
-  if (mObserverService)
-    mObserverService->NotifyObservers(aCookie, "cookie-changed", aData);
-
-  // fire a cookieIcon notification if the cookie was downgraded or flagged
-  // by p3p. the cookieIcon notification is now deprecated, but we still need
-  // this until consumers can be fixed. to see if cookies have been
-  // downgraded or flagged, listen to cookie-changed directly.
-  if (mCookiesPermissions == BEHAVIOR_P3P &&
-      (!nsCRT::strcmp(aData, NS_LITERAL_STRING("added").get()) ||
-       !nsCRT::strcmp(aData, NS_LITERAL_STRING("changed").get()))) {
-    nsCookieStatus status;
-    aCookie->GetStatus(&status);
-    if (status == nsICookie::STATUS_DOWNGRADED ||
-        status == nsICookie::STATUS_FLAGGED) {
-      mCookieIconVisible = PR_TRUE;
-      if (mObserverService)
-        mObserverService->NotifyObservers(nsnull, "cookieIcon", NS_LITERAL_STRING("on").get());
-    }
-  }
-}
-
 // this method is deprecated. listen to the cookie-changed notification instead.
 NS_IMETHODIMP
 nsCookieService::GetCookieIconIsVisible(PRBool *aIsVisible)
 {
   *aIsVisible = mCookieIconVisible;
   return NS_OK;
 }
 
 /******************************************************************************
- * nsCookieService:
- * pref observer impl
- ******************************************************************************/
-
-void
-nsCookieService::PrefChanged(nsIPrefBranch *aPrefBranch)
-{
-  PRInt32 val;
-  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookiesPermissions, &val)))
-    mCookiesPermissions = LIMIT(val, 0, 3, 0);
-
-  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxNumberOfCookies, &val)))
-    mMaxNumberOfCookies = LIMIT(val, 0, 0xFFFF, 0xFFFF);
-
-  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxCookiesPerHost, &val)))
-    mMaxCookiesPerHost = LIMIT(val, 0, 0xFFFF, 0xFFFF);
-}
-
-/******************************************************************************
- * nsICookieManager impl:
- * nsICookieManager
- ******************************************************************************/
-
-NS_IMETHODIMP
-nsCookieService::RemoveAll()
-{
-  RemoveAllFromMemory();
-  NotifyChanged(nsnull, NS_LITERAL_STRING("cleared").get());
-  Write();
-  return NS_OK;
-}
-
-PR_STATIC_CALLBACK(PLDHashOperator)
-COMArrayCallback(nsCookieEntry *aEntry,
-                 void          *aArg)
-{
-  for (nsCookie *cookie = aEntry->Head(); cookie; cookie = cookie->Next()) {
-    NS_STATIC_CAST(nsCOMArray<nsICookie>*, aArg)->AppendObject(cookie);
-  }
-  return PL_DHASH_NEXT;
-}
-
-NS_IMETHODIMP
-nsCookieService::GetEnumerator(nsISimpleEnumerator **aEnumerator)
-{
-  RemoveExpiredCookies(NOW_IN_SECONDS);
-
-  nsCOMArray<nsICookie> cookieList(mCookieCount);
-  mHostTable.EnumerateEntries(COMArrayCallback, &cookieList);
-
-  return NS_NewArrayEnumerator(aEnumerator, cookieList);
-}
-
-NS_IMETHODIMP
-nsCookieService::Add(const nsACString &aDomain,
-                     const nsACString &aPath,
-                     const nsACString &aName,
-                     const nsACString &aValue,
-                     PRBool            aIsSecure,
-                     PRBool            aIsSession,
-                     PRInt64           aExpiry)
-{
-  nsInt64 currentTime = NOW_IN_SECONDS;
-
-  nsRefPtr<nsCookie> cookie =
-    nsCookie::Create(aName, aValue, aDomain, aPath,
-                     nsInt64(aExpiry),
-                     currentTime,
-                     aIsSession,
-                     aIsSecure,
-                     PR_FALSE,
-                     nsICookie::STATUS_UNKNOWN,
-                     nsICookie::POLICY_UNKNOWN);
-  if (!cookie) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  AddInternal(cookie, currentTime, nsnull, nsnull);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsCookieService::Remove(const nsACString &aHost,
-                        const nsACString &aName,
-                        const nsACString &aPath,
-                        PRBool           aBlocked)
-{
-  nsListIter matchIter;
-  if (FindCookie(PromiseFlatCString(aHost),
-                 PromiseFlatCString(aName),
-                 PromiseFlatCString(aPath),
-                 matchIter)) {
-    nsRefPtr<nsCookie> cookie = matchIter.current;
-    RemoveCookieFromList(matchIter);
-    NotifyChanged(cookie, NS_LITERAL_STRING("deleted").get());
-
-    // check if we need to add the host to the permissions blacklist.
-    if (aBlocked && mPermissionService) {
-      nsCAutoString host(NS_LITERAL_CSTRING("http://") + cookie->RawHost());
-      nsCOMPtr<nsIURI> uri;
-      NS_NewURI(getter_AddRefs(uri), host);
-
-      if (uri)
-        mPermissionService->SetAccess(uri, nsICookiePermission::ACCESS_DENY);
-    }
-
-    LazyWrite();
-  }
-  return NS_OK;
-}
-
-/******************************************************************************
- * nsCookieService impl:
- * private file I/O functions
- ******************************************************************************/
-
-nsresult
-nsCookieService::Read()
-{
-  nsresult rv;
-  nsCOMPtr<nsIInputStream> fileInputStream;
-  rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), mCookieFile);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  static const char kTrue[] = "TRUE";
-
-  nsCAutoString buffer;
-  PRBool isMore = PR_TRUE;
-  PRInt32 hostIndex, isDomainIndex, pathIndex, secureIndex, expiresIndex, nameIndex, cookieIndex;
-  nsASingleFragmentCString::char_iterator iter;
-  PRInt32 numInts;
-  PRInt64 expires;
-  PRBool isDomain, isHttpOnly = PR_FALSE;
-  nsInt64 currentTime = NOW_IN_SECONDS;
-  // we use lastAccessedCounter to keep cookies in recently-used order,
-  // so we start by initializing to currentTime (somewhat arbitrary)
-  nsInt64 lastAccessedCounter = currentTime;
-  nsCookie *newCookie;
-
-  /* file format is:
-   *
-   * host \t isDomain \t path \t secure \t expires \t name \t cookie
-   *
-   * if this format isn't respected we move onto the next line in the file.
-   * isDomain is "TRUE" or "FALSE" (default to "FALSE")
-   * isSecure is "TRUE" or "FALSE" (default to "TRUE")
-   * expires is a PRInt64 integer
-   * note 1: cookie can contain tabs.
-   * note 2: cookies are written in order of lastAccessed time:
-   *         most-recently used come first; least-recently-used come last.
-   */
-
-  /*
-   * ...but due to bug 178933, we hide HttpOnly cookies from older code
-   * in a comment, so they don't expose HttpOnly cookies to JS.
-   *
-   * The format for HttpOnly cookies is
-   *
-   * #HttpOnly_host \t isDomain \t path \t secure \t expires \t name \t cookie
-   *
-   */
-
-  while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
-    if (StringBeginsWith(buffer, NS_LITERAL_CSTRING(kHttpOnlyPrefix))) {
-      isHttpOnly = PR_TRUE;
-      hostIndex = sizeof(kHttpOnlyPrefix) - 1;
-    } else if (buffer.IsEmpty() || buffer.First() == '#') {
-      continue;
-    } else {
-      isHttpOnly = PR_FALSE;
-      hostIndex = 0;
-    }
-
-    // this is a cheap, cheesy way of parsing a tab-delimited line into
-    // string indexes, which can be lopped off into substrings. just for
-    // purposes of obfuscation, it also checks that each token was found.
-    // todo: use iterators?
-    if ((isDomainIndex = buffer.FindChar('\t', hostIndex)     + 1) == 0 ||
-        (pathIndex     = buffer.FindChar('\t', isDomainIndex) + 1) == 0 ||
-        (secureIndex   = buffer.FindChar('\t', pathIndex)     + 1) == 0 ||
-        (expiresIndex  = buffer.FindChar('\t', secureIndex)   + 1) == 0 ||
-        (nameIndex     = buffer.FindChar('\t', expiresIndex)  + 1) == 0 ||
-        (cookieIndex   = buffer.FindChar('\t', nameIndex)     + 1) == 0) {
-      continue;
-    }
-
-    // check the expirytime first - if it's expired, ignore
-    // nullstomp the trailing tab, to avoid copying the string
-    buffer.BeginWriting(iter);
-    *(iter += nameIndex - 1) = char(0);
-    numInts = PR_sscanf(buffer.get() + expiresIndex, "%lld", &expires);
-    if (numInts != 1 || nsInt64(expires) < currentTime) {
-      continue;
-    }
-
-    isDomain = Substring(buffer, isDomainIndex, pathIndex - isDomainIndex - 1)
-               .EqualsLiteral(kTrue);
-    const nsASingleFragmentCString &host = Substring(buffer, hostIndex, isDomainIndex - hostIndex - 1);
-    // check for bad legacy cookies (domain not starting with a dot, or containing a port),
-    // and discard
-    if (isDomain && !host.IsEmpty() && host.First() != '.' ||
-        host.FindChar(':') != kNotFound) {
-      continue;
-    }
-
-    // create a new nsCookie and assign the data.
-    newCookie =
-      nsCookie::Create(Substring(buffer, nameIndex, cookieIndex - nameIndex - 1),
-                       Substring(buffer, cookieIndex, buffer.Length() - cookieIndex),
-                       host,
-                       Substring(buffer, pathIndex, secureIndex - pathIndex - 1),
-                       nsInt64(expires),
-                       lastAccessedCounter,
-                       PR_FALSE,
-                       Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).EqualsLiteral(kTrue),
-                       isHttpOnly,
-                       nsICookie::STATUS_UNKNOWN,
-                       nsICookie::POLICY_UNKNOWN);
-    if (!newCookie) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    // trick: keep the cookies in most-recently-used order,
-    // by successively decrementing the lastAccessed time
-    lastAccessedCounter -= nsInt64(1);
-
-    if (!AddCookieToList(newCookie)) {
-      // It is purpose that created us; purpose that connects us;
-      // purpose that pulls us; that guides us; that drives us.
-      // It is purpose that defines us; purpose that binds us.
-      // When a cookie no longer has purpose, it has a choice:
-      // it can return to the source to be deleted, or it can go
-      // into exile, and stay hidden inside the Matrix.
-      // Let's choose deletion.
-      delete newCookie;
-    }
-  }
-
-  mCookieChanged = PR_FALSE;
-  return NS_OK;
-}
-
-PR_STATIC_CALLBACK(PLDHashOperator)
-cookieListCallback(nsCookieEntry *aEntry,
-                   void          *aArg)
-{
-  for (nsCookie *cookie = aEntry->Head(); cookie; cookie = cookie->Next()) {
-    NS_STATIC_CAST(nsVoidArray*, aArg)->AppendElement(cookie);
-  }
-  return PL_DHASH_NEXT;
-}
-
-nsresult
-nsCookieService::Write()
-{
-  if (!mCookieChanged) {
-    return NS_OK;
-  }
-
-  if (!mCookieFile) {
-    return NS_ERROR_NULL_POINTER;
-  }
-
-  nsresult rv;
-  nsCOMPtr<nsIOutputStream> fileOutputStream;
-  rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
-                                       mCookieFile,
-                                       -1,
-                                       0600);
-  if (NS_FAILED(rv)) {
-    NS_ERROR("failed to open cookies.txt for writing");
-    return rv;
-  }
-
-  // get a buffered output stream 4096 bytes big, to optimize writes
-  nsCOMPtr<nsIOutputStream> bufferedOutputStream;
-  rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), fileOutputStream, 4096);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  static const char kHeader[] =
-      "# HTTP Cookie File\n"
-      "# http://wp.netscape.com/newsref/std/cookie_spec.html\n"
-      "# This is a generated file!  Do not edit.\n"
-      "# To delete cookies, use the Cookie Manager.\n\n";
-  // note: kTrue and kFalse have leading/trailing tabs already added
-  static const char kTrue[] = "\tTRUE\t";
-  static const char kFalse[] = "\tFALSE\t";
-  static const char kTab[] = "\t";
-  static const char kNew[] = "\n";
-
-  // create a new nsVoidArray to hold the cookie list, and sort it
-  // such that least-recently-used cookies come last
-  nsVoidArray sortedCookieList(mCookieCount);
-  mHostTable.EnumerateEntries(cookieListCallback, &sortedCookieList);
-  sortedCookieList.Sort(compareCookiesForWriting, nsnull);
-
-  bufferedOutputStream->Write(kHeader, sizeof(kHeader) - 1, &rv);
-
-  /* file format is:
-   *
-   * host \t isDomain \t path \t secure \t expires \t name \t cookie
-   *
-   * isDomain is "TRUE" or "FALSE"
-   * isSecure is "TRUE" or "FALSE"
-   * expires is a PRInt64 integer
-   * note 1: cookie can contain tabs.
-   * note 2: cookies are written in order of lastAccessed time:
-   *         most-recently used come first; least-recently-used come last.
-   */
-
-  /*
-   * XXX but see above in ::Read for the HttpOnly hack
-   */
-   
-  nsCookie *cookie;
-  nsInt64 currentTime = NOW_IN_SECONDS;
-  char dateString[22];
-  PRUint32 dateLen;
-  for (PRUint32 i = 0; i < mCookieCount; ++i) {
-    cookie = NS_STATIC_CAST(nsCookie*, sortedCookieList.ElementAt(i));
-
-    // don't write entry if cookie has expired, or is a session cookie
-    if (cookie->IsSession() || cookie->Expiry() <= currentTime) {
-      continue;
-    }
-
-    // XXX hack for HttpOnly. see bug 178993.
-    if (cookie->IsHttpOnly()) {
-      bufferedOutputStream->Write(kHttpOnlyPrefix, sizeof(kHttpOnlyPrefix) - 1, &rv);
-    }
-    bufferedOutputStream->Write(cookie->Host().get(), cookie->Host().Length(), &rv);
-    if (cookie->IsDomain()) {
-      bufferedOutputStream->Write(kTrue, sizeof(kTrue) - 1, &rv);
-    } else {
-      bufferedOutputStream->Write(kFalse, sizeof(kFalse) - 1, &rv);
-    }
-    bufferedOutputStream->Write(cookie->Path().get(), cookie->Path().Length(), &rv);
-    if (cookie->IsSecure()) {
-      bufferedOutputStream->Write(kTrue, sizeof(kTrue) - 1, &rv);
-    } else {
-      bufferedOutputStream->Write(kFalse, sizeof(kFalse) - 1, &rv);
-    }
-    dateLen = PR_snprintf(dateString, sizeof(dateString), "%lld", PRInt64(cookie->Expiry()));
-    bufferedOutputStream->Write(dateString, dateLen, &rv);
-    bufferedOutputStream->Write(kTab, sizeof(kTab) - 1, &rv);
-    bufferedOutputStream->Write(cookie->Name().get(), cookie->Name().Length(), &rv);
-    bufferedOutputStream->Write(kTab, sizeof(kTab) - 1, &rv);
-    bufferedOutputStream->Write(cookie->Value().get(), cookie->Value().Length(), &rv);
-    bufferedOutputStream->Write(kNew, sizeof(kNew) - 1, &rv);
-  }
-
-  // All went ok. Maybe except for problems in Write(), but the stream detects
-  // that for us
-  nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOutputStream);
-  NS_ASSERTION(safeStream, "expected a safe output stream!");
-  if (safeStream) {
-    rv = safeStream->Finish();
-    if (NS_FAILED(rv)) {
-      NS_WARNING("failed to save cookie file! possible dataloss");
-      return rv;
-    }
-  }
-
-  mCookieChanged = PR_FALSE;
-  return NS_OK;
-}
-
-/******************************************************************************
  * nsCookieService impl:
  * private GetCookie/SetCookie helpers
  ******************************************************************************/
 
 // processes a single cookie, and returns PR_TRUE if there are more cookies
 // to be processed
 PRBool
-nsCookieService::SetCookieInternal(nsIURI             *aHostURI,
+nsCookieService::SetCookieInternal(nsICookieContainer *aContainer,
+                                   nsIURI             *aHostURI,
                                    nsIChannel         *aChannel,
                                    nsDependentCString &aCookieHeader,
                                    nsInt64             aServerTime,
                                    nsCookieStatus      aStatus,
                                    nsCookiePolicy      aPolicy)
 {
   // create a stack-based nsCookieAttributes, to store all the
   // attributes parsed from the cookie
@@ -1305,24 +735,25 @@ nsCookieService::SetCookieInternal(nsIUR
   const PRBool newCookie = ParseAttributes(aCookieHeader, cookieAttributes);
 
   // calculate expiry time of cookie. we need to pass in cookieStatus, since
   // the cookie may have been downgraded to a session cookie by p3p.
   const nsInt64 currentTime = NOW_IN_SECONDS;
   cookieAttributes.isSession = GetExpiry(cookieAttributes, aServerTime,
                                          currentTime, aStatus);
 
-  CheckAndAdd(aHostURI, aChannel, cookieAttributes,
+  CheckAndAdd(aContainer, aHostURI, aChannel, cookieAttributes,
               aStatus, aPolicy, savedCookieHeader);
 
   return newCookie;
 }
 
 void
-nsCookieService::CheckAndAdd(nsIURI               *aHostURI,
+nsCookieService::CheckAndAdd(nsICookieContainer   *aContainer,
+                             nsIURI               *aHostURI,
                              nsIChannel           *aChannel,
                              nsCookieAttributes   &aAttributes,
                              nsCookieStatus        aStatus,
                              const nsCookiePolicy  aPolicy,
                              const nsAFlatCString &aCookieHeader)
 {
   // reject cookie if it's over the size limit, per RFC2109
   if ((aAttributes.name.Length() + aAttributes.value.Length()) > kMaxBytesPerCookie) {
@@ -1361,112 +792,46 @@ nsCookieService::CheckAndAdd(nsIURI     
                      aStatus,
                      aPolicy);
   if (!cookie) {
     return;
   }
 
   // check permissions from site permission list, or ask the user,
   // to determine if we can set the cookie
-  if (mPermissionService) {
+  nsCOMPtr<nsICookiePermission> permissionService = do_QueryInterface(aContainer);
+  if (!permissionService)
+    permissionService = mPermissionService;
+
+  if (permissionService) {
     PRBool permission;
     // we need to think about prompters/parent windows here - TestPermission
     // needs one to prompt, so right now it has to fend for itself to get one
-    mPermissionService->CanSetCookie(aHostURI,
+    permissionService->CanSetCookie(aHostURI,
                                      aChannel,
                                      NS_STATIC_CAST(nsICookie2*, NS_STATIC_CAST(nsCookie*, cookie)),
                                      &aAttributes.isSession,
                                      &aAttributes.expiryTime.mValue,
                                      &permission);
     if (!permission) {
       COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "cookie rejected by permission manager");
-      NotifyRejected(aHostURI);
+      char *cid;
+      aContainer->GetContainerId(&cid);
+      NotifyRejected(aHostURI, NS_ConvertASCIItoUTF16(cid).get());
+      nsMemory::Free(cid);
       return;
     }
 
     // update isSession and expiry attributes, in case they changed
     cookie->SetIsSession(aAttributes.isSession);
     cookie->SetExpiry(aAttributes.expiryTime);
   }
 
-  // add the cookie to the list. AddInternal() takes care of logging.
-  AddInternal(cookie, NOW_IN_SECONDS, aHostURI, aCookieHeader.get());
-}
-
-// this is a backend function for adding a cookie to the list, via SetCookie.
-// also used in the cookie manager, for profile migration from IE.
-// it either replaces an existing cookie; or adds the cookie to the hashtable,
-// and deletes a cookie (if maximum number of cookies has been
-// reached). also performs list maintenance by removing expired cookies.
-void
-nsCookieService::AddInternal(nsCookie   *aCookie,
-                             nsInt64    aCurrentTime,
-                             nsIURI     *aHostURI,
-                             const char *aCookieHeader)
-{
-  nsListIter matchIter;
-  const PRBool foundCookie =
-    FindCookie(aCookie->Host(), aCookie->Name(), aCookie->Path(), matchIter);
-
-  nsRefPtr<nsCookie> oldCookie;
-  if (foundCookie) {
-    oldCookie = matchIter.current;
-    RemoveCookieFromList(matchIter);
-
-    // check if the cookie has expired
-    if (aCookie->Expiry() <= aCurrentTime) {
-      COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "previously stored cookie was deleted");
-      NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
-      return;
-    }
-
-    // preserve creation time of cookie
-    if (oldCookie) {
-      aCookie->SetCreationTime(oldCookie->CreationTime());
-    }
-
-  } else {
-    // check if cookie has already expired
-    if (aCookie->Expiry() <= aCurrentTime) {
-      COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "cookie has already expired");
-      return;
-    }
-
-    // check if we have to delete an old cookie.
-    nsEnumerationData data(aCurrentTime, LL_MAXINT);
-    if (CountCookiesFromHostInternal(aCookie->RawHost(), data) >= mMaxCookiesPerHost) {
-      // remove the oldest cookie from host
-      oldCookie = data.iter.current;
-      RemoveCookieFromList(data.iter);
-
-    } else if (mCookieCount >= mMaxNumberOfCookies) {
-      // try to make room, by removing expired cookies
-      RemoveExpiredCookies(aCurrentTime);
-
-      // check if we still have to get rid of something
-      if (mCookieCount >= mMaxNumberOfCookies) {
-        // find the position of the oldest cookie, and remove it
-        data.oldestTime = LL_MAXINT;
-        FindOldestCookie(data);
-        oldCookie = data.iter.current;
-        RemoveCookieFromList(data.iter);
-      }
-    }
-
-    // if we deleted an old cookie, notify consumers
-    if (oldCookie)
-      NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
-  }
-
-  // add the cookie to head of list
-  AddCookieToList(aCookie);
-  NotifyChanged(aCookie, foundCookie ? NS_LITERAL_STRING("changed").get()
-                                     : NS_LITERAL_STRING("added").get());
-
-  COOKIE_LOGSUCCESS(SET_COOKIE, aHostURI, aCookieHeader, aCookie);
+  // add the cookie to the container
+  aContainer->SetCookie(aHostURI, cookie);
 }
 
 /******************************************************************************
  * nsCookieService impl:
  * private cookie header parsing functions
  ******************************************************************************/
 
 // The following comment block elucidates the function of ParseAttributes.
@@ -1708,16 +1073,74 @@ nsCookieService::ParseAttributes(nsDepen
       aCookieAttributes.isHttpOnly = PR_TRUE;
   }
 
   // rebind aCookieHeader, in case we need to process another cookie
   aCookieHeader.Rebind(cookieStart, cookieEnd);
   return newCookie;
 }
 
+PRBool
+nsCookieService::GetExpiry(nsCookieAttributes &aCookieAttributes,
+                           nsInt64            aServerTime,
+                           nsInt64            aCurrentTime,
+                           nsCookieStatus     aStatus)
+{
+  /* Determine when the cookie should expire. This is done by taking the difference between 
+   * the server time and the time the server wants the cookie to expire, and adding that 
+   * difference to the client time. This localizes the client time regardless of whether or
+   * not the TZ environment variable was set on the client.
+   *
+   * Note: We need to consider accounting for network lag here, per RFC.
+   */
+  nsInt64 delta;
+
+  // check for max-age attribute first; this overrides expires attribute
+  if (!aCookieAttributes.maxage.IsEmpty()) {
+    // obtain numeric value of maxageAttribute
+    PRInt64 maxage;
+    PRInt32 numInts = PR_sscanf(aCookieAttributes.maxage.get(), "%lld", &maxage);
+
+    // default to session cookie if the conversion failed
+    if (numInts != 1) {
+      return PR_TRUE;
+    }
+
+    delta = nsInt64(maxage);
+
+  // check for expires attribute
+  } else if (!aCookieAttributes.expires.IsEmpty()) {
+    nsInt64 expires;
+    PRTime tempExpires;
+
+    // parse expiry time
+    if (PR_ParseTimeString(aCookieAttributes.expires.get(), PR_TRUE, &tempExpires) == PR_SUCCESS) {
+      expires = nsInt64(tempExpires) / USEC_PER_SEC;
+    } else {
+      return PR_TRUE;
+    }
+
+    delta = expires - aServerTime;
+
+  // default to session cookie if no attributes found
+  } else {
+    return PR_TRUE;
+  }
+
+  // if this addition overflows, expiryTime will be less than currentTime
+  // and the cookie will be expired - that's okay.
+  aCookieAttributes.expiryTime = aCurrentTime + delta;
+
+  // we need to return whether the cookie is a session cookie or not:
+  // the cookie may have been previously downgraded by p3p prefs,
+  // so we take that into account here. only applies to non-expired cookies.
+  return aStatus == nsICookie::STATUS_DOWNGRADED &&
+         aCookieAttributes.expiryTime > aCurrentTime;
+}
+
 /******************************************************************************
  * nsCookieService impl:
  * private domain & permission compliance enforcement functions
  ******************************************************************************/
 
 // returns PR_TRUE if aHost is an IP address
 PRBool
 nsCookieService::IsIPAddress(const nsAFlatCString &aHost)
@@ -1828,17 +1251,18 @@ nsCookieService::IsForeign(nsIURI *aHost
   }
 
   // don't have enough dots to chop firstHost, or the subdomain levels differ;
   // so we just do the plain old check, IsInDomain(firstHost, currentHost).
   return !IsInDomain(NS_LITERAL_CSTRING(".") + firstHost, currentHost);
 }
 
 nsCookieStatus
-nsCookieService::CheckPrefs(nsIURI         *aHostURI,
+nsCookieService::CheckPrefs(nsICookiePermission *aPermissionService,
+                            nsIURI         *aHostURI,
                             nsIURI         *aFirstURI,
                             nsIChannel     *aChannel,
                             const char     *aCookieHeader,
                             nsCookiePolicy &aPolicy)
 {
   // pref tree:
   // 0) get the scheme strings from the two URI's
   // 1) disallow ftp
@@ -1870,19 +1294,19 @@ nsCookieService::CheckPrefs(nsIURI      
   // don't let ftp sites get/set cookies (could be a security issue)
   if (currentURIScheme.EqualsLiteral("ftp")) {
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "ftp sites cannot read cookies");
     return STATUS_REJECTED_WITH_ERROR;
   }
 
   // check the permission list first; if we find an entry, it overrides
   // default prefs. see bug 184059.
-  if (mPermissionService) {
+  if (aPermissionService) {
     nsCookieAccess access;
-    rv = mPermissionService->CanAccess(aHostURI, aFirstURI, aChannel, &access);
+    rv = aPermissionService->CanAccess(aHostURI, aFirstURI, aChannel, &access);
 
     // if we found an entry, use it
     if (NS_SUCCEEDED(rv)) {
       switch (access) {
       case nsICookiePermission::ACCESS_DENY:
         COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are blocked for this site");
         return nsICookie::STATUS_REJECTED;
 
@@ -2047,254 +1471,15 @@ nsCookieService::CheckPath(nsCookieAttri
 
   if (aCookieAttributes.path.Length() > kMaxBytesPerPath ||
       aCookieAttributes.path.FindChar('\t') != kNotFound )
     return PR_FALSE;
 
   return PR_TRUE;
 }
 
-PRBool
-nsCookieService::GetExpiry(nsCookieAttributes &aCookieAttributes,
-                           nsInt64            aServerTime,
-                           nsInt64            aCurrentTime,
-                           nsCookieStatus     aStatus)
-{
-  /* Determine when the cookie should expire. This is done by taking the difference between 
-   * the server time and the time the server wants the cookie to expire, and adding that 
-   * difference to the client time. This localizes the client time regardless of whether or
-   * not the TZ environment variable was set on the client.
-   *
-   * Note: We need to consider accounting for network lag here, per RFC.
-   */
-  nsInt64 delta;
-
-  // check for max-age attribute first; this overrides expires attribute
-  if (!aCookieAttributes.maxage.IsEmpty()) {
-    // obtain numeric value of maxageAttribute
-    PRInt64 maxage;
-    PRInt32 numInts = PR_sscanf(aCookieAttributes.maxage.get(), "%lld", &maxage);
-
-    // default to session cookie if the conversion failed
-    if (numInts != 1) {
-      return PR_TRUE;
-    }
-
-    delta = nsInt64(maxage);
-
-  // check for expires attribute
-  } else if (!aCookieAttributes.expires.IsEmpty()) {
-    nsInt64 expires;
-    PRTime tempExpires;
-
-    // parse expiry time
-    if (PR_ParseTimeString(aCookieAttributes.expires.get(), PR_TRUE, &tempExpires) == PR_SUCCESS) {
-      expires = nsInt64(tempExpires) / USEC_PER_SEC;
-    } else {
-      return PR_TRUE;
-    }
-
-    delta = expires - aServerTime;
-
-  // default to session cookie if no attributes found
-  } else {
-    return PR_TRUE;
-  }
-
-  // if this addition overflows, expiryTime will be less than currentTime
-  // and the cookie will be expired - that's okay.
-  aCookieAttributes.expiryTime = aCurrentTime + delta;
-
-  // we need to return whether the cookie is a session cookie or not:
-  // the cookie may have been previously downgraded by p3p prefs,
-  // so we take that into account here. only applies to non-expired cookies.
-  return aStatus == nsICookie::STATUS_DOWNGRADED &&
-         aCookieAttributes.expiryTime > aCurrentTime;
-}
-
-/******************************************************************************
- * nsCookieService impl:
- * private cookielist management functions
- ******************************************************************************/
-
-void
-nsCookieService::RemoveAllFromMemory()
-{
-  // clearing the hashtable will call each nsCookieEntry's dtor,
-  // which releases all their respective children.
-  mHostTable.Clear();
-  mCookieCount = 0;
-  mCookieChanged = PR_TRUE;
-}
-
-PLDHashOperator PR_CALLBACK
-removeExpiredCallback(nsCookieEntry *aEntry,
-                      void          *aArg)
-{
-  const nsInt64 &currentTime = *NS_STATIC_CAST(nsInt64*, aArg);
-  for (nsListIter iter(aEntry, nsnull, aEntry->Head()); iter.current; ) {
-    if (iter.current->Expiry() <= currentTime)
-      // remove from list. this takes care of updating the iterator for us
-      nsCookieService::gCookieService->RemoveCookieFromList(iter);
-    else
-      ++iter;
-  }
-  return PL_DHASH_NEXT;
-}
-
-// removes any expired cookies from memory
-void
-nsCookieService::RemoveExpiredCookies(nsInt64 aCurrentTime)
-{
-  mHostTable.EnumerateEntries(removeExpiredCallback, &aCurrentTime);
-}
-
-// find whether a given cookie has been previously set. this is provided by the
-// nsICookieManager2 interface.
-NS_IMETHODIMP
-nsCookieService::CookieExists(nsICookie2 *aCookie,
-                              PRBool     *aFoundCookie)
-{
-  NS_ENSURE_ARG_POINTER(aCookie);
-
-  // just a placeholder
-  nsEnumerationData data(NOW_IN_SECONDS, LL_MININT);
-  nsCookie *cookie = NS_STATIC_CAST(nsCookie*, aCookie);
-
-  *aFoundCookie = FindCookie(cookie->Host(), cookie->Name(), cookie->Path(), data.iter);
-  return NS_OK;
-}
-
-// count the number of cookies from a given host, and simultaneously find the
-// oldest cookie from the host.
-PRUint32
-nsCookieService::CountCookiesFromHostInternal(const nsACString  &aHost,
-                                              nsEnumerationData &aData)
-{
-  PRUint32 countFromHost = 0;
-
-  nsCAutoString hostWithDot(NS_LITERAL_CSTRING(".") + aHost);
-
-  const char *currentDot = hostWithDot.get();
-  const char *nextDot = currentDot + 1;
-  do {
-    nsCookieEntry *entry = mHostTable.GetEntry(currentDot);
-    for (nsListIter iter(entry); iter.current; ++iter) {
-      // only count non-expired cookies
-      if (iter.current->Expiry() > aData.currentTime) {
-        ++countFromHost;
-
-        // check if we've found the oldest cookie so far
-        if (aData.oldestTime > iter.current->LastAccessed()) {
-          aData.oldestTime = iter.current->LastAccessed();
-          aData.iter = iter;
-        }
-      }
-    }
-
-    currentDot = nextDot;
-    if (currentDot)
-      nextDot = strchr(currentDot + 1, '.');
-
-  } while (currentDot);
-
-  return countFromHost;
-}
-
-// count the number of cookies stored by a particular host. this is provided by the
-// nsICookieManager2 interface.
-NS_IMETHODIMP
-nsCookieService::CountCookiesFromHost(const nsACString &aHost,
-                                      PRUint32         *aCountFromHost)
-{
-  // we don't care about finding the oldest cookie here, so disable the search
-  nsEnumerationData data(NOW_IN_SECONDS, LL_MININT);
-  
-  *aCountFromHost = CountCookiesFromHostInternal(aHost, data);
-  return NS_OK;
-}
-
-// find an exact previous match.
-PRBool
-nsCookieService::FindCookie(const nsAFlatCString &aHost,
-                            const nsAFlatCString &aName,
-                            const nsAFlatCString &aPath,
-                            nsListIter           &aIter)
-{
-  nsCookieEntry *entry = mHostTable.GetEntry(aHost.get());
-  for (aIter = nsListIter(entry); aIter.current; ++aIter) {
-    if (aPath.Equals(aIter.current->Path()) &&
-        aName.Equals(aIter.current->Name())) {
-      return PR_TRUE;
-    }
-  }
-
-  return PR_FALSE;
-}
-
-// removes a cookie from the hashtable, and update the iterator state.
-void
-nsCookieService::RemoveCookieFromList(nsListIter &aIter)
-{
-  if (!aIter.prev && !aIter.current->Next()) {
-    // we're removing the last element in the list - so just remove the entry
-    // from the hash. note that the entryclass' dtor will take care of
-    // releasing this last element for us!
-    mHostTable.RawRemoveEntry(aIter.entry);
-    aIter.current = nsnull;
-
-  } else {
-    // just remove the element from the list, and increment the iterator
-    nsCookie *next = aIter.current->Next();
-    NS_RELEASE(aIter.current);
-    if (aIter.prev) {
-      // element to remove is not the head
-      aIter.current = aIter.prev->Next() = next;
-    } else {
-      // element to remove is the head
-      aIter.current = aIter.entry->Head() = next;
-    }
-  }
-
-  --mCookieCount;
-  mCookieChanged = PR_TRUE;
-}
-
-PRBool
-nsCookieService::AddCookieToList(nsCookie *aCookie)
-{
-  nsCookieEntry *entry = mHostTable.PutEntry(aCookie->Host().get());
-
-  if (!entry) {
-    NS_ERROR("can't insert element into a null entry!");
-    return PR_FALSE;
-  }
-
-  NS_ADDREF(aCookie);
-
-  aCookie->Next() = entry->Head();
-  entry->Head() = aCookie;
-  ++mCookieCount;
-  mCookieChanged = PR_TRUE;
-
-  return PR_TRUE;
-}
-
-PR_STATIC_CALLBACK(PLDHashOperator)
-findOldestCallback(nsCookieEntry *aEntry,
-                   void          *aArg)
-{
-  nsEnumerationData *data = NS_STATIC_CAST(nsEnumerationData*, aArg);
-  for (nsListIter iter(aEntry, nsnull, aEntry->Head()); iter.current; ++iter) {
-    // check if we've found the oldest cookie so far
-    if (data->oldestTime > iter.current->LastAccessed()) {
-      data->oldestTime = iter.current->LastAccessed();
-      data->iter = iter;
-    }
-  }
-  return PL_DHASH_NEXT;
-}
-
+// notify observers that a cookie was rejected due to the users' prefs.
 void
-nsCookieService::FindOldestCookie(nsEnumerationData &aData)
+nsCookieService::NotifyRejected(nsIURI *aHostURI, const PRUnichar *aData)
 {
-  mHostTable.EnumerateEntries(findOldestCallback, &aData);
+  if (mObserverService)
+    mObserverService->NotifyObservers(aHostURI, "cookie-rejected", aData);
 }
Index: netwerk/cookie/src/nsCookieService.h
===================================================================
RCS file: /cvsroot/mozilla/netwerk/cookie/src/nsCookieService.h,v
retrieving revision 1.25
diff -p -U 8 -r1.25 nsCookieService.h
--- netwerk/cookie/src/nsCookieService.h	5 May 2007 21:09:54 -0000	1.25
+++ netwerk/cookie/src/nsCookieService.h	14 May 2007 09:24:22 -0000
@@ -17,16 +17,17 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2003
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Daniel Witte (dwitte@stanford.edu)
  *   Michiel van Leeuwen (mvl@exedo.nl)
+ *   Loune Lam (lpgcritter at nasquan dot com)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -35,195 +36,93 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsCookieService_h__
 #define nsCookieService_h__
 
-#include "nsICookieServiceInternal.h"
 #include "nsICookieManager.h"
 #include "nsICookieManager2.h"
+#include "nsICookieContainer.h"
+#include "nsICookieService.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 
 #include "nsCookie.h"
 #include "nsString.h"
 #include "nsTHashtable.h"
+#include "nsInterfaceHashtable.h"
+#include "nsHashKeys.h"
 
 #include "nsInt64.h"
 
 struct nsCookieAttributes;
 struct nsListIter;
 struct nsEnumerationData;
 
-class nsAutoVoidArray;
-
 class nsIPrefBranch;
 class nsICookieConsent;
 class nsICookiePermission;
 class nsIPrefBranch;
 class nsIObserverService;
 class nsIURI;
 class nsIChannel;
-class nsITimer;
-class nsIFile;
-
-// hash entry class
-class nsCookieEntry : public PLDHashEntryHdr
-{
-  public:
-    // Hash methods
-    typedef const char* KeyType;
-    typedef const char* KeyTypePointer;
-
-    // do nothing with aHost - we require mHead to be set before we're live!
-    nsCookieEntry(KeyTypePointer aHost)
-     : mHead(nsnull)
-    {
-    }
-
-    nsCookieEntry(const nsCookieEntry& toCopy)
-    {
-      // if we end up here, things will break. nsTHashtable shouldn't
-      // allow this, since we set ALLOW_MEMMOVE to true.
-      NS_NOTREACHED("nsCookieEntry copy constructor is forbidden!");
-    }
-
-    ~nsCookieEntry()
-    {
-      // walk the linked list, and de-link everything by releasing & nulling.
-      // this allows the parent host entry to be deleted by the hashtable.
-      // note: we know mHead cannot be null here - we always set mHead to a
-      // valid nsCookie (if it were null, the hashtable wouldn't be able to find
-      // this entry, because the key string is provided by mHead).
-      nsCookie *current = mHead, *next;
-      do {
-        next = current->Next();
-        NS_RELEASE(current);
-      } while ((current = next));
-    }
-
-    KeyType GetKey() const
-    {
-      return HostPtr();
-    }
-
-    PRBool KeyEquals(KeyTypePointer aKey) const
-    {
-      return !strcmp(HostPtr(), aKey);
-    }
-
-    static KeyTypePointer KeyToPointer(KeyType aKey)
-    {
-      return aKey;
-    }
-
-    static PLDHashNumber HashKey(KeyTypePointer aKey)
-    {
-      // PL_DHashStringKey doesn't use the table parameter, so we can safely
-      // pass nsnull
-      return PL_DHashStringKey(nsnull, aKey);
-    }
-
-    enum { ALLOW_MEMMOVE = PR_TRUE };
-
-    // get methods
-    inline const nsDependentCString Host() const { return mHead->Host(); }
-
-    // linked list management helper
-    inline nsCookie*& Head() { return mHead; }
-
-    inline KeyTypePointer HostPtr() const
-    {
-      return mHead->Host().get();
-    }
-
-  private:
-    nsCookie *mHead;
-};
 
 /******************************************************************************
  * nsCookieService:
  * class declaration
  ******************************************************************************/
 
-class nsCookieService : public nsICookieServiceInternal
-                      , public nsICookieManager2
+class nsCookieService : public nsICookieService
                       , public nsIObserver
                       , public nsSupportsWeakReference
 {
   public:
     // nsISupports
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSICOOKIESERVICE
-    NS_DECL_NSICOOKIESERVICEINTERNAL
-    NS_DECL_NSICOOKIEMANAGER
-    NS_DECL_NSICOOKIEMANAGER2
 
     nsCookieService();
     virtual ~nsCookieService();
     static nsCookieService*       GetSingleton();
+    static NS_METHOD              GetDefaultContainer(nsISupports* aOuter, const nsIID& aIID, void* *aResult);
     nsresult                      Init();
 
   protected:
-    void                          PrefChanged(nsIPrefBranch *aPrefBranch);
-    nsresult                      Read();
-    nsresult                      Write();
-    void                          GetCookieList(nsIURI *aHostURI, nsIURI *aFirstURI, nsIChannel *aChannel, const nsACString *aName, PRBool isHttpBound, nsAutoVoidArray &aResult);
-    char*                         CookieStringFromArray(const nsAutoVoidArray& aCookieList, nsIURI *aHostURI);
-    PRBool                        SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, nsDependentCString &aCookieHeader, nsInt64 aServerTime, nsCookieStatus aStatus, nsCookiePolicy aPolicy);
-    void                          CheckAndAdd(nsIURI *aHostURI, nsIChannel *aChannel, nsCookieAttributes &aAttributes, nsCookieStatus aStatus, nsCookiePolicy aPolicy, const nsAFlatCString &aCookieHeader);
-    void                          AddInternal(nsCookie *aCookie, nsInt64 aCurrentTime, nsIURI *aHostURI, const char *aCookieHeader);
-    void                          RemoveCookieFromList(nsListIter &aIter);
-    PRBool                        AddCookieToList(nsCookie *aCookie);
+
+    char*                         CookieStringFromArray(nsIArray* aCookieList, nsIURI *aHostURI);
+    PRBool                        SetCookieInternal(nsICookieContainer *aContainer, nsIURI *aHostURI, nsIChannel *aChannel, nsDependentCString &aCookieHeader, nsInt64 aServerTime, nsCookieStatus aStatus, nsCookiePolicy aPolicy);
+    void                          CheckAndAdd(nsICookieContainer *aContainer, nsIURI *aHostURI, nsIChannel *aChannel, nsCookieAttributes &aAttributes, nsCookieStatus aStatus, nsCookiePolicy aPolicy, const nsAFlatCString &aCookieHeader);
     static PRBool                 GetTokenValue(nsASingleFragmentCString::const_char_iterator &aIter, nsASingleFragmentCString::const_char_iterator &aEndIter, nsDependentCSubstring &aTokenString, nsDependentCSubstring &aTokenValue, PRBool &aEqualsFound);
     static PRBool                 ParseAttributes(nsDependentCString &aCookieHeader, nsCookieAttributes &aCookie);
+    static PRBool                 GetExpiry(nsCookieAttributes &aCookie, nsInt64 aServerTime, nsInt64 aCurrentTime, nsCookieStatus aStatus);
+ 
     static PRBool                 IsIPAddress(const nsAFlatCString &aHost);
     static PRBool                 IsInDomain(const nsACString &aDomain, const nsACString &aHost, PRBool aIsDomain = PR_TRUE);
     static PRBool                 IsForeign(nsIURI *aHostURI, nsIURI *aFirstURI);
-    nsCookieStatus                CheckPrefs(nsIURI *aHostURI, nsIURI *aFirstURI, nsIChannel *aChannel, const char *aCookieHeader, nsCookiePolicy &aPolicy);
+    nsCookieStatus                CheckPrefs(nsICookiePermission *aPermissionService, nsIURI *aHostURI, nsIURI *aFirstURI, nsIChannel *aChannel, const char *aCookieHeader, nsCookiePolicy &aPolicy);
     static PRBool                 CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI);
     static PRBool                 CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
-    static PRBool                 GetExpiry(nsCookieAttributes &aCookie, nsInt64 aServerTime, nsInt64 aCurrentTime, nsCookieStatus aStatus);
-    void                          RemoveAllFromMemory();
-    void                          RemoveExpiredCookies(nsInt64 aCurrentTime);
-    PRBool                        FindCookie(const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter);
-    void                          FindOldestCookie(nsEnumerationData &aData);
-    PRUint32                      CountCookiesFromHostInternal(const nsACString &aHost, nsEnumerationData &aData);
-    void                          NotifyRejected(nsIURI *aHostURI);
-    void                          NotifyChanged(nsICookie2 *aCookie, const PRUnichar *aData);
-
-    // Use LazyWrite to save the cookies file on a timer. It will write
-    // the file only once if repeatedly hammered quickly.
-    void                          LazyWrite();
-    static void                   DoLazyWrite(nsITimer *aTimer, void *aClosure);
 
+    void                          NotifyRejected(nsIURI *aHostURI, const PRUnichar *aData);
   protected:
     // cached members
-    nsCOMPtr<nsIFile>             mCookieFile;
     nsCOMPtr<nsIObserverService>  mObserverService;
     nsCOMPtr<nsICookieConsent>    mP3PService;
     nsCOMPtr<nsICookiePermission> mPermissionService;
 
     // impl members
-    nsCOMPtr<nsITimer>            mWriteTimer;
-    nsTHashtable<nsCookieEntry>   mHostTable;
-    PRUint32                      mCookieCount;
-    PRPackedBool                  mCookieChanged;
+    nsInterfaceHashtable<nsCharPtrHashKey, nsICookieContainer> mContainerTable;
     PRPackedBool                  mCookieIconVisible;
+	nsCString                     mDefaultContainerId;
 
     // cached prefs
     PRUint8                       mCookiesPermissions;   // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT, P3P}
-    PRUint16                      mMaxNumberOfCookies;
-    PRUint16                      mMaxCookiesPerHost;
 
     // private static member, used to cache a ptr to nsCookieService,
     // so we can make nsCookieService a singleton xpcom object.
     static nsCookieService        *gCookieService;
-
-    // this callback needs access to member functions
-    friend PLDHashOperator PR_CALLBACK removeExpiredCallback(nsCookieEntry *aEntry, void *aArg);
 };
 
 #endif // nsCookieService_h__
Index: netwerk/protocol/http/src/nsHttpChannel.cpp
===================================================================
RCS file: /cvsroot/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp,v
retrieving revision 1.308
diff -p -U 8 -r1.308 nsHttpChannel.cpp
--- netwerk/protocol/http/src/nsHttpChannel.cpp	13 May 2007 17:09:51 -0000	1.308
+++ netwerk/protocol/http/src/nsHttpChannel.cpp	14 May 2007 09:24:36 -0000
@@ -115,16 +115,17 @@ nsHttpChannel::nsHttpChannel()
     , mCanceled(PR_FALSE)
     , mTransactionReplaced(PR_FALSE)
     , mUploadStreamHasHeaders(PR_FALSE)
     , mAuthRetryPending(PR_FALSE)
     , mSuppressDefensiveAuth(PR_FALSE)
     , mResuming(PR_FALSE)
     , mInitedCacheEntry(PR_FALSE)
     , mCacheForOfflineUse(PR_FALSE)
+    , mCookieContainer(nsnull)
 {
     LOG(("Creating nsHttpChannel @%x\n", this));
 
     // grab a reference to the handler to ensure that it doesn't go away.
     nsHttpHandler *handler = gHttpHandler;
     NS_ADDREF(handler);
 }
 
@@ -224,16 +225,22 @@ nsHttpChannel::Init(nsIURI *uri,
     rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
     if (NS_FAILED(rv)) return rv;
 
     rv = gHttpHandler->
         AddStandardRequestHeaders(&mRequestHead.Headers(), caps,
                                   !mConnectionInfo->UsingSSL() &&
                                   mConnectionInfo->UsingHttpProxy());
 
+    // set to the default cookie container
+    nsICookieService *cs = gHttpHandler->GetCookieService();
+    nsCOMPtr<nsICookieContainer> container;
+    cs->GetDefaultContainer(getter_AddRefs(container));
+    SetCookieContainer(container);
+
     return rv;
 }
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel <private>
 //-----------------------------------------------------------------------------
 
 nsresult
@@ -583,17 +590,18 @@ nsHttpChannel::SetupTransaction()
 
 void
 nsHttpChannel::AddCookiesToRequest()
 {
     nsXPIDLCString cookie;
 
     nsICookieService *cs = gHttpHandler->GetCookieService();
     if (cs)
-        cs->GetCookieStringFromHttp(mURI,
+        cs->GetCookieStringFromHttp(mCookieContainer,
+                                    mURI,
                                     mDocumentURI ? mDocumentURI : mOriginalURI,
                                     this,
                                     getter_Copies(cookie));
     if (cookie.IsEmpty())
         cookie = mUserSetCookieHeader;
     else if (!mUserSetCookieHeader.IsEmpty())
         cookie.Append(NS_LITERAL_CSTRING("; ") + mUserSetCookieHeader);
 
@@ -2118,16 +2126,22 @@ nsHttpChannel::SetupReplacementChannel(n
     if (mConnectionInfo->UsingSSL())
         newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
 
     newChannel->SetOriginalURI(mOriginalURI);
     newChannel->SetLoadGroup(mLoadGroup); 
     newChannel->SetNotificationCallbacks(mCallbacks);
     newChannel->SetLoadFlags(newLoadFlags);
 
+    // set the new channel cookie container to that of this channel
+    nsCOMPtr<nsICookieCollector> cookieCollector(do_QueryInterface(newChannel));
+    if (cookieCollector) {
+        cookieCollector->SetCookieContainer(mCookieContainer);
+    }
+
     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
     if (!httpChannel)
         return NS_OK; // no other options to set
 
     if (preserveMethod) {
         nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(httpChannel);
         if (mUploadStream && uploadChannel) {
             // rewind upload stream
@@ -3228,16 +3242,17 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
     NS_INTERFACE_MAP_ENTRY(nsICacheListener)
     NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
     NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
     NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
     NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
     NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
     NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyCallback)
     NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
+    NS_INTERFACE_MAP_ENTRY(nsICookieCollector)
 NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsIRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::GetName(nsACString &aName)
@@ -4061,17 +4076,18 @@ nsHttpChannel::SetCookie(const char *aCo
         return NS_OK;
 
     nsICookieService *cs = gHttpHandler->GetCookieService();
     NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE);
 
     nsCOMPtr<nsIPrompt> prompt;
     GetCallback(prompt);
 
-    return cs->SetCookieStringFromHttp(mURI,
+    return cs->SetCookieStringFromHttp(mCookieContainer,
+                                       mURI,
                                        mDocumentURI ? mDocumentURI : mOriginalURI,
                                        prompt,
                                        aCookieHeader,
                                        mResponseHead->PeekHeader(nsHttp::Date),
                                        this);
 }
 
 //-----------------------------------------------------------------------------
@@ -4842,8 +4858,29 @@ nsHttpChannel::nsContentEncodings::Prepa
                                              nsCaseInsensitiveCStringComparator())) {
         mCurEnd = mCurStart;
         return PrepareForNext();
     }
         
     mReady = PR_TRUE;
     return NS_OK;
 }
+
+
+//-----------------------------------------------------------------------------
+// nsHttpChannel::nsICookieCollector
+//-----------------------------------------------------------------------------
+/* attribute nsICookieContainer cookieContainer; */
+NS_IMETHODIMP
+nsHttpChannel::GetCookieContainer(nsICookieContainer * *aCookieContainer)
+{
+    NS_ENSURE_ARG_POINTER(aCookieContainer);
+	*aCookieContainer = mCookieContainer;
+    NS_IF_ADDREF(*aCookieContainer);
+    return NS_OK;
+}
+NS_IMETHODIMP
+nsHttpChannel::SetCookieContainer(nsICookieContainer * aCookieContainer)
+{
+    mCookieContainer = aCookieContainer;
+    return NS_OK;
+}
+
Index: netwerk/protocol/http/src/nsHttpChannel.h
===================================================================
RCS file: /cvsroot/mozilla/netwerk/protocol/http/src/nsHttpChannel.h,v
retrieving revision 1.89
diff -p -U 8 -r1.89 nsHttpChannel.h
--- netwerk/protocol/http/src/nsHttpChannel.h	23 Mar 2007 21:56:32 -0000	1.89
+++ netwerk/protocol/http/src/nsHttpChannel.h	14 May 2007 09:24:37 -0000
@@ -75,16 +75,18 @@
 #include "nsIOutputStream.h"
 #include "nsIAsyncInputStream.h"
 #include "nsIPrompt.h"
 #include "nsIResumableChannel.h"
 #include "nsISupportsPriority.h"
 #include "nsIProtocolProxyCallback.h"
 #include "nsICancelable.h"
 #include "nsIProxiedChannel.h"
+#include "nsICookieCollector.h"
+#include "nsICookieContainer.h"
 
 class nsHttpResponseHead;
 class nsAHttpConnection;
 class nsIHttpAuthenticator;
 class nsProxyInfo;
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel
@@ -98,16 +100,17 @@ class nsHttpChannel : public nsHashPrope
                     , public nsIUploadChannel
                     , public nsICacheListener
                     , public nsIEncodedChannel
                     , public nsITransportEventSink
                     , public nsIResumableChannel
                     , public nsISupportsPriority
                     , public nsIProtocolProxyCallback
                     , public nsIProxiedChannel
+                    , public nsICookieCollector
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIREQUEST
     NS_DECL_NSICHANNEL
     NS_DECL_NSIHTTPCHANNEL
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
@@ -116,16 +119,17 @@ public:
     NS_DECL_NSICACHELISTENER
     NS_DECL_NSIENCODEDCHANNEL
     NS_DECL_NSIHTTPCHANNELINTERNAL
     NS_DECL_NSITRANSPORTEVENTSINK
     NS_DECL_NSIRESUMABLECHANNEL
     NS_DECL_NSISUPPORTSPRIORITY
     NS_DECL_NSIPROTOCOLPROXYCALLBACK
     NS_DECL_NSIPROXIEDCHANNEL
+    NS_DECL_NSICOOKIECOLLECTOR
 
     nsHttpChannel();
     virtual ~nsHttpChannel();
 
     nsresult Init(nsIURI *uri,
                   PRUint8 capabilities,
                   nsProxyInfo* proxyInfo);
 
@@ -221,16 +225,18 @@ private:
     nsCOMPtr<nsISupports>             mOwner;
     nsCOMPtr<nsIInterfaceRequestor>   mCallbacks;
     nsCOMPtr<nsIProgressEventSink>    mProgressSink;
     nsCOMPtr<nsIInputStream>          mUploadStream;
     nsCOMPtr<nsIURI>                  mReferrer;
     nsCOMPtr<nsISupports>             mSecurityInfo;
     nsCOMPtr<nsICancelable>           mProxyRequest;
 
+    nsCOMPtr<nsICookieContainer>      mCookieContainer;
+
     nsHttpRequestHead                 mRequestHead;
     nsHttpResponseHead               *mResponseHead;
 
     nsRefPtr<nsInputStreamPump>       mTransactionPump;
     nsHttpTransaction                *mTransaction;     // hard ref
     nsHttpConnectionInfo             *mConnectionInfo;  // hard ref
 
     nsCString                         mSpec; // ASCII encoded URL spec
Index: toolkit/content/widgets/tabbrowser.xml
===================================================================
RCS file: /cvsroot/mozilla/toolkit/content/widgets/tabbrowser.xml,v
retrieving revision 1.228
diff -p -U 8 -r1.228 tabbrowser.xml
--- toolkit/content/widgets/tabbrowser.xml	2 May 2007 20:09:02 -0000	1.228
+++ toolkit/content/widgets/tabbrowser.xml	14 May 2007 09:25:09 -0000
@@ -1051,23 +1051,24 @@
 
       <method name="loadOneTab">
         <parameter name="aURI"/>
         <parameter name="aReferrerURI"/>
         <parameter name="aCharset"/>
         <parameter name="aPostData"/>
         <parameter name="aLoadInBackground"/>
         <parameter name="aAllowThirdPartyFixup"/>
+        <parameter name="aInheritOptions"/>
         <body>
           <![CDATA[
             var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
                          this.mPrefs.getBoolPref("browser.tabs.loadInBackground");
             var owner = bgLoad ? null : this.selectedTab;
             var tab = this.addTab(aURI, aReferrerURI, aCharset, aPostData, owner,
-                                  aAllowThirdPartyFixup);
+                                  aAllowThirdPartyFixup, aInheritOptions);
             // Set newly selected tab after quick timeout, otherwise hideous focus problems
             // can occur when "browser.tabs.loadInBackground" is false and presshell is not ready
             if (!bgLoad) {
               function selectNewForegroundTab(browser, tab) {
                 browser.selectedTab = tab;
               }
               setTimeout(selectNewForegroundTab, 0, getBrowser(), tab);
             }
@@ -1122,16 +1123,17 @@
 
       <method name="addTab">
         <parameter name="aURI"/>
         <parameter name="aReferrerURI"/>
         <parameter name="aCharset"/>
         <parameter name="aPostData"/>
         <parameter name="aOwner"/>
         <parameter name="aAllowThirdPartyFixup"/>
+        <parameter name="aInheritOptions"/>
         <body>
           <![CDATA[
             this._browsers = null; // invalidate cache
 
             if (!this.mTabbedMode)
               this.enterTabbedMode();
 
             // if we're adding tabs, we're past interrupt mode, ditch the owner
@@ -1232,16 +1234,22 @@
             var uniqueId = "panel" + Date.now() + position;
             this.mPanelContainer.lastChild.id = uniqueId;
             t.linkedPanel = uniqueId;
             t.linkedBrowser = b;
             t._tPos = position;
             if (t.previousSibling.selected)
               t.setAttribute("afterselected", true);
 
+            // inherit the cookie container
+            if (aInheritOptions && aInheritOptions["cookieContainer"]) {
+              b.docShell.QueryInterface(Components.interfaces.nsICookieCollector);
+              b.docShell.cookieContainer = aInheritOptions["cookieContainer"];
+            }
+
             if (!blank) {
               // Stop the existing about:blank load.  Otherwise, if aURI
               // doesn't stop in-progress loads on its own, we'll get into
               // trouble with multiple parallel loads running at once.
               b.stop();
 
               // pretend the user typed this so it'll be available till
               // the document successfully loads
