uriloader/exthandler/win/nsOSHelperAppService.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
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: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * vim:set ts=2 sts=2 sw=2 et cin:
     3  *
     4  * This Source Code Form is subject to the terms of the Mozilla Public
     5  * License, v. 2.0. If a copy of the MPL was not distributed with this
     6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     8 #include "nsOSHelperAppService.h"
     9 #include "nsISupports.h"
    10 #include "nsString.h"
    11 #include "nsXPIDLString.h"
    12 #include "nsIURL.h"
    13 #include "nsIMIMEInfo.h"
    14 #include "nsMIMEInfoWin.h"
    15 #include "nsMimeTypes.h"
    16 #include "nsILocalFileWin.h"
    17 #include "nsIProcess.h"
    18 #include "plstr.h"
    19 #include "nsAutoPtr.h"
    20 #include "nsNativeCharsetUtils.h"
    21 #include "nsIWindowsRegKey.h"
    23 // shellapi.h is needed to build with WIN32_LEAN_AND_MEAN
    24 #include <shellapi.h>
    26 #define LOG(args) PR_LOG(mLog, PR_LOG_DEBUG, args)
    28 // helper methods: forward declarations...
    29 static nsresult GetExtensionFrom4xRegistryInfo(const nsACString& aMimeType, 
    30                                                nsString& aFileExtension);
    31 static nsresult GetExtensionFromWindowsMimeDatabase(const nsACString& aMimeType,
    32                                                     nsString& aFileExtension);
    34 nsOSHelperAppService::nsOSHelperAppService() : 
    35   nsExternalHelperAppService()
    36   , mAppAssoc(nullptr)
    37 {
    38   CoInitialize(nullptr);
    39   CoCreateInstance(CLSID_ApplicationAssociationRegistration, nullptr,
    40                    CLSCTX_INPROC, IID_IApplicationAssociationRegistration,
    41                    (void**)&mAppAssoc);
    42 }
    44 nsOSHelperAppService::~nsOSHelperAppService()
    45 {
    46   if (mAppAssoc)
    47     mAppAssoc->Release();
    48   mAppAssoc = nullptr;
    49   CoUninitialize();
    50 }
    52 // The windows registry provides a mime database key which lists a set of mime types and corresponding "Extension" values. 
    53 // we can use this to look up our mime type to see if there is a preferred extension for the mime type.
    54 static nsresult GetExtensionFromWindowsMimeDatabase(const nsACString& aMimeType,
    55                                                     nsString& aFileExtension)
    56 {
    57   nsAutoString mimeDatabaseKey;
    58   mimeDatabaseKey.AssignLiteral("MIME\\Database\\Content Type\\");
    60   AppendASCIItoUTF16(aMimeType, mimeDatabaseKey);
    62   nsCOMPtr<nsIWindowsRegKey> regKey = 
    63     do_CreateInstance("@mozilla.org/windows-registry-key;1");
    64   if (!regKey) 
    65     return NS_ERROR_NOT_AVAILABLE;
    67   nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
    68                              mimeDatabaseKey,
    69                              nsIWindowsRegKey::ACCESS_QUERY_VALUE);
    71   if (NS_SUCCEEDED(rv))
    72      regKey->ReadStringValue(NS_LITERAL_STRING("Extension"), aFileExtension);
    74   return NS_OK;
    75 }
    77 // We have a serious problem!! I have this content type and the windows registry only gives me
    78 // helper apps based on extension. Right now, we really don't have a good place to go for 
    79 // trying to figure out the extension for a particular mime type....One short term hack is to look
    80 // this information in 4.x (it's stored in the windows regsitry). 
    81 static nsresult GetExtensionFrom4xRegistryInfo(const nsACString& aMimeType,
    82                                                nsString& aFileExtension)
    83 {
    84   nsCOMPtr<nsIWindowsRegKey> regKey = 
    85     do_CreateInstance("@mozilla.org/windows-registry-key;1");
    86   if (!regKey) 
    87     return NS_ERROR_NOT_AVAILABLE;
    89   nsresult rv = regKey->
    90     Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
    91          NS_LITERAL_STRING("Software\\Netscape\\Netscape Navigator\\Suffixes"),
    92          nsIWindowsRegKey::ACCESS_QUERY_VALUE);
    93   if (NS_FAILED(rv))
    94     return NS_ERROR_NOT_AVAILABLE;
    96   rv = regKey->ReadStringValue(NS_ConvertASCIItoUTF16(aMimeType),
    97                                aFileExtension);
    98   if (NS_FAILED(rv))
    99     return NS_OK;
   101   aFileExtension.Insert(char16_t('.'), 0);
   103   // this may be a comma separated list of extensions...just take the 
   104   // first one for now...
   106   int32_t pos = aFileExtension.FindChar(char16_t(','));
   107   if (pos > 0) {
   108     // we have a comma separated list of types...
   109     // truncate everything after the first comma (including the comma)
   110     aFileExtension.Truncate(pos); 
   111   }
   113   return NS_OK;
   114 }
   116 nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, bool * aHandlerExists)
   117 {
   118   // look up the protocol scheme in the windows registry....if we find a match then we have a handler for it...
   119   *aHandlerExists = false;
   120   if (aProtocolScheme && *aProtocolScheme)
   121   {
   122     // Vista: use new application association interface
   123     if (mAppAssoc) {
   124       wchar_t * pResult = nullptr;
   125       NS_ConvertASCIItoUTF16 scheme(aProtocolScheme);
   126       // We are responsible for freeing returned strings.
   127       HRESULT hr = mAppAssoc->QueryCurrentDefault(scheme.get(),
   128                                                   AT_URLPROTOCOL, AL_EFFECTIVE,
   129                                                   &pResult);
   130       if (SUCCEEDED(hr)) {
   131         CoTaskMemFree(pResult);
   132         *aHandlerExists = true;
   133       }
   134       return NS_OK;
   135     }
   137     HKEY hKey;
   138     LONG err = ::RegOpenKeyExW(HKEY_CLASSES_ROOT,
   139                                NS_ConvertASCIItoUTF16(aProtocolScheme).get(),
   140                                0,
   141                                KEY_QUERY_VALUE,
   142                                &hKey);
   143     if (err == ERROR_SUCCESS)
   144     {
   145       err = ::RegQueryValueExW(hKey, L"URL Protocol",
   146                                nullptr, nullptr, nullptr, nullptr);
   147       *aHandlerExists = (err == ERROR_SUCCESS);
   148       // close the key
   149       ::RegCloseKey(hKey);
   150     }
   151   }
   153   return NS_OK;
   154 }
   156 NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval)
   157 {
   158   nsCOMPtr<nsIWindowsRegKey> regKey = 
   159     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   160   if (!regKey) 
   161     return NS_ERROR_NOT_AVAILABLE;
   163   NS_ConvertASCIItoUTF16 buf(aScheme);
   165   // Vista: use new application association interface
   166   if (mAppAssoc) {
   167     wchar_t * pResult = nullptr;
   168     // We are responsible for freeing returned strings.
   169     HRESULT hr = mAppAssoc->QueryCurrentDefault(buf.get(),
   170                                                 AT_URLPROTOCOL, AL_EFFECTIVE,
   171                                                 &pResult);
   172     if (SUCCEEDED(hr)) {
   173       nsCOMPtr<nsIFile> app;
   174       nsAutoString appInfo(pResult);
   175       CoTaskMemFree(pResult);
   176       if (NS_SUCCEEDED(GetDefaultAppInfo(appInfo, _retval, getter_AddRefs(app))))
   177         return NS_OK;
   178     }
   179     return NS_ERROR_NOT_AVAILABLE;
   180   }
   182   nsCOMPtr<nsIFile> app;
   183   GetDefaultAppInfo(buf, _retval, getter_AddRefs(app));
   185   if (!_retval.Equals(buf))
   186     return NS_OK;
   188   // Fall back to full path
   189   buf.AppendLiteral("\\shell\\open\\command");
   190   nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   191                              buf,
   192                              nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   193   if (NS_FAILED(rv))
   194     return NS_ERROR_NOT_AVAILABLE;   
   196   rv = regKey->ReadStringValue(EmptyString(), _retval); 
   198   return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   199 }
   201 // GetMIMEInfoFromRegistry: This function obtains the values of some of the nsIMIMEInfo
   202 // attributes for the mimeType/extension associated with the input registry key.  The default
   203 // entry for that key is the name of a registry key under HKEY_CLASSES_ROOT.  The default
   204 // value for *that* key is the descriptive name of the type.  The EditFlags value is a binary
   205 // value; the low order bit of the third byte of which indicates that the user does not need
   206 // to be prompted.
   207 //
   208 // This function sets only the Description attribute of the input nsIMIMEInfo.
   209 /* static */
   210 nsresult nsOSHelperAppService::GetMIMEInfoFromRegistry(const nsAFlatString& fileType, nsIMIMEInfo *pInfo)
   211 {
   212   nsresult rv = NS_OK;
   214   NS_ENSURE_ARG(pInfo);
   215   nsCOMPtr<nsIWindowsRegKey> regKey = 
   216     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   217   if (!regKey) 
   218     return NS_ERROR_NOT_AVAILABLE;
   220   rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   221                     fileType, nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   222   if (NS_FAILED(rv))
   223     return NS_ERROR_FAILURE;
   225   // OK, the default value here is the description of the type.
   226   nsAutoString description;
   227   rv = regKey->ReadStringValue(EmptyString(), description);
   228   if (NS_SUCCEEDED(rv))
   229     pInfo->SetDescription(description);
   231   return NS_OK;
   232 }
   234 /////////////////////////////////////////////////////////////////////////////////////////////////
   235 // method overrides used to gather information from the windows registry for
   236 // various mime types. 
   237 ////////////////////////////////////////////////////////////////////////////////////////////////
   239 /// Looks up the type for the extension aExt and compares it to aType
   240 /* static */ bool
   241 nsOSHelperAppService::typeFromExtEquals(const char16_t* aExt, const char *aType)
   242 {
   243   if (!aType)
   244     return false;
   245   nsAutoString fileExtToUse;
   246   if (aExt[0] != char16_t('.'))
   247     fileExtToUse = char16_t('.');
   249   fileExtToUse.Append(aExt);
   251   bool eq = false;
   252   nsCOMPtr<nsIWindowsRegKey> regKey = 
   253     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   254   if (!regKey) 
   255     return eq;
   257   nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   258                              fileExtToUse,
   259                              nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   260   if (NS_FAILED(rv))
   261       return eq;
   263   nsAutoString type;
   264   rv = regKey->ReadStringValue(NS_LITERAL_STRING("Content Type"), type);
   265   if (NS_SUCCEEDED(rv))
   266      eq = type.EqualsASCII(aType);
   268   return eq;
   269 }
   271 // Strip a handler command string of its quotes and parameters.
   272 static void CleanupHandlerPath(nsString& aPath)
   273 {
   274   // Example command strings passed into this routine:
   276   // 1) C:\Program Files\Company\some.exe -foo -bar
   277   // 2) C:\Program Files\Company\some.dll
   278   // 3) C:\Windows\some.dll,-foo -bar
   279   // 4) C:\Windows\some.cpl,-foo -bar
   281   int32_t lastCommaPos = aPath.RFindChar(',');
   282   if (lastCommaPos != kNotFound)
   283     aPath.Truncate(lastCommaPos);
   285   aPath.AppendLiteral(" ");
   287   // case insensitive
   288   uint32_t index = aPath.Find(".exe ", true);
   289   if (index == kNotFound)
   290     index = aPath.Find(".dll ", true);
   291   if (index == kNotFound)
   292     index = aPath.Find(".cpl ", true);
   294   if (index != kNotFound)
   295     aPath.Truncate(index + 4);
   296   aPath.Trim(" ", true, true);
   297 }
   299 // Strip the windows host process bootstrap executable rundll32.exe
   300 // from a handler's command string if it exists.
   301 static void StripRundll32(nsString& aCommandString)
   302 {
   303   // Example rundll formats:
   304   // C:\Windows\System32\rundll32.exe "path to dll"
   305   // rundll32.exe "path to dll"
   306   // C:\Windows\System32\rundll32.exe "path to dll", var var
   307   // rundll32.exe "path to dll", var var
   309   NS_NAMED_LITERAL_STRING(rundllSegment, "rundll32.exe ");
   310   NS_NAMED_LITERAL_STRING(rundllSegmentShort, "rundll32 ");
   312   // case insensitive
   313   int32_t strLen = rundllSegment.Length();
   314   int32_t index = aCommandString.Find(rundllSegment, true);
   315   if (index == kNotFound) {
   316     strLen = rundllSegmentShort.Length();
   317     index = aCommandString.Find(rundllSegmentShort, true);
   318   }
   320   if (index != kNotFound) {
   321     uint32_t rundllSegmentLength = index + strLen;
   322     aCommandString.Cut(0, rundllSegmentLength);
   323   }
   324 }
   326 // Returns the fully qualified path to an application handler based on
   327 // a parameterized command string. Note this routine should not be used
   328 // to launch the associated application as it strips parameters and
   329 // rundll.exe from the string. Designed for retrieving display information
   330 // on a particular handler.   
   331 /* static */ bool nsOSHelperAppService::CleanupCmdHandlerPath(nsAString& aCommandHandler)
   332 {
   333   nsAutoString handlerCommand(aCommandHandler);
   335   // Straight command path:
   336   //
   337   // %SystemRoot%\system32\NOTEPAD.EXE var
   338   // "C:\Program Files\iTunes\iTunes.exe" var var
   339   // C:\Program Files\iTunes\iTunes.exe var var
   340   //
   341   // Example rundll handlers:
   342   //
   343   // rundll32.exe "%ProgramFiles%\Win...ery\PhotoViewer.dll", var var
   344   // rundll32.exe "%ProgramFiles%\Windows Photo Gallery\PhotoViewer.dll"
   345   // C:\Windows\System32\rundll32.exe "path to dll", var var
   346   // %SystemRoot%\System32\rundll32.exe "%ProgramFiles%\Win...ery\Photo
   347   //    Viewer.dll", var var
   349   // Expand environment variables so we have full path strings.
   350   uint32_t bufLength = ::ExpandEnvironmentStringsW(handlerCommand.get(),
   351                                                    L"", 0);
   352   if (bufLength == 0) // Error
   353     return false;
   355   nsAutoArrayPtr<wchar_t> destination(new wchar_t[bufLength]);
   356   if (!destination)
   357     return false;
   358   if (!::ExpandEnvironmentStringsW(handlerCommand.get(), destination,
   359                                    bufLength))
   360     return false;
   362   handlerCommand = static_cast<const wchar_t*>(destination);
   364   // Remove quotes around paths
   365   handlerCommand.StripChars("\"");
   367   // Strip windows host process bootstrap so we can get to the actual
   368   // handler.
   369   StripRundll32(handlerCommand);
   371   // Trim any command parameters so that we have a native path we can
   372   // initialize a local file with.
   373   CleanupHandlerPath(handlerCommand);
   375   aCommandHandler.Assign(handlerCommand);
   376   return true;
   377 }
   379 // The "real" name of a given helper app (as specified by the path to the 
   380 // executable file held in various registry keys) is stored n the VERSIONINFO
   381 // block in the file's resources. We need to find the path to the executable
   382 // and then retrieve the "FileDescription" field value from the file. 
   383 nsresult
   384 nsOSHelperAppService::GetDefaultAppInfo(const nsAString& aAppInfo,
   385                                         nsAString& aDefaultDescription, 
   386                                         nsIFile** aDefaultApplication)
   387 {
   388   nsAutoString handlerCommand;
   390   // If all else fails, use the file type key name, which will be 
   391   // something like "pngfile" for .pngs, "WMVFile" for .wmvs, etc. 
   392   aDefaultDescription = aAppInfo;
   393   *aDefaultApplication = nullptr;
   395   if (aAppInfo.IsEmpty())
   396     return NS_ERROR_FAILURE;
   398   // aAppInfo may be a file, file path, program id, or
   399   // Applications reference -
   400   // c:\dir\app.exe
   401   // Applications\appfile.exe/dll (shell\open...)
   402   // ProgID.progid (shell\open...)
   404   nsAutoString handlerKeyName(aAppInfo);
   406   nsCOMPtr<nsIWindowsRegKey> chkKey = 
   407     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   408   if (!chkKey) 
   409     return NS_ERROR_FAILURE;
   411   nsresult rv = chkKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   412                              handlerKeyName, 
   413                              nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   414   if (NS_FAILED(rv)) {
   415     // It's a file system path to a handler 
   416     handlerCommand.Assign(aAppInfo);
   417   }
   418   else {
   419     handlerKeyName.AppendLiteral("\\shell\\open\\command");
   420     nsCOMPtr<nsIWindowsRegKey> regKey = 
   421       do_CreateInstance("@mozilla.org/windows-registry-key;1");
   422     if (!regKey) 
   423       return NS_ERROR_FAILURE;
   425     nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   426                                handlerKeyName, 
   427                                nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   428     if (NS_FAILED(rv))
   429       return NS_ERROR_FAILURE;
   431     // OK, the default value here is the description of the type.
   432     rv = regKey->ReadStringValue(EmptyString(), handlerCommand);
   433     if (NS_FAILED(rv)) {
   435       // Check if there is a DelegateExecute string
   436       nsAutoString delegateExecute;
   437       rv = regKey->ReadStringValue(NS_LITERAL_STRING("DelegateExecute"), delegateExecute);
   438       NS_ENSURE_SUCCESS(rv, rv);
   440       // Look for InProcServer32
   441       nsAutoString delegateExecuteRegPath;
   442       delegateExecuteRegPath.AssignLiteral("CLSID\\");
   443       delegateExecuteRegPath.Append(delegateExecute);
   444       delegateExecuteRegPath.AppendLiteral("\\InProcServer32");
   445       rv = chkKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   446                         delegateExecuteRegPath, 
   447                         nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   448       if (NS_SUCCEEDED(rv)) {
   449         rv = chkKey->ReadStringValue(EmptyString(), handlerCommand);
   450       }
   452       if (NS_FAILED(rv)) {
   453         // Look for LocalServer32
   454         delegateExecuteRegPath.AssignLiteral("CLSID\\");
   455         delegateExecuteRegPath.Append(delegateExecute);
   456         delegateExecuteRegPath.AppendLiteral("\\LocalServer32");
   457         rv = chkKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   458                           delegateExecuteRegPath, 
   459                           nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   460         NS_ENSURE_SUCCESS(rv, rv);
   461         rv = chkKey->ReadStringValue(EmptyString(), handlerCommand);
   462         NS_ENSURE_SUCCESS(rv, rv);
   463       }
   464     }
   465   }
   467   if (!CleanupCmdHandlerPath(handlerCommand))
   468     return NS_ERROR_FAILURE;
   470   // XXX FIXME: If this fails, the UI will display the full command
   471   // string.
   472   // There are some rare cases this can happen - ["url.dll" -foo]
   473   // for example won't resolve correctly to the system dir. The 
   474   // subsequent launch of the helper app will work though.
   475   nsCOMPtr<nsIFile> lf;
   476   NS_NewLocalFile(handlerCommand, true, getter_AddRefs(lf));
   477   if (!lf)
   478     return NS_ERROR_FILE_NOT_FOUND;
   480   nsILocalFileWin* lfw = nullptr;
   481   CallQueryInterface(lf, &lfw);
   483   if (lfw) {
   484     // The "FileDescription" field contains the actual name of the application.
   485     lfw->GetVersionInfoField("FileDescription", aDefaultDescription);
   486     // QI addref'ed for us.
   487     *aDefaultApplication = lfw;
   488   }
   490   return NS_OK;
   491 }
   493 already_AddRefed<nsMIMEInfoWin> nsOSHelperAppService::GetByExtension(const nsAFlatString& aFileExt, const char *aTypeHint)
   494 {
   495   if (aFileExt.IsEmpty())
   496     return nullptr;
   498   // windows registry assumes your file extension is going to include the '.'.
   499   // so make sure it's there...
   500   nsAutoString fileExtToUse;
   501   if (aFileExt.First() != char16_t('.'))
   502     fileExtToUse = char16_t('.');
   504   fileExtToUse.Append(aFileExt);
   506   // Try to get an entry from the windows registry.
   507   nsCOMPtr<nsIWindowsRegKey> regKey = 
   508     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   509   if (!regKey) 
   510     return nullptr; 
   512   nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   513                              fileExtToUse,
   514                              nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   515   if (NS_FAILED(rv))
   516     return nullptr; 
   518   nsAutoCString typeToUse;
   519   if (aTypeHint && *aTypeHint) {
   520     typeToUse.Assign(aTypeHint);
   521   }
   522   else {
   523     nsAutoString temp;
   524     if (NS_FAILED(regKey->ReadStringValue(NS_LITERAL_STRING("Content Type"),
   525                   temp)) || temp.IsEmpty()) {
   526       return nullptr; 
   527     }
   528     // Content-Type is always in ASCII
   529     LossyAppendUTF16toASCII(temp, typeToUse);
   530   }
   532   nsRefPtr<nsMIMEInfoWin> mimeInfo = new nsMIMEInfoWin(typeToUse);
   534   // don't append the '.'
   535   mimeInfo->AppendExtension(NS_ConvertUTF16toUTF8(Substring(fileExtToUse, 1)));
   536   mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
   538   nsAutoString appInfo;
   539   bool found;
   541   // Retrieve the default application for this extension
   542   if (mAppAssoc) {
   543     // Vista: use the new application association COM interfaces
   544     // for resolving helpers.
   545     nsString assocType(fileExtToUse);
   546     wchar_t * pResult = nullptr;
   547     HRESULT hr = mAppAssoc->QueryCurrentDefault(assocType.get(),
   548                                                 AT_FILEEXTENSION, AL_EFFECTIVE,
   549                                                 &pResult);
   550     if (SUCCEEDED(hr)) {
   551       found = true;
   552       appInfo.Assign(pResult);
   553       CoTaskMemFree(pResult);
   554     } 
   555     else {
   556       found = false;
   557     }
   558   } 
   559   else
   560   {
   561     found = NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), 
   562                                                  appInfo));
   563   }
   565   // Bug 358297 - ignore the default handler, force the user to choose app
   566   if (appInfo.EqualsLiteral("XPSViewer.Document"))
   567     found = false;
   569   if (!found) {
   570     return nullptr;
   571   }
   573   // Get other nsIMIMEInfo fields from registry, if possible.
   574   nsAutoString defaultDescription;
   575   nsCOMPtr<nsIFile> defaultApplication;
   577   if (NS_FAILED(GetDefaultAppInfo(appInfo, defaultDescription,
   578                                   getter_AddRefs(defaultApplication)))) {
   579     return nullptr;
   580   }
   582   mimeInfo->SetDefaultDescription(defaultDescription);
   583   mimeInfo->SetDefaultApplicationHandler(defaultApplication);
   585   // Grab the general description
   586   GetMIMEInfoFromRegistry(appInfo, mimeInfo);
   588   return mimeInfo.forget();
   589 }
   591 already_AddRefed<nsIMIMEInfo> nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, const nsACString& aFileExt, bool *aFound)
   592 {
   593   *aFound = true;
   595   const nsCString& flatType = PromiseFlatCString(aMIMEType);
   596   const nsCString& flatExt = PromiseFlatCString(aFileExt);
   598   nsAutoString fileExtension;
   599   /* XXX The Equals is a gross hack to wallpaper over the most common Win32
   600    * extension issues caused by the fix for bug 116938.  See bug
   601    * 120327, comment 271 for why this is needed.  Not even sure we
   602    * want to remove this once we have fixed all this stuff to work
   603    * right; any info we get from the OS on this type is pretty much
   604    * useless....
   605    * We'll do extension-based lookup for this type later in this function.
   606    */
   607   if (!aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM)) {
   608     // (1) try to use the windows mime database to see if there is a mapping to a file extension
   609     // (2) try to see if we have some left over 4.x registry info we can peek at...
   610     GetExtensionFromWindowsMimeDatabase(aMIMEType, fileExtension);
   611     LOG(("Windows mime database: extension '%s'\n", fileExtension.get()));
   612     if (fileExtension.IsEmpty()) {
   613       GetExtensionFrom4xRegistryInfo(aMIMEType, fileExtension);
   614       LOG(("4.x Registry: extension '%s'\n", fileExtension.get()));
   615     }
   616   }
   617   // If we found an extension for the type, do the lookup
   618   nsRefPtr<nsMIMEInfoWin> mi;
   619   if (!fileExtension.IsEmpty())
   620     mi = GetByExtension(fileExtension, flatType.get());
   621   LOG(("Extension lookup on '%s' found: 0x%p\n", fileExtension.get(), mi.get()));
   623   bool hasDefault = false;
   624   if (mi) {
   625     mi->GetHasDefaultHandler(&hasDefault);
   626     // OK. We might have the case that |aFileExt| is a valid extension for the
   627     // mimetype we were given. In that case, we do want to append aFileExt
   628     // to the mimeinfo that we have. (E.g.: We are asked for video/mpeg and
   629     // .mpg, but the primary extension for video/mpeg is .mpeg. But because
   630     // .mpg is an extension for video/mpeg content, we want to append it)
   631     if (!aFileExt.IsEmpty() && typeFromExtEquals(NS_ConvertUTF8toUTF16(flatExt).get(), flatType.get())) {
   632       LOG(("Appending extension '%s' to mimeinfo, because its mimetype is '%s'\n",
   633            flatExt.get(), flatType.get()));
   634       bool extExist = false;
   635       mi->ExtensionExists(aFileExt, &extExist);
   636       if (!extExist)
   637         mi->AppendExtension(aFileExt);
   638     }
   639   }
   640   if (!mi || !hasDefault) {
   641     nsRefPtr<nsMIMEInfoWin> miByExt =
   642       GetByExtension(NS_ConvertUTF8toUTF16(aFileExt), flatType.get());
   643     LOG(("Ext. lookup for '%s' found 0x%p\n", flatExt.get(), miByExt.get()));
   644     if (!miByExt && mi)
   645       return mi.forget();
   646     if (miByExt && !mi) {
   647       return miByExt.forget();
   648     }
   649     if (!miByExt && !mi) {
   650       *aFound = false;
   651       mi = new nsMIMEInfoWin(flatType);
   652       if (!aFileExt.IsEmpty()) {
   653         mi->AppendExtension(aFileExt);
   654       }
   656       return mi.forget();
   657     }
   659     // if we get here, mi has no default app. copy from extension lookup.
   660     nsCOMPtr<nsIFile> defaultApp;
   661     nsAutoString desc;
   662     miByExt->GetDefaultDescription(desc);
   664     mi->SetDefaultDescription(desc);
   665   }
   666   return mi.forget();
   667 }
   669 NS_IMETHODIMP
   670 nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString &aScheme,
   671                                                    bool *found,
   672                                                    nsIHandlerInfo **_retval)
   673 {
   674   NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!");
   676   nsresult rv = OSProtocolHandlerExists(nsPromiseFlatCString(aScheme).get(),
   677                                         found);
   678   if (NS_FAILED(rv))
   679     return rv;
   681   nsMIMEInfoWin *handlerInfo =
   682     new nsMIMEInfoWin(aScheme, nsMIMEInfoBase::eProtocolInfo);
   683   NS_ENSURE_TRUE(handlerInfo, NS_ERROR_OUT_OF_MEMORY);
   684   NS_ADDREF(*_retval = handlerInfo);
   686   if (!*found) {
   687     // Code that calls this requires an object regardless if the OS has
   688     // something for us, so we return the empty object.
   689     return NS_OK;
   690   }
   692   nsAutoString desc;
   693   GetApplicationDescription(aScheme, desc);
   694   handlerInfo->SetDefaultDescription(desc);
   696   return NS_OK;
   697 }

mercurial