Bug 595305 - Factor cookie third-party URI code into separate API. r=bent, a=betaN+

This commit is contained in:
Dan Witte 2010-10-19 09:37:03 -07:00
Родитель 49745c22d6
Коммит f90d6cec5d
15 изменённых файлов: 705 добавлений и 117 удалений

Просмотреть файл

@ -328,4 +328,8 @@
#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__ */

Просмотреть файл

@ -148,6 +148,7 @@ CPPSRCS = \
nsFileDataProtocolHandler.cpp \
nsFrameMessageManager.cpp \
nsInProcessTabChildGlobal.cpp \
ThirdPartyUtil.cpp \
$(NULL)
GQI_SRCS = contentbase.gqi

Просмотреть файл

@ -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);
}

Просмотреть файл

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

Просмотреть файл

@ -97,6 +97,7 @@
#include "nsXULPopupManager.h"
#include "nsFocusManager.h"
#include "nsIContentUtils.h"
#include "ThirdPartyUtil.h"
#include "mozilla/Services.h"
#include "nsIEventListenerService.h"
@ -331,6 +332,7 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(IndexedDatabaseManager,
defined(android)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAccelerometerSystem)
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ThirdPartyUtil, Init)
//-----------------------------------------------------------------------------
@ -883,6 +885,7 @@ 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) || \
@ -1039,6 +1042,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
defined(android)
{ &kNS_ACCELEROMETER_CID, false, NULL, nsAccelerometerSystemConstructor },
#endif
{ &kTHIRDPARTYUTIL_CID, false, NULL, ThirdPartyUtilConstructor },
{ NULL }
};
@ -1184,6 +1188,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
defined(android)
{ NS_ACCELEROMETER_CONTRACTID, &kNS_ACCELEROMETER_CID },
#endif
{ THIRDPARTYUTIL_CONTRACTID, &kTHIRDPARTYUTIL_CID },
{ NULL }
};

Просмотреть файл

@ -141,6 +141,7 @@ XPIDLSRCS = \
nsIURIWithPrincipal.idl \
nsIURIClassifier.idl \
nsIRedirectResultListener.idl \
mozIThirdPartyUtil.idl \
$(NULL)
ifdef MOZ_TOOLKIT_SEARCH

Просмотреть файл

@ -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"
%}

Просмотреть файл

@ -39,10 +39,22 @@
#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*
@ -55,9 +67,11 @@ CookieServiceChild::GetSingleton()
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");
@ -68,9 +82,15 @@ CookieServiceChild::CookieServiceChild()
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()
@ -78,6 +98,30 @@ 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,
@ -89,18 +133,14 @@ CookieServiceChild::GetCookieStringInternal(nsIURI *aHostURI,
*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);
@ -117,13 +157,10 @@ CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
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;
@ -131,11 +168,25 @@ CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
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,

Просмотреть файл

@ -41,17 +41,21 @@
#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();
@ -77,7 +81,13 @@ protected:
const char *aServerTime,
bool aFromHttp);
nsCOMPtr<nsICookiePermission> mPermissionService;
void PrefChanged(nsIPrefBranch *aPrefBranch);
bool RequireThirdPartyCheck();
nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
PRUint8 mCookieBehavior;
bool mThirdPartySession;
};
}

Просмотреть файл

@ -61,28 +61,27 @@ 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)
@ -90,14 +89,13 @@ CookieServiceParent::RecvSetCookieString(const IPC::URI& aHost,
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;

Просмотреть файл

@ -55,12 +55,12 @@ public:
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);

Просмотреть файл

@ -73,15 +73,12 @@ parent:
*
* @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
@ -89,12 +86,12 @@ parent:
*
* @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);
@ -103,13 +100,12 @@ parent:
*
* @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
@ -123,10 +119,10 @@ parent:
*
* @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);

Просмотреть файл

@ -66,6 +66,7 @@
#include "nsILineInputStream.h"
#include "nsIEffectiveTLDService.h"
#include "nsIIDNService.h"
#include "mozIThirdPartyUtil.h"
#include "nsTArray.h"
#include "nsCOMArray.h"
@ -1096,11 +1097,13 @@ nsCookieService::GetCookieStringCommon(nsIURI *aHostURI,
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;
}
@ -1136,19 +1139,21 @@ nsCookieService::SetCookieStringCommon(nsIURI *aHostURI,
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)
@ -1170,7 +1175,7 @@ nsCookieService::SetCookieStringInternal(nsIURI *aHostURI,
}
// 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) {
@ -1251,6 +1256,12 @@ nsCookieService::PrefChanged(nsIPrefBranch *aPrefBranch)
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");
}
}
/******************************************************************************
@ -1884,7 +1895,7 @@ public:
void
nsCookieService::GetCookieStringInternal(nsIURI *aHostURI,
nsIURI *aOriginatingURI,
bool aIsForeign,
PRBool aHttpBound,
nsCString &aCookieString)
{
@ -1911,7 +1922,7 @@ nsCookieService::GetCookieStringInternal(nsIURI *aHostURI,
}
// 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) {
@ -2593,52 +2604,16 @@ static inline PRBool IsSubdomainOf(const nsCString &a, const nsCString &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)
@ -2679,16 +2654,13 @@ nsCookieService::CheckPrefs(nsIURI *aHostURI,
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;
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;
}
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "context is third party");
return STATUS_REJECTED;
}
// if nothing has complained, accept cookie

Просмотреть файл

@ -68,6 +68,7 @@ class nsIChannel;
class mozIStorageService;
class mozIStorageStatementCallback;
class mozIStorageCompletionCallback;
class mozIThirdPartyUtil;
class ReadCookieDBListener;
struct nsCookieAttributes;
@ -229,9 +230,9 @@ class nsCookieService : public nsICookieService
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);
@ -239,9 +240,8 @@ class nsCookieService : public nsICookieService
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);
@ -256,6 +256,7 @@ class nsCookieService : public nsICookieService
// cached members.
nsCOMPtr<nsIObserverService> mObserverService;
nsCOMPtr<nsICookiePermission> mPermissionService;
nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
nsCOMPtr<nsIEffectiveTLDService> mTLDService;
nsCOMPtr<nsIIDNService> mIDNService;
nsCOMPtr<mozIStorageService> mStorageService;

Просмотреть файл

@ -142,6 +142,8 @@ interface nsICookiePermission : nsISupports
* 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);
};