LCOV - code coverage report
Current view: directory - docshell/base - nsDSURIContentListener.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 155 0 0.0 %
Date: 2012-06-02 Functions: 16 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Mozilla browser.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications, Inc.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1999
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Travis Bogard <travis@netscape.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsDocShell.h"
      40                 : #include "nsDSURIContentListener.h"
      41                 : #include "nsIChannel.h"
      42                 : #include "nsServiceManagerUtils.h"
      43                 : #include "nsXPIDLString.h"
      44                 : #include "nsDocShellCID.h"
      45                 : #include "nsIWebNavigationInfo.h"
      46                 : #include "nsIDOMWindow.h"
      47                 : #include "nsAutoPtr.h"
      48                 : #include "nsIHttpChannel.h"
      49                 : #include "nsIScriptSecurityManager.h"
      50                 : #include "nsNetError.h"
      51                 : #include "mozilla/Preferences.h"
      52                 : 
      53                 : using namespace mozilla;
      54                 : 
      55                 : static bool sIgnoreXFrameOptions = false;
      56                 : 
      57                 : //*****************************************************************************
      58                 : //***    nsDSURIContentListener: Object Management
      59                 : //*****************************************************************************
      60                 : 
      61               0 : nsDSURIContentListener::nsDSURIContentListener(nsDocShell* aDocShell)
      62                 :     : mDocShell(aDocShell), 
      63               0 :       mParentContentListener(nsnull)
      64                 : {
      65                 :   static bool initializedPrefCache = false;
      66                 : 
      67                 :   // Set up a pref cache for sIgnoreXFrameOptions, if we haven't already.
      68               0 :   if (NS_UNLIKELY(!initializedPrefCache)) {
      69                 :     // Lock the pref so that the user's changes to it, if any, are ignored.
      70               0 :     nsIPrefBranch *root = Preferences::GetRootBranch();
      71               0 :     root->LockPref("b2g.ignoreXFrameOptions");
      72                 : 
      73               0 :     Preferences::AddBoolVarCache(&sIgnoreXFrameOptions, "b2g.ignoreXFrameOptions");
      74               0 :     initializedPrefCache = true;
      75                 :   }
      76               0 : }
      77                 : 
      78               0 : nsDSURIContentListener::~nsDSURIContentListener()
      79                 : {
      80               0 : }
      81                 : 
      82                 : nsresult
      83               0 : nsDSURIContentListener::Init() 
      84                 : {
      85                 :     nsresult rv;
      86               0 :     mNavInfo = do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID, &rv);
      87               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get webnav info");
      88               0 :     return rv;
      89                 : }
      90                 : 
      91                 : 
      92                 : //*****************************************************************************
      93                 : // nsDSURIContentListener::nsISupports
      94                 : //*****************************************************************************   
      95                 : 
      96               0 : NS_IMPL_THREADSAFE_ADDREF(nsDSURIContentListener)
      97               0 : NS_IMPL_THREADSAFE_RELEASE(nsDSURIContentListener)
      98                 : 
      99               0 : NS_INTERFACE_MAP_BEGIN(nsDSURIContentListener)
     100               0 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURIContentListener)
     101               0 :     NS_INTERFACE_MAP_ENTRY(nsIURIContentListener)
     102               0 :     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     103               0 : NS_INTERFACE_MAP_END
     104                 : 
     105                 : //*****************************************************************************
     106                 : // nsDSURIContentListener::nsIURIContentListener
     107                 : //*****************************************************************************   
     108                 : 
     109                 : NS_IMETHODIMP
     110               0 : nsDSURIContentListener::OnStartURIOpen(nsIURI* aURI, bool* aAbortOpen)
     111                 : {
     112                 :     // If mDocShell is null here, that means someone's starting a load
     113                 :     // in our docshell after it's already been destroyed.  Don't let
     114                 :     // that happen.
     115               0 :     if (!mDocShell) {
     116               0 :         *aAbortOpen = true;
     117               0 :         return NS_OK;
     118                 :     }
     119                 :     
     120               0 :     nsCOMPtr<nsIURIContentListener> parentListener;
     121               0 :     GetParentContentListener(getter_AddRefs(parentListener));
     122               0 :     if (parentListener)
     123               0 :         return parentListener->OnStartURIOpen(aURI, aAbortOpen);
     124                 : 
     125               0 :     return NS_OK;
     126                 : }
     127                 : 
     128                 : NS_IMETHODIMP 
     129               0 : nsDSURIContentListener::DoContent(const char* aContentType, 
     130                 :                                   bool aIsContentPreferred,
     131                 :                                   nsIRequest* request,
     132                 :                                   nsIStreamListener** aContentHandler,
     133                 :                                   bool* aAbortProcess)
     134                 : {
     135                 :     nsresult rv;
     136               0 :     NS_ENSURE_ARG_POINTER(aContentHandler);
     137               0 :     NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
     138                 : 
     139                 :     // Check whether X-Frame-Options permits us to load this content in an
     140                 :     // iframe and abort the load (unless we've disabled x-frame-options
     141                 :     // checking).
     142               0 :     if (!CheckFrameOptions(request)) {
     143               0 :         *aAbortProcess = true;
     144               0 :         return NS_OK;
     145                 :     }
     146                 : 
     147               0 :     *aAbortProcess = false;
     148                 : 
     149                 :     // determine if the channel has just been retargeted to us...
     150               0 :     nsLoadFlags loadFlags = 0;
     151               0 :     nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
     152                 : 
     153               0 :     if (aOpenedChannel)
     154               0 :       aOpenedChannel->GetLoadFlags(&loadFlags);
     155                 : 
     156               0 :     if(loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
     157                 :     {
     158                 :         // XXX: Why does this not stop the content too?
     159               0 :         mDocShell->Stop(nsIWebNavigation::STOP_NETWORK);
     160                 : 
     161               0 :         mDocShell->SetLoadType(aIsContentPreferred ? LOAD_LINK : LOAD_NORMAL);
     162                 :     }
     163                 : 
     164               0 :     rv = mDocShell->CreateContentViewer(aContentType, request, aContentHandler);
     165                 : 
     166               0 :     if (rv == NS_ERROR_REMOTE_XUL) {
     167               0 :       request->Cancel(rv);
     168               0 :       return NS_OK;
     169                 :     }
     170                 : 
     171               0 :     if (NS_FAILED(rv)) {
     172                 :        // it's okay if we don't know how to handle the content   
     173               0 :         return NS_OK;
     174                 :     }
     175                 : 
     176               0 :     if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) {
     177               0 :         nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(static_cast<nsIDocShell*>(mDocShell));
     178               0 :         NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
     179               0 :         domWindow->Focus();
     180                 :     }
     181                 : 
     182               0 :     return NS_OK;
     183                 : }
     184                 : 
     185                 : NS_IMETHODIMP
     186               0 : nsDSURIContentListener::IsPreferred(const char* aContentType,
     187                 :                                     char ** aDesiredContentType,
     188                 :                                     bool* aCanHandle)
     189                 : {
     190               0 :     NS_ENSURE_ARG_POINTER(aCanHandle);
     191               0 :     NS_ENSURE_ARG_POINTER(aDesiredContentType);
     192                 : 
     193                 :     // the docshell has no idea if it is the preferred content provider or not.
     194                 :     // It needs to ask its parent if it is the preferred content handler or not...
     195                 : 
     196               0 :     nsCOMPtr<nsIURIContentListener> parentListener;
     197               0 :     GetParentContentListener(getter_AddRefs(parentListener));
     198               0 :     if (parentListener) {
     199               0 :         return parentListener->IsPreferred(aContentType,
     200                 :                                                    aDesiredContentType,
     201               0 :                                                    aCanHandle);
     202                 :     }
     203                 :     // we used to return false here if we didn't have a parent properly
     204                 :     // registered at the top of the docshell hierarchy to dictate what
     205                 :     // content types this docshell should be a preferred handler for.  But
     206                 :     // this really makes it hard for developers using iframe or browser tags
     207                 :     // because then they need to make sure they implement
     208                 :     // nsIURIContentListener otherwise all link clicks would get sent to
     209                 :     // another window because we said we weren't the preferred handler type.
     210                 :     // I'm going to change the default now...if we can handle the content,
     211                 :     // and someone didn't EXPLICITLY set a nsIURIContentListener at the top
     212                 :     // of our docshell chain, then we'll now always attempt to process the
     213                 :     // content ourselves...
     214                 :     return CanHandleContent(aContentType,
     215                 :                             true,
     216                 :                             aDesiredContentType,
     217               0 :                             aCanHandle);
     218                 : }
     219                 : 
     220                 : NS_IMETHODIMP
     221               0 : nsDSURIContentListener::CanHandleContent(const char* aContentType,
     222                 :                                          bool aIsContentPreferred,
     223                 :                                          char ** aDesiredContentType,
     224                 :                                          bool* aCanHandleContent)
     225                 : {
     226               0 :     NS_PRECONDITION(aCanHandleContent, "Null out param?");
     227               0 :     NS_ENSURE_ARG_POINTER(aDesiredContentType);
     228                 : 
     229               0 :     *aCanHandleContent = false;
     230               0 :     *aDesiredContentType = nsnull;
     231                 : 
     232               0 :     nsresult rv = NS_OK;
     233               0 :     if (aContentType) {
     234               0 :         PRUint32 canHandle = nsIWebNavigationInfo::UNSUPPORTED;
     235               0 :         rv = mNavInfo->IsTypeSupported(nsDependentCString(aContentType),
     236                 :                                        mDocShell,
     237               0 :                                        &canHandle);
     238               0 :         *aCanHandleContent = (canHandle != nsIWebNavigationInfo::UNSUPPORTED);
     239                 :     }
     240                 : 
     241               0 :     return rv;
     242                 : }
     243                 : 
     244                 : NS_IMETHODIMP
     245               0 : nsDSURIContentListener::GetLoadCookie(nsISupports ** aLoadCookie)
     246                 : {
     247               0 :     NS_IF_ADDREF(*aLoadCookie = nsDocShell::GetAsSupports(mDocShell));
     248               0 :     return NS_OK;
     249                 : }
     250                 : 
     251                 : NS_IMETHODIMP
     252               0 : nsDSURIContentListener::SetLoadCookie(nsISupports * aLoadCookie)
     253                 : {
     254                 : #ifdef DEBUG
     255                 :     nsRefPtr<nsDocLoader> cookieAsDocLoader =
     256               0 :         nsDocLoader::GetAsDocLoader(aLoadCookie);
     257               0 :     NS_ASSERTION(cookieAsDocLoader && cookieAsDocLoader == mDocShell,
     258                 :                  "Invalid load cookie being set!");
     259                 : #endif
     260               0 :     return NS_OK;
     261                 : }
     262                 : 
     263                 : NS_IMETHODIMP 
     264               0 : nsDSURIContentListener::GetParentContentListener(nsIURIContentListener**
     265                 :                                                  aParentListener)
     266                 : {
     267               0 :     if (mWeakParentContentListener)
     268                 :     {
     269                 :         nsCOMPtr<nsIURIContentListener> tempListener =
     270               0 :             do_QueryReferent(mWeakParentContentListener);
     271               0 :         *aParentListener = tempListener;
     272               0 :         NS_IF_ADDREF(*aParentListener);
     273                 :     }
     274                 :     else {
     275               0 :         *aParentListener = mParentContentListener;
     276               0 :         NS_IF_ADDREF(*aParentListener);
     277                 :     }
     278               0 :     return NS_OK;
     279                 : }
     280                 : 
     281                 : NS_IMETHODIMP
     282               0 : nsDSURIContentListener::SetParentContentListener(nsIURIContentListener* 
     283                 :                                                  aParentListener)
     284                 : {
     285               0 :     if (aParentListener)
     286                 :     {
     287                 :         // Store the parent listener as a weak ref. Parents not supporting
     288                 :         // nsISupportsWeakReference assert but may still be used.
     289               0 :         mParentContentListener = nsnull;
     290               0 :         mWeakParentContentListener = do_GetWeakReference(aParentListener);
     291               0 :         if (!mWeakParentContentListener)
     292                 :         {
     293               0 :             mParentContentListener = aParentListener;
     294                 :         }
     295                 :     }
     296                 :     else
     297                 :     {
     298               0 :         mWeakParentContentListener = nsnull;
     299               0 :         mParentContentListener = nsnull;
     300                 :     }
     301               0 :     return NS_OK;
     302                 : }
     303                 : 
     304                 : // Check if X-Frame-Options permits this document to be loaded as a subdocument.
     305               0 : bool nsDSURIContentListener::CheckFrameOptions(nsIRequest* request)
     306                 : {
     307                 :     // If X-Frame-Options checking is disabled, return true unconditionally.
     308               0 :     if (sIgnoreXFrameOptions) {
     309               0 :         return true;
     310                 :     }
     311                 : 
     312               0 :     nsCAutoString xfoHeaderValue;
     313                 : 
     314               0 :     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
     315               0 :     if (!httpChannel) {
     316               0 :         return true;
     317                 :     }
     318                 : 
     319               0 :     httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-Frame-Options"),
     320               0 :                                    xfoHeaderValue);
     321                 : 
     322                 :     // return early if header does not have one of the two values with meaning
     323               0 :     if (!xfoHeaderValue.LowerCaseEqualsLiteral("deny") &&
     324               0 :         !xfoHeaderValue.LowerCaseEqualsLiteral("sameorigin"))
     325               0 :         return true;
     326                 : 
     327               0 :     if (mDocShell) {
     328                 :         // We need to check the location of this window and the location of the top
     329                 :         // window, if we're not the top.  X-F-O: SAMEORIGIN requires that the
     330                 :         // document must be same-origin with top window.  X-F-O: DENY requires that
     331                 :         // the document must never be framed.
     332               0 :         nsCOMPtr<nsIDOMWindow> thisWindow = do_GetInterface(static_cast<nsIDocShell*>(mDocShell));
     333                 :         // If we don't have DOMWindow there is no risk of clickjacking
     334               0 :         if (!thisWindow)
     335               0 :             return true;
     336                 : 
     337               0 :         nsCOMPtr<nsIDOMWindow> topWindow;
     338               0 :         thisWindow->GetTop(getter_AddRefs(topWindow));
     339                 : 
     340                 :         // if the document is in the top window, it's not in a frame.
     341               0 :         if (thisWindow == topWindow)
     342               0 :             return true;
     343                 : 
     344                 :         // Find the top docshell in our parent chain that doesn't have the system
     345                 :         // principal and use it for the principal comparison.  Finding the top
     346                 :         // content-type docshell doesn't work because some chrome documents are
     347                 :         // loaded in content docshells (see bug 593387).
     348                 :         nsCOMPtr<nsIDocShellTreeItem> thisDocShellItem(do_QueryInterface(
     349               0 :                                                        static_cast<nsIDocShell*> (mDocShell)));
     350               0 :         nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem,
     351               0 :                                       curDocShellItem = thisDocShellItem;
     352               0 :         nsCOMPtr<nsIDocument> topDoc;
     353                 :         nsresult rv;
     354                 :         nsCOMPtr<nsIScriptSecurityManager> ssm =
     355               0 :             do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
     356               0 :         if (!ssm)
     357               0 :             return false;
     358                 : 
     359                 :         // Traverse up the parent chain to the top docshell that doesn't have
     360                 :         // a system principal
     361               0 :         while (NS_SUCCEEDED(curDocShellItem->GetParent(getter_AddRefs(parentDocShellItem))) &&
     362               0 :                parentDocShellItem) {
     363               0 :             bool system = false;
     364               0 :             topDoc = do_GetInterface(parentDocShellItem);
     365               0 :             if (topDoc) {
     366               0 :                 if (NS_SUCCEEDED(ssm->IsSystemPrincipal(topDoc->NodePrincipal(),
     367                 :                                                         &system)) && system) {
     368               0 :                     break;
     369                 :                 }
     370                 :             }
     371                 :             else {
     372               0 :                 return false;
     373                 :             }
     374               0 :             curDocShellItem = parentDocShellItem;
     375                 :         }
     376                 : 
     377                 :         // If this document has the top non-SystemPrincipal docshell it is not being
     378                 :         // framed or it is being framed by a chrome document, which we allow.
     379               0 :         if (curDocShellItem == thisDocShellItem)
     380               0 :             return true;
     381                 : 
     382                 :         // If the X-Frame-Options value is SAMEORIGIN, then the top frame in the
     383                 :         // parent chain must be from the same origin as this document.
     384               0 :         if (xfoHeaderValue.LowerCaseEqualsLiteral("sameorigin")) {
     385               0 :             nsCOMPtr<nsIURI> uri;
     386               0 :             httpChannel->GetURI(getter_AddRefs(uri));
     387               0 :             topDoc = do_GetInterface(curDocShellItem);
     388               0 :             nsCOMPtr<nsIURI> topUri;
     389               0 :             topDoc->NodePrincipal()->GetURI(getter_AddRefs(topUri));
     390               0 :             rv = ssm->CheckSameOriginURI(uri, topUri, true);
     391               0 :             if (NS_SUCCEEDED(rv))
     392               0 :                 return true;
     393                 :         }
     394                 : 
     395                 :         else {
     396                 :             // If the value of the header is DENY, then the document
     397                 :             // should never be permitted to load as a subdocument.
     398               0 :             NS_ASSERTION(xfoHeaderValue.LowerCaseEqualsLiteral("deny"),
     399                 :                          "How did we get here with some random header value?");
     400                 :         }
     401                 : 
     402                 :         // cancel the load and display about:blank
     403               0 :         httpChannel->Cancel(NS_BINDING_ABORTED);
     404               0 :         nsCOMPtr<nsIWebNavigation> webNav(do_QueryObject(mDocShell));
     405               0 :         if (webNav) {
     406               0 :             webNav->LoadURI(NS_LITERAL_STRING("about:blank").get(),
     407               0 :                             0, nsnull, nsnull, nsnull);
     408                 :         }
     409               0 :         return false;
     410                 :     }
     411                 : 
     412               0 :     return true;
     413                 : }

Generated by: LCOV version 1.7