LCOV - code coverage report
Current view: top level - netwerk/protocol/about - nsAboutProtocolHandler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 106 172 61.6 %
Date: 2017-07-14 16:53:18 Functions: 16 28 57.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "base/basictypes.h"
       7             : #include "mozilla/ArrayUtils.h"
       8             : 
       9             : #include "nsAboutProtocolHandler.h"
      10             : #include "nsIURI.h"
      11             : #include "nsIAboutModule.h"
      12             : #include "nsString.h"
      13             : #include "nsNetCID.h"
      14             : #include "nsAboutProtocolUtils.h"
      15             : #include "nsError.h"
      16             : #include "nsNetUtil.h"
      17             : #include "nsIObjectInputStream.h"
      18             : #include "nsIObjectOutputStream.h"
      19             : #include "nsAutoPtr.h"
      20             : #include "nsIWritablePropertyBag2.h"
      21             : #include "nsIChannel.h"
      22             : #include "nsIScriptError.h"
      23             : 
      24             : namespace mozilla {
      25             : namespace net {
      26             : 
      27             : static NS_DEFINE_CID(kSimpleURICID,     NS_SIMPLEURI_CID);
      28             : static NS_DEFINE_CID(kNestedAboutURICID, NS_NESTEDABOUTURI_CID);
      29             : 
      30           4 : static bool IsSafeForUntrustedContent(nsIAboutModule *aModule, nsIURI *aURI) {
      31             :   uint32_t flags;
      32           4 :   nsresult rv = aModule->GetURIFlags(aURI, &flags);
      33           4 :   NS_ENSURE_SUCCESS(rv, false);
      34             : 
      35           4 :   return (flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) != 0;
      36             : }
      37             : 
      38          28 : static bool IsSafeToLinkForUntrustedContent(nsIAboutModule *aModule, nsIURI *aURI) {
      39             :   uint32_t flags;
      40          28 :   nsresult rv = aModule->GetURIFlags(aURI, &flags);
      41          28 :   NS_ENSURE_SUCCESS(rv, false);
      42             : 
      43          28 :   return (flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) && (flags & nsIAboutModule::MAKE_LINKABLE);
      44             : }
      45             : ////////////////////////////////////////////////////////////////////////////////
      46             : 
      47         592 : NS_IMPL_ISUPPORTS(nsAboutProtocolHandler, nsIProtocolHandler,
      48             :     nsIProtocolHandlerWithDynamicFlags, nsISupportsWeakReference)
      49             : 
      50             : ////////////////////////////////////////////////////////////////////////////////
      51             : // nsIProtocolHandler methods:
      52             : 
      53             : NS_IMETHODIMP
      54           0 : nsAboutProtocolHandler::GetScheme(nsACString &result)
      55             : {
      56           0 :     result.AssignLiteral("about");
      57           0 :     return NS_OK;
      58             : }
      59             : 
      60             : NS_IMETHODIMP
      61           0 : nsAboutProtocolHandler::GetDefaultPort(int32_t *result)
      62             : {
      63           0 :     *result = -1;        // no port for about: URLs
      64           0 :     return NS_OK;
      65             : }
      66             : 
      67             : NS_IMETHODIMP
      68          41 : nsAboutProtocolHandler::GetProtocolFlags(uint32_t *result)
      69             : {
      70          41 :     *result = URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD | URI_SCHEME_NOT_SELF_LINKABLE;
      71          41 :     return NS_OK;
      72             : }
      73             : 
      74             : NS_IMETHODIMP
      75          41 : nsAboutProtocolHandler::GetFlagsForURI(nsIURI* aURI, uint32_t* aFlags)
      76             : {
      77             :     // First use the default (which is "unsafe for content"):
      78          41 :     GetProtocolFlags(aFlags);
      79             : 
      80             :     // Now try to see if this URI overrides the default:
      81          82 :     nsCOMPtr<nsIAboutModule> aboutMod;
      82          41 :     nsresult rv = NS_GetAboutModule(aURI, getter_AddRefs(aboutMod));
      83          41 :     if (NS_FAILED(rv)) {
      84             :       // Swallow this and just tell the consumer the default:
      85           0 :       return NS_OK;
      86             :     }
      87          41 :     uint32_t aboutModuleFlags = 0;
      88          41 :     rv = aboutMod->GetURIFlags(aURI, &aboutModuleFlags);
      89             :     // This should never happen, so pass back the error:
      90          41 :     NS_ENSURE_SUCCESS(rv, rv);
      91             : 
      92             :     // Secure (https) pages can load safe about pages without becoming
      93             :     // mixed content.
      94          41 :     if (aboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) {
      95          20 :         *aFlags |= URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
      96             :         // about: pages can only be loaded by unprivileged principals
      97             :         // if they are marked as LINKABLE
      98          20 :         if (aboutModuleFlags & nsIAboutModule::MAKE_LINKABLE) {
      99             :             // Replace URI_DANGEROUS_TO_LOAD with URI_LOADABLE_BY_ANYONE.
     100          20 :             *aFlags &= ~URI_DANGEROUS_TO_LOAD;
     101          20 :             *aFlags |= URI_LOADABLE_BY_ANYONE;
     102             :         }
     103             :     }
     104          41 :     return NS_OK;
     105             : }
     106             : 
     107             : NS_IMETHODIMP
     108          30 : nsAboutProtocolHandler::NewURI(const nsACString &aSpec,
     109             :                                const char *aCharset, // ignore charset info
     110             :                                nsIURI *aBaseURI,
     111             :                                nsIURI **result)
     112             : {
     113          30 :     *result = nullptr;
     114             :     nsresult rv;
     115             : 
     116             :     // Use a simple URI to parse out some stuff first
     117          60 :     nsCOMPtr<nsIURI> url = do_CreateInstance(kSimpleURICID, &rv);
     118          30 :     if (NS_FAILED(rv)) return rv;
     119             : 
     120          30 :     rv = url->SetSpec(aSpec);
     121          30 :     if (NS_FAILED(rv)) {
     122           0 :         return rv;
     123             :     }
     124             : 
     125             :     // Unfortunately, people create random about: URIs that don't correspond to
     126             :     // about: modules...  Since those URIs will never open a channel, might as
     127             :     // well consider them unsafe for better perf, and just in case.
     128          30 :     bool isSafe = false;
     129             : 
     130          60 :     nsCOMPtr<nsIAboutModule> aboutMod;
     131          30 :     rv = NS_GetAboutModule(url, getter_AddRefs(aboutMod));
     132          30 :     if (NS_SUCCEEDED(rv)) {
     133          28 :         isSafe = IsSafeToLinkForUntrustedContent(aboutMod, url);
     134             :     }
     135             : 
     136          30 :     if (isSafe) {
     137             :         // We need to indicate that this baby is safe.  Use an inner URI that
     138             :         // no one but the security manager will see.  Make sure to preserve our
     139             :         // path, in case someone decides to hardcode checks for particular
     140             :         // about: URIs somewhere.
     141          42 :         nsAutoCString spec;
     142          21 :         rv = url->GetPath(spec);
     143          21 :         NS_ENSURE_SUCCESS(rv, rv);
     144             : 
     145          21 :         spec.Insert("moz-safe-about:", 0);
     146             : 
     147          42 :         nsCOMPtr<nsIURI> inner;
     148          21 :         rv = NS_NewURI(getter_AddRefs(inner), spec);
     149          21 :         NS_ENSURE_SUCCESS(rv, rv);
     150             : 
     151          42 :         nsSimpleNestedURI* outer = new nsNestedAboutURI(inner, aBaseURI);
     152          21 :         NS_ENSURE_TRUE(outer, NS_ERROR_OUT_OF_MEMORY);
     153             : 
     154             :         // Take a ref to it in the COMPtr we plan to return
     155          21 :         url = outer;
     156             : 
     157          21 :         rv = outer->SetSpec(aSpec);
     158          21 :         NS_ENSURE_SUCCESS(rv, rv);
     159             :     }
     160             : 
     161             :     // We don't want to allow mutation, since it would allow safe and
     162             :     // unsafe URIs to change into each other...
     163          30 :     NS_TryToSetImmutable(url);
     164          30 :     url.swap(*result);
     165          30 :     return NS_OK;
     166             : }
     167             : 
     168             : NS_IMETHODIMP
     169           4 : nsAboutProtocolHandler::NewChannel2(nsIURI* uri,
     170             :                                     nsILoadInfo* aLoadInfo,
     171             :                                     nsIChannel** result)
     172             : {
     173           4 :     NS_ENSURE_ARG_POINTER(uri);
     174             : 
     175             :     // about:what you ask?
     176           8 :     nsCOMPtr<nsIAboutModule> aboutMod;
     177           4 :     nsresult rv = NS_GetAboutModule(uri, getter_AddRefs(aboutMod));
     178             : 
     179           8 :     nsAutoCString path;
     180           4 :     nsresult rv2 = NS_GetAboutModuleName(uri, path);
     181           4 :     if (NS_SUCCEEDED(rv2) && path.EqualsLiteral("srcdoc")) {
     182             :         // about:srcdoc is meant to be unresolvable, yet is included in the
     183             :         // about lookup tables so that it can pass security checks when used in
     184             :         // a srcdoc iframe.  To ensure that it stays unresolvable, we pretend
     185             :         // that it doesn't exist.
     186           0 :       rv = NS_ERROR_FACTORY_NOT_REGISTERED;
     187             :     }
     188             : 
     189           4 :     if (NS_SUCCEEDED(rv)) {
     190             :         // The standard return case:
     191           4 :         rv = aboutMod->NewChannel(uri, aLoadInfo, result);
     192           4 :         if (NS_SUCCEEDED(rv)) {
     193             :             // Not all implementations of nsIAboutModule::NewChannel()
     194             :             // set the LoadInfo on the newly created channel yet, as
     195             :             // an interim solution we set the LoadInfo here if not
     196             :             // available on the channel. Bug 1087720
     197           8 :             nsCOMPtr<nsILoadInfo> loadInfo = (*result)->GetLoadInfo();
     198           4 :             if (aLoadInfo != loadInfo) {
     199           0 :                 if (loadInfo) {
     200           0 :                     NS_ASSERTION(false,
     201             :                         "nsIAboutModule->newChannel(aURI, aLoadInfo) needs to set LoadInfo");
     202             :                     const char16_t* params[] = {
     203             :                         u"nsIAboutModule->newChannel(aURI)",
     204             :                         u"nsIAboutModule->newChannel(aURI, aLoadInfo)"
     205           0 :                     };
     206           0 :                     nsContentUtils::ReportToConsole(
     207             :                         nsIScriptError::warningFlag,
     208           0 :                         NS_LITERAL_CSTRING("Security by Default"),
     209             :                         nullptr, // aDocument
     210             :                         nsContentUtils::eNECKO_PROPERTIES,
     211             :                         "APIDeprecationWarning",
     212           0 :                         params, mozilla::ArrayLength(params));
     213             :                 }
     214           0 :                 (*result)->SetLoadInfo(aLoadInfo);
     215             :             }
     216             : 
     217             :             // If this URI is safe for untrusted content, enforce that its
     218             :             // principal be based on the channel's originalURI by setting the
     219             :             // owner to null.
     220             :             // Note: this relies on aboutMod's newChannel implementation
     221             :             // having set the proper originalURI, which probably isn't ideal.
     222           4 :             if (IsSafeForUntrustedContent(aboutMod, uri)) {
     223           4 :                 (*result)->SetOwner(nullptr);
     224             :             }
     225             : 
     226           8 :             RefPtr<nsNestedAboutURI> aboutURI;
     227           8 :             nsresult rv2 = uri->QueryInterface(kNestedAboutURICID,
     228           8 :                                                getter_AddRefs(aboutURI));
     229           4 :             if (NS_SUCCEEDED(rv2) && aboutURI->GetBaseURI()) {
     230             :                 nsCOMPtr<nsIWritablePropertyBag2> writableBag =
     231           4 :                     do_QueryInterface(*result);
     232           2 :                 if (writableBag) {
     233           2 :                     writableBag->
     234           6 :                         SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
     235           6 :                                                aboutURI->GetBaseURI());
     236             :                 }
     237             :             }
     238             :         }
     239           4 :         return rv;
     240             :     }
     241             : 
     242             :     // mumble...
     243             : 
     244           0 :     if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) {
     245             :         // This looks like an about: we don't know about.  Convert
     246             :         // this to an invalid URI error.
     247           0 :         rv = NS_ERROR_MALFORMED_URI;
     248             :     }
     249             : 
     250           0 :     return rv;
     251             : }
     252             : 
     253             : NS_IMETHODIMP
     254           0 : nsAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
     255             : {
     256           0 :     return NewChannel2(uri, nullptr, result);
     257             : }
     258             : 
     259             : NS_IMETHODIMP
     260           0 : nsAboutProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
     261             : {
     262             :     // don't override anything.
     263           0 :     *_retval = false;
     264           0 :     return NS_OK;
     265             : }
     266             : 
     267             : ////////////////////////////////////////////////////////////////////////////////
     268             : // Safe about protocol handler impl
     269             : 
     270         489 : NS_IMPL_ISUPPORTS(nsSafeAboutProtocolHandler, nsIProtocolHandler, nsISupportsWeakReference)
     271             : 
     272             : // nsIProtocolHandler methods:
     273             : 
     274             : NS_IMETHODIMP
     275           0 : nsSafeAboutProtocolHandler::GetScheme(nsACString &result)
     276             : {
     277           0 :     result.AssignLiteral("moz-safe-about");
     278           0 :     return NS_OK;
     279             : }
     280             : 
     281             : NS_IMETHODIMP
     282           0 : nsSafeAboutProtocolHandler::GetDefaultPort(int32_t *result)
     283             : {
     284           0 :     *result = -1;        // no port for moz-safe-about: URLs
     285           0 :     return NS_OK;
     286             : }
     287             : 
     288             : NS_IMETHODIMP
     289          42 : nsSafeAboutProtocolHandler::GetProtocolFlags(uint32_t *result)
     290             : {
     291          42 :     *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE | URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
     292          42 :     return NS_OK;
     293             : }
     294             : 
     295             : NS_IMETHODIMP
     296          27 : nsSafeAboutProtocolHandler::NewURI(const nsACString &aSpec,
     297             :                                    const char *aCharset, // ignore charset info
     298             :                                    nsIURI *aBaseURI,
     299             :                                    nsIURI **result)
     300             : {
     301             :     nsresult rv;
     302             : 
     303          54 :     nsCOMPtr<nsIURI> url = do_CreateInstance(kSimpleURICID, &rv);
     304          27 :     if (NS_FAILED(rv)) return rv;
     305             : 
     306          27 :     rv = url->SetSpec(aSpec);
     307          27 :     if (NS_FAILED(rv)) {
     308           0 :         return rv;
     309             :     }
     310             : 
     311          27 :     NS_TryToSetImmutable(url);
     312             : 
     313          27 :     *result = nullptr;
     314          27 :     url.swap(*result);
     315          27 :     return rv;
     316             : }
     317             : 
     318             : NS_IMETHODIMP
     319           0 : nsSafeAboutProtocolHandler::NewChannel2(nsIURI* uri,
     320             :                                         nsILoadInfo* aLoadInfo,
     321             :                                         nsIChannel** result)
     322             : {
     323           0 :     *result = nullptr;
     324           0 :     return NS_ERROR_NOT_AVAILABLE;
     325             : }
     326             : 
     327             : NS_IMETHODIMP
     328           0 : nsSafeAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
     329             : {
     330           0 :     *result = nullptr;
     331           0 :     return NS_ERROR_NOT_AVAILABLE;
     332             : }
     333             : 
     334             : NS_IMETHODIMP
     335           0 : nsSafeAboutProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
     336             : {
     337             :     // don't override anything.
     338           0 :     *_retval = false;
     339           0 :     return NS_OK;
     340             : }
     341             : 
     342             : ////////////////////////////////////////////////////////////
     343             : // nsNestedAboutURI implementation
     344         758 : NS_INTERFACE_MAP_BEGIN(nsNestedAboutURI)
     345         758 :   if (aIID.Equals(kNestedAboutURICID))
     346           4 :       foundInterface = static_cast<nsIURI*>(this);
     347             :   else
     348         754 : NS_INTERFACE_MAP_END_INHERITING(nsSimpleNestedURI)
     349             : 
     350             : // nsISerializable
     351             : NS_IMETHODIMP
     352           0 : nsNestedAboutURI::Read(nsIObjectInputStream* aStream)
     353             : {
     354           0 :     nsresult rv = nsSimpleNestedURI::Read(aStream);
     355           0 :     if (NS_FAILED(rv)) return rv;
     356             : 
     357             :     bool haveBase;
     358           0 :     rv = aStream->ReadBoolean(&haveBase);
     359           0 :     if (NS_FAILED(rv)) return rv;
     360             : 
     361           0 :     if (haveBase) {
     362           0 :         nsCOMPtr<nsISupports> supports;
     363           0 :         rv = aStream->ReadObject(true, getter_AddRefs(supports));
     364           0 :         if (NS_FAILED(rv)) return rv;
     365             : 
     366           0 :         mBaseURI = do_QueryInterface(supports, &rv);
     367           0 :         if (NS_FAILED(rv)) return rv;
     368             :     }
     369             : 
     370           0 :     return NS_OK;
     371             : }
     372             : 
     373             : NS_IMETHODIMP
     374           0 : nsNestedAboutURI::Write(nsIObjectOutputStream* aStream)
     375             : {
     376           0 :     nsresult rv = nsSimpleNestedURI::Write(aStream);
     377           0 :     if (NS_FAILED(rv)) return rv;
     378             : 
     379           0 :     rv = aStream->WriteBoolean(mBaseURI != nullptr);
     380           0 :     if (NS_FAILED(rv)) return rv;
     381             : 
     382           0 :     if (mBaseURI) {
     383             :         // A previous iteration of this code wrote out mBaseURI as nsISupports
     384             :         // and then read it in as nsIURI, which is non-kosher when mBaseURI
     385             :         // implements more than just a single line of interfaces and the
     386             :         // canonical nsISupports* isn't the one a static_cast<> of mBaseURI
     387             :         // would produce.  For backwards compatibility with existing
     388             :         // serializations we continue to write mBaseURI as nsISupports but
     389             :         // switch to reading it as nsISupports, with a post-read QI to get to
     390             :         // nsIURI.
     391             :         rv = aStream->WriteCompoundObject(mBaseURI, NS_GET_IID(nsISupports),
     392           0 :                                           true);
     393           0 :         if (NS_FAILED(rv)) return rv;
     394             :     }
     395             : 
     396           0 :     return NS_OK;
     397             : }
     398             : 
     399             : // nsSimpleURI
     400             : /* virtual */ nsSimpleURI*
     401          11 : nsNestedAboutURI::StartClone(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
     402             :                              const nsACString& aNewRef)
     403             : {
     404             :     // Sadly, we can't make use of nsSimpleNestedURI::StartClone here.
     405             :     // However, this function is expected to exactly match that function,
     406             :     // aside from the "new ns***URI()" call.
     407          11 :     NS_ENSURE_TRUE(mInnerURI, nullptr);
     408             : 
     409          22 :     nsCOMPtr<nsIURI> innerClone;
     410             :     nsresult rv;
     411          11 :     if (aRefHandlingMode == eHonorRef) {
     412           8 :         rv = mInnerURI->Clone(getter_AddRefs(innerClone));
     413           3 :     } else if (aRefHandlingMode == eReplaceRef) {
     414           0 :         rv = mInnerURI->CloneWithNewRef(aNewRef, getter_AddRefs(innerClone));
     415             :     } else {
     416           3 :         rv = mInnerURI->CloneIgnoringRef(getter_AddRefs(innerClone));
     417             :     }
     418             : 
     419          11 :     if (NS_FAILED(rv)) {
     420           0 :         return nullptr;
     421             :     }
     422             : 
     423          22 :     nsNestedAboutURI* url = new nsNestedAboutURI(innerClone, mBaseURI);
     424          11 :     SetRefOnClone(url, aRefHandlingMode, aNewRef);
     425          11 :     url->SetMutable(false);
     426             : 
     427          11 :     return url;
     428             : }
     429             : 
     430             : // nsIClassInfo
     431             : NS_IMETHODIMP
     432           0 : nsNestedAboutURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
     433             : {
     434           0 :     *aClassIDNoAlloc = kNestedAboutURICID;
     435           0 :     return NS_OK;
     436             : }
     437             : 
     438             : } // namespace net
     439             : } // namespace mozilla

Generated by: LCOV version 1.13