Bug 595305 - Factor cookie third-party URI code into separate API. r=bent, a=betaN+
authorDan Witte <dwitte@mozilla.com>
Tue, 19 Oct 2010 09:37:03 -0700
changeset 56094 56815e37d436bad9a337bd9726c5d6754cfeea69
parent 56093 9926aff395c1ba654059c0f5281a87eee9b8009a
child 56095 d35efa6966ac87245fe35442460a19f5f786e1a7
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbent, betaN
bugs595305
milestone2.0b8pre
Bug 595305 - Factor cookie third-party URI code into separate API. r=bent, a=betaN+
content/base/public/nsContentCID.h
content/base/src/Makefile.in
content/base/src/ThirdPartyUtil.cpp
content/base/src/ThirdPartyUtil.h
layout/build/nsLayoutModule.cpp
netwerk/base/public/Makefile.in
netwerk/base/public/mozIThirdPartyUtil.idl
netwerk/cookie/CookieServiceChild.cpp
netwerk/cookie/CookieServiceChild.h
netwerk/cookie/CookieServiceParent.cpp
netwerk/cookie/CookieServiceParent.h
netwerk/cookie/PCookieService.ipdl
netwerk/cookie/nsCookieService.cpp
netwerk/cookie/nsCookieService.h
netwerk/cookie/nsICookiePermission.idl
--- a/content/base/public/nsContentCID.h
+++ b/content/base/public/nsContentCID.h
@@ -323,9 +323,13 @@
   { 0x9a, 0x8a, 0x86, 0xaf, 0xdb, 0x9f, 0xbb, 0xb6 } }
 #define NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID \
   "@mozilla.org/childprocessmessagemanager;1"
   
 // {f96f5ec9-755b-447e-b1f3-717d1a84bb41}
 #define NS_PLUGINDOCUMENT_CID \
 { 0xf96f5ec9, 0x755b, 0x447e, { 0xb1, 0xf3, 0x71, 0x7d, 0x1a, 0x84, 0xbb, 0x41 } }
 
+// {08c6cc8b-cfb0-421d-b1f7-683ff2989681}
+#define THIRDPARTYUTIL_CID \
+ {0x08c6cc8b, 0xcfb0, 0x421d, {0xb1, 0xf7, 0x68, 0x3f, 0xf2, 0x98, 0x96, 0x81}}
+
 #endif /* nsContentCID_h__ */
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -143,16 +143,17 @@ CPPSRCS		= \
 		nsXHTMLContentSerializer.cpp \
 		nsXMLContentSerializer.cpp \
 		nsXMLHttpRequest.cpp \
 		nsXMLNameSpaceMap.cpp \
 		Link.cpp \
 		nsFileDataProtocolHandler.cpp \
 		nsFrameMessageManager.cpp \
 		nsInProcessTabChildGlobal.cpp \
+		ThirdPartyUtil.cpp \
 		$(NULL)
 
 GQI_SRCS = contentbase.gqi
 
 # we don't want the shared lib, but we want to force the creation of a
 # static lib.
 FORCE_STATIC_LIB = 1
 
new file mode 100644
--- /dev/null
+++ b/content/base/src/ThirdPartyUtil.cpp
@@ -0,0 +1,312 @@
+/* ***** 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 third party utility 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 "ThirdPartyUtil.h"
+#include "nsNetUtil.h"
+#include "nsIServiceManager.h"
+#include "nsIHttpChannelInternal.h"
+#include "nsIDOMWindow.h"
+#include "nsILoadContext.h"
+#include "nsIPrincipal.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "nsThreadUtils.h"
+
+NS_IMPL_ISUPPORTS1(ThirdPartyUtil, mozIThirdPartyUtil)
+
+nsresult
+ThirdPartyUtil::Init()
+{
+  NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_AVAILABLE);
+
+  nsresult rv;
+  mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
+  return rv;
+}
+
+// Get the base domain for aHostURI; e.g. for "www.bbc.co.uk", this would be
+// "bbc.co.uk". Only properly-formed URI's are tolerated, though a trailing
+// dot may be present (and will be stripped). If aHostURI is an IP address,
+// an alias such as 'localhost', an eTLD such as 'co.uk', or the empty string,
+// aBaseDomain will be the exact host. The result of this function should only
+// be used in exact string comparisons, since substring comparisons will not
+// be valid for the special cases elided above.
+nsresult
+ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI,
+                              nsCString& aBaseDomain)
+{
+  // Get the base domain. this will fail if the host contains a leading dot,
+  // more than one trailing dot, or is otherwise malformed.
+  nsresult rv = mTLDService->GetBaseDomain(aHostURI, 0, aBaseDomain);
+  if (rv == NS_ERROR_HOST_IS_IP_ADDRESS ||
+      rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
+    // aHostURI is either an IP address, an alias such as 'localhost', an eTLD
+    // such as 'co.uk', or the empty string. Uses the normalized host in such
+    // cases.
+    rv = aHostURI->GetAsciiHost(aBaseDomain);
+  }
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // aHostURI (and thus aBaseDomain) may contain a trailing dot; if so, trim it.
+  if (!aBaseDomain.IsEmpty() && aBaseDomain.Last() == '.')
+    aBaseDomain.Truncate(aBaseDomain.Length() - 1);
+
+  // Reject any URIs without a host that aren't file:// URIs. This makes it the
+  // only way we can get a base domain consisting of the empty string, which
+  // means we can safely perform foreign tests on such URIs where "not foreign"
+  // means "the involved URIs are all file://".
+  if (aBaseDomain.IsEmpty()) {
+    PRBool isFileURI = PR_FALSE;
+    aHostURI->SchemeIs("file", &isFileURI);
+    NS_ENSURE_TRUE(isFileURI, NS_ERROR_INVALID_ARG);
+  }
+
+  return NS_OK;
+}
+
+// Determine if aFirstDomain is a different base domain to aSecondURI; or, if
+// the concept of base domain does not apply, determine if the two hosts are not
+// string-identical.
+nsresult
+ThirdPartyUtil::IsThirdPartyInternal(const nsCString& aFirstDomain,
+                                     nsIURI* aSecondURI,
+                                     PRBool* aResult)
+{
+  NS_ASSERTION(aSecondURI, "null URI!");
+
+  // Get the base domain for aSecondURI.
+  nsCString secondDomain;
+  nsresult rv = GetBaseDomain(aSecondURI, secondDomain);
+  if (NS_FAILED(rv))
+    return rv;
+
+  // Check strict equality.
+  *aResult = aFirstDomain != secondDomain;
+  return NS_OK;
+}
+
+// Get the URI associated with a window.
+already_AddRefed<nsIURI>
+ThirdPartyUtil::GetURIFromWindow(nsIDOMWindow* aWin)
+{
+  nsCOMPtr<nsIScriptObjectPrincipal> scriptObjPrin = do_QueryInterface(aWin);
+  NS_ENSURE_TRUE(scriptObjPrin, NULL);
+
+  nsIPrincipal* prin = scriptObjPrin->GetPrincipal();
+  NS_ENSURE_TRUE(prin, NULL);
+
+  nsCOMPtr<nsIURI> result;
+  prin->GetURI(getter_AddRefs(result));
+  return result.forget();
+}
+
+// Determine if aFirstURI is third party with respect to aSecondURI. See docs
+// for mozIThirdPartyUtil.
+NS_IMETHODIMP
+ThirdPartyUtil::IsThirdPartyURI(nsIURI* aFirstURI,
+                                nsIURI* aSecondURI,
+                                PRBool* aResult)
+{
+  NS_ENSURE_ARG(aFirstURI);
+  NS_ENSURE_ARG(aSecondURI);
+  NS_ASSERTION(aResult, "null outparam pointer");
+
+  nsCString firstHost;
+  nsresult rv = GetBaseDomain(aFirstURI, firstHost);
+  if (NS_FAILED(rv))
+    return rv;
+
+  return IsThirdPartyInternal(firstHost, aSecondURI, aResult);
+}
+
+// Determine if any URI of the window hierarchy of aWindow is foreign with
+// respect to aSecondURI. See docs for mozIThirdPartyUtil.
+NS_IMETHODIMP
+ThirdPartyUtil::IsThirdPartyWindow(nsIDOMWindow* aWindow,
+                                   nsIURI* aURI,
+                                   PRBool* aResult)
+{
+  NS_ENSURE_ARG(aWindow);
+  NS_ASSERTION(aResult, "null outparam pointer");
+
+  PRBool result;
+
+  // Get the URI of the window, and its base domain.
+  nsCOMPtr<nsIURI> currentURI = GetURIFromWindow(aWindow);
+  NS_ENSURE_TRUE(currentURI, NS_ERROR_INVALID_ARG);
+
+  nsCString bottomDomain;
+  nsresult rv = GetBaseDomain(currentURI, bottomDomain);
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (aURI) {
+    // Determine whether aURI is foreign with respect to currentURI.
+    rv = IsThirdPartyInternal(bottomDomain, aURI, &result);
+    if (NS_FAILED(rv))
+      return rv;
+
+    if (result) {
+      *aResult = true;
+      return NS_OK;
+    }
+  }
+
+  nsCOMPtr<nsIDOMWindow> current = aWindow, parent;
+  nsCOMPtr<nsIURI> parentURI;
+  do {
+    rv = current->GetParent(getter_AddRefs(parent));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (SameCOMIdentity(parent, current)) {
+      // We're at the topmost content window. We already know the answer.
+      *aResult = false;
+      return NS_OK;
+    }
+
+    parentURI = GetURIFromWindow(parent);
+    NS_ENSURE_TRUE(parentURI, NS_ERROR_INVALID_ARG);
+
+    rv = IsThirdPartyInternal(bottomDomain, parentURI, &result);
+    if (NS_FAILED(rv))
+      return rv;
+
+    if (result) {
+      *aResult = true;
+      return NS_OK;
+    }
+
+    current = parent;
+    currentURI = parentURI;
+  } while (1);
+
+  NS_NOTREACHED("should've returned");
+  return NS_ERROR_UNEXPECTED;
+}
+
+// Determine if the URI associated with aChannel or any URI of the window
+// hierarchy associated with the channel is foreign with respect to aSecondURI.
+// See docs for mozIThirdPartyUtil.
+NS_IMETHODIMP 
+ThirdPartyUtil::IsThirdPartyChannel(nsIChannel* aChannel,
+                                    nsIURI* aURI,
+                                    PRBool* aResult)
+{
+  NS_ENSURE_ARG(aChannel);
+  NS_ASSERTION(aResult, "null outparam pointer");
+
+  nsresult rv;
+  PRBool doForce = false;
+  nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
+    do_QueryInterface(aChannel);
+  if (httpChannelInternal) {
+    rv = httpChannelInternal->GetForceAllowThirdPartyCookie(&doForce);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // If aURI was not supplied, and we're forcing, then we're by definition
+    // not foreign. If aURI was supplied, we still want to check whether it's
+    // foreign with respect to the channel URI. (The forcing only applies to
+    // whatever window hierarchy exists above the channel.)
+    if (doForce && !aURI) {
+      *aResult = false;
+      return NS_OK;
+    }
+  }
+
+  // Obtain the URI from the channel, and its base domain.
+  nsCOMPtr<nsIURI> channelURI;
+  aChannel->GetURI(getter_AddRefs(channelURI));
+  NS_ENSURE_TRUE(channelURI, NS_ERROR_INVALID_ARG);
+
+  nsCString channelDomain;
+  rv = GetBaseDomain(channelURI, channelDomain);
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (aURI) {
+    // Determine whether aURI is foreign with respect to channelURI.
+    PRBool result;
+    rv = IsThirdPartyInternal(channelDomain, aURI, &result);
+    if (NS_FAILED(rv))
+     return rv;
+
+    // If it's foreign, or we're forcing, we're done.
+    if (result || doForce) {
+      *aResult = result;
+      return NS_OK;
+    }
+  }
+
+  // Find the associated window and its parent window.
+  nsCOMPtr<nsILoadContext> ctx;
+  NS_QueryNotificationCallbacks(aChannel, ctx);
+  if (!ctx) return NS_ERROR_INVALID_ARG;
+
+  // If there is no window, the consumer kicking off the load didn't provide one
+  // to the channel. This is limited to loads of certain types of resources. If
+  // those loads require cookies, the forceAllowThirdPartyCookie property should
+  // be set on the channel.
+  nsCOMPtr<nsIDOMWindow> ourWin, parentWin;
+  ctx->GetAssociatedWindow(getter_AddRefs(ourWin));
+  if (!ourWin) return NS_ERROR_INVALID_ARG;
+
+  ourWin->GetParent(getter_AddRefs(parentWin));
+  NS_ENSURE_TRUE(parentWin, NS_ERROR_INVALID_ARG);
+
+  if (SameCOMIdentity(ourWin, parentWin)) {
+    // Check whether this is the document channel for this window (representing
+    // a load of a new page). This covers the case of a freshly kicked-off load
+    // (e.g. the user typing something in the location bar, or clicking on a
+    // bookmark), where the window's URI hasn't yet been set, and will be bogus.
+    // This is a bit of a nasty hack, but we will hopefully flag these channels
+    // better later.
+    nsLoadFlags flags;
+    rv = aChannel->GetLoadFlags(&flags);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (flags & nsIChannel::LOAD_DOCUMENT_URI) {
+      // We only need to compare aURI to the channel URI -- the window's will be
+      // bogus. We already know the answer.
+      *aResult = false;
+      return NS_OK;
+    }
+  }
+
+  // Check the window hierarchy. This covers most cases for an ordinary page
+  // load from the location bar.
+  return IsThirdPartyWindow(ourWin, channelURI, aResult);
+}
+
new file mode 100644
--- /dev/null
+++ b/content/base/src/ThirdPartyUtil.h
@@ -0,0 +1,68 @@
+/* ***** 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 third party utility 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 ***** */
+
+#ifndef ThirdPartyUtil_h__
+#define ThirdPartyUtil_h__
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "mozIThirdPartyUtil.h"
+#include "nsIEffectiveTLDService.h"
+
+class nsIURI;
+class nsIChannel;
+class nsIDOMWindow;
+
+class ThirdPartyUtil : public mozIThirdPartyUtil
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_MOZITHIRDPARTYUTIL
+
+  nsresult Init();
+
+private:
+  nsresult GetBaseDomain(nsIURI* aHostURI, nsCString& aBaseDomain);
+  nsresult IsThirdPartyInternal(const nsCString& aFirstDomain,
+    nsIURI* aSecondURI, PRBool* aResult);
+  static already_AddRefed<nsIURI> GetURIFromWindow(nsIDOMWindow* aWin);
+
+  nsCOMPtr<nsIEffectiveTLDService> mTLDService;
+};
+
+#endif
+
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -92,16 +92,17 @@
 #include "nsBox.h"
 #include "nsIFrameTraversal.h"
 #include "nsLayoutCID.h"
 #include "nsILanguageAtomService.h"
 #include "nsStyleSheetService.h"
 #include "nsXULPopupManager.h"
 #include "nsFocusManager.h"
 #include "nsIContentUtils.h"
+#include "ThirdPartyUtil.h"
 #include "mozilla/Services.h"
 
 #include "nsIEventListenerService.h"
 #include "nsIFrameMessageManager.h"
 
 // Transformiix stuff
 #include "nsXPathEvaluator.h"
 #include "txMozillaXSLTProcessor.h"
@@ -326,16 +327,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsChannel
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(IndexedDatabaseManager,
                                          IndexedDatabaseManager::GetOrCreateInstance)
 #if defined(XP_UNIX)    || \
     defined(_WINDOWS)   || \
     defined(machintosh) || \
     defined(android)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAccelerometerSystem)
 #endif
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ThirdPartyUtil, Init)
 
 //-----------------------------------------------------------------------------
 
 // Per bug 209804, it is necessary to observe the "xpcom-shutdown" event and
 // perform shutdown of the layout modules at that time instead of waiting for
 // our module destructor to run.  If we do not do this, then we risk holding
 // references to objects in other component libraries that have already been
 // shutdown (and possibly unloaded if 60709 is ever fixed).
@@ -878,16 +880,17 @@ NS_DEFINE_NAMED_CID(NS_GLOBALMESSAGEMANA
 NS_DEFINE_NAMED_CID(NS_PARENTPROCESSMESSAGEMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_CHILDPROCESSMESSAGEMANAGER_CID);
 NS_DEFINE_NAMED_CID(NSCHANNELPOLICY_CID);
 NS_DEFINE_NAMED_CID(NS_SCRIPTSECURITYMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_PRINCIPAL_CID);
 NS_DEFINE_NAMED_CID(NS_SYSTEMPRINCIPAL_CID);
 NS_DEFINE_NAMED_CID(NS_NULLPRINCIPAL_CID);
 NS_DEFINE_NAMED_CID(NS_SECURITYNAMESET_CID);
+NS_DEFINE_NAMED_CID(THIRDPARTYUTIL_CID);
 
 #if defined(XP_UNIX)    || \
     defined(_WINDOWS)   || \
     defined(machintosh) || \
     defined(android)
 NS_DEFINE_NAMED_CID(NS_ACCELEROMETER_CID);
 #endif
 
@@ -1034,16 +1037,17 @@ static const mozilla::Module::CIDEntry k
   { &kNS_NULLPRINCIPAL_CID, false, NULL, nsNullPrincipalConstructor },
   { &kNS_SECURITYNAMESET_CID, false, NULL, nsSecurityNameSetConstructor },
 #if defined(XP_UNIX)    || \
     defined(_WINDOWS)   || \
     defined(machintosh) || \
     defined(android)
   { &kNS_ACCELEROMETER_CID, false, NULL, nsAccelerometerSystemConstructor },
 #endif
+  { &kTHIRDPARTYUTIL_CID, false, NULL, ThirdPartyUtilConstructor },
   { NULL }
 };
 
 static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
   XPCONNECT_CONTRACTS
   { "@mozilla.org/layout/xul-boxobject;1", &kNS_BOXOBJECT_CID },
 #ifdef MOZ_XUL
   { "@mozilla.org/layout/xul-boxobject-listbox;1", &kNS_LISTBOXOBJECT_CID },
@@ -1179,16 +1183,17 @@ static const mozilla::Module::ContractID
   { NS_NULLPRINCIPAL_CONTRACTID, &kNS_NULLPRINCIPAL_CID },
   { NS_SECURITYNAMESET_CONTRACTID, &kNS_SECURITYNAMESET_CID },
 #if defined(XP_UNIX)    || \
     defined(_WINDOWS)   || \
     defined(machintosh) || \
     defined(android)
   { NS_ACCELEROMETER_CONTRACTID, &kNS_ACCELEROMETER_CID },
 #endif
+  { THIRDPARTYUTIL_CONTRACTID, &kTHIRDPARTYUTIL_CID },
   { NULL }
 };
 
 static const mozilla::Module::CategoryEntry kLayoutCategories[] = {
   XPCONNECT_CATEGORIES
   { JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY, "Image", NS_HTMLIMGELEMENT_CONTRACTID },
   { JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY, "Image", "HTMLImageElement" },
   { JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY, "Option", NS_HTMLOPTIONELEMENT_CONTRACTID },
--- a/netwerk/base/public/Makefile.in
+++ b/netwerk/base/public/Makefile.in
@@ -136,16 +136,17 @@ XPIDLSRCS	= \
 		nsIChannelEventSink.idl \
 		nsINetUtil.idl \
 		nsIProxiedChannel.idl \
 		nsIRandomGenerator.idl \
 		nsIStrictTransportSecurityService.idl \
 		nsIURIWithPrincipal.idl \
 		nsIURIClassifier.idl \
 		nsIRedirectResultListener.idl \
+		mozIThirdPartyUtil.idl \
 		$(NULL)
 
 ifdef MOZ_TOOLKIT_SEARCH
 XPIDLSRCS	+= nsIBrowserSearchService.idl
 endif
 
 EXPORTS		= \
 		netCore.h \
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/mozIThirdPartyUtil.idl
@@ -0,0 +1,167 @@
+/* ***** 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 third party utility 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 "nsISupports.idl"
+
+interface nsIURI;
+interface nsIDOMWindow;
+interface nsIChannel;
+
+/**
+ * Utility functions for determining whether a given URI, channel, or window
+ * hierarchy is third party with respect to a known URI.
+ */
+[scriptable, uuid(55385caa-1b94-4376-a34c-b47c51ef0837)]
+interface mozIThirdPartyUtil : nsISupports
+{
+  /**
+   * isThirdPartyURI
+   *
+   * Determine whether two URIs are third party with respect to each other.
+   * This is determined by computing the base domain for both URIs. If they can
+   * be determined, and the base domains match, the request is defined as first
+   * party. If it cannot be determined because one or both URIs do not have a
+   * base domain (for instance, in the case of IP addresses, host aliases such
+   * as 'localhost', or a file:// URI), an exact string comparison on host is
+   * performed.
+   *
+   * For example, the URI "http://mail.google.com/" is not third party with
+   * respect to "http://images.google.com/", but "http://mail.yahoo.com/" and
+   * "http://192.168.1.1/" are.
+   *
+   * @return true if aFirstURI is third party with respect to aSecondURI.
+   *
+   * @throws if either URI is null, has a malformed host, or has an empty host
+   *         and is not a file:// URI.
+   */
+  boolean isThirdPartyURI(in nsIURI aFirstURI, in nsIURI aSecondURI);
+
+  /**
+   * isThirdPartyWindow
+   *
+   * Determine whether the given window hierarchy is third party. This is done
+   * as follows:
+   *
+   * 1) Obtain the URI of the principal associated with 'aWindow'. Call this the
+   *    'bottom URI'.
+   * 2) If 'aURI' is provided, determine if it is third party with respect to
+   *    the bottom URI. If so, return.
+   * 3) Find the same-type parent window, if there is one, and its URI.
+   *    Determine whether it is third party with respect to the bottom URI. If
+   *    so, return.
+   *
+   * Therefore, each level in the window hierarchy is tested. (This means that
+   * nested iframes with different base domains, even though the bottommost and
+   * topmost URIs might be equal, will be considered third party.)
+   *
+   * @param aWindow
+   *        The bottommost window in the hierarchy.
+   * @param aURI
+   *        A URI to test against. If null, the URI of the principal
+   *        associated with 'aWindow' will be used.
+   *
+   * For example, if 'aURI' is "http://mail.google.com/", 'aWindow' has a URI
+   * of "http://google.com/", and its parent is the topmost content window with
+   * a URI of "http://mozilla.com", the result will be true.
+   *
+   * @return true if 'aURI' is third party with respect to any of the URIs
+   *         associated with aWindow and its same-type parents.
+   *
+   * @throws if aWindow is null; the same-type parent of any window in the
+   *         hierarchy cannot be determined; or the URI associated with any
+   *         window in the hierarchy is null, has a malformed host, or has an
+   *         empty host and is not a file:// URI.
+   *
+   * @see isThirdPartyURI
+   */
+  boolean isThirdPartyWindow(in nsIDOMWindow aWindow, [optional] in nsIURI aURI);
+
+  /**
+   * isThirdPartyChannel
+   *
+   * Determine whether the given channel and its content window hierarchy is
+   * third party. This is done as follows:
+   *
+   * 1) If 'aChannel' is an nsIHttpChannel and has the
+   *    'forceAllowThirdPartyCookie' property set, then:
+   *    a) If 'aURI' is null, return false.
+   *    b) Otherwise, find the URI of the channel, determine whether it is
+   *       foreign with respect to 'aURI', and return.
+   * 2) Find the URI of the channel and determine whether it is third party with
+   *    respect to the URI of the channel. If so, return.
+   * 3) Obtain the bottommost nsIDOMWindow, and its same-type parent if it
+   *    exists, from the channel's notification callbacks. Then:
+   *    a) If the parent is the same as the bottommost window, and the channel
+   *       has the LOAD_DOCUMENT_URI flag set, return false. This represents the
+   *       case where a toplevel load is occurring and the window's URI has not
+   *       yet been updated. (We have already checked that 'aURI' is not foreign
+   *       with respect to the channel URI.)
+   *    b) Otherwise, return the result of isThirdPartyWindow with arguments
+   *       of the channel's bottommost window and the channel URI, respectively.
+   *
+   * Therefore, both the channel's URI and each level in the window hierarchy
+   * associated with the channel is tested.
+   *
+   * @param aChannel
+   *        The channel associated with the load.
+   * @param aURI
+   *        A URI to test against. If null, the URI of the channel will be used.
+   *
+   * For example, if 'aURI' is "http://mail.google.com/", 'aChannel' has a URI
+   * of "http://google.com/", and its parent is the topmost content window with
+   * a URI of "http://mozilla.com", the result will be true.
+   *
+   * @return true if aURI is third party with respect to the channel URI or any
+   *         of the URIs associated with the same-type window hierarchy of the
+   *         channel.
+   *
+   * @throws if 'aChannel' is null; the channel has no notification callbacks or
+   *         an associated window; or isThirdPartyWindow throws.
+   *
+   * @see isThirdPartyWindow
+   */
+  boolean isThirdPartyChannel(in nsIChannel aChannel, [optional] in nsIURI aURI);
+};
+
+%{ C++
+/**
+ * The mozIThirdPartyUtil implementation is an XPCOM service registered
+ * under the ContractID:
+ */
+#define THIRDPARTYUTIL_CONTRACTID "@mozilla.org/thirdpartyutil;1"
+%}
+
--- a/netwerk/cookie/CookieServiceChild.cpp
+++ b/netwerk/cookie/CookieServiceChild.cpp
@@ -34,114 +34,165 @@
  * 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"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch2.h"
 
 namespace mozilla {
 namespace net {
 
+// Behavior pref constants
+static const PRInt32 BEHAVIOR_ACCEPT = 0;
+static const PRInt32 BEHAVIOR_REJECTFOREIGN = 1;
+static const PRInt32 BEHAVIOR_REJECT = 2;
+
+// Pref string constants
+static const char kPrefCookieBehavior[] = "network.cookie.cookieBehavior";
+static const char kPrefThirdPartySession[] =
+  "network.cookie.thirdparty.sessionOnly";
+
 static CookieServiceChild *gCookieService;
 
 CookieServiceChild*
 CookieServiceChild::GetSingleton()
 {
   if (!gCookieService)
     gCookieService = new CookieServiceChild();
 
   NS_ADDREF(gCookieService);
   return gCookieService;
 }
 
-NS_IMPL_ISUPPORTS1(CookieServiceChild, nsICookieService)
+NS_IMPL_ISUPPORTS2(CookieServiceChild, nsICookieService, nsIObserver)
 
 CookieServiceChild::CookieServiceChild()
+  : mCookieBehavior(BEHAVIOR_ACCEPT)
+  , mThirdPartySession(false)
 {
   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");
+  // Init our prefs and observer.
+  nsCOMPtr<nsIPrefBranch2> prefBranch =
+    do_GetService(NS_PREFSERVICE_CONTRACTID);
+  NS_WARN_IF_FALSE(prefBranch, "no prefservice");
+  if (prefBranch) {
+    prefBranch->AddObserver(kPrefCookieBehavior, this, PR_TRUE);
+    prefBranch->AddObserver(kPrefThirdPartySession, this, PR_TRUE);
+    PrefChanged(prefBranch);
+  }
 }
 
 CookieServiceChild::~CookieServiceChild()
 {
   gCookieService = nsnull;
 }
 
+void
+CookieServiceChild::PrefChanged(nsIPrefBranch *aPrefBranch)
+{
+  PRInt32 val;
+  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieBehavior, &val)))
+    mCookieBehavior =
+      val >= BEHAVIOR_ACCEPT && val <= BEHAVIOR_REJECT ? val : BEHAVIOR_ACCEPT;
+
+  PRBool boolval;
+  if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kPrefThirdPartySession, &boolval)))
+    mThirdPartySession = !!boolval;
+
+  if (!mThirdPartyUtil && RequireThirdPartyCheck()) {
+    mThirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
+    NS_ASSERTION(mThirdPartyUtil, "require ThirdPartyUtil service");
+  }
+}
+
+bool
+CookieServiceChild::RequireThirdPartyCheck()
+{
+  return mCookieBehavior == BEHAVIOR_REJECTFOREIGN || mThirdPartySession;
+}
+
 nsresult
 CookieServiceChild::GetCookieStringInternal(nsIURI *aHostURI,
                                             nsIChannel *aChannel,
                                             char **aCookieString,
                                             bool aFromHttp)
 {
   NS_ENSURE_ARG(aHostURI);
   NS_ENSURE_ARG_POINTER(aCookieString);
 
   *aCookieString = NULL;
 
-  // Determine the originating URI. Failure is acceptable.
-  nsCOMPtr<nsIURI> originatingURI;
-  if (!mPermissionService) {
-    NS_WARNING("nsICookiePermission unavailable! Cookie may be rejected");
-    mPermissionService->GetOriginatingURI(aChannel,
-                                          getter_AddRefs(originatingURI));
-  }
+  // Determine whether the request is foreign. Failure is acceptable.
+  PRBool isForeign = true;
+  if (RequireThirdPartyCheck())
+    mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
 
   // Synchronously call the parent.
   nsCAutoString result;
-  SendGetCookieString(IPC::URI(aHostURI), IPC::URI(originatingURI),
-                      aFromHttp, &result);
+  SendGetCookieString(IPC::URI(aHostURI), !!isForeign, 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);
 
-  // Determine the originating URI. Failure is acceptable.
-  nsCOMPtr<nsIURI> originatingURI;
-  if (!mPermissionService) {
-    NS_WARNING("nsICookiePermission unavailable! Cookie may be rejected");
-    mPermissionService->GetOriginatingURI(aChannel,
-                                          getter_AddRefs(originatingURI));
-  }
+  // Determine whether the request is foreign. Failure is acceptable.
+  PRBool isForeign = true;
+  if (RequireThirdPartyCheck())
+    mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
 
   nsDependentCString cookieString(aCookieString);
   nsDependentCString serverTime;
   if (aServerTime)
     serverTime.Rebind(aServerTime);
 
   // Synchronously call the parent.
-  SendSetCookieString(IPC::URI(aHostURI), IPC::URI(originatingURI),
+  SendSetCookieString(IPC::URI(aHostURI), !!isForeign,
                       cookieString, serverTime, aFromHttp);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+CookieServiceChild::Observe(nsISupports     *aSubject,
+                            const char      *aTopic,
+                            const PRUnichar *aData)
+{
+  NS_ASSERTION(strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0,
+               "not a pref change topic!");
+
+  nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
+  if (prefBranch)
+    PrefChanged(prefBranch);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 CookieServiceChild::GetCookieString(nsIURI *aHostURI,
                                     nsIChannel *aChannel,
                                     char **aCookieString)
 {
   return GetCookieStringInternal(aHostURI, aChannel, aCookieString, false);
 }
 
 NS_IMETHODIMP
--- a/netwerk/cookie/CookieServiceChild.h
+++ b/netwerk/cookie/CookieServiceChild.h
@@ -36,27 +36,31 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_net_CookieServiceChild_h__
 #define mozilla_net_CookieServiceChild_h__
 
 #include "mozilla/net/PCookieServiceChild.h"
 #include "nsICookieService.h"
-#include "nsICookiePermission.h"
+#include "nsIObserver.h"
+#include "nsIPrefBranch.h"
+#include "mozIThirdPartyUtil.h"
 
 namespace mozilla {
 namespace net {
 
 class CookieServiceChild : public PCookieServiceChild
                          , public nsICookieService
+                         , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICOOKIESERVICE
+  NS_DECL_NSIOBSERVER
 
   CookieServiceChild();
   virtual ~CookieServiceChild();
 
   static CookieServiceChild* GetSingleton();
 
 protected:
   void SerializeURIs(nsIURI *aHostURI,
@@ -72,16 +76,22 @@ protected:
                                    bool aFromHttp);
 
   nsresult SetCookieStringInternal(nsIURI *aHostURI,
                                    nsIChannel *aChannel,
                                    const char *aCookieString,
                                    const char *aServerTime,
                                    bool aFromHttp);
 
-  nsCOMPtr<nsICookiePermission> mPermissionService;
+  void PrefChanged(nsIPrefBranch *aPrefBranch);
+
+  bool RequireThirdPartyCheck();
+
+  nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
+  PRUint8 mCookieBehavior;
+  bool mThirdPartySession;
 };
 
 }
 }
 
 #endif // mozilla_net_CookieServiceChild_h__
 
--- a/netwerk/cookie/CookieServiceParent.cpp
+++ b/netwerk/cookie/CookieServiceParent.cpp
@@ -56,53 +56,51 @@ CookieServiceParent::CookieServiceParent
 }
 
 CookieServiceParent::~CookieServiceParent()
 {
 }
 
 bool
 CookieServiceParent::RecvGetCookieString(const IPC::URI& aHost,
-                                         const IPC::URI& aOriginating,
+                                         const bool& aIsForeign,
                                          const bool& aFromHttp,
                                          nsCString* aResult)
 {
   if (!mCookieService)
     return true;
 
-  // Deserialize URIs. Having a host URI is mandatory and should always be
+  // Deserialize URI. Having a host URI is mandatory and should always be
   // provided by the child; thus we consider failure fatal.
   nsCOMPtr<nsIURI> hostURI(aHost);
-  nsCOMPtr<nsIURI> originatingURI(aOriginating);
   if (!hostURI)
     return false;
 
-  mCookieService->GetCookieStringInternal(hostURI, originatingURI,
+  mCookieService->GetCookieStringInternal(hostURI, aIsForeign,
                                           aFromHttp, *aResult);
   return true;
 }
 
 bool
 CookieServiceParent::RecvSetCookieString(const IPC::URI& aHost,
-                                         const IPC::URI& aOriginating,
+                                         const bool& aIsForeign,
                                          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
+  // Deserialize URI. Having a host URI is mandatory and should always be
   // provided by the child; thus we consider failure fatal.
   nsCOMPtr<nsIURI> hostURI(aHost);
-  nsCOMPtr<nsIURI> originatingURI(aOriginating);
   if (!hostURI)
     return false;
 
-  mCookieService->SetCookieStringInternal(hostURI, originatingURI,
+  mCookieService->SetCookieStringInternal(hostURI, aIsForeign,
                                           aCookieString, aServerTime,
                                           aFromHttp);
   return true;
 }
 
 }
 }
 
--- a/netwerk/cookie/CookieServiceParent.h
+++ b/netwerk/cookie/CookieServiceParent.h
@@ -50,22 +50,22 @@ namespace net {
 class CookieServiceParent : public PCookieServiceParent
 {
 public:
   CookieServiceParent();
   virtual ~CookieServiceParent();
 
 protected:
   virtual bool RecvGetCookieString(const IPC::URI& aHost,
-                                   const IPC::URI& aOriginating,
+                                   const bool& aIsForeign,
                                    const bool& aFromHttp,
                                    nsCString* aResult);
 
   virtual bool RecvSetCookieString(const IPC::URI& aHost,
-                                   const IPC::URI& aOriginating,
+                                   const bool& aIsForeign,
                                    const nsCString& aCookieString,
                                    const nsCString& aServerTime,
                                    const bool& aFromHttp);
 
   nsRefPtr<nsCookieService> mCookieService;
 };
 
 }
--- a/netwerk/cookie/PCookieService.ipdl
+++ b/netwerk/cookie/PCookieService.ipdl
@@ -68,70 +68,66 @@ parent:
 
   /*
    * Get the complete cookie string associated with the URI. This is a sync
    * call in order to avoid race conditions -- for instance, an HTTP response
    * on the parent and script access on the child.
    *
    * @param host
    *        Same as the 'aURI' argument to nsICookieService.getCookieString.
-   * @param originating
-   *        The originating URI associated with the request. This is used
-   *        to determine whether the request is first or third party, for
-   *        purposes of allowing access to cookies. This should be obtained
-   *        from nsICookiePermission.getOriginatingURI. This parameter may
-   *        be null; in this case, the request is assumed to be third party
-   *        and may be rejected depending on user preferences. In
-   *        nsICookieService.getCookieString, this argument is determined
-   *        from the aChannel argument.
+   * @param isForeign
+   *        True if the the request is third party, for purposes of allowing
+   *        access to cookies. This should be obtained from
+   *        mozIThirdPartyUtil.isThirdPartyChannel. Third party requests may be
+   *        rejected depending on user preferences; if those checks are
+   *        disabled, this parameter is ignored.
    * @param fromHttp
    *        Whether the result is for an HTTP request header. This should be
    *        true for nsICookieService.getCookieStringFromHttp calls, false
    *        otherwise.
    *
    * @see nsICookieService.getCookieString
    * @see nsICookieService.getCookieStringFromHttp
-   * @see nsICookiePermission.getOriginatingURI
+   * @see mozIThirdPartyUtil.isThirdPartyChannel
    *
    * @return the resulting cookie string.
    */
   sync GetCookieString(URI host,
-                       URI originating,
+                       bool isForeign,
                        bool fromHttp)
        returns (nsCString result);
 
   /*
    * Set a cookie string.
    *
    * @param host
    *        Same as the 'aURI' argument to nsICookieService.setCookieString.
-   * @param originating
-   *        The originating URI associated with the request. This is used
-   *        to determine whether the request is first or third party, for
-   *        purposes of allowing access to cookies. This should be obtained
-   *        from nsICookiePermission.getOriginatingURI. This parameter may
-   *        be null; in this case, the request is assumed to be third party
-   *        and may be rejected depending on user preferences.
+   * @param isForeign
+   *        True if the the request is third party, for purposes of allowing
+   *        access to cookies. This should be obtained from
+   *        mozIThirdPartyUtil.isThirdPartyChannel. Third party requests may be
+   *        rejected depending on user preferences; if those checks are
+   *        disabled, this parameter is ignored.
    * @param cookieString
    *        Same as the 'aCookie' argument to nsICookieService.setCookieString.
    * @param serverTime
    *        Same as the 'aServerTime' argument to
    *        nsICookieService.setCookieStringFromHttp. If the string is empty or
    *        null (e.g. for non-HTTP requests), the current local time is used.
    * @param fromHttp
    *        Whether the result is for an HTTP request header. This should be
    *        true for nsICookieService.setCookieStringFromHttp calls, false
    *        otherwise.
    *
    * @see nsICookieService.setCookieString
    * @see nsICookieService.setCookieStringFromHttp
-   * @see nsICookiePermission.getOriginatingURI
+   * @see mozIThirdPartyUtil.isThirdPartyChannel
    */
   SetCookieString(URI host,
-                  URI originating,
+                  bool isForeign,
                   nsCString cookieString,
                   nsCString serverTime,
                   bool fromHttp);
 
   __delete__();
 };
 
 }
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -61,16 +61,17 @@
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsIChannel.h"
 #include "nsIFile.h"
 #include "nsIObserverService.h"
 #include "nsILineInputStream.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIIDNService.h"
+#include "mozIThirdPartyUtil.h"
 
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 #include "nsIMutableArray.h"
 #include "nsArrayEnumerator.h"
 #include "nsEnumeratorUtils.h"
 #include "nsAutoPtr.h"
 #include "nsReadableUtils.h"
@@ -1091,21 +1092,23 @@ nsresult
 nsCookieService::GetCookieStringCommon(nsIURI *aHostURI,
                                        nsIChannel *aChannel,
                                        bool aHttpBound,
                                        char** aCookie)
 {
   NS_ENSURE_ARG(aHostURI);
   NS_ENSURE_ARG(aCookie);
 
-  nsCOMPtr<nsIURI> originatingURI;
-  GetOriginatingURI(aChannel, getter_AddRefs(originatingURI));
+  // Determine whether the request is foreign. Failure is acceptable.
+  PRBool isForeign = true;
+  if (RequireThirdPartyCheck())
+    mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
 
   nsCAutoString result;
-  GetCookieStringInternal(aHostURI, originatingURI, aHttpBound, result);
+  GetCookieStringInternal(aHostURI, isForeign, aHttpBound, result);
   *aCookie = result.IsEmpty() ? nsnull : ToNewCString(result);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCookieService::SetCookieString(nsIURI     *aHostURI,
                                  nsIPrompt  *aPrompt,
                                  const char *aCookieHeader,
@@ -1131,29 +1134,31 @@ nsCookieService::SetCookieStringCommon(n
                                        const char *aCookieHeader,
                                        const char *aServerTime,
                                        nsIChannel *aChannel,
                                        bool aFromHttp) 
 {
   NS_ENSURE_ARG(aHostURI);
   NS_ENSURE_ARG(aCookieHeader);
 
-  nsCOMPtr<nsIURI> originatingURI;
-  GetOriginatingURI(aChannel, getter_AddRefs(originatingURI));
+  // Determine whether the request is foreign. Failure is acceptable.
+  PRBool isForeign = true;
+  if (RequireThirdPartyCheck())
+    mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
 
   nsDependentCString cookieString(aCookieHeader);
   nsDependentCString serverTime(aServerTime ? aServerTime : "");
-  SetCookieStringInternal(aHostURI, originatingURI, cookieString,
+  SetCookieStringInternal(aHostURI, isForeign, cookieString,
                           serverTime, aFromHttp);
   return NS_OK;
 }
 
 void
 nsCookieService::SetCookieStringInternal(nsIURI          *aHostURI,
-                                         nsIURI          *aOriginatingURI,
+                                         bool             aIsForeign,
                                          const nsCString &aCookieHeader,
                                          const nsCString &aServerTime,
                                          PRBool           aFromHttp) 
 {
   NS_ASSERTION(aHostURI, "null host!");
 
   // get the base domain for the host URI.
   // e.g. for "www.bbc.co.uk", this would be "bbc.co.uk".
@@ -1165,17 +1170,17 @@ nsCookieService::SetCookieStringInternal
   nsresult rv = GetBaseDomain(aHostURI, baseDomain, requireHostMatch);
   if (NS_FAILED(rv)) {
     COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, 
                       "couldn't get base domain from URI");
     return;
   }
 
   // check default prefs
-  CookieStatus cookieStatus = CheckPrefs(aHostURI, aOriginatingURI, baseDomain,
+  CookieStatus cookieStatus = CheckPrefs(aHostURI, aIsForeign, 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;
   default:
@@ -1246,16 +1251,22 @@ nsCookieService::PrefChanged(nsIPrefBran
     mMaxCookiesPerHost = (PRUint16) LIMIT(val, 1, 0xFFFF, kMaxCookiesPerHost);
 
   if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookiePurgeAge, &val)))
     mCookiePurgeAge = LIMIT(val, 0, PR_INT32_MAX, PR_INT32_MAX) * PR_USEC_PER_SEC;
 
   PRBool boolval;
   if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kPrefThirdPartySession, &boolval)))
     mThirdPartySession = boolval;
+
+  // Lazily instantiate the third party service if necessary.
+  if (!mThirdPartyUtil && RequireThirdPartyCheck()) {
+    mThirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
+    NS_ABORT_IF_FALSE(mThirdPartyUtil, "require ThirdPartyUtil service");
+  }
 }
 
 /******************************************************************************
  * nsICookieManager impl:
  * nsICookieManager
  ******************************************************************************/
 
 NS_IMETHODIMP
@@ -1879,17 +1890,17 @@ public:
     // browser!  see bug 236772.
     // note: CreationID is unique, so two id's can never be equal.
     return aCookie1->CreationID() < aCookie2->CreationID();
   }
 };
 
 void
 nsCookieService::GetCookieStringInternal(nsIURI *aHostURI,
-                                         nsIURI *aOriginatingURI,
+                                         bool aIsForeign,
                                          PRBool aHttpBound,
                                          nsCString &aCookieString)
 {
   NS_ASSERTION(aHostURI, "null host!");
 
   // 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
@@ -1906,17 +1917,17 @@ nsCookieService::GetCookieStringInternal
   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
-  CookieStatus cookieStatus = CheckPrefs(aHostURI, aOriginatingURI, baseDomain,
+  CookieStatus cookieStatus = CheckPrefs(aHostURI, aIsForeign, baseDomain,
                                          requireHostMatch, nsnull);
   // for GetCookie(), we don't fire rejection notifications.
   switch (cookieStatus) {
   case STATUS_REJECTED:
   case STATUS_REJECTED_WITH_ERROR:
     return;
   default:
     break;
@@ -2588,62 +2599,26 @@ static inline PRBool IsSubdomainOf(const
 {
   if (a == b)
     return PR_TRUE;
   if (a.Length() > b.Length())
     return a[a.Length() - b.Length() - 1] == '.' && StringEndsWith(a, b);
   return PR_FALSE;
 }
 
-PRBool
-nsCookieService::IsForeign(const nsCString &aBaseDomain,
-                           PRBool           aRequireHostMatch,
-                           nsIURI          *aFirstURI)
+bool
+nsCookieService::RequireThirdPartyCheck()
 {
-  nsCAutoString firstHost;
-  if (NS_FAILED(aFirstURI->GetAsciiHost(firstHost))) {
-    // assume foreign
-    return PR_TRUE;
-  }
-
-  // trim any trailing dot
-  if (!firstHost.IsEmpty() && firstHost.Last() == '.')
-    firstHost.Truncate(firstHost.Length() - 1);
-
-  // check whether the host is either an IP address, an alias such as
-  // 'localhost', an eTLD such as 'co.uk', or the empty string. in these
-  // cases, require an exact string match for the domain. note that the base
-  // 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 or altering the lifetime of third-party cookies.
-  if (mCookieBehavior != BEHAVIOR_REJECTFOREIGN && !mThirdPartySession)
-    return;
-
-  if (!mPermissionService) {
-    NS_WARNING("nsICookiePermission unavailable! Cookie may be rejected");
-    return;
-  }
-
-  mPermissionService->GetOriginatingURI(aChannel, aURI);
+  // 'true' iff we need to perform a third party test.
+  return mCookieBehavior == BEHAVIOR_REJECTFOREIGN || mThirdPartySession;
 }
 
 CookieStatus
 nsCookieService::CheckPrefs(nsIURI          *aHostURI,
-                            nsIURI          *aOriginatingURI,
+                            bool             aIsForeign,
                             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;
@@ -2674,26 +2649,23 @@ nsCookieService::CheckPrefs(nsIURI      
   }
 
   // check default prefs
   if (mCookieBehavior == BEHAVIOR_REJECT) {
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled");
     return STATUS_REJECTED;
   }
 
-  if (mCookieBehavior == BEHAVIOR_REJECTFOREIGN || mThirdPartySession) {
+  if (RequireThirdPartyCheck() && aIsForeign) {
     // check if cookie is foreign
-    if (!aOriginatingURI ||
-        IsForeign(aBaseDomain, aRequireHostMatch, aOriginatingURI)) {
-      if (mCookieBehavior == BEHAVIOR_ACCEPT && mThirdPartySession)
-        return STATUS_ACCEPT_SESSION;
-
-      COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "context is third party");
-      return STATUS_REJECTED;
-    }
+    if (mCookieBehavior == BEHAVIOR_ACCEPT && mThirdPartySession)
+      return STATUS_ACCEPT_SESSION;
+
+    COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "context is third party");
+    return STATUS_REJECTED;
   }
 
   // if nothing has complained, accept cookie
   return STATUS_ACCEPTED;
 }
 
 // processes domain attribute, and returns PR_TRUE if host has permission to set for this domain.
 PRBool
--- a/netwerk/cookie/nsCookieService.h
+++ b/netwerk/cookie/nsCookieService.h
@@ -63,16 +63,17 @@ class nsIEffectiveTLDService;
 class nsIIDNService;
 class nsIPrefBranch;
 class nsIObserverService;
 class nsIURI;
 class nsIChannel;
 class mozIStorageService;
 class mozIStorageStatementCallback;
 class mozIStorageCompletionCallback;
+class mozIThirdPartyUtil;
 class ReadCookieDBListener;
 
 struct nsCookieAttributes;
 struct nsListIter;
 struct nsEnumerationData;
 
 namespace mozilla {
 namespace net {
@@ -224,43 +225,43 @@ class nsCookieService : public nsICookie
     void                          CancelAsyncRead(PRBool aPurgeReadSet);
     mozIStorageConnection*        GetSyncDBConn();
     void                          EnsureReadDomain(const nsCString &aBaseDomain);
     void                          EnsureReadComplete();
     nsresult                      NormalizeHost(nsCString &aHost);
     nsresult                      GetBaseDomain(nsIURI *aHostURI, nsCString &aBaseDomain, PRBool &aRequireHostMatch);
     nsresult                      GetBaseDomainFromHost(const nsACString &aHost, nsCString &aBaseDomain);
     nsresult                      GetCookieStringCommon(nsIURI *aHostURI, nsIChannel *aChannel, bool aHttpBound, char** aCookie);
-    void                          GetCookieStringInternal(nsIURI *aHostURI, nsIURI *aOriginatingURI, PRBool aHttpBound, nsCString &aCookie);
+    void                          GetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, PRBool aHttpBound, nsCString &aCookie);
     nsresult                      SetCookieStringCommon(nsIURI *aHostURI, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, bool aFromHttp);
-    void                          SetCookieStringInternal(nsIURI *aHostURI, nsIURI *aOriginatingURI, const nsCString &aCookieHeader, const nsCString &aServerTime, PRBool aFromHttp);
+    void                          SetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, const nsCString &aCookieHeader, const nsCString &aServerTime, PRBool aFromHttp);
     PRBool                        SetCookieInternal(nsIURI *aHostURI, const nsCString& aBaseDomain, PRBool aRequireHostMatch, CookieStatus aStatus, nsDependentCString &aCookieHeader, PRInt64 aServerTime, PRBool aFromHttp);
     void                          AddInternal(const nsCString& aBaseDomain, nsCookie *aCookie, PRInt64 aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, PRBool aFromHttp);
     void                          RemoveCookieFromList(const nsListIter &aIter, mozIStorageBindingParamsArray *aParamsArray = NULL);
     void                          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);
-    void                          GetOriginatingURI(nsIChannel *aChannel, nsIURI **aURI);
-    CookieStatus                  CheckPrefs(nsIURI *aHostURI, nsIURI *aOriginatingURI, const nsCString &aBaseDomain, PRBool aRequireHostMatch, const char *aCookieHeader);
+    bool                          RequireThirdPartyCheck();
+    CookieStatus                  CheckPrefs(nsIURI *aHostURI, bool aIsForeign, 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);
     void                          NotifyChanged(nsISupports *aSubject, const PRUnichar *aData);
 
   protected:
     // cached members.
     nsCOMPtr<nsIObserverService>     mObserverService;
     nsCOMPtr<nsICookiePermission>    mPermissionService;
+    nsCOMPtr<mozIThirdPartyUtil>     mThirdPartyUtil;
     nsCOMPtr<nsIEffectiveTLDService> mTLDService;
     nsCOMPtr<nsIIDNService>          mIDNService;
     nsCOMPtr<mozIStorageService>     mStorageService;
 
     // we have two separate DB states: one for normal browsing and one for
     // private browsing, switching between them as appropriate. this state
     // encapsulates both the in-memory table and the on-disk DB.
     // note that the private states' dbConn should always be null - we never
--- a/netwerk/cookie/nsICookiePermission.idl
+++ b/netwerk/cookie/nsICookiePermission.idl
@@ -137,16 +137,18 @@ interface nsICookiePermission : nsISuppo
    * find the root content docshell, and the URI associated with its principal.
    * if the root content docshell or its principal's URI cannot be obtained,
    * this method will throw.
    *
    * @param aChannel
    *        the channel for the load trying to get or set cookies
    *
    * @return the originating URI.
+   *
+   * @status DEPRECATED -- use mozIThirdPartyUtil instead.
    */
   nsIURI getOriginatingURI(in nsIChannel aChannel);
 };
 
 %{ C++
 /**
  * The nsICookiePermission implementation is an XPCOM service registered
  * under the ContractID: