LCOV - code coverage report
Current view: directory - content/base/src - ThirdPartyUtil.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 117 57 48.7 %
Date: 2012-06-02 Functions: 10 8 80.0 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is third party utility code.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * the Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Daniel Witte (dwitte@mozilla.com)
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "ThirdPartyUtil.h"
      39                 : #include "nsNetUtil.h"
      40                 : #include "nsIServiceManager.h"
      41                 : #include "nsIHttpChannelInternal.h"
      42                 : #include "nsIDOMWindow.h"
      43                 : #include "nsILoadContext.h"
      44                 : #include "nsIPrincipal.h"
      45                 : #include "nsIScriptObjectPrincipal.h"
      46                 : #include "nsThreadUtils.h"
      47                 : 
      48              52 : NS_IMPL_ISUPPORTS1(ThirdPartyUtil, mozIThirdPartyUtil)
      49                 : 
      50                 : nsresult
      51               4 : ThirdPartyUtil::Init()
      52                 : {
      53               4 :   NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_AVAILABLE);
      54                 : 
      55                 :   nsresult rv;
      56               4 :   mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
      57               4 :   return rv;
      58                 : }
      59                 : 
      60                 : // Determine if aFirstDomain is a different base domain to aSecondURI; or, if
      61                 : // the concept of base domain does not apply, determine if the two hosts are not
      62                 : // string-identical.
      63                 : nsresult
      64              25 : ThirdPartyUtil::IsThirdPartyInternal(const nsCString& aFirstDomain,
      65                 :                                      nsIURI* aSecondURI,
      66                 :                                      bool* aResult)
      67                 : {
      68              25 :   NS_ASSERTION(aSecondURI, "null URI!");
      69                 : 
      70                 :   // Get the base domain for aSecondURI.
      71              50 :   nsCString secondDomain;
      72              25 :   nsresult rv = GetBaseDomain(aSecondURI, secondDomain);
      73              25 :   if (NS_FAILED(rv))
      74               0 :     return rv;
      75                 : 
      76                 :   // Check strict equality.
      77              25 :   *aResult = aFirstDomain != secondDomain;
      78              25 :   return NS_OK;
      79                 : }
      80                 : 
      81                 : // Get the URI associated with a window.
      82                 : already_AddRefed<nsIURI>
      83               0 : ThirdPartyUtil::GetURIFromWindow(nsIDOMWindow* aWin)
      84                 : {
      85               0 :   nsCOMPtr<nsIScriptObjectPrincipal> scriptObjPrin = do_QueryInterface(aWin);
      86               0 :   NS_ENSURE_TRUE(scriptObjPrin, NULL);
      87                 : 
      88               0 :   nsIPrincipal* prin = scriptObjPrin->GetPrincipal();
      89               0 :   NS_ENSURE_TRUE(prin, NULL);
      90                 : 
      91               0 :   nsCOMPtr<nsIURI> result;
      92               0 :   prin->GetURI(getter_AddRefs(result));
      93               0 :   return result.forget();
      94                 : }
      95                 : 
      96                 : // Determine if aFirstURI is third party with respect to aSecondURI. See docs
      97                 : // for mozIThirdPartyUtil.
      98                 : NS_IMETHODIMP
      99               9 : ThirdPartyUtil::IsThirdPartyURI(nsIURI* aFirstURI,
     100                 :                                 nsIURI* aSecondURI,
     101                 :                                 bool* aResult)
     102                 : {
     103               9 :   NS_ENSURE_ARG(aFirstURI);
     104               7 :   NS_ENSURE_ARG(aSecondURI);
     105               6 :   NS_ASSERTION(aResult, "null outparam pointer");
     106                 : 
     107              12 :   nsCString firstHost;
     108               6 :   nsresult rv = GetBaseDomain(aFirstURI, firstHost);
     109               6 :   if (NS_FAILED(rv))
     110               0 :     return rv;
     111                 : 
     112               6 :   return IsThirdPartyInternal(firstHost, aSecondURI, aResult);
     113                 : }
     114                 : 
     115                 : // Determine if any URI of the window hierarchy of aWindow is foreign with
     116                 : // respect to aSecondURI. See docs for mozIThirdPartyUtil.
     117                 : NS_IMETHODIMP
     118               0 : ThirdPartyUtil::IsThirdPartyWindow(nsIDOMWindow* aWindow,
     119                 :                                    nsIURI* aURI,
     120                 :                                    bool* aResult)
     121                 : {
     122               0 :   NS_ENSURE_ARG(aWindow);
     123               0 :   NS_ASSERTION(aResult, "null outparam pointer");
     124                 : 
     125                 :   bool result;
     126                 : 
     127                 :   // Get the URI of the window, and its base domain.
     128               0 :   nsCOMPtr<nsIURI> currentURI = GetURIFromWindow(aWindow);
     129               0 :   NS_ENSURE_TRUE(currentURI, NS_ERROR_INVALID_ARG);
     130                 : 
     131               0 :   nsCString bottomDomain;
     132               0 :   nsresult rv = GetBaseDomain(currentURI, bottomDomain);
     133               0 :   if (NS_FAILED(rv))
     134               0 :     return rv;
     135                 : 
     136               0 :   if (aURI) {
     137                 :     // Determine whether aURI is foreign with respect to currentURI.
     138               0 :     rv = IsThirdPartyInternal(bottomDomain, aURI, &result);
     139               0 :     if (NS_FAILED(rv))
     140               0 :       return rv;
     141                 : 
     142               0 :     if (result) {
     143               0 :       *aResult = true;
     144               0 :       return NS_OK;
     145                 :     }
     146                 :   }
     147                 : 
     148               0 :   nsCOMPtr<nsIDOMWindow> current = aWindow, parent;
     149               0 :   nsCOMPtr<nsIURI> parentURI;
     150               0 :   do {
     151               0 :     rv = current->GetParent(getter_AddRefs(parent));
     152               0 :     NS_ENSURE_SUCCESS(rv, rv);
     153                 : 
     154               0 :     if (SameCOMIdentity(parent, current)) {
     155                 :       // We're at the topmost content window. We already know the answer.
     156               0 :       *aResult = false;
     157               0 :       return NS_OK;
     158                 :     }
     159                 : 
     160               0 :     parentURI = GetURIFromWindow(parent);
     161               0 :     NS_ENSURE_TRUE(parentURI, NS_ERROR_INVALID_ARG);
     162                 : 
     163               0 :     rv = IsThirdPartyInternal(bottomDomain, parentURI, &result);
     164               0 :     if (NS_FAILED(rv))
     165               0 :       return rv;
     166                 : 
     167               0 :     if (result) {
     168               0 :       *aResult = true;
     169               0 :       return NS_OK;
     170                 :     }
     171                 : 
     172               0 :     current = parent;
     173               0 :     currentURI = parentURI;
     174                 :   } while (1);
     175                 : 
     176                 :   NS_NOTREACHED("should've returned");
     177                 :   return NS_ERROR_UNEXPECTED;
     178                 : }
     179                 : 
     180                 : // Determine if the URI associated with aChannel or any URI of the window
     181                 : // hierarchy associated with the channel is foreign with respect to aSecondURI.
     182                 : // See docs for mozIThirdPartyUtil.
     183                 : NS_IMETHODIMP 
     184              34 : ThirdPartyUtil::IsThirdPartyChannel(nsIChannel* aChannel,
     185                 :                                     nsIURI* aURI,
     186                 :                                     bool* aResult)
     187                 : {
     188              34 :   NS_ENSURE_ARG(aChannel);
     189              21 :   NS_ASSERTION(aResult, "null outparam pointer");
     190                 : 
     191                 :   nsresult rv;
     192              21 :   bool doForce = false;
     193                 :   nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
     194              42 :     do_QueryInterface(aChannel);
     195              21 :   if (httpChannelInternal) {
     196              21 :     rv = httpChannelInternal->GetForceAllowThirdPartyCookie(&doForce);
     197              21 :     NS_ENSURE_SUCCESS(rv, rv);
     198                 : 
     199                 :     // If aURI was not supplied, and we're forcing, then we're by definition
     200                 :     // not foreign. If aURI was supplied, we still want to check whether it's
     201                 :     // foreign with respect to the channel URI. (The forcing only applies to
     202                 :     // whatever window hierarchy exists above the channel.)
     203              21 :     if (doForce && !aURI) {
     204               1 :       *aResult = false;
     205               1 :       return NS_OK;
     206                 :     }
     207                 :   }
     208                 : 
     209                 :   // Obtain the URI from the channel, and its base domain.
     210              40 :   nsCOMPtr<nsIURI> channelURI;
     211              20 :   aChannel->GetURI(getter_AddRefs(channelURI));
     212              20 :   NS_ENSURE_TRUE(channelURI, NS_ERROR_INVALID_ARG);
     213                 : 
     214              40 :   nsCString channelDomain;
     215              20 :   rv = GetBaseDomain(channelURI, channelDomain);
     216              20 :   if (NS_FAILED(rv))
     217               0 :     return rv;
     218                 : 
     219              20 :   if (aURI) {
     220                 :     // Determine whether aURI is foreign with respect to channelURI.
     221                 :     bool result;
     222              19 :     rv = IsThirdPartyInternal(channelDomain, aURI, &result);
     223              19 :     if (NS_FAILED(rv))
     224               0 :      return rv;
     225                 : 
     226                 :     // If it's foreign, or we're forcing, we're done.
     227              19 :     if (result || doForce) {
     228              16 :       *aResult = result;
     229              16 :       return NS_OK;
     230                 :     }
     231                 :   }
     232                 : 
     233                 :   // Find the associated window and its parent window.
     234               8 :   nsCOMPtr<nsILoadContext> ctx;
     235               4 :   NS_QueryNotificationCallbacks(aChannel, ctx);
     236               4 :   if (!ctx) return NS_ERROR_INVALID_ARG;
     237                 : 
     238                 :   // If there is no window, the consumer kicking off the load didn't provide one
     239                 :   // to the channel. This is limited to loads of certain types of resources. If
     240                 :   // those loads require cookies, the forceAllowThirdPartyCookie property should
     241                 :   // be set on the channel.
     242               0 :   nsCOMPtr<nsIDOMWindow> ourWin, parentWin;
     243               0 :   ctx->GetAssociatedWindow(getter_AddRefs(ourWin));
     244               0 :   if (!ourWin) return NS_ERROR_INVALID_ARG;
     245                 : 
     246               0 :   ourWin->GetParent(getter_AddRefs(parentWin));
     247               0 :   NS_ENSURE_TRUE(parentWin, NS_ERROR_INVALID_ARG);
     248                 : 
     249                 :   // Check whether this is the document channel for this window (representing a
     250                 :   // load of a new page). In that situation we want to avoid comparing
     251                 :   // channelURI to ourWin, since what's in ourWin right now will be replaced as
     252                 :   // the channel loads.  This covers the case of a freshly kicked-off load
     253                 :   // (e.g. the user typing something in the location bar, or clicking on a
     254                 :   // bookmark), where the window's URI hasn't yet been set, and will be bogus.
     255                 :   // It also covers situations where a subframe is navigated to someting that
     256                 :   // is same-origin with all its ancestors.  This is a bit of a nasty hack, but
     257                 :   // we will hopefully flag these channels better later.
     258                 :   nsLoadFlags flags;
     259               0 :   rv = aChannel->GetLoadFlags(&flags);
     260               0 :   NS_ENSURE_SUCCESS(rv, rv);
     261                 : 
     262               0 :   if (flags & nsIChannel::LOAD_DOCUMENT_URI) {
     263               0 :     if (SameCOMIdentity(ourWin, parentWin)) {
     264                 :       // We only need to compare aURI to the channel URI -- the window's will be
     265                 :       // bogus. We already know the answer.
     266               0 :       *aResult = false;
     267               0 :       return NS_OK;
     268                 :     }
     269                 : 
     270                 :     // Make sure to still compare to ourWin's ancestors
     271               0 :     ourWin = parentWin;
     272                 :   }
     273                 : 
     274                 :   // Check the window hierarchy. This covers most cases for an ordinary page
     275                 :   // load from the location bar.
     276               0 :   return IsThirdPartyWindow(ourWin, channelURI, aResult);
     277                 : }
     278                 : 
     279                 : // Get the base domain for aHostURI; e.g. for "www.bbc.co.uk", this would be
     280                 : // "bbc.co.uk". Only properly-formed URI's are tolerated, though a trailing
     281                 : // dot may be present. If aHostURI is an IP address, an alias such as
     282                 : // 'localhost', an eTLD such as 'co.uk', or the empty string, aBaseDomain will
     283                 : // be the exact host. The result of this function should only be used in exact
     284                 : // string comparisons, since substring comparisons will not be valid for the
     285                 : // special cases elided above.
     286                 : NS_IMETHODIMP
     287              51 : ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI,
     288                 :                               nsACString& aBaseDomain)
     289                 : {
     290                 :   // Get the base domain. this will fail if the host contains a leading dot,
     291                 :   // more than one trailing dot, or is otherwise malformed.
     292              51 :   nsresult rv = mTLDService->GetBaseDomain(aHostURI, 0, aBaseDomain);
     293              51 :   if (rv == NS_ERROR_HOST_IS_IP_ADDRESS ||
     294                 :       rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
     295                 :     // aHostURI is either an IP address, an alias such as 'localhost', an eTLD
     296                 :     // such as 'co.uk', or the empty string. Uses the normalized host in such
     297                 :     // cases.
     298              11 :     rv = aHostURI->GetAsciiHost(aBaseDomain);
     299                 :   }
     300              51 :   NS_ENSURE_SUCCESS(rv, rv);
     301                 : 
     302                 :   // aHostURI (and thus aBaseDomain) may be the string '.'. If so, fail.
     303              51 :   if (aBaseDomain.Length() == 1 && aBaseDomain.Last() == '.')
     304               0 :     return NS_ERROR_INVALID_ARG;
     305                 : 
     306                 :   // Reject any URIs without a host that aren't file:// URIs. This makes it the
     307                 :   // only way we can get a base domain consisting of the empty string, which
     308                 :   // means we can safely perform foreign tests on such URIs where "not foreign"
     309                 :   // means "the involved URIs are all file://".
     310              51 :   if (aBaseDomain.IsEmpty()) {
     311               5 :     bool isFileURI = false;
     312               5 :     aHostURI->SchemeIs("file", &isFileURI);
     313               5 :     NS_ENSURE_TRUE(isFileURI, NS_ERROR_INVALID_ARG);
     314                 :   }
     315                 : 
     316              51 :   return NS_OK;
     317                 : }

Generated by: LCOV version 1.7