chrome/src/nsChromeRegistry.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: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=78: */
     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
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsChromeRegistry.h"
     8 #include "nsChromeRegistryChrome.h"
     9 #include "nsChromeRegistryContent.h"
    11 #include "prprf.h"
    13 #include "nsCOMPtr.h"
    14 #include "nsError.h"
    15 #include "nsEscape.h"
    16 #include "nsNetUtil.h"
    17 #include "nsString.h"
    19 #include "nsCSSStyleSheet.h"
    20 #include "nsIConsoleService.h"
    21 #include "nsIDocument.h"
    22 #include "nsIDOMDocument.h"
    23 #include "nsIDOMLocation.h"
    24 #include "nsIDOMWindowCollection.h"
    25 #include "nsIDOMWindow.h"
    26 #include "nsIObserverService.h"
    27 #include "nsIPresShell.h"
    28 #include "nsIScriptError.h"
    29 #include "nsIWindowMediator.h"
    30 #include "mozilla/dom/URL.h"
    32 nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
    33 using mozilla::dom::IsChromeURI;
    35 ////////////////////////////////////////////////////////////////////////////////
    37 void
    38 nsChromeRegistry::LogMessage(const char* aMsg, ...)
    39 {
    40   nsCOMPtr<nsIConsoleService> console 
    41     (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
    42   if (!console)
    43     return;
    45   va_list args;
    46   va_start(args, aMsg);
    47   char* formatted = PR_vsmprintf(aMsg, args);
    48   va_end(args);
    49   if (!formatted)
    50     return;
    52   console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get());
    53   PR_smprintf_free(formatted);
    54 }
    56 void
    57 nsChromeRegistry::LogMessageWithContext(nsIURI* aURL, uint32_t aLineNumber, uint32_t flags,
    58                                         const char* aMsg, ...)
    59 {
    60   nsresult rv;
    62   nsCOMPtr<nsIConsoleService> console 
    63     (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
    65   nsCOMPtr<nsIScriptError> error
    66     (do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
    67   if (!console || !error)
    68     return;
    70   va_list args;
    71   va_start(args, aMsg);
    72   char* formatted = PR_vsmprintf(aMsg, args);
    73   va_end(args);
    74   if (!formatted)
    75     return;
    77   nsCString spec;
    78   if (aURL)
    79     aURL->GetSpec(spec);
    81   rv = error->Init(NS_ConvertUTF8toUTF16(formatted),
    82                    NS_ConvertUTF8toUTF16(spec),
    83                    EmptyString(),
    84                    aLineNumber, 0, flags, "chrome registration");
    85   PR_smprintf_free(formatted);
    87   if (NS_FAILED(rv))
    88     return;
    90   console->LogMessage(error);
    91 }
    93 nsChromeRegistry::~nsChromeRegistry()
    94 {
    95   gChromeRegistry = nullptr;
    96 }
    98 NS_INTERFACE_MAP_BEGIN(nsChromeRegistry)
    99   NS_INTERFACE_MAP_ENTRY(nsIChromeRegistry)
   100   NS_INTERFACE_MAP_ENTRY(nsIXULChromeRegistry)
   101   NS_INTERFACE_MAP_ENTRY(nsIToolkitChromeRegistry)
   102 #ifdef MOZ_XUL
   103   NS_INTERFACE_MAP_ENTRY(nsIXULOverlayProvider)
   104 #endif
   105   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   106   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   107   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChromeRegistry)
   108 NS_INTERFACE_MAP_END
   110 NS_IMPL_ADDREF(nsChromeRegistry)
   111 NS_IMPL_RELEASE(nsChromeRegistry)
   113 ////////////////////////////////////////////////////////////////////////////////
   114 // nsIChromeRegistry methods:
   116 already_AddRefed<nsIChromeRegistry>
   117 nsChromeRegistry::GetService()
   118 {
   119   if (!gChromeRegistry)
   120   {
   121     // We don't actually want this ref, we just want the service to
   122     // initialize if it hasn't already.
   123     nsCOMPtr<nsIChromeRegistry> reg(
   124         do_GetService(NS_CHROMEREGISTRY_CONTRACTID));
   125     if (!gChromeRegistry)
   126       return nullptr;
   127   }
   128   nsCOMPtr<nsIChromeRegistry> registry = gChromeRegistry;
   129   return registry.forget();
   130 }
   132 nsresult
   133 nsChromeRegistry::Init()
   134 {
   135   // This initialization process is fairly complicated and may cause reentrant
   136   // getservice calls to resolve chrome URIs (especially locale files). We
   137   // don't want that, so we inform the protocol handler about our existence
   138   // before we are actually fully initialized.
   139   gChromeRegistry = this;
   141   mInitialized = true;
   143   return NS_OK;
   144 }
   146 nsresult
   147 nsChromeRegistry::GetProviderAndPath(nsIURL* aChromeURL,
   148                                      nsACString& aProvider, nsACString& aPath)
   149 {
   150   nsresult rv;
   152 #ifdef DEBUG
   153   bool isChrome;
   154   aChromeURL->SchemeIs("chrome", &isChrome);
   155   NS_ASSERTION(isChrome, "Non-chrome URI?");
   156 #endif
   158   nsAutoCString path;
   159   rv = aChromeURL->GetPath(path);
   160   NS_ENSURE_SUCCESS(rv, rv);
   162   if (path.Length() < 3) {
   163     LogMessage("Invalid chrome URI: %s", path.get());
   164     return NS_ERROR_FAILURE;
   165   }
   167   path.SetLength(nsUnescapeCount(path.BeginWriting()));
   168   NS_ASSERTION(path.First() == '/', "Path should always begin with a slash!");
   170   int32_t slash = path.FindChar('/', 1);
   171   if (slash == 1) {
   172     LogMessage("Invalid chrome URI: %s", path.get());
   173     return NS_ERROR_FAILURE;
   174   }
   176   if (slash == -1) {
   177     aPath.Truncate();
   178   }
   179   else {
   180     if (slash == (int32_t) path.Length() - 1)
   181       aPath.Truncate();
   182     else
   183       aPath.Assign(path.get() + slash + 1, path.Length() - slash - 1);
   185     --slash;
   186   }
   188   aProvider.Assign(path.get() + 1, slash);
   189   return NS_OK;
   190 }
   193 nsresult
   194 nsChromeRegistry::Canonify(nsIURL* aChromeURL)
   195 {
   196   NS_NAMED_LITERAL_CSTRING(kSlash, "/");
   198   nsresult rv;
   200   nsAutoCString provider, path;
   201   rv = GetProviderAndPath(aChromeURL, provider, path);
   202   NS_ENSURE_SUCCESS(rv, rv);
   204   if (path.IsEmpty()) {
   205     nsAutoCString package;
   206     rv = aChromeURL->GetHost(package);
   207     NS_ENSURE_SUCCESS(rv, rv);
   209     // we re-use the "path" local string to build a new URL path
   210     path.Assign(kSlash + provider + kSlash + package);
   211     if (provider.EqualsLiteral("content")) {
   212       path.AppendLiteral(".xul");
   213     }
   214     else if (provider.EqualsLiteral("locale")) {
   215       path.AppendLiteral(".dtd");
   216     }
   217     else if (provider.EqualsLiteral("skin")) {
   218       path.AppendLiteral(".css");
   219     }
   220     else {
   221       return NS_ERROR_INVALID_ARG;
   222     }
   223     aChromeURL->SetPath(path);
   224   }
   225   else {
   226     // prevent directory traversals ("..")
   227     // path is already unescaped once, but uris can get unescaped twice
   228     const char* pos = path.BeginReading();
   229     const char* end = path.EndReading();
   230     while (pos < end) {
   231       switch (*pos) {
   232         case ':':
   233           return NS_ERROR_DOM_BAD_URI;
   234         case '.':
   235           if (pos[1] == '.')
   236             return NS_ERROR_DOM_BAD_URI;
   237           break;
   238         case '%':
   239           // chrome: URIs with double-escapes are trying to trick us.
   240           // watch for %2e, and %25 in case someone triple unescapes
   241           if (pos[1] == '2' &&
   242                ( pos[2] == 'e' || pos[2] == 'E' || 
   243                  pos[2] == '5' ))
   244             return NS_ERROR_DOM_BAD_URI;
   245           break;
   246         case '?':
   247         case '#':
   248           pos = end;
   249           continue;
   250       }
   251       ++pos;
   252     }
   253   }
   255   return NS_OK;
   256 }
   258 NS_IMETHODIMP
   259 nsChromeRegistry::ConvertChromeURL(nsIURI* aChromeURI, nsIURI* *aResult)
   260 {
   261   nsresult rv;
   262   NS_ASSERTION(aChromeURI, "null url!");
   264   if (mOverrideTable.Get(aChromeURI, aResult))
   265     return NS_OK;
   267   nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aChromeURI));
   268   NS_ENSURE_TRUE(chromeURL, NS_NOINTERFACE);
   270   nsAutoCString package, provider, path;
   271   rv = chromeURL->GetHostPort(package);
   272   NS_ENSURE_SUCCESS(rv, rv);
   274   rv = GetProviderAndPath(chromeURL, provider, path);
   275   NS_ENSURE_SUCCESS(rv, rv);
   277   nsIURI* baseURI = GetBaseURIFromPackage(package, provider, path);
   279   uint32_t flags;
   280   rv = GetFlagsFromPackage(package, &flags);
   281   if (NS_FAILED(rv))
   282     return rv;
   284   if (flags & PLATFORM_PACKAGE) {
   285 #if defined(XP_WIN)
   286     path.Insert("win/", 0);
   287 #elif defined(XP_MACOSX)
   288     path.Insert("mac/", 0);
   289 #else
   290     path.Insert("unix/", 0);
   291 #endif
   292   }
   294   if (!baseURI) {
   295     LogMessage("No chrome package registered for chrome://%s/%s/%s",
   296                package.get(), provider.get(), path.get());
   297     return NS_ERROR_FAILURE;
   298   }
   300   return NS_NewURI(aResult, path, nullptr, baseURI);
   301 }
   303 ////////////////////////////////////////////////////////////////////////
   305 // theme stuff
   308 static void FlushSkinBindingsForWindow(nsIDOMWindow* aWindow)
   309 {
   310   // Get the DOM document.
   311   nsCOMPtr<nsIDOMDocument> domDocument;
   312   aWindow->GetDocument(getter_AddRefs(domDocument));
   313   if (!domDocument)
   314     return;
   316   nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
   317   if (!document)
   318     return;
   320   // Annihilate all XBL bindings.
   321   document->FlushSkinBindings();
   322 }
   324 // XXXbsmedberg: move this to nsIWindowMediator
   325 NS_IMETHODIMP nsChromeRegistry::RefreshSkins()
   326 {
   327   nsCOMPtr<nsIWindowMediator> windowMediator
   328     (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
   329   if (!windowMediator)
   330     return NS_OK;
   332   nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
   333   windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
   334   bool more;
   335   windowEnumerator->HasMoreElements(&more);
   336   while (more) {
   337     nsCOMPtr<nsISupports> protoWindow;
   338     windowEnumerator->GetNext(getter_AddRefs(protoWindow));
   339     if (protoWindow) {
   340       nsCOMPtr<nsIDOMWindow> domWindow = do_QueryInterface(protoWindow);
   341       if (domWindow)
   342         FlushSkinBindingsForWindow(domWindow);
   343     }
   344     windowEnumerator->HasMoreElements(&more);
   345   }
   347   FlushSkinCaches();
   349   windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
   350   windowEnumerator->HasMoreElements(&more);
   351   while (more) {
   352     nsCOMPtr<nsISupports> protoWindow;
   353     windowEnumerator->GetNext(getter_AddRefs(protoWindow));
   354     if (protoWindow) {
   355       nsCOMPtr<nsIDOMWindow> domWindow = do_QueryInterface(protoWindow);
   356       if (domWindow)
   357         RefreshWindow(domWindow);
   358     }
   359     windowEnumerator->HasMoreElements(&more);
   360   }
   362   return NS_OK;
   363 }
   365 void
   366 nsChromeRegistry::FlushSkinCaches()
   367 {
   368   nsCOMPtr<nsIObserverService> obsSvc =
   369     mozilla::services::GetObserverService();
   370   NS_ASSERTION(obsSvc, "Couldn't get observer service.");
   372   obsSvc->NotifyObservers(static_cast<nsIChromeRegistry*>(this),
   373                           NS_CHROME_FLUSH_SKINS_TOPIC, nullptr);
   374 }
   376 // XXXbsmedberg: move this to windowmediator
   377 nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindow* aWindow)
   378 {
   379   // Deal with our subframes first.
   380   nsCOMPtr<nsIDOMWindowCollection> frames;
   381   aWindow->GetFrames(getter_AddRefs(frames));
   382   uint32_t length;
   383   frames->GetLength(&length);
   384   uint32_t j;
   385   for (j = 0; j < length; j++) {
   386     nsCOMPtr<nsIDOMWindow> childWin;
   387     frames->Item(j, getter_AddRefs(childWin));
   388     RefreshWindow(childWin);
   389   }
   391   nsresult rv;
   392   // Get the DOM document.
   393   nsCOMPtr<nsIDOMDocument> domDocument;
   394   aWindow->GetDocument(getter_AddRefs(domDocument));
   395   if (!domDocument)
   396     return NS_OK;
   398   nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
   399   if (!document)
   400     return NS_OK;
   402   // Deal with the agent sheets first.  Have to do all the style sets by hand.
   403   nsCOMPtr<nsIPresShell> shell = document->GetShell();
   404   if (shell) {
   405     // Reload only the chrome URL agent style sheets.
   406     nsCOMArray<nsIStyleSheet> agentSheets;
   407     rv = shell->GetAgentStyleSheets(agentSheets);
   408     NS_ENSURE_SUCCESS(rv, rv);
   410     nsCOMArray<nsIStyleSheet> newAgentSheets;
   411     for (int32_t l = 0; l < agentSheets.Count(); ++l) {
   412       nsIStyleSheet *sheet = agentSheets[l];
   414       nsIURI* uri = sheet->GetSheetURI();
   416       if (IsChromeURI(uri)) {
   417         // Reload the sheet.
   418         nsRefPtr<nsCSSStyleSheet> newSheet;
   419         rv = document->LoadChromeSheetSync(uri, true,
   420                                            getter_AddRefs(newSheet));
   421         if (NS_FAILED(rv)) return rv;
   422         if (newSheet) {
   423           rv = newAgentSheets.AppendObject(newSheet) ? NS_OK : NS_ERROR_FAILURE;
   424           if (NS_FAILED(rv)) return rv;
   425         }
   426       }
   427       else {  // Just use the same sheet.
   428         rv = newAgentSheets.AppendObject(sheet) ? NS_OK : NS_ERROR_FAILURE;
   429         if (NS_FAILED(rv)) return rv;
   430       }
   431     }
   433     rv = shell->SetAgentStyleSheets(newAgentSheets);
   434     NS_ENSURE_SUCCESS(rv, rv);
   435   }
   437   // Build an array of nsIURIs of style sheets we need to load.
   438   nsCOMArray<nsIStyleSheet> oldSheets;
   439   nsCOMArray<nsIStyleSheet> newSheets;
   441   int32_t count = document->GetNumberOfStyleSheets();
   443   // Iterate over the style sheets.
   444   int32_t i;
   445   for (i = 0; i < count; i++) {
   446     // Get the style sheet
   447     nsIStyleSheet *styleSheet = document->GetStyleSheetAt(i);
   449     if (!oldSheets.AppendObject(styleSheet)) {
   450       return NS_ERROR_OUT_OF_MEMORY;
   451     }
   452   }
   454   // Iterate over our old sheets and kick off a sync load of the new
   455   // sheet if and only if it's a chrome URL.
   456   for (i = 0; i < count; i++) {
   457     nsRefPtr<nsCSSStyleSheet> sheet = do_QueryObject(oldSheets[i]);
   458     nsIURI* uri = sheet ? sheet->GetOriginalURI() : nullptr;
   460     if (uri && IsChromeURI(uri)) {
   461       // Reload the sheet.
   462       nsRefPtr<nsCSSStyleSheet> newSheet;
   463       // XXX what about chrome sheets that have a title or are disabled?  This
   464       // only works by sheer dumb luck.
   465       document->LoadChromeSheetSync(uri, false, getter_AddRefs(newSheet));
   466       // Even if it's null, we put in in there.
   467       newSheets.AppendObject(newSheet);
   468     }
   469     else {
   470       // Just use the same sheet.
   471       newSheets.AppendObject(sheet);
   472     }
   473   }
   475   // Now notify the document that multiple sheets have been added and removed.
   476   document->UpdateStyleSheets(oldSheets, newSheets);
   477   return NS_OK;
   478 }
   480 void
   481 nsChromeRegistry::FlushAllCaches()
   482 {
   483   nsCOMPtr<nsIObserverService> obsSvc =
   484     mozilla::services::GetObserverService();
   485   NS_ASSERTION(obsSvc, "Couldn't get observer service.");
   487   obsSvc->NotifyObservers((nsIChromeRegistry*) this,
   488                           NS_CHROME_FLUSH_TOPIC, nullptr);
   489 }  
   491 // xxxbsmedberg Move me to nsIWindowMediator
   492 NS_IMETHODIMP
   493 nsChromeRegistry::ReloadChrome()
   494 {
   495   UpdateSelectedLocale();
   496   FlushAllCaches();
   497   // Do a reload of all top level windows.
   498   nsresult rv = NS_OK;
   500   // Get the window mediator
   501   nsCOMPtr<nsIWindowMediator> windowMediator
   502     (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
   503   if (windowMediator) {
   504     nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
   506     rv = windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
   507     if (NS_SUCCEEDED(rv)) {
   508       // Get each dom window
   509       bool more;
   510       rv = windowEnumerator->HasMoreElements(&more);
   511       if (NS_FAILED(rv)) return rv;
   512       while (more) {
   513         nsCOMPtr<nsISupports> protoWindow;
   514         rv = windowEnumerator->GetNext(getter_AddRefs(protoWindow));
   515         if (NS_SUCCEEDED(rv)) {
   516           nsCOMPtr<nsIDOMWindow> domWindow = do_QueryInterface(protoWindow);
   517           if (domWindow) {
   518             nsCOMPtr<nsIDOMLocation> location;
   519             domWindow->GetLocation(getter_AddRefs(location));
   520             if (location) {
   521               rv = location->Reload(false);
   522               if (NS_FAILED(rv)) return rv;
   523             }
   524           }
   525         }
   526         rv = windowEnumerator->HasMoreElements(&more);
   527         if (NS_FAILED(rv)) return rv;
   528       }
   529     }
   530   }
   531   return rv;
   532 }
   534 NS_IMETHODIMP
   535 nsChromeRegistry::AllowScriptsForPackage(nsIURI* aChromeURI, bool *aResult)
   536 {
   537   nsresult rv;
   538   *aResult = false;
   540 #ifdef DEBUG
   541   bool isChrome;
   542   aChromeURI->SchemeIs("chrome", &isChrome);
   543   NS_ASSERTION(isChrome, "Non-chrome URI passed to AllowScriptsForPackage!");
   544 #endif
   546   nsCOMPtr<nsIURL> url (do_QueryInterface(aChromeURI));
   547   NS_ENSURE_TRUE(url, NS_NOINTERFACE);
   549   nsAutoCString provider, file;
   550   rv = GetProviderAndPath(url, provider, file);
   551   NS_ENSURE_SUCCESS(rv, rv);
   553   if (!provider.EqualsLiteral("skin"))
   554     *aResult = true;
   556   return NS_OK;
   557 }
   559 NS_IMETHODIMP
   560 nsChromeRegistry::AllowContentToAccess(nsIURI *aURI, bool *aResult)
   561 {
   562   nsresult rv;
   564   *aResult = false;
   566 #ifdef DEBUG
   567   bool isChrome;
   568   aURI->SchemeIs("chrome", &isChrome);
   569   NS_ASSERTION(isChrome, "Non-chrome URI passed to AllowContentToAccess!");
   570 #endif
   572   nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
   573   if (!url) {
   574     NS_ERROR("Chrome URL doesn't implement nsIURL.");
   575     return NS_ERROR_UNEXPECTED;
   576   }
   578   nsAutoCString package;
   579   rv = url->GetHostPort(package);
   580   NS_ENSURE_SUCCESS(rv, rv);
   582   uint32_t flags;
   583   rv = GetFlagsFromPackage(package, &flags);
   585   if (NS_SUCCEEDED(rv)) {
   586     *aResult = !!(flags & CONTENT_ACCESSIBLE);
   587   }
   588   return NS_OK;
   589 }
   591 NS_IMETHODIMP_(bool)
   592 nsChromeRegistry::WrappersEnabled(nsIURI *aURI)
   593 {
   594   nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aURI));
   595   if (!chromeURL)
   596     return false;
   598   bool isChrome = false;
   599   nsresult rv = chromeURL->SchemeIs("chrome", &isChrome);
   600   if (NS_FAILED(rv) || !isChrome)
   601     return false;
   603   nsAutoCString package;
   604   rv = chromeURL->GetHostPort(package);
   605   if (NS_FAILED(rv))
   606     return false;
   608   uint32_t flags;
   609   rv = GetFlagsFromPackage(package, &flags);
   610   return NS_SUCCEEDED(rv) && (flags & XPCNATIVEWRAPPERS);
   611 }
   613 already_AddRefed<nsChromeRegistry>
   614 nsChromeRegistry::GetSingleton()
   615 {
   616   if (gChromeRegistry) {
   617     nsRefPtr<nsChromeRegistry> registry = gChromeRegistry;
   618     return registry.forget();
   619   }
   621   nsRefPtr<nsChromeRegistry> cr;
   622   if (GeckoProcessType_Content == XRE_GetProcessType())
   623     cr = new nsChromeRegistryContent();
   624   else
   625     cr = new nsChromeRegistryChrome();
   627   if (NS_FAILED(cr->Init()))
   628     return nullptr;
   630   return cr.forget();
   631 }

mercurial