LCOV - code coverage report
Current view: top level - dom/base - ThirdPartyUtil.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 103 136 75.7 %
Date: 2017-07-14 16:53:18 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "ThirdPartyUtil.h"
       8             : #include "nsNetCID.h"
       9             : #include "nsNetUtil.h"
      10             : #include "nsIChannel.h"
      11             : #include "nsIServiceManager.h"
      12             : #include "nsIHttpChannelInternal.h"
      13             : #include "nsIDOMWindow.h"
      14             : #include "nsILoadContext.h"
      15             : #include "nsIPrincipal.h"
      16             : #include "nsIScriptObjectPrincipal.h"
      17             : #include "nsIURI.h"
      18             : #include "nsThreadUtils.h"
      19             : #include "mozilla/Logging.h"
      20             : #include "nsPIDOMWindow.h"
      21             : 
      22         286 : NS_IMPL_ISUPPORTS(ThirdPartyUtil, mozIThirdPartyUtil)
      23             : 
      24             : //
      25             : // MOZ_LOG=thirdPartyUtil:5
      26             : //
      27             : static mozilla::LazyLogModule gThirdPartyLog("thirdPartyUtil");
      28             : #undef LOG
      29             : #define LOG(args)     MOZ_LOG(gThirdPartyLog, mozilla::LogLevel::Debug, args)
      30             : 
      31             : nsresult
      32           2 : ThirdPartyUtil::Init()
      33             : {
      34           2 :   NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_AVAILABLE);
      35             : 
      36             :   nsresult rv;
      37           2 :   mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
      38             : 
      39           2 :   return rv;
      40             : }
      41             : 
      42             : // Determine if aFirstDomain is a different base domain to aSecondURI; or, if
      43             : // the concept of base domain does not apply, determine if the two hosts are not
      44             : // string-identical.
      45             : nsresult
      46          14 : ThirdPartyUtil::IsThirdPartyInternal(const nsCString& aFirstDomain,
      47             :                                      nsIURI* aSecondURI,
      48             :                                      bool* aResult)
      49             : {
      50          14 :   if (!aSecondURI) {
      51           3 :     return NS_ERROR_INVALID_ARG;
      52             :   }
      53             : 
      54             :   // Get the base domain for aSecondURI.
      55          22 :   nsCString secondDomain;
      56          11 :   nsresult rv = GetBaseDomain(aSecondURI, secondDomain);
      57          11 :   LOG(("ThirdPartyUtil::IsThirdPartyInternal %s =? %s", aFirstDomain.get(), secondDomain.get()));
      58          11 :   if (NS_FAILED(rv))
      59           0 :     return rv;
      60             : 
      61             :   // Check strict equality.
      62          11 :   *aResult = aFirstDomain != secondDomain;
      63          11 :   return NS_OK;
      64             : }
      65             : 
      66             : // Get the URI associated with a window.
      67             : NS_IMETHODIMP
      68          59 : ThirdPartyUtil::GetURIFromWindow(mozIDOMWindowProxy* aWin, nsIURI** result)
      69             : {
      70             :   nsresult rv;
      71         118 :   nsCOMPtr<nsIScriptObjectPrincipal> scriptObjPrin = do_QueryInterface(aWin);
      72          59 :   if (!scriptObjPrin) {
      73           0 :     return NS_ERROR_INVALID_ARG;
      74             :   }
      75             : 
      76          59 :   nsIPrincipal* prin = scriptObjPrin->GetPrincipal();
      77          59 :   if (!prin) {
      78           0 :     return NS_ERROR_INVALID_ARG;
      79             :   }
      80             : 
      81          59 :   if (prin->GetIsNullPrincipal()) {
      82           1 :     LOG(("ThirdPartyUtil::GetURIFromWindow can't use null principal\n"));
      83           1 :     return NS_ERROR_INVALID_ARG;
      84             :   }
      85             : 
      86          58 :   rv = prin->GetURI(result);
      87          58 :   return rv;
      88             : }
      89             : 
      90             : // Determine if aFirstURI is third party with respect to aSecondURI. See docs
      91             : // for mozIThirdPartyUtil.
      92             : NS_IMETHODIMP
      93           3 : ThirdPartyUtil::IsThirdPartyURI(nsIURI* aFirstURI,
      94             :                                 nsIURI* aSecondURI,
      95             :                                 bool* aResult)
      96             : {
      97           3 :   NS_ENSURE_ARG(aFirstURI);
      98           3 :   NS_ENSURE_ARG(aSecondURI);
      99           2 :   NS_ASSERTION(aResult, "null outparam pointer");
     100             : 
     101           4 :   nsCString firstHost;
     102           2 :   nsresult rv = GetBaseDomain(aFirstURI, firstHost);
     103           2 :   if (NS_FAILED(rv))
     104           0 :     return rv;
     105             : 
     106           2 :   return IsThirdPartyInternal(firstHost, aSecondURI, aResult);
     107             : }
     108             : 
     109             : // Determine if any URI of the window hierarchy of aWindow is foreign with
     110             : // respect to aSecondURI. See docs for mozIThirdPartyUtil.
     111             : NS_IMETHODIMP
     112          55 : ThirdPartyUtil::IsThirdPartyWindow(mozIDOMWindowProxy* aWindow,
     113             :                                    nsIURI* aURI,
     114             :                                    bool* aResult)
     115             : {
     116          55 :   NS_ENSURE_ARG(aWindow);
     117          55 :   NS_ASSERTION(aResult, "null outparam pointer");
     118             : 
     119             :   bool result;
     120             : 
     121             :   // Get the URI of the window, and its base domain.
     122             :   nsresult rv;
     123         110 :   nsCOMPtr<nsIURI> currentURI;
     124          55 :   rv = GetURIFromWindow(aWindow, getter_AddRefs(currentURI));
     125          55 :   if (NS_FAILED(rv))
     126           0 :     return rv;
     127             : 
     128         110 :   nsCString bottomDomain;
     129          55 :   rv = GetBaseDomain(currentURI, bottomDomain);
     130          55 :   if (NS_FAILED(rv))
     131          50 :     return rv;
     132             : 
     133           5 :   if (aURI) {
     134             :     // Determine whether aURI is foreign with respect to currentURI.
     135           0 :     rv = IsThirdPartyInternal(bottomDomain, aURI, &result);
     136           0 :     if (NS_FAILED(rv))
     137           0 :       return rv;
     138             : 
     139           0 :     if (result) {
     140           0 :       *aResult = true;
     141           0 :       return NS_OK;
     142             :     }
     143             :   }
     144             : 
     145          10 :   nsCOMPtr<nsPIDOMWindowOuter> current = nsPIDOMWindowOuter::From(aWindow), parent;
     146          10 :   nsCOMPtr<nsIURI> parentURI;
     147             :   do {
     148             :     // We use GetScriptableParent rather than GetParent because we consider
     149             :     // <iframe mozbrowser> to be a top-level frame.
     150           5 :     parent = current->GetScriptableParent();
     151           5 :     if (SameCOMIdentity(parent, current)) {
     152             :       // We're at the topmost content window. We already know the answer.
     153           5 :       *aResult = false;
     154           5 :       return NS_OK;
     155             :     }
     156             : 
     157           0 :     rv = GetURIFromWindow(parent, getter_AddRefs(parentURI));
     158           0 :     NS_ENSURE_SUCCESS(rv, rv);
     159             : 
     160           0 :     rv = IsThirdPartyInternal(bottomDomain, parentURI, &result);
     161           0 :     if (NS_FAILED(rv))
     162           0 :       return rv;
     163             : 
     164           0 :     if (result) {
     165           0 :       *aResult = true;
     166           0 :       return NS_OK;
     167             :     }
     168             : 
     169           0 :     current = parent;
     170           0 :     currentURI = parentURI;
     171             :   } while (1);
     172             : 
     173             :   NS_NOTREACHED("should've returned");
     174             :   return NS_ERROR_UNEXPECTED;
     175             : }
     176             : 
     177             : // Determine if the URI associated with aChannel or any URI of the window
     178             : // hierarchy associated with the channel is foreign with respect to aSecondURI.
     179             : // See docs for mozIThirdPartyUtil.
     180             : NS_IMETHODIMP
     181           9 : ThirdPartyUtil::IsThirdPartyChannel(nsIChannel* aChannel,
     182             :                                     nsIURI* aURI,
     183             :                                     bool* aResult)
     184             : {
     185           9 :   LOG(("ThirdPartyUtil::IsThirdPartyChannel [channel=%p]", aChannel));
     186           9 :   NS_ENSURE_ARG(aChannel);
     187           9 :   NS_ASSERTION(aResult, "null outparam pointer");
     188             : 
     189             :   nsresult rv;
     190           9 :   bool doForce = false;
     191             :   nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
     192          18 :     do_QueryInterface(aChannel);
     193           9 :   if (httpChannelInternal) {
     194             :     uint32_t flags;
     195           9 :     rv = httpChannelInternal->GetThirdPartyFlags(&flags);
     196           9 :     NS_ENSURE_SUCCESS(rv, rv);
     197             : 
     198           9 :     doForce = (flags & nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
     199             : 
     200             :     // If aURI was not supplied, and we're forcing, then we're by definition
     201             :     // not foreign. If aURI was supplied, we still want to check whether it's
     202             :     // foreign with respect to the channel URI. (The forcing only applies to
     203             :     // whatever window hierarchy exists above the channel.)
     204           9 :     if (doForce && !aURI) {
     205           0 :       *aResult = false;
     206           0 :       return NS_OK;
     207             :     }
     208             :   }
     209             : 
     210           9 :   bool parentIsThird = false;
     211             : 
     212             :   // Obtain the URI from the channel, and its base domain.
     213          18 :   nsCOMPtr<nsIURI> channelURI;
     214           9 :   rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
     215           9 :   if (NS_FAILED(rv))
     216           0 :     return rv;
     217             : 
     218          18 :   nsCString channelDomain;
     219           9 :   rv = GetBaseDomain(channelURI, channelDomain);
     220           9 :   if (NS_FAILED(rv))
     221           0 :     return rv;
     222             : 
     223           9 :   if (!doForce) {
     224          15 :     if (nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo()) {
     225           9 :       parentIsThird = loadInfo->GetIsInThirdPartyContext();
     226          18 :       if (!parentIsThird &&
     227           9 :           loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) {
     228             :         // Check if the channel itself is third-party to its own requestor.
     229             :         // Unforunately, we have to go through the loading principal.
     230          13 :         nsCOMPtr<nsIURI> parentURI;
     231           8 :         loadInfo->LoadingPrincipal()->GetURI(getter_AddRefs(parentURI));
     232           8 :         rv = IsThirdPartyInternal(channelDomain, parentURI, &parentIsThird);
     233           8 :         if (NS_FAILED(rv))
     234           3 :           return rv;
     235             :       }
     236             :     } else {
     237           0 :       NS_WARNING("Found channel with no loadinfo, assuming third-party request");
     238           0 :       parentIsThird = true;
     239             :     }
     240             :   }
     241             : 
     242             :   // If we're not comparing to a URI, we have our answer. Otherwise, if
     243             :   // parentIsThird, we're not forcing and we know that we're a third-party
     244             :   // request.
     245           6 :   if (!aURI || parentIsThird) {
     246           2 :     *aResult = parentIsThird;
     247           2 :     return NS_OK;
     248             :   }
     249             : 
     250             :   // Determine whether aURI is foreign with respect to channelURI.
     251           4 :   return IsThirdPartyInternal(channelDomain, aURI, aResult);
     252             : }
     253             : 
     254             : NS_IMETHODIMP
     255           5 : ThirdPartyUtil::GetTopWindowForChannel(nsIChannel* aChannel, mozIDOMWindowProxy** aWin)
     256             : {
     257           5 :   NS_ENSURE_ARG(aWin);
     258             : 
     259             :   // Find the associated window and its parent window.
     260          10 :   nsCOMPtr<nsILoadContext> ctx;
     261           5 :   NS_QueryNotificationCallbacks(aChannel, ctx);
     262           5 :   if (!ctx) {
     263           0 :     return NS_ERROR_INVALID_ARG;
     264             :   }
     265             : 
     266          10 :   nsCOMPtr<mozIDOMWindowProxy> window;
     267           5 :   ctx->GetAssociatedWindow(getter_AddRefs(window));
     268           5 :   if (!window) {
     269           1 :     return NS_ERROR_INVALID_ARG;
     270             :   }
     271             : 
     272           8 :   nsCOMPtr<nsPIDOMWindowOuter> top = nsPIDOMWindowOuter::From(window)->GetTop();
     273           4 :   top.forget(aWin);
     274           4 :   return NS_OK;
     275             : }
     276             : 
     277             : // Get the base domain for aHostURI; e.g. for "www.bbc.co.uk", this would be
     278             : // "bbc.co.uk". Only properly-formed URI's are tolerated, though a trailing
     279             : // dot may be present. If aHostURI is an IP address, an alias such as
     280             : // 'localhost', an eTLD such as 'co.uk', or the empty string, aBaseDomain will
     281             : // be the exact host. The result of this function should only be used in exact
     282             : // string comparisons, since substring comparisons will not be valid for the
     283             : // special cases elided above.
     284             : NS_IMETHODIMP
     285         100 : ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI,
     286             :                               nsACString& aBaseDomain)
     287             : {
     288         100 :   if (!aHostURI) {
     289          50 :     return NS_ERROR_INVALID_ARG;
     290             :   }
     291             : 
     292             :   // Get the base domain. this will fail if the host contains a leading dot,
     293             :   // more than one trailing dot, or is otherwise malformed.
     294          50 :   nsresult rv = mTLDService->GetBaseDomain(aHostURI, 0, aBaseDomain);
     295          50 :   if (rv == NS_ERROR_HOST_IS_IP_ADDRESS ||
     296             :       rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
     297             :     // aHostURI is either an IP address, an alias such as 'localhost', an eTLD
     298             :     // such as 'co.uk', or the empty string. Uses the normalized host in such
     299             :     // cases.
     300          50 :     rv = aHostURI->GetAsciiHost(aBaseDomain);
     301             :   }
     302          50 :   NS_ENSURE_SUCCESS(rv, rv);
     303             : 
     304             :   // aHostURI (and thus aBaseDomain) may be the string '.'. If so, fail.
     305          50 :   if (aBaseDomain.Length() == 1 && aBaseDomain.Last() == '.')
     306           0 :     return NS_ERROR_INVALID_ARG;
     307             : 
     308             :   // Reject any URIs without a host that aren't file:// URIs. This makes it the
     309             :   // only way we can get a base domain consisting of the empty string, which
     310             :   // means we can safely perform foreign tests on such URIs where "not foreign"
     311             :   // means "the involved URIs are all file://".
     312          50 :   if (aBaseDomain.IsEmpty()) {
     313           0 :     bool isFileURI = false;
     314           0 :     aHostURI->SchemeIs("file", &isFileURI);
     315           0 :     if (!isFileURI) {
     316           0 :      return NS_ERROR_INVALID_ARG;
     317             :     }
     318             :   }
     319             : 
     320          50 :   return NS_OK;
     321             : }

Generated by: LCOV version 1.13