LCOV - code coverage report
Current view: top level - toolkit/mozapps/extensions - AddonPathService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 90 133 67.7 %
Date: 2017-07-14 16:53:18 Functions: 13 17 76.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       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 "AddonPathService.h"
       7             : 
       8             : #include "amIAddonManager.h"
       9             : #include "nsIURI.h"
      10             : #include "nsXULAppAPI.h"
      11             : #include "jsapi.h"
      12             : #include "nsServiceManagerUtils.h"
      13             : #include "nsLiteralString.h"
      14             : #include "nsThreadUtils.h"
      15             : #include "nsIIOService.h"
      16             : #include "nsNetUtil.h"
      17             : #include "nsIAddonPolicyService.h"
      18             : #include "nsIFileURL.h"
      19             : #include "nsIResProtocolHandler.h"
      20             : #include "nsIChromeRegistry.h"
      21             : #include "nsIJARURI.h"
      22             : #include "nsJSUtils.h"
      23             : #include "mozilla/dom/ScriptSettings.h"
      24             : #include "mozilla/dom/ToJSValue.h"
      25             : #include "mozilla/AddonPathService.h"
      26             : #include "mozilla/Omnijar.h"
      27             : 
      28             : #include <algorithm>
      29             : 
      30             : namespace mozilla {
      31             : 
      32             : struct PathEntryComparator
      33             : {
      34             :   typedef AddonPathService::PathEntry PathEntry;
      35             : 
      36         247 :   bool Equals(const PathEntry& entry1, const PathEntry& entry2) const
      37             :   {
      38         247 :     return entry1.mPath == entry2.mPath;
      39             :   }
      40             : 
      41         657 :   bool LessThan(const PathEntry& entry1, const PathEntry& entry2) const
      42             :   {
      43         657 :     return entry1.mPath < entry2.mPath;
      44             :   }
      45             : };
      46             : 
      47           1 : AddonPathService::AddonPathService()
      48             : {
      49           1 : }
      50             : 
      51           0 : AddonPathService::~AddonPathService()
      52             : {
      53           0 :   sInstance = nullptr;
      54           0 : }
      55             : 
      56          48 : NS_IMPL_ISUPPORTS(AddonPathService, amIAddonPathService)
      57             : 
      58             : AddonPathService *AddonPathService::sInstance;
      59             : 
      60             : /* static */ AddonPathService*
      61           1 : AddonPathService::GetInstance()
      62             : {
      63           1 :   if (!sInstance) {
      64           1 :     sInstance = new AddonPathService();
      65             :   }
      66           1 :   NS_ADDREF(sInstance);
      67           1 :   return sInstance;
      68             : }
      69             : 
      70             : static JSAddonId*
      71          17 : ConvertAddonId(const nsAString& addonIdString)
      72             : {
      73          34 :   AutoSafeJSContext cx;
      74          34 :   JS::RootedValue strv(cx);
      75          17 :   if (!mozilla::dom::ToJSValue(cx, addonIdString, &strv)) {
      76           0 :     return nullptr;
      77             :   }
      78          34 :   JS::RootedString str(cx, strv.toString());
      79          17 :   return JS::NewAddonId(cx, str);
      80             : }
      81             : 
      82             : JSAddonId*
      83         147 : AddonPathService::Find(const nsAString& path)
      84             : {
      85             :   // Use binary search to find the nearest entry that is <= |path|.
      86             :   PathEntryComparator comparator;
      87         147 :   unsigned index = mPaths.IndexOfFirstElementGt(PathEntry(path, nullptr), comparator);
      88         147 :   if (index == 0) {
      89          12 :     return nullptr;
      90             :   }
      91         135 :   const PathEntry& entry = mPaths[index - 1];
      92             : 
      93             :   // Return the entry's addon if its path is a prefix of |path|.
      94         135 :   if (StringBeginsWith(path, entry.mPath)) {
      95          15 :     return entry.mAddonId;
      96             :   }
      97         120 :   return nullptr;
      98             : }
      99             : 
     100             : NS_IMETHODIMP
     101           0 : AddonPathService::FindAddonId(const nsAString& path, nsAString& addonIdString)
     102             : {
     103           0 :   if (JSAddonId* id = Find(path)) {
     104           0 :     JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(id));
     105           0 :     AssignJSFlatString(addonIdString, flat);
     106             :   }
     107           0 :   return NS_OK;
     108             : }
     109             : 
     110             : /* static */ JSAddonId*
     111         185 : AddonPathService::FindAddonId(const nsAString& path)
     112             : {
     113             :   // If no service has been created, then we're not going to find anything.
     114         185 :   if (!sInstance) {
     115          38 :     return nullptr;
     116             :   }
     117             : 
     118         147 :   return sInstance->Find(path);
     119             : }
     120             : 
     121             : NS_IMETHODIMP
     122          17 : AddonPathService::InsertPath(const nsAString& path, const nsAString& addonIdString)
     123             : {
     124          17 :   JSAddonId* addonId = ConvertAddonId(addonIdString);
     125             : 
     126             :   // Add the new path in sorted order.
     127             :   PathEntryComparator comparator;
     128          17 :   mPaths.InsertElementSorted(PathEntry(path, addonId), comparator);
     129          17 :   return NS_OK;
     130             : }
     131             : 
     132             : NS_IMETHODIMP
     133           0 : AddonPathService::MapURIToAddonId(nsIURI* aURI, nsAString& addonIdString)
     134             : {
     135           0 :   if (JSAddonId* id = MapURIToAddonID(aURI)) {
     136           0 :     JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(id));
     137           0 :     AssignJSFlatString(addonIdString, flat);
     138             :   }
     139           0 :   return NS_OK;
     140             : }
     141             : 
     142             : static nsresult
     143         464 : ResolveURI(nsIURI* aURI, nsAString& out)
     144             : {
     145             :   bool equals;
     146             :   nsresult rv;
     147         928 :   nsCOMPtr<nsIURI> uri;
     148         928 :   nsAutoCString spec;
     149             : 
     150             :   // Resolve resource:// URIs. At the end of this if/else block, we
     151             :   // have both spec and uri variables identifying the same URI.
     152         464 :   if (NS_SUCCEEDED(aURI->SchemeIs("resource", &equals)) && equals) {
     153         278 :     nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
     154         139 :     if (NS_WARN_IF(NS_FAILED(rv)))
     155           0 :       return rv;
     156             : 
     157         278 :     nsCOMPtr<nsIProtocolHandler> ph;
     158         139 :     rv = ioService->GetProtocolHandler("resource", getter_AddRefs(ph));
     159         139 :     if (NS_WARN_IF(NS_FAILED(rv)))
     160           0 :       return rv;
     161             : 
     162         278 :     nsCOMPtr<nsIResProtocolHandler> irph(do_QueryInterface(ph, &rv));
     163         139 :     if (NS_WARN_IF(NS_FAILED(rv)))
     164           0 :       return rv;
     165             : 
     166         139 :     rv = irph->ResolveURI(aURI, spec);
     167         139 :     if (NS_WARN_IF(NS_FAILED(rv)))
     168           0 :       return rv;
     169             : 
     170         139 :     rv = ioService->NewURI(spec, nullptr, nullptr, getter_AddRefs(uri));
     171         139 :     if (NS_WARN_IF(NS_FAILED(rv)))
     172           0 :       return rv;
     173         325 :   } else if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &equals)) && equals) {
     174             :     // Going through the Chrome Registry may be prohibitively slow for many of
     175             :     // the well-known chrome:// URI packages, so check for a few of them here
     176             :     // first in order to fail early if we don't have a chrome:// URI which
     177             :     // could have been provided by an add-on.
     178         286 :     nsAutoCString package;
     179         281 :     rv = aURI->GetHostPort(package);
     180         843 :     if (NS_WARN_IF(NS_FAILED(rv)) ||
     181         562 :         package.EqualsLiteral("branding") ||
     182         429 :         package.EqualsLiteral("browser") ||
     183         296 :         package.EqualsLiteral("branding") ||
     184         153 :         package.EqualsLiteral("global") ||
     185          10 :         package.EqualsLiteral("global-platform") ||
     186          10 :         package.EqualsLiteral("mozapps") ||
     187          10 :         package.EqualsLiteral("necko") ||
     188          10 :         package.EqualsLiteral("passwordmgr") ||
     189         291 :         package.EqualsLiteral("pippki") ||
     190           5 :         package.EqualsLiteral("pipnss")) {
     191             :       // Returning a failure code means the URI isn't associated with an add-on
     192             :       // ID.
     193         276 :       return NS_ERROR_FAILURE;
     194             :     }
     195             : 
     196             :     nsCOMPtr<nsIChromeRegistry> chromeReg =
     197          10 :       mozilla::services::GetChromeRegistryService();
     198           5 :     if (NS_WARN_IF(!chromeReg))
     199           0 :       return NS_ERROR_UNEXPECTED;
     200             : 
     201           5 :     rv = chromeReg->ConvertChromeURL(aURI, getter_AddRefs(uri));
     202           5 :     if (NS_WARN_IF(NS_FAILED(rv)))
     203           0 :       return rv;
     204             :   } else {
     205          44 :     uri = aURI;
     206             :   }
     207             : 
     208         188 :   if (NS_SUCCEEDED(uri->SchemeIs("jar", &equals)) && equals) {
     209           0 :     nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(uri, &rv);
     210           0 :     if (NS_WARN_IF(NS_FAILED(rv)))
     211           0 :       return rv;
     212             : 
     213           0 :     nsCOMPtr<nsIURI> jarFileURI;
     214           0 :     rv = jarURI->GetJARFile(getter_AddRefs(jarFileURI));
     215           0 :     if (NS_WARN_IF(NS_FAILED(rv)))
     216           0 :       return rv;
     217             : 
     218           0 :     return ResolveURI(jarFileURI, out);
     219             :   }
     220             : 
     221         188 :   if (NS_SUCCEEDED(uri->SchemeIs("file", &equals)) && equals) {
     222         370 :     nsCOMPtr<nsIFileURL> baseFileURL = do_QueryInterface(uri, &rv);
     223         185 :     if (NS_WARN_IF(NS_FAILED(rv)))
     224           0 :       return rv;
     225             : 
     226         370 :     nsCOMPtr<nsIFile> file;
     227         185 :     rv = baseFileURL->GetFile(getter_AddRefs(file));
     228         185 :     if (NS_WARN_IF(NS_FAILED(rv)))
     229           0 :       return rv;
     230             : 
     231         185 :     return file->GetPath(out);
     232             :   }
     233           3 :   return NS_ERROR_FAILURE;
     234             : }
     235             : 
     236             : JSAddonId*
     237         533 : MapURIToAddonID(nsIURI* aURI)
     238             : {
     239         533 :   if (!NS_IsMainThread() || !XRE_IsParentProcess()) {
     240          69 :     return nullptr;
     241             :   }
     242             : 
     243             :   bool equals;
     244             :   nsresult rv;
     245         464 :   if (NS_SUCCEEDED(aURI->SchemeIs("moz-extension", &equals)) && equals) {
     246           0 :     nsCOMPtr<nsIAddonPolicyService> service = do_GetService("@mozilla.org/addons/policy-service;1");
     247           0 :     if (service) {
     248           0 :       nsString addonId;
     249           0 :       rv = service->ExtensionURIToAddonId(aURI, addonId);
     250           0 :       if (NS_FAILED(rv))
     251           0 :         return nullptr;
     252             : 
     253           0 :       return ConvertAddonId(addonId);
     254             :     }
     255             :   }
     256             : 
     257         928 :   nsAutoString filePath;
     258         464 :   rv = ResolveURI(aURI, filePath);
     259         464 :   if (NS_FAILED(rv))
     260         279 :     return nullptr;
     261             : 
     262         370 :   nsCOMPtr<nsIFile> greJar = Omnijar::GetPath(Omnijar::GRE);
     263         370 :   nsCOMPtr<nsIFile> appJar = Omnijar::GetPath(Omnijar::APP);
     264         185 :   if (greJar && appJar) {
     265           0 :     nsAutoString greJarString, appJarString;
     266           0 :     if (NS_FAILED(greJar->GetPath(greJarString)) || NS_FAILED(appJar->GetPath(appJarString)))
     267           0 :       return nullptr;
     268             : 
     269             :     // If |aURI| is part of either Omnijar, then it can't be part of an
     270             :     // add-on. This catches pretty much all URLs for Firefox content.
     271           0 :     if (filePath.Equals(greJarString) || filePath.Equals(appJarString))
     272           0 :       return nullptr;
     273             :   }
     274             : 
     275             :   // If it's not part of Firefox, we resort to binary searching through the
     276             :   // add-on paths.
     277         185 :   return AddonPathService::FindAddonId(filePath);
     278             : }
     279             : 
     280             : } // namespace mozilla

Generated by: LCOV version 1.13