/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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 "nsGlobalWindowOuter.h" #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsIChannel.h" #include "nsIServiceManager.h" #include "nsIHttpChannelInternal.h" #include "nsIDOMWindow.h" #include "nsILoadContext.h" #include "nsIPrincipal.h" #include "nsIScriptObjectPrincipal.h" #include "nsIURI.h" #include "nsReadableUtils.h" #include "nsThreadUtils.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/dom/Document.h" #include "mozilla/Logging.h" #include "mozilla/StaticPtr.h" #include "mozilla/Unused.h" #include "nsGlobalWindowOuter.h" NS_IMPL_ISUPPORTS(ThirdPartyUtil, mozIThirdPartyUtil) // // MOZ_LOG=thirdPartyUtil:5 // static mozilla::LazyLogModule gThirdPartyLog("thirdPartyUtil"); #undef LOG #define LOG(args) MOZ_LOG(gThirdPartyLog, mozilla::LogLevel::Debug, args) static mozilla::StaticRefPtr gService; // static void ThirdPartyUtil::Startup() { nsCOMPtr tpu; if (NS_WARN_IF(!(tpu = do_GetService(THIRDPARTYUTIL_CONTRACTID)))) { NS_WARNING("Failed to get third party util!"); } } nsresult ThirdPartyUtil::Init() { NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_AVAILABLE); MOZ_ASSERT(!gService); gService = this; mozilla::ClearOnShutdown(&gService); mTLDService = nsEffectiveTLDService::GetInstance(); return mTLDService ? NS_OK : NS_ERROR_FAILURE; } ThirdPartyUtil::~ThirdPartyUtil() { gService = nullptr; } // static ThirdPartyUtil* ThirdPartyUtil::GetInstance() { if (gService) { return gService; } nsCOMPtr tpuService = mozilla::services::GetThirdPartyUtil(); if (!tpuService) { return nullptr; } MOZ_ASSERT( gService, "gService must have been initialized in nsEffectiveTLDService::Init"); return gService; } // 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) { if (!aSecondURI) { return NS_ERROR_INVALID_ARG; } // Get the base domain for aSecondURI. nsAutoCString secondDomain; nsresult rv = GetBaseDomain(aSecondURI, secondDomain); LOG(("ThirdPartyUtil::IsThirdPartyInternal %s =? %s", aFirstDomain.get(), secondDomain.get())); if (NS_FAILED(rv)) return rv; *aResult = IsThirdPartyInternal(aFirstDomain, secondDomain); return NS_OK; } nsCString ThirdPartyUtil::GetBaseDomainFromWindow(nsPIDOMWindowOuter* aWindow) { mozilla::dom::Document* doc = aWindow ? aWindow->GetExtantDoc() : nullptr; if (!doc) { return EmptyCString(); } return doc->GetBaseDomain(); } NS_IMETHODIMP ThirdPartyUtil::GetPrincipalFromWindow(mozIDOMWindowProxy* aWin, nsIPrincipal** result) { nsCOMPtr scriptObjPrin = do_QueryInterface(aWin); if (!scriptObjPrin) { return NS_ERROR_INVALID_ARG; } nsCOMPtr prin = scriptObjPrin->GetPrincipal(); if (!prin) { return NS_ERROR_INVALID_ARG; } prin.forget(result); return NS_OK; } // Get the URI associated with a window. NS_IMETHODIMP ThirdPartyUtil::GetURIFromWindow(mozIDOMWindowProxy* aWin, nsIURI** result) { nsCOMPtr prin; nsresult rv = GetPrincipalFromWindow(aWin, getter_AddRefs(prin)); if (NS_FAILED(rv)) { return rv; } if (prin->GetIsNullPrincipal()) { LOG(("ThirdPartyUtil::GetURIFromWindow can't use null principal\n")); return NS_ERROR_INVALID_ARG; } rv = prin->GetURI(result); return rv; } // 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"); nsAutoCString 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(mozIDOMWindowProxy* aWindow, nsIURI* aURI, bool* aResult) { NS_ENSURE_ARG(aWindow); NS_ASSERTION(aResult, "null outparam pointer"); bool result; nsCString bottomDomain = GetBaseDomainFromWindow(nsPIDOMWindowOuter::From(aWindow)); if (bottomDomain.IsEmpty()) { // We may have an about:blank window here. Fall back to the slower code // path which is principal aware. nsCOMPtr currentURI; nsresult rv = GetURIFromWindow(aWindow, getter_AddRefs(currentURI)); if (NS_FAILED(rv)) { return rv; } rv = GetBaseDomain(currentURI, bottomDomain); if (NS_FAILED(rv)) { return rv; } } // Ignore about:blank URIs here since they have no domain and attempting to // compare against them will fail. if (aURI && !NS_IsAboutBlank(aURI)) { // Determine whether aURI is foreign with respect to currentURI. nsresult rv = IsThirdPartyInternal(bottomDomain, aURI, &result); if (NS_FAILED(rv)) return rv; if (result) { *aResult = true; return NS_OK; } } nsPIDOMWindowOuter* current = nsPIDOMWindowOuter::From(aWindow); do { // We use GetScriptableParent rather than GetParent because we consider //