chrome/src/nsChromeRegistryChrome.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     6 #include "mozilla/dom/PContentParent.h"
     7 #include "RegistryMessageUtils.h"
     8 #include "nsResProtocolHandler.h"
    10 #include "nsChromeRegistryChrome.h"
    12 #if defined(XP_WIN)
    13 #include <windows.h>
    14 #elif defined(XP_MACOSX)
    15 #include <CoreServices/CoreServices.h>
    16 #endif
    18 #include "nsArrayEnumerator.h"
    19 #include "nsComponentManager.h"
    20 #include "nsEnumeratorUtils.h"
    21 #include "nsNetUtil.h"
    22 #include "nsStringEnumerator.h"
    23 #include "nsTextFormatter.h"
    24 #include "nsXPCOMCIDInternal.h"
    26 #include "mozilla/LookAndFeel.h"
    28 #include "nsICommandLine.h"
    29 #include "nsILocaleService.h"
    30 #include "nsIObserverService.h"
    31 #include "nsIPrefBranch.h"
    32 #include "nsIPrefService.h"
    33 #include "mozilla/Preferences.h"
    34 #include "nsIResProtocolHandler.h"
    35 #include "nsIScriptError.h"
    36 #include "nsIXPConnect.h"
    37 #include "nsIXULRuntime.h"
    39 #define UILOCALE_CMD_LINE_ARG "UILocale"
    41 #define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
    42 #define SELECTED_LOCALE_PREF "general.useragent.locale"
    43 #define SELECTED_SKIN_PREF   "general.skins.selectedSkin"
    44 #define PACKAGE_OVERRIDE_BRANCH "chrome.override_package."
    46 using namespace mozilla;
    48 static PLDHashOperator
    49 RemoveAll(PLDHashTable *table, PLDHashEntryHdr *entry, uint32_t number, void *arg)
    50 {
    51   return (PLDHashOperator) (PL_DHASH_NEXT | PL_DHASH_REMOVE);
    52 }
    54 // We use a "best-fit" algorithm for matching locales and themes. 
    55 // 1) the exact selected locale/theme
    56 // 2) (locales only) same language, different country
    57 //    e.g. en-GB is the selected locale, only en-US is available
    58 // 3) any available locale/theme
    60 /**
    61  * Match the language-part of two lang-COUNTRY codes, hopefully but
    62  * not guaranteed to be in the form ab-CD or abz-CD. "ab" should also
    63  * work, any other garbage-in will produce undefined results as long
    64  * as it does not crash.
    65  */
    66 static bool
    67 LanguagesMatch(const nsACString& a, const nsACString& b)
    68 {
    69   if (a.Length() < 2 || b.Length() < 2)
    70     return false;
    72   nsACString::const_iterator as, ae, bs, be;
    73   a.BeginReading(as);
    74   a.EndReading(ae);
    75   b.BeginReading(bs);
    76   b.EndReading(be);
    78   while (*as == *bs) {
    79     if (*as == '-')
    80       return true;
    82     ++as; ++bs;
    84     // reached the end
    85     if (as == ae && bs == be)
    86       return true;
    88     // "a" is short
    89     if (as == ae)
    90       return (*bs == '-');
    92     // "b" is short
    93     if (bs == be)
    94       return (*as == '-');
    95   }
    97   return false;
    98 }
   100 nsChromeRegistryChrome::nsChromeRegistryChrome()
   101   : mProfileLoaded(false)
   102 {
   103   mPackagesHash.ops = nullptr;
   104 }
   106 nsChromeRegistryChrome::~nsChromeRegistryChrome()
   107 {
   108   if (mPackagesHash.ops)
   109     PL_DHashTableFinish(&mPackagesHash);
   110 }
   112 nsresult
   113 nsChromeRegistryChrome::Init()
   114 {
   115   nsresult rv = nsChromeRegistry::Init();
   116   if (NS_FAILED(rv))
   117     return rv;
   119   mSelectedLocale = NS_LITERAL_CSTRING("en-US");
   120   mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
   122   PL_DHashTableInit(&mPackagesHash, &kTableOps,
   123                     nullptr, sizeof(PackageEntry), 16);
   125   bool safeMode = false;
   126   nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
   127   if (xulrun)
   128     xulrun->GetInSafeMode(&safeMode);
   130   nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
   131   nsCOMPtr<nsIPrefBranch> prefs;
   133   if (safeMode)
   134     prefserv->GetDefaultBranch(nullptr, getter_AddRefs(prefs));
   135   else
   136     prefs = do_QueryInterface(prefserv);
   138   if (!prefs) {
   139     NS_WARNING("Could not get pref service!");
   140   }
   141   else {
   142     nsXPIDLCString provider;
   143     rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
   144     if (NS_SUCCEEDED(rv))
   145       mSelectedSkin = provider;
   147     SelectLocaleFromPref(prefs);
   149     rv = prefs->AddObserver(MATCH_OS_LOCALE_PREF, this, true);
   150     rv = prefs->AddObserver(SELECTED_LOCALE_PREF, this, true);
   151     rv = prefs->AddObserver(SELECTED_SKIN_PREF, this, true);
   152   }
   154   nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
   155   if (obsService) {
   156     obsService->AddObserver(this, "command-line-startup", true);
   157     obsService->AddObserver(this, "profile-initial-state", true);
   158   }
   160   return NS_OK;
   161 }
   163 NS_IMETHODIMP
   164 nsChromeRegistryChrome::CheckForOSAccessibility()
   165 {
   166   int32_t useAccessibilityTheme =
   167     LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
   169   if (useAccessibilityTheme) {
   170     /* Set the skin to classic and remove pref observers */
   171     if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
   172       mSelectedSkin.AssignLiteral("classic/1.0");
   173       RefreshSkins();
   174     }
   176     nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
   177     if (prefs) {
   178       prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
   179     }
   180   }
   182   return NS_OK;
   183 }
   185 NS_IMETHODIMP
   186 nsChromeRegistryChrome::GetLocalesForPackage(const nsACString& aPackage,
   187                                        nsIUTF8StringEnumerator* *aResult)
   188 {
   189   nsCString realpackage;
   190   nsresult rv = OverrideLocalePackage(aPackage, realpackage);
   191   if (NS_FAILED(rv))
   192     return rv;
   194   nsTArray<nsCString> *a = new nsTArray<nsCString>;
   195   if (!a)
   196     return NS_ERROR_OUT_OF_MEMORY;
   198   PackageEntry* entry =
   199       static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
   200                                                       & realpackage,
   201                                                       PL_DHASH_LOOKUP));
   203   if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
   204     entry->locales.EnumerateToArray(a);
   205   }
   207   rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
   208   if (NS_FAILED(rv))
   209     delete a;
   211   return rv;
   212 }
   214 static nsresult
   215 getUILangCountry(nsACString& aUILang)
   216 {
   217   nsresult rv;
   219   nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
   220   NS_ENSURE_SUCCESS(rv, rv);
   222   nsAutoString uiLang;
   223   rv = localeService->GetLocaleComponentForUserAgent(uiLang);
   224   NS_ENSURE_SUCCESS(rv, rv);
   226   CopyUTF16toUTF8(uiLang, aUILang);
   227   return NS_OK;
   228 }
   230 NS_IMETHODIMP
   231 nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool *aResult)
   232 {
   233   *aResult = false;
   235   nsAutoCString locale;
   236   GetSelectedLocale(package, locale);
   237   if (locale.Length() < 2)
   238     return NS_OK;
   240   // first check the intl.uidirection.<locale> preference, and if that is not
   241   // set, check the same preference but with just the first two characters of
   242   // the locale. If that isn't set, default to left-to-right.
   243   nsAutoCString prefString = NS_LITERAL_CSTRING("intl.uidirection.") + locale;
   244   nsCOMPtr<nsIPrefBranch> prefBranch (do_GetService(NS_PREFSERVICE_CONTRACTID));
   245   if (!prefBranch)
   246     return NS_OK;
   248   nsXPIDLCString dir;
   249   prefBranch->GetCharPref(prefString.get(), getter_Copies(dir));
   250   if (dir.IsEmpty()) {
   251     int32_t hyphen = prefString.FindChar('-');
   252     if (hyphen >= 1) {
   253       nsAutoCString shortPref(Substring(prefString, 0, hyphen));
   254       prefBranch->GetCharPref(shortPref.get(), getter_Copies(dir));
   255     }
   256   }
   257   *aResult = dir.EqualsLiteral("rtl");
   258   return NS_OK;
   259 }
   261 nsresult
   262 nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
   263                                           nsACString& aLocale)
   264 {
   265   nsCString realpackage;
   266   nsresult rv = OverrideLocalePackage(aPackage, realpackage);
   267   if (NS_FAILED(rv))
   268     return rv;
   269   PackageEntry* entry =
   270       static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
   271                                                       & realpackage,
   272                                                       PL_DHASH_LOOKUP));
   274   if (PL_DHASH_ENTRY_IS_FREE(entry))
   275     return NS_ERROR_FAILURE;
   277   aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
   278   if (aLocale.IsEmpty())
   279     return NS_ERROR_FAILURE;
   281   return NS_OK;
   282 }
   284 nsresult
   285 nsChromeRegistryChrome::OverrideLocalePackage(const nsACString& aPackage,
   286                                               nsACString& aOverride)
   287 {
   288   const nsACString& pref = NS_LITERAL_CSTRING(PACKAGE_OVERRIDE_BRANCH) + aPackage;
   289   nsAdoptingCString override = mozilla::Preferences::GetCString(PromiseFlatCString(pref).get());
   290   if (override) {
   291     aOverride = override;
   292   }
   293   else {
   294     aOverride = aPackage;
   295   }
   296   return NS_OK;
   297 }
   299 nsresult
   300 nsChromeRegistryChrome::SelectLocaleFromPref(nsIPrefBranch* prefs)
   301 {
   302   nsresult rv;
   303   bool matchOSLocale = false;
   304   rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOSLocale);
   306   if (NS_SUCCEEDED(rv) && matchOSLocale) {
   307     // compute lang and region code only when needed!
   308     nsAutoCString uiLocale;
   309     rv = getUILangCountry(uiLocale);
   310     if (NS_SUCCEEDED(rv))
   311       mSelectedLocale = uiLocale;
   312   }
   313   else {
   314     nsXPIDLCString provider;
   315     rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
   316     if (NS_SUCCEEDED(rv)) {
   317       mSelectedLocale = provider;
   318     }
   319   }
   321   if (NS_FAILED(rv))
   322     NS_ERROR("Couldn't select locale from pref!");
   324   return rv;
   325 }
   327 NS_IMETHODIMP
   328 nsChromeRegistryChrome::Observe(nsISupports *aSubject, const char *aTopic,
   329                                 const char16_t *someData)
   330 {
   331   nsresult rv = NS_OK;
   333   if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
   334     nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
   335     NS_ASSERTION(prefs, "Bad observer call!");
   337     NS_ConvertUTF16toUTF8 pref(someData);
   339     if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
   340         pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
   341         rv = UpdateSelectedLocale();
   342         if (NS_SUCCEEDED(rv) && mProfileLoaded)
   343           FlushAllCaches();
   344     }
   345     else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
   346       nsXPIDLCString provider;
   347       rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
   348       if (NS_FAILED(rv)) {
   349         NS_ERROR("Couldn't get new skin pref!");
   350         return rv;
   351       }
   353       mSelectedSkin = provider;
   354       RefreshSkins();
   355     } else {
   356       NS_ERROR("Unexpected pref!");
   357     }
   358   }
   359   else if (!strcmp("command-line-startup", aTopic)) {
   360     nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
   361     if (cmdLine) {
   362       nsAutoString uiLocale;
   363       rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
   364                                         false, uiLocale);
   365       if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
   366         CopyUTF16toUTF8(uiLocale, mSelectedLocale);
   367         nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
   368         if (prefs) {
   369           prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
   370         }
   371       }
   372     }
   373   }
   374   else if (!strcmp("profile-initial-state", aTopic)) {
   375     mProfileLoaded = true;
   376   }
   377   else {
   378     NS_ERROR("Unexpected observer topic!");
   379   }
   381   return rv;
   382 }
   384 NS_IMETHODIMP
   385 nsChromeRegistryChrome::CheckForNewChrome()
   386 {
   387   PL_DHashTableEnumerate(&mPackagesHash, RemoveAll, nullptr);
   388   mOverlayHash.Clear();
   389   mStyleHash.Clear();
   390   mOverrideTable.Clear();
   392   nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
   393   return NS_OK;
   394 }
   396 nsresult nsChromeRegistryChrome::UpdateSelectedLocale()
   397 {
   398   nsresult rv = NS_OK;
   399   nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
   400   if (prefs) {
   401     rv = SelectLocaleFromPref(prefs);
   402     if (NS_SUCCEEDED(rv)) {
   403       nsCOMPtr<nsIObserverService> obsSvc =
   404         mozilla::services::GetObserverService();
   405       NS_ASSERTION(obsSvc, "Couldn't get observer service.");
   406       obsSvc->NotifyObservers((nsIChromeRegistry*) this,
   407                               "selected-locale-has-changed", nullptr);
   408     }
   409   }
   411   return rv;
   412 }
   414 static void
   415 SerializeURI(nsIURI* aURI,
   416              SerializedURI& aSerializedURI)
   417 {
   418   if (!aURI)
   419     return;
   421   aURI->GetSpec(aSerializedURI.spec);
   422   aURI->GetOriginCharset(aSerializedURI.charset);
   423 }
   425 static PLDHashOperator
   426 EnumerateOverride(nsIURI* aURIKey,
   427                   nsIURI* aURI,
   428                   void* aArg)
   429 {
   430   nsTArray<OverrideMapping>* overrides =
   431       static_cast<nsTArray<OverrideMapping>*>(aArg);
   433   SerializedURI chromeURI, overrideURI;
   435   SerializeURI(aURIKey, chromeURI);
   436   SerializeURI(aURI, overrideURI);
   438   OverrideMapping override = {
   439     chromeURI, overrideURI
   440   };
   441   overrides->AppendElement(override);
   442   return (PLDHashOperator)PL_DHASH_NEXT;
   443 }
   445 struct EnumerationArgs
   446 {
   447   InfallibleTArray<ChromePackage>& packages;
   448   const nsCString& selectedLocale;
   449   const nsCString& selectedSkin;
   450 };
   452 void
   453 nsChromeRegistryChrome::SendRegisteredChrome(
   454     mozilla::dom::PContentParent* aParent)
   455 {
   456   InfallibleTArray<ChromePackage> packages;
   457   InfallibleTArray<ResourceMapping> resources;
   458   InfallibleTArray<OverrideMapping> overrides;
   460   EnumerationArgs args = {
   461     packages, mSelectedLocale, mSelectedSkin
   462   };
   463   PL_DHashTableEnumerate(&mPackagesHash, CollectPackages, &args);
   465   nsCOMPtr<nsIIOService> io (do_GetIOService());
   466   NS_ENSURE_TRUE_VOID(io);
   468   nsCOMPtr<nsIProtocolHandler> ph;
   469   nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
   470   NS_ENSURE_SUCCESS_VOID(rv);
   472   //FIXME: Some substitutions are set up lazily and might not exist yet
   473   nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph));
   474   nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
   475   rph->CollectSubstitutions(resources);
   477   mOverrideTable.EnumerateRead(&EnumerateOverride, &overrides);
   479   bool success = aParent->SendRegisterChrome(packages, resources, overrides,
   480                                              mSelectedLocale);
   481   NS_ENSURE_TRUE_VOID(success);
   482 }
   484 PLDHashOperator
   485 nsChromeRegistryChrome::CollectPackages(PLDHashTable *table,
   486                                   PLDHashEntryHdr *entry,
   487                                   uint32_t number,
   488                                   void *arg)
   489 {
   490   EnumerationArgs* args = static_cast<EnumerationArgs*>(arg);
   491   PackageEntry* package = static_cast<PackageEntry*>(entry);
   493   SerializedURI contentURI, localeURI, skinURI;
   495   SerializeURI(package->baseURI, contentURI);
   496   SerializeURI(package->locales.GetBase(args->selectedLocale,
   497                                         nsProviderArray::LOCALE), localeURI);
   498   SerializeURI(package->skins.GetBase(args->selectedSkin, nsProviderArray::ANY),
   499                skinURI);
   501   ChromePackage chromePackage = {
   502     package->package,
   503     contentURI,
   504     localeURI,
   505     skinURI,
   506     package->flags
   507   };
   508   args->packages.AppendElement(chromePackage);
   509   return (PLDHashOperator)PL_DHASH_NEXT;
   510 }
   512 static bool
   513 CanLoadResource(nsIURI* aResourceURI)
   514 {
   515   bool isLocalResource = false;
   516   (void)NS_URIChainHasFlags(aResourceURI,
   517                             nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
   518                             &isLocalResource);
   519   return isLocalResource;
   520 }
   522 nsIURI*
   523 nsChromeRegistryChrome::GetBaseURIFromPackage(const nsCString& aPackage,
   524                                               const nsCString& aProvider,
   525                                               const nsCString& aPath)
   526 {
   527   PackageEntry* entry =
   528       static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
   529                                                       &aPackage,
   530                                                       PL_DHASH_LOOKUP));
   532   if (PL_DHASH_ENTRY_IS_FREE(entry)) {
   533     if (!mInitialized)
   534       return nullptr;
   536     LogMessage("No chrome package registered for chrome://%s/%s/%s",
   537                aPackage.get(), aProvider.get(), aPath.get());
   539     return nullptr;
   540   }
   542   if (aProvider.EqualsLiteral("locale")) {
   543     return entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE);
   544   }
   545   else if (aProvider.EqualsLiteral("skin")) {
   546     return entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
   547   }
   548   else if (aProvider.EqualsLiteral("content")) {
   549     return entry->baseURI;
   550   }
   551   return nullptr;
   552 }
   554 nsresult
   555 nsChromeRegistryChrome::GetFlagsFromPackage(const nsCString& aPackage,
   556                                             uint32_t* aFlags)
   557 {
   558   PackageEntry* entry =
   559       static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
   560                                                       & (nsACString&) aPackage,
   561                                                       PL_DHASH_LOOKUP));
   562   if (PL_DHASH_ENTRY_IS_FREE(entry))
   563     return NS_ERROR_NOT_AVAILABLE;
   565   *aFlags = entry->flags;
   566   return NS_OK;
   567 }
   569 PLHashNumber
   570 nsChromeRegistryChrome::HashKey(PLDHashTable *table, const void *key)
   571 {
   572   const nsACString& str = *reinterpret_cast<const nsACString*>(key);
   573   return HashString(str);
   574 }
   576 bool
   577 nsChromeRegistryChrome::MatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
   578                            const void *key)
   579 {
   580   const nsACString& str = *reinterpret_cast<const nsACString*>(key);
   581   const PackageEntry* pentry = static_cast<const PackageEntry*>(entry);
   582   return str.Equals(pentry->package);
   583 }
   585 void
   586 nsChromeRegistryChrome::ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
   587 {
   588   PackageEntry* pentry = static_cast<PackageEntry*>(entry);
   589   pentry->~PackageEntry();
   590 }
   592 bool
   593 nsChromeRegistryChrome::InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
   594                             const void *key)
   595 {
   596   const nsACString& str = *reinterpret_cast<const nsACString*>(key);
   598   new (entry) PackageEntry(str);
   599   return true;
   600 }
   602 const PLDHashTableOps
   603 nsChromeRegistryChrome::kTableOps = {
   604   PL_DHashAllocTable,
   605   PL_DHashFreeTable,
   606   HashKey,
   607   MatchKey,
   608   PL_DHashMoveEntryStub,
   609   ClearEntry,
   610   PL_DHashFinalizeStub,
   611   InitEntry
   612 };
   614 nsChromeRegistryChrome::ProviderEntry*
   615 nsChromeRegistryChrome::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
   616 {
   617   int32_t i = mArray.Count();
   618   if (!i)
   619     return nullptr;
   621   ProviderEntry* found = nullptr;  // Only set if we find a partial-match locale
   622   ProviderEntry* entry;
   624   while (i--) {
   625     entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
   626     if (aPreferred.Equals(entry->provider))
   627       return entry;
   629     if (aType != LOCALE)
   630       continue;
   632     if (LanguagesMatch(aPreferred, entry->provider)) {
   633       found = entry;
   634       continue;
   635     }
   637     if (!found && entry->provider.EqualsLiteral("en-US"))
   638       found = entry;
   639   }
   641   if (!found && aType != EXACT)
   642     return entry;
   644   return found;
   645 }
   647 nsIURI*
   648 nsChromeRegistryChrome::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
   649 {
   650   ProviderEntry* provider = GetProvider(aPreferred, aType);
   652   if (!provider)
   653     return nullptr;
   655   return provider->baseURI;
   656 }
   658 const nsACString&
   659 nsChromeRegistryChrome::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
   660 {
   661   ProviderEntry* entry = GetProvider(aPreferred, aType);
   663   if (entry)
   664     return entry->provider;
   666   return EmptyCString();
   667 }
   669 void
   670 nsChromeRegistryChrome::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
   671 {
   672   ProviderEntry* provider = GetProvider(aProvider, EXACT);
   674   if (provider) {
   675     provider->baseURI = aBaseURL;
   676     return;
   677   }
   679   // no existing entries, add a new one
   680   provider = new ProviderEntry(aProvider, aBaseURL);
   681   if (!provider)
   682     return; // It's safe to silently fail on OOM
   684   mArray.AppendElement(provider);
   685 }
   687 void
   688 nsChromeRegistryChrome::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a)
   689 {
   690   int32_t i = mArray.Count();
   691   while (i--) {
   692     ProviderEntry *entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
   693     a->AppendElement(entry->provider);
   694   }
   695 }
   697 void
   698 nsChromeRegistryChrome::nsProviderArray::Clear()
   699 {
   700   int32_t i = mArray.Count();
   701   while (i--) {
   702     ProviderEntry* entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
   703     delete entry;
   704   }
   706   mArray.Clear();
   707 }
   709 void
   710 nsChromeRegistryChrome::OverlayListEntry::AddURI(nsIURI* aURI)
   711 {
   712   int32_t i = mArray.Count();
   713   while (i--) {
   714     bool equals;
   715     if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
   716       return;
   717   }
   719   mArray.AppendObject(aURI);
   720 }
   722 void
   723 nsChromeRegistryChrome::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
   724 {
   725   OverlayListEntry* entry = mTable.PutEntry(aBase);
   726   if (entry)
   727     entry->AddURI(aOverlay);
   728 }
   730 const nsCOMArray<nsIURI>*
   731 nsChromeRegistryChrome::OverlayListHash::GetArray(nsIURI* aBase)
   732 {
   733   OverlayListEntry* entry = mTable.GetEntry(aBase);
   734   if (!entry)
   735     return nullptr;
   737   return &entry->mArray;
   738 }
   740 #ifdef MOZ_XUL
   741 NS_IMETHODIMP
   742 nsChromeRegistryChrome::GetStyleOverlays(nsIURI *aChromeURL,
   743                                          nsISimpleEnumerator **aResult)
   744 {
   745   const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(aChromeURL);
   746   if (!parray)
   747     return NS_NewEmptyEnumerator(aResult);
   749   return NS_NewArrayEnumerator(aResult, *parray);
   750 }
   752 NS_IMETHODIMP
   753 nsChromeRegistryChrome::GetXULOverlays(nsIURI *aChromeURL,
   754                                        nsISimpleEnumerator **aResult)
   755 {
   756   const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(aChromeURL);
   757   if (!parray)
   758     return NS_NewEmptyEnumerator(aResult);
   760   return NS_NewArrayEnumerator(aResult, *parray);
   761 }
   762 #endif // MOZ_XUL
   764 nsIURI*
   765 nsChromeRegistry::ManifestProcessingContext::GetManifestURI()
   766 {
   767   if (!mManifestURI) {
   768     nsCString uri;
   769     mFile.GetURIString(uri);
   770     NS_NewURI(getter_AddRefs(mManifestURI), uri);
   771   }
   772   return mManifestURI;
   773 }
   775 nsIXPConnect*
   776 nsChromeRegistry::ManifestProcessingContext::GetXPConnect()
   777 {
   778   if (!mXPConnect)
   779     mXPConnect = do_GetService("@mozilla.org/js/xpc/XPConnect;1");
   781   return mXPConnect;
   782 }
   784 already_AddRefed<nsIURI>
   785 nsChromeRegistry::ManifestProcessingContext::ResolveURI(const char* uri)
   786 {
   787   nsIURI* baseuri = GetManifestURI();
   788   if (!baseuri)
   789     return nullptr;
   791   nsCOMPtr<nsIURI> resolved;
   792   nsresult rv = NS_NewURI(getter_AddRefs(resolved), uri, baseuri);
   793   if (NS_FAILED(rv))
   794     return nullptr;
   796   return resolved.forget();
   797 }
   799 static void
   800 EnsureLowerCase(char *aBuf)
   801 {
   802   for (; *aBuf; ++aBuf) {
   803     char ch = *aBuf;
   804     if (ch >= 'A' && ch <= 'Z')
   805       *aBuf = ch + 'a' - 'A';
   806   }
   807 }
   809 void
   810 nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int lineno,
   811                                         char *const * argv, bool platform,
   812                                         bool contentaccessible)
   813 {
   814   char* package = argv[0];
   815   char* uri = argv[1];
   817   EnsureLowerCase(package);
   819   nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
   820   if (!resolved) {
   821     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
   822                           "During chrome registration, unable to create URI '%s'.", uri);
   823     return;
   824   }
   826   if (!CanLoadResource(resolved)) {
   827     LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
   828                           "During chrome registration, cannot register non-local URI '%s' as content.",
   829                           uri);
   830     return;
   831   }
   833   PackageEntry* entry =
   834     static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
   835                                                     & (const nsACString&) nsDependentCString(package),
   836                                                     PL_DHASH_ADD));
   837   if (!entry)
   838     return;
   840   entry->baseURI = resolved;
   842   if (platform)
   843     entry->flags |= PLATFORM_PACKAGE;
   844   if (contentaccessible)
   845     entry->flags |= CONTENT_ACCESSIBLE;
   846 }
   848 void
   849 nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno,
   850                                        char *const * argv, bool platform,
   851                                        bool contentaccessible)
   852 {
   853   char* package = argv[0];
   854   char* provider = argv[1];
   855   char* uri = argv[2];
   857   EnsureLowerCase(package);
   859   nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
   860   if (!resolved) {
   861     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
   862                           "During chrome registration, unable to create URI '%s'.", uri);
   863     return;
   864   }
   866   if (!CanLoadResource(resolved)) {
   867     LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
   868                           "During chrome registration, cannot register non-local URI '%s' as content.",
   869                           uri);
   870     return;
   871   }
   873   PackageEntry* entry =
   874     static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
   875                                                     & (const nsACString&) nsDependentCString(package),
   876                                                     PL_DHASH_ADD));
   877   if (!entry)
   878     return;
   880   entry->locales.SetBase(nsDependentCString(provider), resolved);
   881 }
   883 void
   884 nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx, int lineno,
   885                                      char *const * argv, bool platform,
   886                                      bool contentaccessible)
   887 {
   888   char* package = argv[0];
   889   char* provider = argv[1];
   890   char* uri = argv[2];
   892   EnsureLowerCase(package);
   894   nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
   895   if (!resolved) {
   896     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
   897                           "During chrome registration, unable to create URI '%s'.", uri);
   898     return;
   899   }
   901   if (!CanLoadResource(resolved)) {
   902     LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
   903                           "During chrome registration, cannot register non-local URI '%s' as content.",
   904                           uri);
   905     return;
   906   }
   908   PackageEntry* entry =
   909     static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
   910                                                     & (const nsACString&) nsDependentCString(package),
   911                                                     PL_DHASH_ADD));
   912   if (!entry)
   913     return;
   915   entry->skins.SetBase(nsDependentCString(provider), resolved);
   916 }
   918 void
   919 nsChromeRegistryChrome::ManifestOverlay(ManifestProcessingContext& cx, int lineno,
   920                                         char *const * argv, bool platform,
   921                                         bool contentaccessible)
   922 {
   923   char* base = argv[0];
   924   char* overlay = argv[1];
   926   nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
   927   nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
   928   if (!baseuri || !overlayuri) {
   929     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
   930                           "During chrome registration, unable to create URI.");
   931     return;
   932   }
   934   if (!CanLoadResource(overlayuri)) {
   935     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
   936                           "Cannot register non-local URI '%s' as an overlay.", overlay);
   937     return;
   938   }
   940   mOverlayHash.Add(baseuri, overlayuri);
   941 }
   943 void
   944 nsChromeRegistryChrome::ManifestStyle(ManifestProcessingContext& cx, int lineno,
   945                                       char *const * argv, bool platform,
   946                                       bool contentaccessible)
   947 {
   948   char* base = argv[0];
   949   char* overlay = argv[1];
   951   nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
   952   nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
   953   if (!baseuri || !overlayuri) {
   954     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
   955                           "During chrome registration, unable to create URI.");
   956     return;
   957   }
   959   if (!CanLoadResource(overlayuri)) {
   960     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
   961                           "Cannot register non-local URI '%s' as a style overlay.", overlay);
   962     return;
   963   }
   965   mStyleHash.Add(baseuri, overlayuri);
   966 }
   968 void
   969 nsChromeRegistryChrome::ManifestOverride(ManifestProcessingContext& cx, int lineno,
   970                                          char *const * argv, bool platform,
   971                                          bool contentaccessible)
   972 {
   973   char* chrome = argv[0];
   974   char* resolved = argv[1];
   976   nsCOMPtr<nsIURI> chromeuri = cx.ResolveURI(chrome);
   977   nsCOMPtr<nsIURI> resolveduri = cx.ResolveURI(resolved);
   978   if (!chromeuri || !resolveduri) {
   979     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
   980                           "During chrome registration, unable to create URI.");
   981     return;
   982   }
   984   if (!CanLoadResource(resolveduri)) {
   985     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
   986                           "Cannot register non-local URI '%s' for an override.", resolved);
   987     return;
   988   }
   989   mOverrideTable.Put(chromeuri, resolveduri);
   990 }
   992 void
   993 nsChromeRegistryChrome::ManifestResource(ManifestProcessingContext& cx, int lineno,
   994                                          char *const * argv, bool platform,
   995                                          bool contentaccessible)
   996 {
   997   char* package = argv[0];
   998   char* uri = argv[1];
  1000   EnsureLowerCase(package);
  1001   nsDependentCString host(package);
  1003   nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
  1004   if (!io) {
  1005     NS_WARNING("No IO service trying to process chrome manifests");
  1006     return;
  1009   nsCOMPtr<nsIProtocolHandler> ph;
  1010   nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
  1011   if (NS_FAILED(rv))
  1012     return;
  1014   nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph);
  1016   bool exists = false;
  1017   rv = rph->HasSubstitution(host, &exists);
  1018   if (exists) {
  1019     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
  1020                           "Duplicate resource declaration for '%s' ignored.", package);
  1021     return;
  1024   nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
  1025   if (!resolved) {
  1026     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
  1027                           "During chrome registration, unable to create URI '%s'.", uri);
  1028     return;
  1031   if (!CanLoadResource(resolved)) {
  1032     LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
  1033                           "Warning: cannot register non-local URI '%s' as a resource.",
  1034                           uri);
  1035     return;
  1038   rph->SetSubstitution(host, resolved);

mercurial