Bug 537156 - [e10s] Implement cookies. r=jduell,sdwilsh; sr=bz
authorDan Witte <dwitte@mozilla.com>
Thu, 25 Mar 2010 16:02:28 -0700
changeset 46770 9f69e891fb0893080450325f94d4f5a9cc6a296d
parent 46769 437ca4f9a036d2677eb53da17f5c69bd21f171e1
child 46771 cd86e0ea3d2d549a5a7a7c3ca066e4b4fd39a3ea
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell, sdwilsh, bz
bugs537156
milestone1.9.3a4pre
Bug 537156 - [e10s] Implement cookies. r=jduell,sdwilsh; sr=bz
extensions/cookie/nsCookieModule.cpp
extensions/cookie/nsCookiePermission.cpp
extensions/cookie/nsCookiePermission.h
ipc/ipdl/Makefile.in
netwerk/build/nsNetModule.cpp
netwerk/cookie/src/CookieServiceChild.cpp
netwerk/cookie/src/CookieServiceChild.h
netwerk/cookie/src/CookieServiceParent.cpp
netwerk/cookie/src/CookieServiceParent.h
netwerk/cookie/src/Makefile.in
netwerk/cookie/src/PCookieService.ipdl
netwerk/cookie/src/ipdl.mk
netwerk/cookie/src/nsCookieService.cpp
netwerk/cookie/src/nsCookieService.h
netwerk/cookie/test/unit_ipc/head_ipc_setup.js
netwerk/cookie/test/unit_ipc/test_ipc_parser_0001.js
netwerk/cookie/test/unit_ipc/test_ipc_parser_0019.js
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PNecko.ipdl
--- a/extensions/cookie/nsCookieModule.cpp
+++ b/extensions/cookie/nsCookieModule.cpp
@@ -44,17 +44,17 @@
 #include "nsICategoryManager.h"
 #include "nsCookiePromptService.h"
 #include "nsCookiePermission.h"
 #include "nsXPIDLString.h"
 
 // Define the constructor function for the objects
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPermissionManager, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPopupWindowManager, Init)
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCookiePermission, Init)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsCookiePermission)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCookiePromptService)
 
 // The list of components we register
 static const nsModuleComponentInfo components[] = {
     { "PermissionManager",
       NS_PERMISSIONMANAGER_CID,
       NS_PERMISSIONMANAGER_CONTRACTID,
       nsPermissionManagerConstructor
--- a/extensions/cookie/nsCookiePermission.cpp
+++ b/extensions/cookie/nsCookiePermission.cpp
@@ -106,22 +106,25 @@ IsFromMailNews(nsIURI *aURI)
   return PR_FALSE;
 }
 #endif
 
 NS_IMPL_ISUPPORTS2(nsCookiePermission,
                    nsICookiePermission,
                    nsIObserver)
 
-nsresult
+bool
 nsCookiePermission::Init()
 {
+  // Initialize nsIPermissionManager and fetch relevant prefs. This is only
+  // required for some methods on nsICookiePermission, so it should be done
+  // lazily.
   nsresult rv;
   mPermMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
-  if (NS_FAILED(rv)) return rv;
+  if (NS_FAILED(rv)) return false;
 
   // failure to access the pref service is non-fatal...
   nsCOMPtr<nsIPrefBranch2> prefBranch =
       do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefBranch) {
     prefBranch->AddObserver(kCookiesLifetimePolicy, this, PR_FALSE);
     prefBranch->AddObserver(kCookiesLifetimeDays, this, PR_FALSE);
     prefBranch->AddObserver(kCookiesAlwaysAcceptSession, this, PR_FALSE);
@@ -150,17 +153,17 @@ nsCookiePermission::Init()
           prefBranch->SetIntPref(kCookiesLifetimePolicy, ACCEPT_FOR_N_DAYS);
         else
           prefBranch->SetIntPref(kCookiesLifetimePolicy, ACCEPT_SESSION);
       }
       prefBranch->SetBoolPref(kCookiesPrefsMigrated, PR_TRUE);
     }
   }
 
-  return NS_OK;
+  return true;
 }
 
 void
 nsCookiePermission::PrefChanged(nsIPrefBranch *aPrefBranch,
                                 const char    *aPref)
 {
   PRInt32 val;
 
@@ -179,16 +182,20 @@ nsCookiePermission::PrefChanged(nsIPrefB
       NS_SUCCEEDED(aPrefBranch->GetBoolPref(kCookiesAlwaysAcceptSession, &val)))
     mCookiesAlwaysAcceptSession = val;
 }
 
 NS_IMETHODIMP
 nsCookiePermission::SetAccess(nsIURI         *aURI,
                               nsCookieAccess  aAccess)
 {
+  // Lazily initialize ourselves
+  if (!EnsureInitialized())
+    return NS_ERROR_UNEXPECTED;
+
   //
   // NOTE: nsCookieAccess values conveniently match up with
   //       the permission codes used by nsIPermissionManager.
   //       this is nice because it avoids conversion code.
   //
   return mPermMgr->Add(aURI, kPermissionType, aAccess,
                        nsIPermissionManager::EXPIRE_NEVER, 0);
 }
@@ -201,17 +208,21 @@ nsCookiePermission::CanAccess(nsIURI    
 #ifdef MOZ_MAIL_NEWS
   // If this URI is a mailnews one (e.g. imap etc), don't allow cookies for
   // it.
   if (IsFromMailNews(aURI)) {
     *aResult = ACCESS_DENY;
     return NS_OK;
   }
 #endif // MOZ_MAIL_NEWS
-  
+
+  // Lazily initialize ourselves
+  if (!EnsureInitialized())
+    return NS_ERROR_UNEXPECTED;
+
   // finally, check with permission manager...
   nsresult rv = mPermMgr->TestPermission(aURI, kPermissionType, (PRUint32 *) aResult);
   if (NS_SUCCEEDED(rv)) {
     switch (*aResult) {
     // if we have one of the publicly-available values, just return it
     case nsIPermissionManager::UNKNOWN_ACTION: // ACCESS_DEFAULT
     case nsIPermissionManager::ALLOW_ACTION:   // ACCESS_ALLOW
     case nsIPermissionManager::DENY_ACTION:    // ACCESS_DENY
@@ -239,16 +250,20 @@ nsCookiePermission::CanSetCookie(nsIURI 
                                  PRBool     *aIsSession,
                                  PRInt64    *aExpiry,
                                  PRBool     *aResult)
 {
   NS_ASSERTION(aURI, "null uri");
 
   *aResult = kDefaultPolicy;
 
+  // Lazily initialize ourselves
+  if (!EnsureInitialized())
+    return NS_ERROR_UNEXPECTED;
+
   PRUint32 perm;
   mPermMgr->TestPermission(aURI, kPermissionType, &perm);
   switch (perm) {
   case nsICookiePermission::ACCESS_SESSION:
     *aIsSession = PR_TRUE;
 
   case nsIPermissionManager::ALLOW_ACTION: // ACCESS_ALLOW
     *aResult = PR_TRUE;
@@ -502,17 +517,17 @@ nsCookiePermission::Observe(nsISupports 
   NS_ASSERTION(!nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic),
                "unexpected topic - we only deal with pref changes!");
 
   if (prefBranch)
     PrefChanged(prefBranch, NS_LossyConvertUTF16toASCII(aData).get());
   return NS_OK;
 }
 
-PRBool
+bool
 nsCookiePermission::InPrivateBrowsing()
 {
   PRBool inPrivateBrowsingMode = PR_FALSE;
   if (!mPBService)
     mPBService = do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
   if (mPBService)
     mPBService->GetPrivateBrowsingEnabled(&inPrivateBrowsingMode);
   return inPrivateBrowsingMode;
--- a/extensions/cookie/nsCookiePermission.h
+++ b/extensions/cookie/nsCookiePermission.h
@@ -57,21 +57,22 @@ public:
 
   nsCookiePermission() 
     : mCookiesLifetimeSec(LL_MAXINT)
     , mCookiesLifetimePolicy(0) // ACCEPT_NORMALLY
     , mCookiesAlwaysAcceptSession(PR_FALSE)
     {}
   virtual ~nsCookiePermission() {}
 
-  nsresult Init();
-  void     PrefChanged(nsIPrefBranch *, const char *);
+  bool Init();
+  void PrefChanged(nsIPrefBranch *, const char *);
 
 private:
-  PRBool InPrivateBrowsing();
+  bool EnsureInitialized() { return mPermMgr != NULL || Init(); };
+  bool InPrivateBrowsing();
 
   nsCOMPtr<nsIPermissionManager> mPermMgr;
   nsCOMPtr<nsIPrivateBrowsingService> mPBService;
 
   PRInt64      mCookiesLifetimeSec;            // lifetime limit specified in seconds
   PRUint8      mCookiesLifetimePolicy;         // pref for how long cookies are stored
   PRPackedBool mCookiesAlwaysAcceptSession;    // don't prompt for session cookies
 };
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -53,16 +53,17 @@ EXPORT_LIBRARY = 1
 ##-----------------------------------------------------------------------------
 ## When you add IPDL files to a source directory, list the directory here.
 ##
 IPDLDIRS =  \
   dom/plugins  \
   dom/ipc  \
   netwerk/ipc  \
   netwerk/protocol/http/src  \
+  netwerk/cookie/src  \
   ipc/ipdl/test/cxx  \
   ipc/testshell  \
   js/src/ipc  \
   $(NULL)
 ##-----------------------------------------------------------------------------
 
 ifdef MOZ_IPDL_TESTS
 DIRS += test
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -170,20 +170,20 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDirInde
 
 #include "nsStreamListenerTee.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsStreamListenerTee)
 
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifdef NECKO_COOKIES
 #include "nsCookieService.h"
-NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsCookieService, nsCookieService::GetSingleton)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsICookieService,
+  nsCookieService::GetXPCOMSingleton)
 #endif
 
-
 ///////////////////////////////////////////////////////////////////////////////
 #ifdef NECKO_WIFI
 
 #include "nsWifiMonitor.h"
 #undef LOG
 #undef LOG_ENABLED
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWifiMonitor)
 
@@ -1106,23 +1106,23 @@ static const nsModuleComponentInfo gNetM
        nsApplicationCacheNamespaceConstructor
     },
 #endif
 
 #ifdef NECKO_COOKIES
     { NS_COOKIEMANAGER_CLASSNAME,
       NS_COOKIEMANAGER_CID,
       NS_COOKIEMANAGER_CONTRACTID,
-      nsCookieServiceConstructor
+      nsICookieServiceConstructor
     },
 
     { NS_COOKIESERVICE_CLASSNAME,
       NS_COOKIESERVICE_CID,
       NS_COOKIESERVICE_CONTRACTID,
-      nsCookieServiceConstructor
+      nsICookieServiceConstructor
     },
 #endif
 
 #ifdef NECKO_WIFI
     {
       NS_WIFI_MONITOR_CLASSNAME,
       NS_WIFI_MONITOR_COMPONENT_CID,
       NS_WIFI_MONITOR_CONTRACTID,
new file mode 100644
--- /dev/null
+++ b/netwerk/cookie/src/CookieServiceChild.cpp
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 2; 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
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Witte <dwitte@mozilla.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 "mozilla/net/CookieServiceChild.h"
+#include "mozilla/net/NeckoChild.h"
+#include "nsIURI.h"
+
+namespace mozilla {
+namespace net {
+
+static CookieServiceChild *gCookieService;
+
+CookieServiceChild*
+CookieServiceChild::GetSingleton()
+{
+  if (!gCookieService)
+    gCookieService = new CookieServiceChild();
+
+  NS_ADDREF(gCookieService);
+  return gCookieService;
+}
+
+NS_IMPL_ISUPPORTS1(CookieServiceChild, nsICookieService)
+
+CookieServiceChild::CookieServiceChild()
+{
+  NS_ASSERTION(IsNeckoChild(), "not a child process");
+
+  // This corresponds to Release() in DeallocPCookieService.
+  NS_ADDREF_THIS();
+
+  // Create a child PCookieService actor.
+  NeckoChild::InitNeckoChild();
+  gNeckoChild->SendPCookieServiceConstructor(this);
+
+  mPermissionService = do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
+  if (!mPermissionService)
+    NS_WARNING("couldn't get nsICookiePermission in child");
+}
+
+CookieServiceChild::~CookieServiceChild()
+{
+  gCookieService = nsnull;
+}
+
+void
+CookieServiceChild::SerializeURIs(nsIURI *aHostURI,
+                                  nsIChannel *aChannel,
+                                  nsCString &aHostSpec,
+                                  nsCString &aHostCharset,
+                                  nsCString &aOriginatingSpec,
+                                  nsCString &aOriginatingCharset)
+{
+  // Serialize the host URI.
+  // TODO: The cookieservice deals exclusively with ASCII hosts, but not paths.
+  // We should fix that, and then we can just serialize the spec as ASCII here.
+  aHostURI->GetSpec(aHostSpec);
+  aHostURI->GetOriginCharset(aHostCharset);
+
+  // Determine and serialize the originating URI. Failure is acceptable.
+  if (!mPermissionService) {
+    NS_WARNING("nsICookiePermission unavailable! Cookie may be rejected");
+    return;
+  }
+
+  nsCOMPtr<nsIURI> originatingURI;
+  mPermissionService->GetOriginatingURI(aChannel,
+                                        getter_AddRefs(originatingURI));
+  if (originatingURI) {
+    originatingURI->GetSpec(aOriginatingSpec);
+    originatingURI->GetOriginCharset(aOriginatingSpec);
+  }
+}
+
+nsresult
+CookieServiceChild::GetCookieStringInternal(nsIURI *aHostURI,
+                                            nsIChannel *aChannel,
+                                            char **aCookieString,
+                                            bool aFromHttp)
+{
+  NS_ENSURE_ARG(aHostURI);
+  NS_ENSURE_ARG_POINTER(aCookieString);
+
+  *aCookieString = NULL;
+
+  nsCAutoString hostSpec, hostCharset, originatingSpec, originatingCharset;
+  SerializeURIs(aHostURI, aChannel, hostSpec, hostCharset,
+                originatingSpec, originatingCharset);
+
+  // Synchronously call the parent.
+  nsCAutoString result;
+  SendGetCookieString(hostSpec, hostCharset,
+                      originatingSpec, originatingCharset,
+                      aFromHttp, &result);
+  if (!result.IsEmpty())
+    *aCookieString = ToNewCString(result);
+
+  return NS_OK;
+}
+
+nsresult
+CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
+                                            nsIChannel *aChannel,
+                                            const char *aCookieString,
+                                            const char *aServerTime,
+                                            bool aFromHttp)
+{
+  NS_ENSURE_ARG(aHostURI);
+  NS_ENSURE_ARG_POINTER(aCookieString);
+
+  nsCAutoString hostSpec, hostCharset, originatingSpec, originatingCharset;
+  SerializeURIs(aHostURI, aChannel, hostSpec, hostCharset,
+                originatingSpec, originatingCharset);
+
+  nsDependentCString cookieString(aCookieString);
+  nsDependentCString serverTime;
+  if (aServerTime)
+    serverTime.Rebind(aServerTime);
+
+  // Synchronously call the parent.
+  SendSetCookieString(hostSpec, hostCharset,
+                      originatingSpec, originatingCharset,
+                      cookieString, serverTime, aFromHttp);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+CookieServiceChild::GetCookieString(nsIURI *aHostURI,
+                                    nsIChannel *aChannel,
+                                    char **aCookieString)
+{
+  return GetCookieStringInternal(aHostURI, aChannel, aCookieString, false);
+}
+
+NS_IMETHODIMP
+CookieServiceChild::GetCookieStringFromHttp(nsIURI *aHostURI,
+                                            nsIURI *aFirstURI,
+                                            nsIChannel *aChannel,
+                                            char **aCookieString)
+{
+  return GetCookieStringInternal(aHostURI, aChannel, aCookieString, true);
+}
+
+NS_IMETHODIMP
+CookieServiceChild::SetCookieString(nsIURI *aHostURI,
+                                    nsIPrompt *aPrompt,
+                                    const char *aCookieString,
+                                    nsIChannel *aChannel)
+{
+  return SetCookieStringInternal(aHostURI, aChannel, aCookieString,
+                                 nsnull, false);
+}
+
+NS_IMETHODIMP
+CookieServiceChild::SetCookieStringFromHttp(nsIURI     *aHostURI,
+                                            nsIURI     *aFirstURI,
+                                            nsIPrompt  *aPrompt,
+                                            const char *aCookieString,
+                                            const char *aServerTime,
+                                            nsIChannel *aChannel) 
+{
+  return SetCookieStringInternal(aHostURI, aChannel, aCookieString,
+                                 aServerTime, true);
+}
+
+}
+}
+
new file mode 100644
--- /dev/null
+++ b/netwerk/cookie/src/CookieServiceChild.h
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 2; 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
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Witte <dwitte@mozilla.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 mozilla_net_CookieServiceChild_h__
+#define mozilla_net_CookieServiceChild_h__
+
+#include "mozilla/net/PCookieServiceChild.h"
+#include "nsICookieService.h"
+#include "nsICookiePermission.h"
+
+namespace mozilla {
+namespace net {
+
+class CookieServiceChild : public PCookieServiceChild
+                         , public nsICookieService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSICOOKIESERVICE
+
+  CookieServiceChild();
+  virtual ~CookieServiceChild();
+
+  static CookieServiceChild* GetSingleton();
+
+protected:
+  void SerializeURIs(nsIURI *aHostURI,
+                     nsIChannel *aChannel,
+                     nsCString &aHostSpec,
+                     nsCString &aHostCharset,
+                     nsCString &aOriginatingSpec,
+                     nsCString &aOriginatingCharset);
+
+  nsresult GetCookieStringInternal(nsIURI *aHostURI,
+                                   nsIChannel *aChannel,
+                                   char **aCookieString,
+                                   bool aFromHttp);
+
+  nsresult SetCookieStringInternal(nsIURI *aHostURI,
+                                   nsIChannel *aChannel,
+                                   const char *aCookieString,
+                                   const char *aServerTime,
+                                   bool aFromHttp);
+
+  nsCOMPtr<nsICookiePermission> mPermissionService;
+};
+
+}
+}
+
+#endif // mozilla_net_CookieServiceChild_h__
+
new file mode 100644
--- /dev/null
+++ b/netwerk/cookie/src/CookieServiceParent.cpp
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 2; 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
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Witte <dwitte@mozilla.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 "mozilla/net/CookieServiceParent.h"
+#include "nsCookieService.h"
+#include "nsNetUtil.h"
+
+namespace mozilla {
+namespace net {
+
+CookieServiceParent::CookieServiceParent()
+{
+  // Instantiate the cookieservice via the service manager, so it sticks around
+  // until shutdown.
+  nsCOMPtr<nsICookieService> cs = do_GetService(NS_COOKIESERVICE_CONTRACTID);
+
+  // Get the nsCookieService instance directly, so we can call internal methods.
+  mCookieService =
+    already_AddRefed<nsCookieService>(nsCookieService::GetSingleton());
+  NS_ASSERTION(mCookieService, "couldn't get nsICookieService");
+
+  mIOService = do_GetService(NS_IOSERVICE_CONTRACTID);
+  NS_ASSERTION(mIOService, "couldn't get nsIIOService");
+}
+
+CookieServiceParent::~CookieServiceParent()
+{
+}
+
+bool
+CookieServiceParent::RecvGetCookieString(const nsCString& aHostSpec,
+                                         const nsCString& aHostCharset,
+                                         const nsCString& aOriginatingSpec,
+                                         const nsCString& aOriginatingCharset,
+                                         const bool& aFromHttp,
+                                         nsCString* aResult)
+{
+  if (!mCookieService)
+    return true;
+
+  // Deserialize URIs. Having a host URI is mandatory and should always be
+  // provided by the child; thus we consider failure fatal.
+  nsCOMPtr<nsIURI> hostURI, originatingURI;
+  NS_NewURI(getter_AddRefs(hostURI),
+            aHostSpec, aHostCharset.get(),
+            nsnull, mIOService);
+  NS_NewURI(getter_AddRefs(originatingURI),
+            aOriginatingSpec, aOriginatingCharset.get(),
+            nsnull, mIOService);
+  if (!hostURI)
+    return false;
+
+  mCookieService->GetCookieInternal(hostURI, originatingURI,
+                                    aFromHttp, *aResult);
+  return true;
+}
+
+bool
+CookieServiceParent::RecvSetCookieString(const nsCString& aHostSpec,
+                                         const nsCString& aHostCharset,
+                                         const nsCString& aOriginatingSpec,
+                                         const nsCString& aOriginatingCharset,
+                                         const nsCString& aCookieString,
+                                         const nsCString& aServerTime,
+                                         const bool& aFromHttp)
+{
+  if (!mCookieService)
+    return true;
+
+  // Deserialize URIs. Having a host URI is mandatory and should always be
+  // provided by the child; thus we consider failure fatal.
+  nsCOMPtr<nsIURI> hostURI, originatingURI;
+  NS_NewURI(getter_AddRefs(hostURI),
+            aHostSpec, aHostCharset.get(),
+            nsnull, mIOService);
+  NS_NewURI(getter_AddRefs(originatingURI),
+            aOriginatingSpec, aOriginatingCharset.get(),
+            nsnull, mIOService);
+  if (!hostURI)
+    return false;
+
+  mCookieService->SetCookieStringInternal(hostURI, originatingURI,
+                                          aCookieString, aServerTime,
+                                          aFromHttp);
+  return true;
+}
+
+}
+}
+
new file mode 100644
--- /dev/null
+++ b/netwerk/cookie/src/CookieServiceParent.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 2; 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
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Witte <dwitte@mozilla.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 mozilla_net_CookieServiceParent_h
+#define mozilla_net_CookieServiceParent_h
+
+#include "mozilla/net/PCookieServiceParent.h"
+
+class nsCookieService;
+class nsIIOService;
+
+namespace mozilla {
+namespace net {
+
+class CookieServiceParent : public PCookieServiceParent
+{
+public:
+  CookieServiceParent();
+  virtual ~CookieServiceParent();
+
+protected:
+  virtual bool RecvGetCookieString(const nsCString& aHostSpec,
+                                   const nsCString& aHostCharset,
+                                   const nsCString& aOriginatingSpec,
+                                   const nsCString& aOriginatingCharset,
+                                   const bool& aFromHttp,
+                                   nsCString* aResult);
+
+  virtual bool RecvSetCookieString(const nsCString& aHostSpec,
+                                   const nsCString& aHostCharset,
+                                   const nsCString& aOriginatingSpec,
+                                   const nsCString& aOriginatingCharset,
+                                   const nsCString& aCookieString,
+                                   const nsCString& aServerTime,
+                                   const bool& aFromHttp);
+
+  nsRefPtr<nsCookieService> mCookieService;
+  nsCOMPtr<nsIIOService> mIOService;
+};
+
+}
+}
+
+#endif // mozilla_net_CookieServiceParent_h
+
--- a/netwerk/cookie/src/Makefile.in
+++ b/netwerk/cookie/src/Makefile.in
@@ -41,17 +41,32 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= necko
 LIBRARY_NAME	= neckocookie_s
 FORCE_STATIC_LIB	= 1
 LIBXUL_LIBRARY  = 1
 
-
 CPPSRCS		= \
 		nsCookie.cpp \
 		nsCookieService.cpp \
 		$(NULL)
 
+ifdef MOZ_IPC
+EXPORTS_NAMESPACES = mozilla/net
+
+EXPORTS_mozilla/net = \
+		CookieServiceParent.h \
+		CookieServiceChild.h  \
+		$(NULL)
+
+CPPSRCS += \
+		CookieServiceParent.cpp \
+		CookieServiceChild.cpp \
+		$(NULL)
+endif
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DIMPL_NS_NET
new file mode 100644
--- /dev/null
+++ b/netwerk/cookie/src/PCookieService.ipdl
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+
+/* ***** 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
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Witte <dwitte@mozilla.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 protocol "PNecko.ipdl";
+
+namespace mozilla {
+namespace net {
+
+sync protocol PCookieService
+{
+  manager PNecko;
+
+parent:
+  sync GetCookieString(nsCString hostSpec,
+                       nsCString hostCharset,
+                       nsCString originatingSpec,
+                       nsCString originatingCharset,
+                       bool fromHttp)
+       returns (nsCString result);
+
+  SetCookieString(nsCString hostSpec,
+                  nsCString hostCharset,
+                  nsCString originatingSpec,
+                  nsCString originatingCharset,
+                  nsCString cookieString,
+                  nsCString serverTime,
+                  bool fromHttp);
+
+  __delete__();
+};
+
+}
+}
+
new file mode 100644
--- /dev/null
+++ b/netwerk/cookie/src/ipdl.mk
@@ -0,0 +1,41 @@
+# ***** 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 Firefox.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Daniel Witte <dwitte@mozilla.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 *****
+
+IPDLSRCS =            \
+  PCookieService.ipdl \
+  $(NULL)
+
--- a/netwerk/cookie/src/nsCookieService.cpp
+++ b/netwerk/cookie/src/nsCookieService.cpp
@@ -34,16 +34,21 @@
  * 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 ***** */
 
+#ifdef MOZ_IPC
+#include "mozilla/net/CookieServiceChild.h"
+#include "mozilla/net/NeckoCommon.h"
+#endif
+
 #include "nsCookieService.h"
 #include "nsIServiceManager.h"
 
 #include "nsIIOService.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefBranch2.h"
 #include "nsIPrefService.h"
 #include "nsICookiePermission.h"
@@ -68,16 +73,18 @@
 #include "prprf.h"
 #include "nsNetUtil.h"
 #include "nsNetCID.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsIPrivateBrowsingService.h"
 #include "nsNetCID.h"
 #include "mozilla/storage.h"
 
+using namespace mozilla::net;
+
 /******************************************************************************
  * 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_";
@@ -462,21 +469,36 @@ static RemoveCookieDBListener sRemoveCoo
 
 } // anonymous namespace
 
 /******************************************************************************
  * nsCookieService impl:
  * singleton instance ctor/dtor methods
  ******************************************************************************/
 
-nsCookieService *nsCookieService::gCookieService = nsnull;
+static nsCookieService *gCookieService;
+
+nsICookieService*
+nsCookieService::GetXPCOMSingleton()
+{
+#ifdef MOZ_IPC
+  if (IsNeckoChild())
+    return CookieServiceChild::GetSingleton();
+#endif
+
+  return GetSingleton();
+}
 
 nsCookieService*
 nsCookieService::GetSingleton()
 {
+#ifdef MOZ_IPC
+  NS_ASSERTION(!IsNeckoChild(), "not a parent process");
+#endif
+
   if (gCookieService) {
     NS_ADDREF(gCookieService);
     return gCookieService;
   }
 
   // Create a new singleton nsCookieService.
   // We AddRef only once since XPCOM has rules about the ordering of module
   // teardowns - by the time our module destructor is called, it's too late to
@@ -881,133 +903,159 @@ nsCookieService::Observe(nsISupports    
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCookieService::GetCookieString(nsIURI     *aHostURI,
                                  nsIChannel *aChannel,
                                  char       **aCookie)
 {
-  GetCookieInternal(aHostURI, aChannel, PR_FALSE, aCookie);
-  
+  NS_ENSURE_ARG(aHostURI);
+  NS_ENSURE_ARG(aCookie);
+
+  nsCOMPtr<nsIURI> originatingURI;
+  GetOriginatingURI(aChannel, getter_AddRefs(originatingURI));
+
+  nsCAutoString result;
+  GetCookieInternal(aHostURI, originatingURI, PR_FALSE, result);
+  *aCookie = result.IsEmpty() ? nsnull : ToNewCString(result);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCookieService::GetCookieStringFromHttp(nsIURI     *aHostURI,
                                          nsIURI     *aFirstURI,
                                          nsIChannel *aChannel,
                                          char       **aCookie)
 {
-  GetCookieInternal(aHostURI, aChannel, PR_TRUE, aCookie);
-
+  NS_ENSURE_ARG(aHostURI);
+  NS_ENSURE_ARG(aCookie);
+
+  nsCOMPtr<nsIURI> originatingURI;
+  GetOriginatingURI(aChannel, getter_AddRefs(originatingURI));
+
+  nsCAutoString result;
+  GetCookieInternal(aHostURI, originatingURI, PR_TRUE, result);
+  *aCookie = result.IsEmpty() ? nsnull : ToNewCString(result);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCookieService::SetCookieString(nsIURI     *aHostURI,
                                  nsIPrompt  *aPrompt,
                                  const char *aCookieHeader,
                                  nsIChannel *aChannel)
 {
-  return SetCookieStringInternal(aHostURI, aPrompt, aCookieHeader, nsnull, aChannel, PR_FALSE);
+  NS_ENSURE_ARG(aHostURI);
+  NS_ENSURE_ARG(aCookieHeader);
+
+  nsCOMPtr<nsIURI> originatingURI;
+  GetOriginatingURI(aChannel, getter_AddRefs(originatingURI));
+
+  nsDependentCString cookieString(aCookieHeader);
+  SetCookieStringInternal(aHostURI, originatingURI,
+                          cookieString, EmptyCString(), PR_FALSE);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCookieService::SetCookieStringFromHttp(nsIURI     *aHostURI,
                                          nsIURI     *aFirstURI,
                                          nsIPrompt  *aPrompt,
                                          const char *aCookieHeader,
                                          const char *aServerTime,
                                          nsIChannel *aChannel) 
 {
-  return SetCookieStringInternal(aHostURI, aPrompt, aCookieHeader, aServerTime, aChannel, PR_TRUE);
+  NS_ENSURE_ARG(aHostURI);
+  NS_ENSURE_ARG(aCookieHeader);
+
+  nsCOMPtr<nsIURI> originatingURI;
+  GetOriginatingURI(aChannel, getter_AddRefs(originatingURI));
+
+  nsDependentCString cookieString(aCookieHeader);
+  nsDependentCString serverTime(aServerTime ? aServerTime : "");
+  SetCookieStringInternal(aHostURI, originatingURI, cookieString,
+                          serverTime, PR_TRUE);
+  return NS_OK;
 }
 
-nsresult
-nsCookieService::SetCookieStringInternal(nsIURI     *aHostURI,
-                                         nsIPrompt  *aPrompt,
-                                         const char *aCookieHeader,
-                                         const char *aServerTime,
-                                         nsIChannel *aChannel,
-                                         PRBool      aFromHttp) 
+void
+nsCookieService::SetCookieStringInternal(nsIURI          *aHostURI,
+                                         nsIURI          *aOriginatingURI,
+                                         const nsCString &aCookieHeader,
+                                         const nsCString &aServerTime,
+                                         PRBool           aFromHttp) 
 {
-  if (!aHostURI) {
-    COOKIE_LOGFAILURE(SET_COOKIE, nsnull, aCookieHeader, "host URI is null");
-    return NS_OK;
-  }
-
   // get the base domain for the host URI.
   // e.g. for "www.bbc.co.uk", this would be "bbc.co.uk".
   // file:// URI's (i.e. with an empty host) are allowed, but any other
   // scheme must have a non-empty host. A trailing dot in the host
   // is acceptable, and will be stripped.
   PRBool requireHostMatch;
   nsCAutoString baseDomain;
   nsresult rv = GetBaseDomain(aHostURI, baseDomain, requireHostMatch);
   if (NS_FAILED(rv)) {
     COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, 
                       "couldn't get base domain from URI");
-    return NS_OK;
+    return;
   }
 
   // check default prefs
-  PRUint32 cookieStatus = CheckPrefs(aHostURI, aChannel, baseDomain,
-                                     requireHostMatch, aCookieHeader);
+  PRUint32 cookieStatus = CheckPrefs(aHostURI, aOriginatingURI, baseDomain,
+                                     requireHostMatch, aCookieHeader.get());
   // fire a notification if cookie was rejected (but not if there was an error)
   switch (cookieStatus) {
   case STATUS_REJECTED:
     NotifyRejected(aHostURI);
   case STATUS_REJECTED_WITH_ERROR:
-    return NS_OK;
+    return;
   }
 
   // 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
   // user is prompted).
   PRTime tempServerTime;
   PRInt64 serverTime;
-  if (aServerTime &&
-      PR_ParseTimeString(aServerTime, PR_TRUE, &tempServerTime) == PR_SUCCESS) {
+  PRStatus result = PR_ParseTimeString(aServerTime.get(), PR_TRUE,
+                                       &tempServerTime);
+  if (result == PR_SUCCESS) {
     serverTime = tempServerTime / PR_USEC_PER_SEC;
   } else {
     serverTime = PR_Now() / PR_USEC_PER_SEC;
   }
 
   // We may be adding a bunch of cookies to the DB, so we use async batching
   // with storage to make this super fast.
   nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
   if (mDBState->dbConn) {
     mDBState->stmtInsert->NewBindingParamsArray(getter_AddRefs(paramsArray));
   }
 
-  // switch to a nice string type now, and process each cookie in the header
+  // process each cookie in the header
   nsDependentCString cookieHeader(aCookieHeader);
-  while (SetCookieInternal(aHostURI, aChannel, baseDomain, requireHostMatch,
+  while (SetCookieInternal(aHostURI, baseDomain, requireHostMatch,
                            cookieHeader, serverTime, aFromHttp, paramsArray));
 
   // If we had a params array, go ahead and write it out to disk now.
   if (paramsArray) {
     // ...but only if we have sufficient length!
     PRUint32 length;
     paramsArray->GetLength(&length);
     if (length == 0)
-      return NS_OK;
+      return;
 
     rv = mDBState->stmtInsert->BindParameters(paramsArray);
     NS_ASSERT_SUCCESS(rv);
     nsCOMPtr<mozIStoragePendingStatement> handle;
     rv = mDBState->stmtInsert->ExecuteAsync(&sInsertCookieDBListener,
                                             getter_AddRefs(handle));
     NS_ASSERT_SUCCESS(rv);
   }
-
-  return NS_OK;
 }
 
 // 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);
@@ -1483,22 +1531,20 @@ public:
     // browser!  see bug 236772.
     // note: CreationID is unique, so two id's can never be equal.
     return aCookie1->CreationID() < aCookie2->CreationID();
   }
 };
 
 void
 nsCookieService::GetCookieInternal(nsIURI      *aHostURI,
-                                   nsIChannel  *aChannel,
+                                   nsIURI      *aOriginatingURI,
                                    PRBool       aHttpBound,
-                                   char       **aCookie)
+                                   nsCString   &aCookieString)
 {
-  *aCookie = nsnull;
-
   if (!aHostURI) {
     COOKIE_LOGFAILURE(GET_COOKIE, nsnull, nsnull, "host URI is null");
     return;
   }
 
   // get the base domain, host, and path from the URI.
   // e.g. for "www.bbc.co.uk", the base domain would be "bbc.co.uk".
   // file:// URI's (i.e. with an empty host) are allowed, but any other
@@ -1515,17 +1561,17 @@ nsCookieService::GetCookieInternal(nsIUR
   if (!hostFromURI.IsEmpty() && hostFromURI.Last() == '.')
     hostFromURI.Truncate(hostFromURI.Length() - 1);
   if (NS_FAILED(rv)) {
     COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, nsnull, "invalid host/path from URI");
     return;
   }
 
   // check default prefs
-  PRUint32 cookieStatus = CheckPrefs(aHostURI, aChannel, baseDomain,
+  PRUint32 cookieStatus = CheckPrefs(aHostURI, aOriginatingURI, baseDomain,
                                      requireHostMatch, nsnull);
   // for GetCookie(), we don't fire rejection notifications.
   switch (cookieStatus) {
   case STATUS_REJECTED:
   case STATUS_REJECTED_WITH_ERROR:
     return;
   }
 
@@ -1638,51 +1684,45 @@ nsCookieService::GetCookieInternal(nsIUR
     }
   }
 
   // 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).
   foundCookieList.Sort(CompareCookiesForSending());
 
-  nsCAutoString cookieData;
   for (PRInt32 i = 0; i < count; ++i) {
     cookie = foundCookieList.ElementAt(i);
 
     // check if we have anything to write
     if (!cookie->Name().IsEmpty() || !cookie->Value().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 (!aCookieString.IsEmpty()) {
+        aCookieString.AppendLiteral("; ");
       }
 
       if (!cookie->Name().IsEmpty()) {
         // we have a name and value - write both
-        cookieData += cookie->Name() + NS_LITERAL_CSTRING("=") + cookie->Value();
+        aCookieString += cookie->Name() + NS_LITERAL_CSTRING("=") + cookie->Value();
       } else {
         // just write value
-        cookieData += cookie->Value();
+        aCookieString += cookie->Value();
       }
     }
   }
 
-  // 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, nsnull);
-    *aCookie = ToNewCString(cookieData);
-  }
+  if (!aCookieString.IsEmpty())
+    COOKIE_LOGSUCCESS(GET_COOKIE, aHostURI, aCookieString, nsnull, nsnull);
 }
 
 // processes a single cookie, and returns PR_TRUE if there are more cookies
 // to be processed
 PRBool
 nsCookieService::SetCookieInternal(nsIURI                        *aHostURI,
-                                   nsIChannel                    *aChannel,
                                    const nsCString               &aBaseDomain,
                                    PRBool                         aRequireHostMatch,
                                    nsDependentCString            &aCookieHeader,
                                    PRInt64                        aServerTime,
                                    PRBool                         aFromHttp,
                                    mozIStorageBindingParamsArray *aParamsArray)
 {
   // create a stack-based nsCookieAttributes, to store all the
@@ -1741,20 +1781,20 @@ nsCookieService::SetCookieInternal(nsIUR
                      cookieAttributes.isHttpOnly);
   if (!cookie)
     return newCookie;
 
   // check permissions from site permission list, or ask the user,
   // to determine if we can set the cookie
   if (mPermissionService) {
     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
+    // Not passing an nsIChannel here means CanSetCookie will use the currently
+    // active window to display the prompt. This isn't exactly ideal...
     mPermissionService->CanSetCookie(aHostURI,
-                                     aChannel,
+                                     nsnull,
                                      static_cast<nsICookie2*>(static_cast<nsCookie*>(cookie)),
                                      &cookieAttributes.isSession,
                                      &cookieAttributes.expiryTime,
                                      &permission);
     if (!permission) {
       COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "cookie rejected by permission manager");
       NotifyRejected(aHostURI);
       return newCookie;
@@ -2217,19 +2257,36 @@ nsCookieService::IsForeign(const nsCStri
   // domain parameter will be equivalent to the host in this case.
   if (aRequireHostMatch)
     return !firstHost.Equals(aBaseDomain);
 
   // ensure the originating domain is also derived from the host's base domain.
   return !IsSubdomainOf(firstHost, aBaseDomain);
 }
 
+void
+nsCookieService::GetOriginatingURI(nsIChannel *aChannel,
+                                   nsIURI **aURI)
+{
+  // Determine the originating URI. We only need to do this if we're
+  // rejecting third-party cookies.
+  if (mCookiesPermissions != BEHAVIOR_REJECTFOREIGN)
+    return;
+
+  if (!mPermissionService) {
+    NS_WARNING("nsICookiePermission unavailable! Cookie may be rejected");
+    return;
+  }
+
+  mPermissionService->GetOriginatingURI(aChannel, aURI);
+}
+
 PRUint32
 nsCookieService::CheckPrefs(nsIURI          *aHostURI,
-                            nsIChannel      *aChannel,
+                            nsIURI          *aOriginatingURI,
                             const nsCString &aBaseDomain,
                             PRBool           aRequireHostMatch,
                             const char      *aCookieHeader)
 {
   nsresult rv;
 
   // don't let ftp sites get/set cookies (could be a security issue)
   PRBool ftp;
@@ -2237,17 +2294,19 @@ nsCookieService::CheckPrefs(nsIURI      
     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) {
     nsCookieAccess access;
-    rv = mPermissionService->CanAccess(aHostURI, aChannel, &access);
+    // Not passing an nsIChannel here is probably OK; our implementation
+    // doesn't do anything with it anyway.
+    rv = mPermissionService->CanAccess(aHostURI, nsnull, &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 STATUS_REJECTED;
 
@@ -2259,26 +2318,18 @@ nsCookieService::CheckPrefs(nsIURI      
 
   // check default prefs
   if (mCookiesPermissions == BEHAVIOR_REJECT) {
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled");
     return STATUS_REJECTED;
 
   } else if (mCookiesPermissions == BEHAVIOR_REJECTFOREIGN) {
     // check if cookie is foreign
-    if (!mPermissionService) {
-      NS_WARNING("Foreign cookie blocking enabled, but nsICookiePermission unavailable! Rejecting cookie");
-      COOKIE_LOGSTRING(PR_LOG_WARNING, ("CheckPrefs(): foreign blocking enabled, but nsICookiePermission unavailable! Rejecting cookie"));
-      return STATUS_REJECTED;
-    }
-
-    nsCOMPtr<nsIURI> firstURI;
-    rv = mPermissionService->GetOriginatingURI(aChannel, getter_AddRefs(firstURI));
-
-    if (NS_FAILED(rv) || IsForeign(aBaseDomain, aRequireHostMatch, firstURI)) {
+    if (!aOriginatingURI ||
+        IsForeign(aBaseDomain, aRequireHostMatch, aOriginatingURI)) {
       COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "originating server test failed");
       return STATUS_REJECTED;
     }
   }
 
   // if nothing has complained, accept cookie
   return STATUS_ACCEPTED;
 }
@@ -2539,17 +2590,17 @@ purgeCookiesCallback(nsCookieEntry *aEnt
     nsCookie *cookie = cookies[i];
 
     // check if the cookie has expired
     if (cookie->Expiry() <= data.currentTime) {
       data.removedList->AppendElement(cookie, PR_FALSE);
       COOKIE_LOGEVICTED(cookie);
 
       // remove from list; do not increment our iterator
-      nsCookieService::gCookieService->RemoveCookieFromList(iter, array);
+      gCookieService->RemoveCookieFromList(iter, array);
 
     } else {
       // check if the cookie is over the age limit
       if (cookie->LastAccessed() <= data.purgeTime) {
         data.purgeList.AppendElement(iter);
 
       } else if (cookie->LastAccessed() < data.oldestTime) {
         // reset our indicator
--- a/netwerk/cookie/src/nsCookieService.h
+++ b/netwerk/cookie/src/nsCookieService.h
@@ -51,28 +51,36 @@
 #include "nsCookie.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "nsHashKeys.h"
 #include "nsTHashtable.h"
 #include "mozIStorageStatement.h"
 #include "mozIStorageConnection.h"
 
-struct nsCookieAttributes;
-struct nsListIter;
-struct nsEnumerationData;
-
 class nsICookiePermission;
 class nsIEffectiveTLDService;
 class nsIIDNService;
 class nsIPrefBranch;
 class nsIObserverService;
 class nsIURI;
 class nsIChannel;
 
+struct nsCookieAttributes;
+struct nsListIter;
+struct nsEnumerationData;
+
+namespace mozilla {
+namespace net {
+#ifdef MOZ_IPC
+class CookieServiceParent;
+#endif
+}
+}
+
 // hash entry class
 class nsCookieEntry : public PLDHashEntryHdr
 {
   public:
     // Hash methods
     typedef const nsCString& KeyType;
     typedef const nsCString* KeyTypePointer;
     typedef nsTArray< nsRefPtr<nsCookie> > ArrayType;
@@ -154,40 +162,41 @@ class nsCookieService : public nsICookie
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSICOOKIESERVICE
     NS_DECL_NSICOOKIEMANAGER
     NS_DECL_NSICOOKIEMANAGER2
 
     nsCookieService();
     virtual ~nsCookieService();
-    static nsCookieService*       GetSingleton();
+    static nsICookieService*      GetXPCOMSingleton();
     nsresult                      Init();
 
   protected:
     void                          PrefChanged(nsIPrefBranch *aPrefBranch);
     nsresult                      InitDB();
     nsresult                      TryInitDB(PRBool aDeleteExistingDB);
     nsresult                      CreateTable();
     void                          CloseDB();
     nsresult                      Read();
     nsresult                      NormalizeHost(nsCString &aHost);
     nsresult                      GetBaseDomain(nsIURI *aHostURI, nsCString &aBaseDomain, PRBool &aRequireHostMatch);
     nsresult                      GetBaseDomainFromHost(const nsACString &aHost, nsCString &aBaseDomain);
-    void                          GetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, PRBool aHttpBound, char **aCookie);
-    nsresult                      SetCookieStringInternal(nsIURI *aHostURI, nsIPrompt *aPrompt, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, PRBool aFromHttp);
-    PRBool                        SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, const nsCString& aBaseDomain, PRBool aRequireHostMatch, nsDependentCString &aCookieHeader, PRInt64 aServerTime, PRBool aFromHttp, mozIStorageBindingParamsArray *aParamsArray = NULL);
+    void                          GetCookieInternal(nsIURI *aHostURI, nsIURI *aOriginatingURI, PRBool aHttpBound, nsCString &aCookie);
+    void                          SetCookieStringInternal(nsIURI *aHostURI, nsIURI *aOriginatingURI, const nsCString &aCookieHeader, const nsCString &aServerTime, PRBool aFromHttp);
+    PRBool                        SetCookieInternal(nsIURI *aHostURI, const nsCString& aBaseDomain, PRBool aRequireHostMatch, nsDependentCString &aCookieHeader, PRInt64 aServerTime, PRBool aFromHttp, mozIStorageBindingParamsArray *aParamsArray = NULL);
     void                          AddInternal(const nsCString& aBaseDomain, nsCookie *aCookie, PRInt64 aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, PRBool aFromHttp, mozIStorageBindingParamsArray *aParamsArray = NULL);
     void                          RemoveCookieFromList(const nsListIter &aIter, mozIStorageBindingParamsArray *aParamsArray = NULL);
     PRBool                        AddCookieToList(const nsCString& aBaseDomain, nsCookie *aCookie, mozIStorageBindingParamsArray *aParamsArray, PRBool aWriteToDB = PR_TRUE);
     void                          UpdateCookieInList(nsCookie *aCookie, PRInt64 aLastAccessed, mozIStorageBindingParamsArray *aParamsArray);
     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);
     PRBool                        IsForeign(const nsCString &aBaseDomain, PRBool aRequireHostMatch, nsIURI *aFirstURI);
-    PRUint32                      CheckPrefs(nsIURI *aHostURI, nsIChannel *aChannel, const nsCString &aBaseDomain, PRBool aRequireHostMatch, const char *aCookieHeader);
+    void                          GetOriginatingURI(nsIChannel *aChannel, nsIURI **aURI);
+    PRUint32                      CheckPrefs(nsIURI *aHostURI, nsIURI *aOriginatingURI, const nsCString &aBaseDomain, PRBool aRequireHostMatch, const char *aCookieHeader);
     PRBool                        CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, PRBool aRequireHostMatch);
     static PRBool                 CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
     static PRBool                 GetExpiry(nsCookieAttributes &aCookie, PRInt64 aServerTime, PRInt64 aCurrentTime);
     void                          RemoveAllFromMemory();
     void                          PurgeCookies(PRInt64 aCurrentTimeInUsec);
     PRBool                        FindCookie(const nsCString& aBaseDomain, const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter, PRInt64 aCurrentTime);
     PRUint32                      CountCookiesFromHostInternal(const nsCString &aBaseDomain, nsEnumerationData &aData);
     void                          NotifyRejected(nsIURI *aHostURI);
@@ -210,17 +219,18 @@ class nsCookieService : public nsICookie
     DBState                       mPrivateDBState;
 
     // cached prefs
     PRUint8                       mCookiesPermissions;   // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT}
     PRUint16                      mMaxNumberOfCookies;
     PRUint16                      mMaxCookiesPerHost;
     PRInt64                       mCookiePurgeAge;
 
-    // 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 purgeCookiesCallback(nsCookieEntry *aEntry, void *aArg);
+
+    static nsCookieService*       GetSingleton();
+#ifdef MOZ_IPC
+    friend class mozilla::net::CookieServiceParent;
+#endif
 };
 
 #endif // nsCookieService_h__
new file mode 100644
--- /dev/null
+++ b/netwerk/cookie/test/unit_ipc/head_ipc_setup.js
@@ -0,0 +1,15 @@
+
+/** 
+ * Turn on e10s networking (god help us)
+ */
+Components.classes["@mozilla.org/process/environment;1"]
+          .getService(Components.interfaces.nsIEnvironment)
+          .set("NECKO_E10S_HTTP", "1");
+
+// If using NSPR logging, create child log as "${NSPR_LOG_FILE}.child" 
+// - TODO: remove when bug 534764 is fixed
+var env = Components.classes["@mozilla.org/process/environment;1"]
+          .getService(Components.interfaces.nsIEnvironment);
+var log = env.get("NSPR_LOG_FILE");
+if (log) 
+  env.set("NSPR_LOG_FILE", log + ".child");
new file mode 100644
--- /dev/null
+++ b/netwerk/cookie/test/unit_ipc/test_ipc_parser_0001.js
@@ -0,0 +1,3 @@
+function run_test() {
+  run_test_in_child("../unit/test_parser_0001.js");
+}
new file mode 100644
--- /dev/null
+++ b/netwerk/cookie/test/unit_ipc/test_ipc_parser_0019.js
@@ -0,0 +1,3 @@
+function run_test() {
+  run_test_in_child("../unit/test_parser_0019.js");
+}
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -37,16 +37,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHttp.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/dom/ContentProcessChild.h"
 #include "mozilla/net/HttpChannelChild.h"
+#include "mozilla/net/CookieServiceChild.h"
 
 namespace mozilla {
 namespace net {
 
 PNeckoChild *gNeckoChild = nsnull;
 
 // C++ file contents
 NeckoChild::NeckoChild()
@@ -98,10 +99,28 @@ NeckoChild::DeallocPHttpChannel(PHttpCha
 {
   NS_ABORT_IF_FALSE(IsNeckoChild(), "DeallocPHttpChannel called by non-child!");
 
   HttpChannelChild *p = static_cast<HttpChannelChild*>(channel);
   p->Release();
   return true;
 }
 
+PCookieServiceChild* 
+NeckoChild::AllocPCookieService()
+{
+  // We don't allocate here: see nsCookieService::GetSingleton()
+  NS_NOTREACHED("AllocPCookieService should not be called");
+  return nsnull;
+}
+
+bool 
+NeckoChild::DeallocPCookieService(PCookieServiceChild* cs)
+{
+  NS_ASSERTION(IsNeckoChild(), "DeallocPCookieService called by non-child!");
+
+  CookieServiceChild *p = static_cast<CookieServiceChild*>(cs);
+  p->Release();
+  return true;
+}
+
 }} // mozilla::net
 
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -56,16 +56,18 @@ public:
   virtual ~NeckoChild();
 
   static void InitNeckoChild();
   static void DestroyNeckoChild();
 
 protected:
   virtual PHttpChannelChild* AllocPHttpChannel();
   virtual bool DeallocPHttpChannel(PHttpChannelChild*);
+  virtual PCookieServiceChild* AllocPCookieService();
+  virtual bool DeallocPCookieService(PCookieServiceChild*);
 };
 
 /**
  * Reference to the PNecko Child protocol.
  * Null if this is not a content process.
  */
 extern PNeckoChild *gNeckoChild;
 
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -36,16 +36,17 @@
  * 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 "nsHttp.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/net/HttpChannelParent.h"
+#include "mozilla/net/CookieServiceParent.h"
 
 namespace mozilla {
 namespace net {
 
 // C++ file contents
 NeckoParent::NeckoParent()
 {
 }
@@ -65,11 +66,23 @@ NeckoParent::AllocPHttpChannel()
 bool 
 NeckoParent::DeallocPHttpChannel(PHttpChannelParent* channel)
 {
   HttpChannelParent *p = static_cast<HttpChannelParent *>(channel);
   p->Release();
   return true;
 }
 
+PCookieServiceParent* 
+NeckoParent::AllocPCookieService()
+{
+  return new CookieServiceParent();
+}
+
+bool 
+NeckoParent::DeallocPCookieService(PCookieServiceParent* cs)
+{
+  delete cs;
+  return true;
+}
 
 }} // mozilla::net
 
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -53,14 +53,16 @@ class NeckoParent :
 {
 public:
   NeckoParent();
   virtual ~NeckoParent();
 
 protected:
   virtual PHttpChannelParent* AllocPHttpChannel();
   virtual bool DeallocPHttpChannel(PHttpChannelParent*);
+  virtual PCookieServiceParent* AllocPCookieService();
+  virtual bool DeallocPCookieService(PCookieServiceParent*);
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_NeckoParent_h
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -35,28 +35,31 @@
  * 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 protocol "PContentProcess.ipdl";
 include protocol "PHttpChannel.ipdl";
+include protocol "PCookieService.ipdl";
 
 namespace mozilla {
 namespace net {
 
 
 //-------------------------------------------------------------------
-protocol PNecko
+sync protocol PNecko
 {
   manager PContentProcess;
   manages PHttpChannel;
+  manages PCookieService;
 
 parent:
   __delete__();
 
   PHttpChannel();
+  PCookieService();
 };
 
 
 } // namespace net
 } // namespace mozilla