--- 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: