LCOV - code coverage report
Current view: top level - netwerk/protocol/res - SubstitutingProtocolHandler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 141 216 65.3 %
Date: 2017-07-14 16:53:18 Functions: 13 22 59.1 %
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 file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/chrome/RegistryMessageUtils.h"
       8             : #include "mozilla/dom/ContentParent.h"
       9             : #include "mozilla/Unused.h"
      10             : 
      11             : #include "SubstitutingProtocolHandler.h"
      12             : #include "nsIChannel.h"
      13             : #include "nsIIOService.h"
      14             : #include "nsIFile.h"
      15             : #include "nsNetCID.h"
      16             : #include "nsNetUtil.h"
      17             : #include "nsURLHelper.h"
      18             : #include "nsEscape.h"
      19             : 
      20             : using mozilla::dom::ContentParent;
      21             : 
      22             : namespace mozilla {
      23             : namespace net {
      24             : 
      25             : // Log module for Substituting Protocol logging. We keep the pre-existing module
      26             : // name of "nsResProtocol" to avoid disruption.
      27             : static LazyLogModule gResLog("nsResProtocol");
      28             : 
      29             : static NS_DEFINE_CID(kSubstitutingURLCID, NS_SUBSTITUTINGURL_CID);
      30             : 
      31             : //---------------------------------------------------------------------------------
      32             : // SubstitutingURL : overrides nsStandardURL::GetFile to provide nsIFile resolution
      33             : //---------------------------------------------------------------------------------
      34             : 
      35             : nsresult
      36         200 : SubstitutingURL::EnsureFile()
      37             : {
      38         400 :   nsAutoCString ourScheme;
      39         200 :   nsresult rv = GetScheme(ourScheme);
      40         200 :   NS_ENSURE_SUCCESS(rv, rv);
      41             : 
      42             :   // Get the handler associated with this scheme. It would be nice to just
      43             :   // pass this in when constructing SubstitutingURLs, but we need a generic
      44             :   // factory constructor.
      45         400 :   nsCOMPtr<nsIIOService> io = do_GetIOService(&rv);
      46         400 :   nsCOMPtr<nsIProtocolHandler> handler;
      47         200 :   rv = io->GetProtocolHandler(ourScheme.get(), getter_AddRefs(handler));
      48         200 :   NS_ENSURE_SUCCESS(rv, rv);
      49         400 :   nsCOMPtr<nsISubstitutingProtocolHandler> substHandler = do_QueryInterface(handler);
      50         200 :   MOZ_ASSERT(substHandler);
      51             : 
      52         400 :   nsAutoCString spec;
      53         200 :   rv = substHandler->ResolveURI(this, spec);
      54         200 :   if (NS_FAILED(rv))
      55           0 :     return rv;
      56             : 
      57         400 :   nsAutoCString scheme;
      58         200 :   rv = net_ExtractURLScheme(spec, scheme);
      59         200 :   if (NS_FAILED(rv))
      60           0 :     return rv;
      61             : 
      62             :   // Bug 585869:
      63             :   // In most cases, the scheme is jar if it's not file.
      64             :   // Regardless, net_GetFileFromURLSpec should be avoided
      65             :   // when the scheme isn't file.
      66         200 :   if (!scheme.EqualsLiteral("file"))
      67           0 :     return NS_ERROR_NO_INTERFACE;
      68             : 
      69         200 :   return net_GetFileFromURLSpec(spec, getter_AddRefs(mFile));
      70             : }
      71             : 
      72             : /* virtual */ nsStandardURL*
      73          14 : SubstitutingURL::StartClone()
      74             : {
      75          14 :   SubstitutingURL *clone = new SubstitutingURL();
      76          14 :   return clone;
      77             : }
      78             : 
      79             : NS_IMETHODIMP
      80           0 : SubstitutingURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
      81             : {
      82           0 :   *aClassIDNoAlloc = kSubstitutingURLCID;
      83           0 :   return NS_OK;
      84             : }
      85             : 
      86           3 : SubstitutingProtocolHandler::SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags,
      87           3 :                                                          bool aEnforceFileOrJar)
      88             :   : mScheme(aScheme)
      89             :   , mSubstitutions(16)
      90           3 :   , mEnforceFileOrJar(aEnforceFileOrJar)
      91             : {
      92           3 :   mFlags.emplace(aFlags);
      93           3 :   ConstructInternal();
      94           3 : }
      95             : 
      96           0 : SubstitutingProtocolHandler::SubstitutingProtocolHandler(const char* aScheme)
      97             :   : mScheme(aScheme)
      98             :   , mSubstitutions(16)
      99           0 :   , mEnforceFileOrJar(true)
     100             : {
     101           0 :   ConstructInternal();
     102           0 : }
     103             : 
     104             : void
     105           3 : SubstitutingProtocolHandler::ConstructInternal()
     106             : {
     107             :   nsresult rv;
     108           3 :   mIOService = do_GetIOService(&rv);
     109           3 :   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv) && mIOService);
     110           3 : }
     111             : 
     112             : //
     113             : // IPC marshalling.
     114             : //
     115             : 
     116             : nsresult
     117           2 : SubstitutingProtocolHandler::CollectSubstitutions(InfallibleTArray<SubstitutionMapping>& aMappings)
     118             : {
     119          24 :   for (auto iter = mSubstitutions.ConstIter(); !iter.Done(); iter.Next()) {
     120          44 :     nsCOMPtr<nsIURI> uri = iter.Data();
     121          44 :     SerializedURI serialized;
     122          22 :     if (uri) {
     123          22 :       nsresult rv = uri->GetSpec(serialized.spec);
     124          22 :       NS_ENSURE_SUCCESS(rv, rv);
     125          22 :       uri->GetOriginCharset(serialized.charset);
     126             :     }
     127          44 :     SubstitutionMapping substitution = { mScheme, nsCString(iter.Key()), serialized };
     128          22 :     aMappings.AppendElement(substitution);
     129             :   }
     130             : 
     131           2 :   return NS_OK;
     132             : }
     133             : 
     134             : nsresult
     135          33 : SubstitutingProtocolHandler::SendSubstitution(const nsACString& aRoot, nsIURI* aBaseURI)
     136             : {
     137          33 :   if (GeckoProcessType_Content == XRE_GetProcessType()) {
     138          22 :     return NS_OK;
     139             :   }
     140             : 
     141          22 :   nsTArray<ContentParent*> parents;
     142          11 :   ContentParent::GetAll(parents);
     143          11 :   if (!parents.Length()) {
     144          11 :     return NS_OK;
     145             :   }
     146             : 
     147           0 :   SubstitutionMapping mapping;
     148           0 :   mapping.scheme = mScheme;
     149           0 :   mapping.path = aRoot;
     150           0 :   if (aBaseURI) {
     151           0 :     nsresult rv = aBaseURI->GetSpec(mapping.resolvedURI.spec);
     152           0 :     NS_ENSURE_SUCCESS(rv, rv);
     153           0 :     aBaseURI->GetOriginCharset(mapping.resolvedURI.charset);
     154             :   }
     155             : 
     156           0 :   for (uint32_t i = 0; i < parents.Length(); i++) {
     157           0 :     Unused << parents[i]->SendRegisterChromeItem(mapping);
     158             :   }
     159             : 
     160           0 :   return NS_OK;
     161             : }
     162             : 
     163             : //----------------------------------------------------------------------------
     164             : // nsIProtocolHandler
     165             : //----------------------------------------------------------------------------
     166             : 
     167             : nsresult
     168           0 : SubstitutingProtocolHandler::GetScheme(nsACString &result)
     169             : {
     170           0 :   result = mScheme;
     171           0 :   return NS_OK;
     172             : }
     173             : 
     174             : nsresult
     175           0 : SubstitutingProtocolHandler::GetDefaultPort(int32_t *result)
     176             : {
     177           0 :   *result = -1;
     178           0 :   return NS_OK;
     179             : }
     180             : 
     181             : nsresult
     182        1116 : SubstitutingProtocolHandler::GetProtocolFlags(uint32_t *result)
     183             : {
     184        1116 :   if (mFlags.isNothing()) {
     185           0 :     NS_WARNING("Trying to get protocol flags the wrong way - use nsIProtocolHandlerWithDynamicFlags instead");
     186           0 :     return NS_ERROR_NOT_AVAILABLE;
     187             :   }
     188             : 
     189        1116 :   *result = mFlags.ref();
     190        1116 :   return NS_OK;
     191             : }
     192             : 
     193             : nsresult
     194        1062 : SubstitutingProtocolHandler::NewURI(const nsACString &aSpec,
     195             :                                     const char *aCharset,
     196             :                                     nsIURI *aBaseURI,
     197             :                                     nsIURI **result)
     198             : {
     199             :   nsresult rv;
     200             : 
     201        2124 :   RefPtr<SubstitutingURL> url = new SubstitutingURL();
     202        1062 :   if (!url)
     203           0 :     return NS_ERROR_OUT_OF_MEMORY;
     204             : 
     205             :   // unescape any %2f and %2e to make sure nsStandardURL coalesces them.
     206             :   // Later net_GetFileFromURLSpec() will do a full unescape and we want to
     207             :   // treat them the same way the file system will. (bugs 380994, 394075)
     208        2124 :   nsAutoCString spec;
     209        1062 :   const char *src = aSpec.BeginReading();
     210        1062 :   const char *end = aSpec.EndReading();
     211        1062 :   const char *last = src;
     212             : 
     213        1062 :   spec.SetCapacity(aSpec.Length()+1);
     214       82268 :   for ( ; src < end; ++src) {
     215       40603 :     if (*src == '%' && (src < end-2) && *(src+1) == '2') {
     216           0 :       char ch = '\0';
     217           0 :       if (*(src+2) == 'f' || *(src+2) == 'F') {
     218           0 :         ch = '/';
     219           0 :       } else if (*(src+2) == 'e' || *(src+2) == 'E') {
     220           0 :         ch = '.';
     221             :       }
     222             : 
     223           0 :       if (ch) {
     224           0 :         if (last < src) {
     225           0 :           spec.Append(last, src-last);
     226             :         }
     227           0 :         spec.Append(ch);
     228           0 :         src += 2;
     229           0 :         last = src+1; // src will be incremented by the loop
     230             :       }
     231             :     }
     232             :   }
     233        1062 :   if (last < src)
     234        1062 :     spec.Append(last, src-last);
     235             : 
     236        1062 :   rv = url->Init(nsIStandardURL::URLTYPE_STANDARD, -1, spec, aCharset, aBaseURI);
     237        1062 :   if (NS_SUCCEEDED(rv)) {
     238        1062 :     url.forget(result);
     239             :   }
     240        1062 :   return rv;
     241             : }
     242             : 
     243             : nsresult
     244        1031 : SubstitutingProtocolHandler::NewChannel2(nsIURI* uri,
     245             :                                          nsILoadInfo* aLoadInfo,
     246             :                                          nsIChannel** result)
     247             : {
     248        1031 :   NS_ENSURE_ARG_POINTER(uri);
     249        1031 :   NS_ENSURE_ARG_POINTER(aLoadInfo);
     250             : 
     251        2062 :   nsAutoCString spec;
     252        1031 :   nsresult rv = ResolveURI(uri, spec);
     253        1031 :   NS_ENSURE_SUCCESS(rv, rv);
     254             : 
     255        2062 :   nsCOMPtr<nsIURI> newURI;
     256        1031 :   rv = NS_NewURI(getter_AddRefs(newURI), spec);
     257        1031 :   NS_ENSURE_SUCCESS(rv, rv);
     258             : 
     259             :   // We don't want to allow the inner protocol handler to modify the result
     260             :   // principal URI since we want either |uri| or anything pre-set by upper
     261             :   // layers to prevail.
     262        2062 :   nsCOMPtr<nsIURI> savedResultPrincipalURI;
     263        1031 :   rv = aLoadInfo->GetResultPrincipalURI(getter_AddRefs(savedResultPrincipalURI));
     264        1031 :   NS_ENSURE_SUCCESS(rv, rv);
     265             : 
     266        1031 :   rv = NS_NewChannelInternal(result, newURI, aLoadInfo);
     267        1031 :   NS_ENSURE_SUCCESS(rv, rv);
     268             : 
     269        1031 :   rv = aLoadInfo->SetResultPrincipalURI(savedResultPrincipalURI);
     270        1031 :   NS_ENSURE_SUCCESS(rv, rv);
     271        1031 :   rv = (*result)->SetOriginalURI(uri);
     272        1031 :   NS_ENSURE_SUCCESS(rv, rv);
     273             : 
     274        1031 :   return SubstituteChannel(uri, aLoadInfo, result);
     275             : }
     276             : 
     277             : nsresult
     278           0 : SubstitutingProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
     279             : {
     280           0 :   return NewChannel2(uri, nullptr, result);
     281             : }
     282             : 
     283             : nsresult
     284           0 : SubstitutingProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
     285             : {
     286             :   // don't override anything.
     287           0 :   *_retval = false;
     288           0 :   return NS_OK;
     289             : }
     290             : 
     291             : //----------------------------------------------------------------------------
     292             : // nsISubstitutingProtocolHandler
     293             : //----------------------------------------------------------------------------
     294             : 
     295             : nsresult
     296          33 : SubstitutingProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI)
     297             : {
     298          33 :   if (!baseURI) {
     299           0 :     mSubstitutions.Remove(root);
     300           0 :     NotifyObservers(root, baseURI);
     301           0 :     return SendSubstitution(root, baseURI);
     302             :   }
     303             : 
     304             :   // If baseURI isn't a same-scheme URI, we can set the substitution immediately.
     305          66 :   nsAutoCString scheme;
     306          33 :   nsresult rv = baseURI->GetScheme(scheme);
     307          33 :   NS_ENSURE_SUCCESS(rv, rv);
     308          33 :   if (!scheme.Equals(mScheme)) {
     309          60 :     if (mEnforceFileOrJar && !scheme.EqualsLiteral("file") && !scheme.EqualsLiteral("jar")
     310          30 :         && !scheme.EqualsLiteral("app")) {
     311           0 :       NS_WARNING("Refusing to create substituting URI to non-file:// target");
     312           0 :       return NS_ERROR_INVALID_ARG;
     313             :     }
     314             : 
     315          30 :     mSubstitutions.Put(root, baseURI);
     316          30 :     NotifyObservers(root, baseURI);
     317          30 :     return SendSubstitution(root, baseURI);
     318             :   }
     319             : 
     320             :   // baseURI is a same-type substituting URI, let's resolve it first.
     321           6 :   nsAutoCString newBase;
     322           3 :   rv = ResolveURI(baseURI, newBase);
     323           3 :   NS_ENSURE_SUCCESS(rv, rv);
     324             : 
     325           6 :   nsCOMPtr<nsIURI> newBaseURI;
     326           3 :   rv = mIOService->NewURI(newBase, nullptr, nullptr, getter_AddRefs(newBaseURI));
     327           3 :   NS_ENSURE_SUCCESS(rv, rv);
     328             : 
     329           3 :   mSubstitutions.Put(root, newBaseURI);
     330           3 :   NotifyObservers(root, baseURI);
     331           3 :   return SendSubstitution(root, newBaseURI);
     332             : }
     333             : 
     334             : nsresult
     335         169 : SubstitutingProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result)
     336             : {
     337         169 :   NS_ENSURE_ARG_POINTER(result);
     338             : 
     339         169 :   if (mSubstitutions.Get(root, result))
     340         169 :     return NS_OK;
     341             : 
     342           0 :   return GetSubstitutionInternal(root, result);
     343             : }
     344             : 
     345             : nsresult
     346           0 : SubstitutingProtocolHandler::HasSubstitution(const nsACString& root, bool *result)
     347             : {
     348           0 :   NS_ENSURE_ARG_POINTER(result);
     349           0 :   *result = HasSubstitution(root);
     350           0 :   return NS_OK;
     351             : }
     352             : 
     353             : nsresult
     354        1611 : SubstitutingProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result)
     355             : {
     356             :   nsresult rv;
     357             : 
     358        3222 :   nsAutoCString host;
     359        3222 :   nsAutoCString path;
     360        3222 :   nsAutoCString pathname;
     361             : 
     362        3222 :   nsCOMPtr<nsIURL> url = do_QueryInterface(uri);
     363        1611 :   if (!url) {
     364           0 :     return NS_ERROR_MALFORMED_URI;
     365             :   }
     366             : 
     367        1611 :   rv = uri->GetAsciiHost(host);
     368        1611 :   if (NS_FAILED(rv)) return rv;
     369             : 
     370        1611 :   rv = uri->GetPath(path);
     371        1611 :   if (NS_FAILED(rv)) return rv;
     372             : 
     373        1611 :   rv = url->GetFilePath(pathname);
     374        1611 :   if (NS_FAILED(rv)) return rv;
     375             : 
     376        1611 :   if (ResolveSpecialCases(host, path, pathname, result)) {
     377        1442 :     return NS_OK;
     378             :   }
     379             : 
     380         338 :   nsCOMPtr<nsIURI> baseURI;
     381         169 :   rv = GetSubstitution(host, getter_AddRefs(baseURI));
     382         169 :   if (NS_FAILED(rv)) return rv;
     383             : 
     384             :   // Unescape the path so we can perform some checks on it.
     385         169 :   NS_UnescapeURL(pathname);
     386         169 :   if (pathname.FindChar('\\') != -1) {
     387           0 :     return NS_ERROR_MALFORMED_URI;
     388             :   }
     389             : 
     390             :   // Some code relies on an empty path resolving to a file rather than a
     391             :   // directory.
     392         169 :   NS_ASSERTION(path.CharAt(0) == '/', "Path must begin with '/'");
     393         169 :   if (path.Length() == 1) {
     394           0 :     rv = baseURI->GetSpec(result);
     395             :   } else {
     396             :     // Make sure we always resolve the path as file-relative to our target URI.
     397         169 :     path.InsertLiteral(".", 0);
     398             : 
     399         169 :     rv = baseURI->Resolve(path, result);
     400             :   }
     401             : 
     402         169 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     403           0 :     return rv;
     404             :   }
     405             : 
     406         169 :   if (MOZ_LOG_TEST(gResLog, LogLevel::Debug)) {
     407           0 :     nsAutoCString spec;
     408           0 :     uri->GetAsciiSpec(spec);
     409           0 :     MOZ_LOG(gResLog, LogLevel::Debug, ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get()));
     410             :   }
     411         169 :   return rv;
     412             : }
     413             : 
     414             : nsresult
     415           0 : SubstitutingProtocolHandler::AddObserver(nsISubstitutionObserver* aObserver)
     416             : {
     417           0 :   NS_ENSURE_ARG(aObserver);
     418           0 :   if (mObservers.Contains(aObserver)) {
     419           0 :     return NS_ERROR_DUPLICATE_HANDLE;
     420             :   }
     421             : 
     422           0 :   mObservers.AppendElement(aObserver);
     423           0 :   return NS_OK;
     424             : }
     425             : 
     426             : nsresult
     427           0 : SubstitutingProtocolHandler::RemoveObserver(nsISubstitutionObserver* aObserver)
     428             : {
     429           0 :   NS_ENSURE_ARG(aObserver);
     430           0 :   if (!mObservers.Contains(aObserver)) {
     431           0 :     return NS_ERROR_INVALID_ARG;
     432             :   }
     433             : 
     434           0 :   mObservers.RemoveElement(aObserver);
     435           0 :   return NS_OK;
     436             : }
     437             : 
     438             : void
     439          33 : SubstitutingProtocolHandler::NotifyObservers(const nsACString& aRoot,
     440             :                                              nsIURI* aBaseURI)
     441             : {
     442          33 :   for (size_t i = 0; i < mObservers.Length(); ++i) {
     443           0 :     mObservers[i]->OnSetSubstitution(aRoot, aBaseURI);
     444             :   }
     445          33 : }
     446             : 
     447             : } // namespace net
     448             : } // namespace mozilla

Generated by: LCOV version 1.13