author | Dan Witte <dwitte@mozilla.com> |
Tue, 19 Oct 2010 09:37:03 -0700 | |
changeset 56094 | 56815e37d436bad9a337bd9726c5d6754cfeea69 |
parent 56093 | 9926aff395c1ba654059c0f5281a87eee9b8009a |
child 56095 | d35efa6966ac87245fe35442460a19f5f786e1a7 |
push id | 16406 |
push user | dwitte@mozilla.com |
push date | Tue, 19 Oct 2010 16:47:14 +0000 |
treeherder | mozilla-central@d35efa6966ac [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bent, betaN |
bugs | 595305 |
milestone | 2.0b8pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- 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: