diff -r 000000000000 -r 6474c204b198 content/base/src/ThirdPartyUtil.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/base/src/ThirdPartyUtil.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,628 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ThirdPartyUtil.h" +#include "mozilla/Preferences.h" +#include "nsNetUtil.h" +#include "nsIServiceManager.h" +#include "nsIHttpChannelInternal.h" +#include "nsIDOMWindow.h" +#include "nsICookiePermission.h" +#include "nsIDOMDocument.h" +#include "nsIDocument.h" +#include "nsILoadContext.h" +#include "nsIPrincipal.h" +#include "nsIScriptObjectPrincipal.h" +#include "nsThreadUtils.h" +#include "nsPrintfCString.h" +#include "nsIConsoleService.h" +#include "nsContentUtils.h" + +NS_IMPL_ISUPPORTS(ThirdPartyUtil, mozIThirdPartyUtil) + +nsresult +ThirdPartyUtil::Init() +{ + NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_AVAILABLE); + + nsresult rv; + mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv); + mCookiePermissions = do_GetService(NS_COOKIEPERMISSION_CONTRACTID); + return rv; +} + +// 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, + bool* 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; +} + +// Return true if aURI's scheme is white listed, in which case +// getFirstPartyURI() will not require that the firstPartyURI contains a host. +bool ThirdPartyUtil::SchemeIsWhiteListed(nsIURI *aURI) +{ + if (!aURI) + return false; + + nsAutoCString scheme; + nsresult rv = aURI->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, false); + + return (scheme.Equals("about") || scheme.Equals("moz-safe-about") + || scheme.Equals("chrome")); +} + +// Get the URI associated with a window. +already_AddRefed +ThirdPartyUtil::GetURIFromWindow(nsIDOMWindow* aWin) +{ + nsCOMPtr scriptObjPrin = do_QueryInterface(aWin); + NS_ENSURE_TRUE(scriptObjPrin, nullptr); + + nsIPrincipal* prin = scriptObjPrin->GetPrincipal(); + NS_ENSURE_TRUE(prin, nullptr); + + nsCOMPtr result; + prin->GetURI(getter_AddRefs(result)); + return result.forget(); +} + + +nsresult +ThirdPartyUtil::GetOriginatingURI(nsIChannel *aChannel, nsIURI **aURI) +{ + /* to find the originating URI, we use the loadgroup of the channel to obtain + * the window owning the load, and from there, we find the top same-type + * window and its URI. there are several possible cases: + * + * 1) no channel. + * + * 2) a channel with the "force allow third party cookies" option set. + * since we may not have a window, we return the channel URI in this case. + * + * 3) a channel, but no window. this can occur when the consumer kicking + * off the load doesn't provide one to the channel, and should be limited + * to loads of certain types of resources. + * + * 4) a window equal to the top window of same type, with the channel its + * document channel. 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. we return the channel URI in this case. + * + * 5) Anything else. this covers most cases for an ordinary page load from + * the location bar, and will catch nested frames within a page, image + * loads, etc. we return the URI of the root window's document's principal + * in this case. + */ + + *aURI = nullptr; + + // case 1) + if (!aChannel) + return NS_ERROR_NULL_POINTER; + + // case 2) + nsCOMPtr httpChannelInternal = do_QueryInterface(aChannel); + if (httpChannelInternal) + { + bool doForce = false; + if (NS_SUCCEEDED(httpChannelInternal->GetForceAllowThirdPartyCookie(&doForce)) && doForce) + { + // return the channel's URI (we may not have a window) + aChannel->GetURI(aURI); + if (!*aURI) + return NS_ERROR_NULL_POINTER; + + return NS_OK; + } + + // TODO: Why don't we just use this here: + // httpChannelInternal->GetDocumentURI(aURI); + } + + // find the associated window and its top window + nsCOMPtr ctx; + NS_QueryNotificationCallbacks(aChannel, ctx); + nsCOMPtr topWin, ourWin; + if (ctx) { + ctx->GetTopWindow(getter_AddRefs(topWin)); + ctx->GetAssociatedWindow(getter_AddRefs(ourWin)); + } + + // case 3) + if (!topWin) + return NS_ERROR_INVALID_ARG; + + // case 4) + if (ourWin == topWin) { + // Check whether this is the document channel for this window (representing + // a load of a new page). This is a bit of a nasty hack, but we will + // hopefully flag these channels better later. + nsLoadFlags flags; + aChannel->GetLoadFlags(&flags); + + if (flags & nsIChannel::LOAD_DOCUMENT_URI) { + // get the channel URI - the window's will be bogus + aChannel->GetURI(aURI); + if (!*aURI) + return NS_ERROR_NULL_POINTER; + + return NS_OK; + } + } + + // case 5) - get the originating URI from the top window's principal + nsCOMPtr scriptObjPrin = do_QueryInterface(topWin); + NS_ENSURE_TRUE(scriptObjPrin, NS_ERROR_UNEXPECTED); + + nsIPrincipal* prin = scriptObjPrin->GetPrincipal(); + NS_ENSURE_TRUE(prin, NS_ERROR_UNEXPECTED); + + prin->GetURI(aURI); + + if (!*aURI) + return NS_ERROR_NULL_POINTER; + + // all done! + return NS_OK; +} + + +// Determine if aFirstURI is third party with respect to aSecondURI. See docs +// for mozIThirdPartyUtil. +NS_IMETHODIMP +ThirdPartyUtil::IsThirdPartyURI(nsIURI* aFirstURI, + nsIURI* aSecondURI, + bool* 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, + bool* aResult) +{ + NS_ENSURE_ARG(aWindow); + NS_ASSERTION(aResult, "null outparam pointer"); + + bool result; + + // Get the URI of the window, and its base domain. + nsCOMPtr 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 current = aWindow, parent; + nsCOMPtr parentURI; + do { + // We use GetScriptableParent rather than GetParent because we consider + //