Bug 1389836 - Push extensions from MIME info objects to the child. r=bz draft
authorBlake Kaplan <mrbkap@gmail.com>
Wed, 01 Nov 2017 17:49:22 -0700
changeset 697909 459caf229cd0a48889c6ad0bb21cace4d7042b08
parent 697271 e101d5e33cf7e46ba162dee83ef2714cc1c1abf4
child 697910 16288c3e1c4ec701baad773bb00bffee6b309147
push id89140
push userbmo:mrbkap@mozilla.com
push dateTue, 14 Nov 2017 23:40:39 +0000
reviewersbz
bugs1389836
milestone58.0a1
Bug 1389836 - Push extensions from MIME info objects to the child. r=bz It would be really nice to push all of this back up to the parent or to at least make it asynchronous. I think it should be possible since we control when we send the DOM events, but for the moment this should work. With this patch, I extend ProxyMIMEInfo and HandlerInfo with information about the available extensions for a given MIME type. On Linux, at least, we read the system (in my case GNOME) registry in the child and handlers.json in the parent finally merging them again in the child (in ContentHandlerService::FillHandlerInfo). Even though I was unable to get my mochitest to work, it did work well enough that I could verify that this patch was getting all of the proper extensions to the nsContentAreaDragDrop.cpp code. MozReview-Commit-ID: AR3VayMUiDN
uriloader/exthandler/ContentHandlerService.cpp
uriloader/exthandler/HandlerServiceParent.cpp
uriloader/exthandler/PHandlerService.ipdl
uriloader/exthandler/nsExternalHelperAppService.cpp
--- a/uriloader/exthandler/ContentHandlerService.cpp
+++ b/uriloader/exthandler/ContentHandlerService.cpp
@@ -1,13 +1,14 @@
 #include "ContentHandlerService.h"
 #include "HandlerServiceChild.h"
 #include "ContentChild.h"
 #include "nsIMutableArray.h"
 #include "nsIMIMEInfo.h"
+#include "nsIStringEnumerator.h"
 
 using mozilla::dom::ContentChild;
 using mozilla::dom::PHandlerServiceChild;
 using mozilla::dom::HandlerInfo;
 
 namespace mozilla {
 namespace dom {
 
@@ -58,19 +59,43 @@ ContentHandlerService::nsIHandlerInfoToH
     apps->GetLength(&length);
     for (unsigned int i = 0; i < length; i++) {
       apps->QueryElementAt(i, NS_GET_IID(nsIHandlerApp), getter_AddRefs(app));
       app->GetName(name);
       app->GetDetailedDescription(detailedDescription);
       happs.AppendElement(HandlerApp(name, detailedDescription));
     }
   }
+
+  nsTArray<nsCString> extensions;
+
+  if (isMIMEInfo) {
+    nsCOMPtr<nsIUTF8StringEnumerator> extensionsIter;
+    mimeInfo->GetFileExtensions(getter_AddRefs(extensionsIter));
+    if (extensionsIter) {
+      bool hasMore = false;
+      while (NS_SUCCEEDED(extensionsIter->HasMore(&hasMore)) && hasMore) {
+        nsAutoCString extension;
+        if (NS_SUCCEEDED(extensionsIter->GetNext(extension))) {
+          extensions.AppendElement(Move(extension));
+        }
+      }
+    }
+  }
+
   nsHandlerInfoAction action;
   aInfo->GetPreferredAction(&action);
-  HandlerInfo info(type, isMIMEInfo, description, alwaysAskBeforeHandling, happ, happs, action);
+  HandlerInfo info(type,
+                   isMIMEInfo,
+                   description,
+                   alwaysAskBeforeHandling,
+                   Move(extensions),
+                   happ,
+                   happs,
+                   action);
   *aHandlerInfo = info;
 }
 
 
 NS_IMETHODIMP RemoteHandlerApp::GetName(nsAString & aName)
 {
   aName.Assign(mAppChild.name());
   return NS_OK;
@@ -99,45 +124,64 @@ NS_IMETHODIMP RemoteHandlerApp::Equals(n
 
 NS_IMETHODIMP RemoteHandlerApp::LaunchWithURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMPL_ISUPPORTS(RemoteHandlerApp, nsIHandlerApp)
 
-static inline void CopyHanderInfoTonsIHandlerInfo(HandlerInfo info, nsIHandlerInfo* aHandlerInfo)
+static inline void CopyHanderInfoTonsIHandlerInfo(const HandlerInfo& info, nsIHandlerInfo* aHandlerInfo)
 {
   HandlerApp preferredApplicationHandler = info.preferredApplicationHandler();
   nsCOMPtr<nsIHandlerApp> preferredApp(new RemoteHandlerApp(preferredApplicationHandler));
   aHandlerInfo->SetPreferredApplicationHandler(preferredApp);
   nsCOMPtr<nsIMutableArray> possibleHandlers;
   aHandlerInfo->GetPossibleApplicationHandlers(getter_AddRefs(possibleHandlers));
   possibleHandlers->AppendElement(preferredApp);
+
+  if (info.isMIMEInfo()) {
+    const auto& fileExtensions = info.extensions();
+    bool first = true;
+    nsAutoCString extensionsStr;
+    for (const auto& extension : fileExtensions) {
+      if (!first) {
+        extensionsStr.Append(',');
+      }
+
+      extensionsStr.Append(extension);
+      first = false;
+    }
+
+    nsCOMPtr<nsIMIMEInfo> mimeInfo(do_QueryInterface(aHandlerInfo));
+    MOZ_ASSERT(mimeInfo, "parent and child don't agree on whether this is a MIME info");
+    mimeInfo->SetFileExtensions(extensionsStr);
+  }
 }
+
 ContentHandlerService::~ContentHandlerService()
 {
 }
 
 NS_IMETHODIMP ContentHandlerService::AsyncInit()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP ContentHandlerService::Enumerate(nsISimpleEnumerator * *_retval)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP ContentHandlerService::FillHandlerInfo(nsIHandlerInfo *aHandlerInfo, const nsACString & aOverrideType)
 {
-  HandlerInfo info;
+  HandlerInfo info, returnedInfo;
   nsIHandlerInfoToHandlerInfo(aHandlerInfo, &info);
-  mHandlerServiceChild->SendFillHandlerInfo(info, nsCString(aOverrideType), &info);
-  CopyHanderInfoTonsIHandlerInfo(info, aHandlerInfo);
+  mHandlerServiceChild->SendFillHandlerInfo(info, nsCString(aOverrideType), &returnedInfo);
+  CopyHanderInfoTonsIHandlerInfo(returnedInfo, aHandlerInfo);
   return NS_OK;
 }
 
 NS_IMETHODIMP ContentHandlerService::Store(nsIHandlerInfo *aHandlerInfo)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
--- a/uriloader/exthandler/HandlerServiceParent.cpp
+++ b/uriloader/exthandler/HandlerServiceParent.cpp
@@ -1,39 +1,47 @@
 #include "mozilla/Logging.h"
 #include "HandlerServiceParent.h"
 #include "nsIHandlerService.h"
 #include "nsIMIMEInfo.h"
 #include "ContentHandlerService.h"
+#include "nsStringEnumerator.h"
 #ifdef MOZ_WIDGET_GTK
 #include "unix/nsGNOMERegistry.h"
 #endif
 
 using mozilla::dom::HandlerInfo;
 using mozilla::dom::HandlerApp;
 using mozilla::dom::ContentHandlerService;
 using mozilla::dom::RemoteHandlerApp;
 
 namespace {
 
 class ProxyHandlerInfo final : public nsIHandlerInfo {
 public:
   explicit ProxyHandlerInfo(const HandlerInfo& aHandlerInfo);
   NS_DECL_ISUPPORTS;
   NS_DECL_NSIHANDLERINFO;
+
+  nsTArray<nsCString>& Extensions() {
+    return mHandlerInfo.extensions();
+  }
+
 protected:
   ~ProxyHandlerInfo() {}
   HandlerInfo mHandlerInfo;
   nsHandlerInfoAction mPrefAction;
   nsCOMPtr<nsIMutableArray> mPossibleApps;
 };
 
 NS_IMPL_ISUPPORTS(ProxyHandlerInfo, nsIHandlerInfo)
 
-ProxyHandlerInfo::ProxyHandlerInfo(const HandlerInfo& aHandlerInfo) : mHandlerInfo(aHandlerInfo), mPossibleApps(do_CreateInstance(NS_ARRAY_CONTRACTID))
+ProxyHandlerInfo::ProxyHandlerInfo(const HandlerInfo& aHandlerInfo)
+  : mHandlerInfo(aHandlerInfo),
+    mPossibleApps(do_CreateInstance(NS_ARRAY_CONTRACTID))
 {
   for (auto& happ : aHandlerInfo.possibleApplicationHandlers()) {
     mPossibleApps->AppendElement(new RemoteHandlerApp(happ));
   }
 }
 
 /* readonly attribute ACString type; */
 NS_IMETHODIMP ProxyHandlerInfo::GetType(nsACString & aType)
@@ -68,16 +76,17 @@ NS_IMETHODIMP ProxyHandlerInfo::SetPrefe
     aApp->GetName(name);
     aApp->GetDetailedDescription(detailedDescription);
   }
   HandlerApp happ(name, detailedDescription);
   mHandlerInfo = HandlerInfo(mHandlerInfo.type(),
                              mHandlerInfo.isMIMEInfo(),
                              mHandlerInfo.description(),
                              mHandlerInfo.alwaysAskBeforeHandling(),
+                             mHandlerInfo.extensions(),
                              happ,
                              mHandlerInfo.possibleApplicationHandlers(),
                              mHandlerInfo.preferredAction());
   return NS_OK;
 }
 
 /* readonly attribute nsIMutableArray possibleApplicationHandlers; */
 NS_IMETHODIMP ProxyHandlerInfo::GetPossibleApplicationHandlers(nsIMutableArray * *aPossibleApplicationHandlers)
@@ -112,16 +121,17 @@ NS_IMETHODIMP ProxyHandlerInfo::GetPrefe
   return NS_OK;
 }
 NS_IMETHODIMP ProxyHandlerInfo::SetPreferredAction(nsHandlerInfoAction aPreferredAction)
 {
   mHandlerInfo = HandlerInfo(mHandlerInfo.type(),
                              mHandlerInfo.isMIMEInfo(),
                              mHandlerInfo.description(),
                              mHandlerInfo.alwaysAskBeforeHandling(),
+                             mHandlerInfo.extensions(),
                              mHandlerInfo.preferredApplicationHandler(),
                              mHandlerInfo.possibleApplicationHandlers(),
                              aPreferredAction);
   mPrefAction = aPreferredAction;
   return NS_OK;
 }
 
 /* attribute boolean alwaysAskBeforeHandling; */
@@ -131,70 +141,81 @@ NS_IMETHODIMP ProxyHandlerInfo::GetAlway
   return NS_OK;
 }
 NS_IMETHODIMP ProxyHandlerInfo::SetAlwaysAskBeforeHandling(bool aAlwaysAskBeforeHandling)
 {
   mHandlerInfo = HandlerInfo(mHandlerInfo.type(),
                              mHandlerInfo.isMIMEInfo(),
                              mHandlerInfo.description(),
                              aAlwaysAskBeforeHandling,
+                             mHandlerInfo.extensions(),
                              mHandlerInfo.preferredApplicationHandler(),
                              mHandlerInfo.possibleApplicationHandlers(),
                              mHandlerInfo.preferredAction());
   return NS_OK;
 }
 
 
 class ProxyMIMEInfo : public nsIMIMEInfo
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMIMEINFO
   NS_FORWARD_NSIHANDLERINFO(mProxyHandlerInfo->);
 
-  explicit ProxyMIMEInfo(HandlerInfo aHandlerInfo) : mProxyHandlerInfo(new ProxyHandlerInfo(aHandlerInfo)) {}
+  explicit ProxyMIMEInfo(const HandlerInfo &aHandlerInfo)
+    : mProxyHandlerInfo(new ProxyHandlerInfo(aHandlerInfo))
+  {
+  }
 
 private:
   virtual ~ProxyMIMEInfo() {}
-  nsCOMPtr<nsIHandlerInfo> mProxyHandlerInfo;
+  RefPtr<ProxyHandlerInfo> mProxyHandlerInfo;
 
 protected:
   /* additional members */
 };
 
 NS_IMPL_ISUPPORTS(ProxyMIMEInfo, nsIMIMEInfo, nsIHandlerInfo)
 
 /* nsIUTF8StringEnumerator getFileExtensions (); */
 NS_IMETHODIMP ProxyMIMEInfo::GetFileExtensions(nsIUTF8StringEnumerator * *_retval)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  return NS_NewUTF8StringEnumerator(_retval, &mProxyHandlerInfo->Extensions(), this);
 }
 
 /* void setFileExtensions (in AUTF8String aExtensions); */
 NS_IMETHODIMP ProxyMIMEInfo::SetFileExtensions(const nsACString & aExtensions)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* boolean extensionExists (in AUTF8String aExtension); */
 NS_IMETHODIMP ProxyMIMEInfo::ExtensionExists(const nsACString & aExtension, bool *_retval)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  *_retval = mProxyHandlerInfo->Extensions().Contains(aExtension);
+  return NS_OK;
 }
 
 /* void appendExtension (in AUTF8String aExtension); */
 NS_IMETHODIMP ProxyMIMEInfo::AppendExtension(const nsACString & aExtension)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  mProxyHandlerInfo->Extensions().AppendElement(aExtension);
+  return NS_OK;
 }
 
 /* attribute AUTF8String primaryExtension; */
 NS_IMETHODIMP ProxyMIMEInfo::GetPrimaryExtension(nsACString & aPrimaryExtension)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  const auto& extensions = mProxyHandlerInfo->Extensions();
+  if (extensions.IsEmpty()) {
+    return NS_ERROR_FAILURE;
+  }
+  aPrimaryExtension = extensions[0];
+  return NS_OK;
 }
 
 NS_IMETHODIMP ProxyMIMEInfo::SetPrimaryExtension(const nsACString & aPrimaryExtension)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* readonly attribute ACString MIMEType; */
--- a/uriloader/exthandler/PHandlerService.ipdl
+++ b/uriloader/exthandler/PHandlerService.ipdl
@@ -12,16 +12,17 @@ struct HandlerApp {
   nsString detailedDescription;
 };
 
 struct HandlerInfo {
   nsCString type;
   bool isMIMEInfo;
   nsString description;
   bool alwaysAskBeforeHandling;
+  nsCString[] extensions;
   HandlerApp preferredApplicationHandler;
   HandlerApp[] possibleApplicationHandlers;
   long preferredAction;
 };
 
 sync protocol PHandlerService
 {
   manager PContent;
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -1780,17 +1780,17 @@ NS_IMETHODIMP nsExternalAppHandler::OnSt
 
   return NS_OK;
 }
 
 // Convert error info into proper message text and send OnStatusChange
 // notification to the dialog progress listener or nsITransfer implementation.
 void nsExternalAppHandler::SendStatusChange(ErrorType type, nsresult rv, nsIRequest *aRequest, const nsString& path)
 {
-    const char* msgId;
+    const char* msgId = nullptr;
     switch (rv) {
     case NS_ERROR_OUT_OF_MEMORY:
         // No memory
         msgId = "noMemory";
         break;
 
     case NS_ERROR_FILE_DISK_FULL:
     case NS_ERROR_FILE_NO_DEVICE_SPACE: