Tue, 06 Jan 2015 21:39:09 +0100
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;
1007 }
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;
1022 }
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;
1029 }
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;
1036 }
1038 rph->SetSubstitution(host, resolved);
1039 }