bug 1190018 - External protocol handlers don't work in e10s r=mrbkap
☠☠ backed out by 453b41d5aef7 ☠ ☠
authorBrad Lassey <blassey@mozilla.com>
Tue, 25 Aug 2015 19:42:21 -0400
changeset 271333 f6ec673b3b76e61dfc10a8cf70e5efe861107fa9
parent 271332 1cb956020202df4f65eeac7b68794c24610b7a7d
child 271334 70df5b203edb0e9e19c4d64e66bb3a61997a0a6a
push id29638
push userkwierso@gmail.com
push dateFri, 06 Nov 2015 02:44:30 +0000
treeherderautoland@cc48981c026c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1190018
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1190018 - External protocol handlers don't work in e10s r=mrbkap
docshell/build/moz.build
docshell/build/nsDocShellModule.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
uriloader/exthandler/ContentHandlerService.cpp
uriloader/exthandler/ContentHandlerService.h
uriloader/exthandler/HandlerServiceChild.h
uriloader/exthandler/HandlerServiceParent.cpp
uriloader/exthandler/HandlerServiceParent.h
uriloader/exthandler/PHandlerService.ipdl
uriloader/exthandler/moz.build
uriloader/exthandler/nsHandlerService.manifest
--- a/docshell/build/moz.build
+++ b/docshell/build/moz.build
@@ -18,12 +18,14 @@ LOCAL_INCLUDES += [
     '/uriloader/base',
     '/uriloader/exthandler',
     '/uriloader/prefetch',
 ]
 
 if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
     LOCAL_INCLUDES += ['/uriloader/exthandler/mac']
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wshadow']
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -16,16 +16,17 @@
 // uriloader
 #include "nsURILoader.h"
 #include "nsDocLoader.h"
 #include "nsOSHelperAppService.h"
 #include "nsExternalProtocolHandler.h"
 #include "nsPrefetchService.h"
 #include "nsOfflineCacheUpdate.h"
 #include "nsLocalHandlerApp.h"
+#include "ContentHandlerService.h"
 #ifdef MOZ_ENABLE_DBUS
 #include "nsDBusHandlerApp.h"
 #endif
 #if defined(MOZ_WIDGET_ANDROID)
 #include "nsExternalSharingAppService.h"
 #include "nsExternalURLHandlerService.h"
 #endif
 
@@ -33,16 +34,18 @@
 #include "nsSHEntry.h"
 #include "nsSHEntryShared.h"
 #include "nsSHistory.h"
 #include "nsSHTransaction.h"
 
 // download history
 #include "nsDownloadHistory.h"
 
+using mozilla::dom::ContentHandlerService;
+
 static bool gInitialized = false;
 
 // The one time initialization for this module
 static nsresult
 Initialize()
 {
   NS_PRECONDITION(!gInitialized, "docshell module already initialized");
   if (gInitialized) {
@@ -81,16 +84,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsOffline
 NS_GENERIC_FACTORY_CONSTRUCTOR(PlatformLocalHandlerApp_t)
 #ifdef MOZ_ENABLE_DBUS
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDBusHandlerApp)
 #endif
 #if defined(MOZ_WIDGET_ANDROID)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsExternalSharingAppService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsExternalURLHandlerService)
 #endif
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ContentHandlerService, Init)
 
 // session history
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSHEntry)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSHTransaction)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSHistory)
 
 // download history
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloadHistory)
@@ -114,25 +118,28 @@ NS_DEFINE_NAMED_CID(NS_DBUSHANDLERAPP_CI
 NS_DEFINE_NAMED_CID(NS_EXTERNALSHARINGAPPSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_EXTERNALURLHANDLERSERVICE_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_SHENTRY_CID);
 NS_DEFINE_NAMED_CID(NS_SHTRANSACTION_CID);
 NS_DEFINE_NAMED_CID(NS_SHISTORY_CID);
 NS_DEFINE_NAMED_CID(NS_SHISTORY_INTERNAL_CID);
 NS_DEFINE_NAMED_CID(NS_DOWNLOADHISTORY_CID);
+NS_DEFINE_NAMED_CID(NS_CONTENTHANDLERSERVICE_CID);
 
 const mozilla::Module::CIDEntry kDocShellCIDs[] = {
   { &kNS_DOCSHELL_CID, false, nullptr, nsDocShellConstructor },
   { &kNS_DEFAULTURIFIXUP_CID, false, nullptr, nsDefaultURIFixupConstructor },
   { &kNS_WEBNAVIGATION_INFO_CID, false, nullptr, nsWebNavigationInfoConstructor },
   { &kNS_ABOUT_REDIRECTOR_MODULE_CID, false, nullptr, nsAboutRedirector::Create },
   { &kNS_URI_LOADER_CID, false, nullptr, nsURILoaderConstructor },
   { &kNS_DOCUMENTLOADER_SERVICE_CID, false, nullptr, nsDocLoaderConstructor },
   { &kNS_EXTERNALHELPERAPPSERVICE_CID, false, nullptr, nsOSHelperAppServiceConstructor },
+  { &kNS_CONTENTHANDLERSERVICE_CID, false, nullptr, ContentHandlerServiceConstructor,
+    mozilla::Module::CONTENT_PROCESS_ONLY },
   { &kNS_EXTERNALPROTOCOLHANDLER_CID, false, nullptr, nsExternalProtocolHandlerConstructor },
   { &kNS_PREFETCHSERVICE_CID, false, nullptr, nsPrefetchServiceConstructor },
   { &kNS_OFFLINECACHEUPDATESERVICE_CID, false, nullptr, nsOfflineCacheUpdateServiceConstructor },
   { &kNS_OFFLINECACHEUPDATE_CID, false, nullptr, nsOfflineCacheUpdateConstructor },
   { &kNS_LOCALHANDLERAPP_CID, false, nullptr, PlatformLocalHandlerApp_tConstructor },
 #ifdef MOZ_ENABLE_DBUS
   { &kNS_DBUSHANDLERAPP_CID, false, nullptr, nsDBusHandlerAppConstructor },
 #endif
@@ -174,16 +181,17 @@ const mozilla::Module::ContractIDEntry k
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "plugins", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "serviceworkers", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "srcdoc", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "support", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "telemetry", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "webrtc", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_URI_LOADER_CONTRACTID, &kNS_URI_LOADER_CID },
   { NS_DOCUMENTLOADER_SERVICE_CONTRACTID, &kNS_DOCUMENTLOADER_SERVICE_CID },
+  { NS_HANDLERSERVICE_CONTRACTID, &kNS_CONTENTHANDLERSERVICE_CID, mozilla::Module::CONTENT_PROCESS_ONLY },
   { NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &kNS_EXTERNALHELPERAPPSERVICE_CID },
   { NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &kNS_EXTERNALHELPERAPPSERVICE_CID },
   { NS_MIMESERVICE_CONTRACTID, &kNS_EXTERNALHELPERAPPSERVICE_CID },
   { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default", &kNS_EXTERNALPROTOCOLHANDLER_CID },
   { NS_PREFETCHSERVICE_CONTRACTID, &kNS_PREFETCHSERVICE_CID },
   { NS_OFFLINECACHEUPDATESERVICE_CONTRACTID, &kNS_OFFLINECACHEUPDATESERVICE_CID },
   { NS_OFFLINECACHEUPDATE_CONTRACTID, &kNS_OFFLINECACHEUPDATE_CID },
   { NS_LOCALHANDLERAPP_CONTRACTID, &kNS_LOCALHANDLERAPP_CID },
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -13,16 +13,17 @@
 #endif
 
 #include "ContentChild.h"
 
 #include "BlobChild.h"
 #include "CrashReporterChild.h"
 #include "GeckoProfiler.h"
 #include "TabChild.h"
+#include "HandlerServiceChild.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
 #include "mozilla/dom/ContentBridgeChild.h"
@@ -1889,16 +1890,30 @@ ContentChild::AllocPExternalHelperAppChi
 bool
 ContentChild::DeallocPExternalHelperAppChild(PExternalHelperAppChild* aService)
 {
     ExternalHelperAppChild *child = static_cast<ExternalHelperAppChild*>(aService);
     child->Release();
     return true;
 }
 
+PHandlerServiceChild*
+ContentChild::AllocPHandlerServiceChild()
+{
+    HandlerServiceChild* actor =  new HandlerServiceChild();
+    actor->AddRef();
+    return actor;
+}
+
+bool ContentChild::DeallocPHandlerServiceChild(PHandlerServiceChild* aHandlerServiceChild)
+{
+    static_cast<HandlerServiceChild*>(aHandlerServiceChild)->Release();
+    return true;
+}
+
 PCellBroadcastChild*
 ContentChild::AllocPCellBroadcastChild()
 {
     MOZ_CRASH("No one should be allocating PCellBroadcastChild actors");
 }
 
 PCellBroadcastChild*
 ContentChild::SendPCellBroadcastConstructor(PCellBroadcastChild* aActor)
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -268,16 +268,19 @@ public:
             const uint32_t& aContentDispositionHint,
             const nsString& aContentDispositionFilename,
             const bool& aForceSave,
             const int64_t& aContentLength,
             const OptionalURIParams& aReferrer,
             PBrowserChild* aBrowser) override;
     virtual bool DeallocPExternalHelperAppChild(PExternalHelperAppChild *aService) override;
 
+    virtual PHandlerServiceChild* AllocPHandlerServiceChild() override;
+    virtual bool DeallocPHandlerServiceChild(PHandlerServiceChild*) override;
+
     virtual PCellBroadcastChild* AllocPCellBroadcastChild() override;
     PCellBroadcastChild* SendPCellBroadcastConstructor(PCellBroadcastChild* aActor);
     virtual bool DeallocPCellBroadcastChild(PCellBroadcastChild* aActor) override;
 
     virtual PSmsChild* AllocPSmsChild() override;
     virtual bool DeallocPSmsChild(PSmsChild*) override;
 
     virtual PTelephonyChild* AllocPTelephonyChild() override;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -26,16 +26,17 @@
 #include <set>
 
 #include "mozilla/a11y/PDocAccessible.h"
 #include "AppProcessChecker.h"
 #include "AudioChannelService.h"
 #include "BlobParent.h"
 #include "CrashReporterParent.h"
 #include "GMPServiceParent.h"
+#include "HandlerServiceParent.h"
 #include "IHistory.h"
 #include "imgIContainer.h"
 #include "mozIApplication.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
 #include "mozilla/docshell/OfflineCacheUpdateParent.h"
 #include "mozilla/dom/DataStoreService.h"
 #include "mozilla/dom/DataTransfer.h"
@@ -3906,16 +3907,31 @@ ContentParent::AllocPExternalHelperAppPa
 bool
 ContentParent::DeallocPExternalHelperAppParent(PExternalHelperAppParent* aService)
 {
     ExternalHelperAppParent *parent = static_cast<ExternalHelperAppParent *>(aService);
     parent->Release();
     return true;
 }
 
+PHandlerServiceParent*
+ContentParent::AllocPHandlerServiceParent()
+{
+    HandlerServiceParent* actor =  new HandlerServiceParent();
+    actor->AddRef();
+    return actor;
+}
+
+bool
+ContentParent::DeallocPHandlerServiceParent(PHandlerServiceParent* aHandlerServiceParent)
+{
+    static_cast<HandlerServiceParent*>(aHandlerServiceParent)->Release();
+    return true;
+}
+
 PCellBroadcastParent*
 ContentParent::AllocPCellBroadcastParent()
 {
     if (!AssertAppProcessPermission(this, "cellbroadcast")) {
         return nullptr;
     }
 
     CellBroadcastParent* actor = new CellBroadcastParent();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -699,16 +699,19 @@ private:
             const uint32_t& aContentDispositionHint,
             const nsString& aContentDispositionFilename,
             const bool& aForceSave,
             const int64_t& aContentLength,
             const OptionalURIParams& aReferrer,
             PBrowserParent* aBrowser) override;
     virtual bool DeallocPExternalHelperAppParent(PExternalHelperAppParent* aService) override;
 
+    virtual PHandlerServiceParent* AllocPHandlerServiceParent() override;
+    virtual bool DeallocPHandlerServiceParent(PHandlerServiceParent*) override;
+
     virtual PCellBroadcastParent* AllocPCellBroadcastParent() override;
     virtual bool DeallocPCellBroadcastParent(PCellBroadcastParent*) override;
     virtual bool RecvPCellBroadcastConstructor(PCellBroadcastParent* aActor) override;
 
     virtual PSmsParent* AllocPSmsParent() override;
     virtual bool DeallocPSmsParent(PSmsParent*) override;
 
     virtual PTelephonyParent* AllocPTelephonyParent() override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -11,16 +11,17 @@ include protocol PBrowser;
 include protocol PCellBroadcast;
 include protocol PCompositor;
 include protocol PContentBridge;
 include protocol PContentPermissionRequest;
 include protocol PCycleCollectWithLogs;
 include protocol PCrashReporter;
 include protocol PPSMContentDownloader;
 include protocol PExternalHelperApp;
+include protocol PHandlerService;
 include protocol PDeviceStorageRequest;
 include protocol PFileDescriptorSet;
 include protocol PFMRadio;
 include protocol PFileSystemRequest;
 include protocol PHal;
 include protocol PHeapSnapshotTempFileHelper;
 include protocol PIcc;
 include protocol PProcessHangMonitor;
@@ -436,16 +437,17 @@ prio(normal upto urgent) sync protocol P
     manages PCycleCollectWithLogs;
     manages PDeviceStorageRequest;
     manages PFileSystemRequest;
     manages PPSMContentDownloader;
     manages PExternalHelperApp;
     manages PFileDescriptorSet;
     manages PFMRadio;
     manages PHal;
+    manages PHandlerService;
     manages PHeapSnapshotTempFileHelper;
     manages PIcc;
     manages PMedia;
     manages PMemoryReportRequest;
     manages PMobileConnection;
     manages PNecko;
     manages POfflineCacheUpdate;
     manages PPrinting;
@@ -862,16 +864,18 @@ parent:
                        nsCString aContentDisposition,
                        uint32_t aContentDispositionHint,
                        nsString aContentDispositionFilename,
                        bool aForceSave,
                        int64_t aContentLength,
                        OptionalURIParams aReferrer,
                        nullable PBrowser aBrowser);
 
+    PHandlerService();
+
     AddGeolocationListener(Principal principal, bool highAccuracy);
     RemoveGeolocationListener();
     SetGeolocationHigherAccuracy(bool enable);
 
     ConsoleMessage(nsString message);
     ScriptError(nsString message, nsString sourceName, nsString sourceLine,
                 uint32_t lineNumber, uint32_t colNumber, uint32_t flags,
                 nsCString category);
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/ContentHandlerService.cpp
@@ -0,0 +1,171 @@
+#include "ContentHandlerService.h"
+#include "HandlerServiceChild.h"
+#include "ContentChild.h"
+#include "nsIMutableArray.h"
+#include "nsIMIMEInfo.h"
+
+using mozilla::dom::ContentChild;
+using mozilla::dom::PHandlerServiceChild;
+using mozilla::dom::HandlerInfo;
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_ISUPPORTS(ContentHandlerService, nsIHandlerService)
+
+ContentHandlerService::ContentHandlerService()
+{
+}
+
+nsresult
+ContentHandlerService::Init()
+{
+  if (!XRE_IsContentProcess()) {
+    return NS_ERROR_FAILURE;
+  }
+  ContentChild* cpc = ContentChild::GetSingleton();
+
+  mHandlerServiceChild = static_cast<HandlerServiceChild*>(cpc->SendPHandlerServiceConstructor());
+  return NS_OK;
+}
+
+void
+ContentHandlerService::nsIHandlerInfoToHandlerInfo(nsIHandlerInfo* aInfo,
+                                                   HandlerInfo* aHandlerInfo)
+{
+  nsCString type;
+  aInfo->GetType(type);
+  nsCOMPtr<nsIMIMEInfo> mimeInfo = do_QueryInterface(aInfo);
+  bool isMIMEInfo = !!mimeInfo;
+  nsString description;
+  aInfo->GetDescription(description);
+  bool alwaysAskBeforeHandling;
+  aInfo->GetAlwaysAskBeforeHandling(&alwaysAskBeforeHandling);
+  nsCOMPtr<nsIHandlerApp> app;
+  aInfo->GetPreferredApplicationHandler(getter_AddRefs(app));
+  nsString name;
+  nsString detailedDescription;
+  if (app) {
+    app->GetName(name);
+    app->GetDetailedDescription(detailedDescription);
+  }
+  HandlerApp happ(name, detailedDescription);
+  nsHandlerInfoAction action;
+  aInfo->GetPreferredAction(&action);
+  HandlerInfo info(type, isMIMEInfo, description, alwaysAskBeforeHandling, happ, action);
+  *aHandlerInfo = info;
+}
+
+class RemoteHandlerApp : public nsIHandlerApp
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  explicit RemoteHandlerApp(HandlerApp aAppChild) : mAppChild(aAppChild)
+  {
+  }
+
+  NS_IMETHOD GetName(nsAString & aName) override
+  {
+    aName.Assign(mAppChild.name());
+    return NS_OK;
+  }
+
+  NS_IMETHOD SetName(const nsAString & aName) override
+  {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+  NS_IMETHOD GetDetailedDescription(nsAString & aDetailedDescription) override
+  {
+    aDetailedDescription.Assign(mAppChild.detailedDescription());
+    return NS_OK;
+  }
+
+  NS_IMETHOD SetDetailedDescription(const nsAString & aDetailedDescription) override
+  {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+  NS_IMETHOD Equals(nsIHandlerApp *aHandlerApp, bool *_retval) override
+  {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+  NS_IMETHOD LaunchWithURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext) override
+  {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+private:
+  virtual ~RemoteHandlerApp()
+  {
+  }
+  HandlerApp mAppChild;
+};
+
+NS_IMPL_ISUPPORTS(RemoteHandlerApp, nsIHandlerApp)
+
+static inline void CopyHanderInfoTonsIHandlerInfo(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, false);
+}
+ContentHandlerService::~ContentHandlerService()
+{
+}
+
+NS_IMETHODIMP ContentHandlerService::Enumerate(nsISimpleEnumerator * *_retval)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP ContentHandlerService::FillHandlerInfo(nsIHandlerInfo *aHandlerInfo, const nsACString & aOverrideType)
+{
+  HandlerInfo info;
+  nsIHandlerInfoToHandlerInfo(aHandlerInfo, &info);
+  mHandlerServiceChild->SendFillHandlerInfo(info, nsCString(aOverrideType), &info);
+  CopyHanderInfoTonsIHandlerInfo(info, aHandlerInfo);
+  return NS_OK;
+}
+
+NS_IMETHODIMP ContentHandlerService::Store(nsIHandlerInfo *aHandlerInfo)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP ContentHandlerService::Exists(nsIHandlerInfo *aHandlerInfo, bool *_retval)
+{
+  HandlerInfo info;
+  nsIHandlerInfoToHandlerInfo(aHandlerInfo, &info);
+  mHandlerServiceChild->SendExists(info, _retval);
+  return NS_OK;
+}
+
+NS_IMETHODIMP ContentHandlerService::Remove(nsIHandlerInfo *aHandlerInfo)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+
+NS_IMETHODIMP ContentHandlerService::GetTypeFromExtension(const nsACString & aFileExtension, nsACString & _retval)
+{
+  nsCString* cachedType = nullptr;
+  if (!!mExtToTypeMap.Get(aFileExtension, &cachedType) && !!cachedType) {
+    _retval.Assign(*cachedType);
+    return NS_OK;
+  }
+  nsCString type;
+  mHandlerServiceChild->SendGetTypeFromExtension(nsCString(aFileExtension), &type);
+  _retval.Assign(type);
+  mExtToTypeMap.Put(nsCString(aFileExtension), new nsCString(type));
+
+  return NS_OK;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/ContentHandlerService.h
@@ -0,0 +1,33 @@
+#ifndef ContentHandlerService_h
+#define ContentHandlerService_h
+
+#include "nsIHandlerService.h"
+#include "nsClassHashtable.h"
+#include "HandlerServiceChild.h"
+
+#define  NS_CONTENTHANDLERSERVICE_CID                                   \
+  {0xc4b6fb7c, 0xbfb1, 0x49dc, {0xa6, 0x5f, 0x03, 0x57, 0x96, 0x52, 0x4b, 0x53}}
+
+namespace mozilla {
+namespace dom {
+
+class PHandlerServiceChild;
+
+class ContentHandlerService : public nsIHandlerService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIHANDLERSERVICE
+
+  ContentHandlerService();
+  nsresult Init();
+  static void nsIHandlerInfoToHandlerInfo(nsIHandlerInfo* aInfo, HandlerInfo* aHandlerInfo);
+
+private:
+  virtual ~ContentHandlerService();
+  RefPtr<HandlerServiceChild> mHandlerServiceChild;
+  nsClassHashtable<nsCStringHashKey, nsCString> mExtToTypeMap;
+};
+}
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/HandlerServiceChild.h
@@ -0,0 +1,15 @@
+#ifndef handler_service_child_h
+#define handler_service_child_h
+
+#include "mozilla/dom/PHandlerServiceChild.h"
+
+class HandlerServiceChild final : public mozilla::dom::PHandlerServiceChild
+{
+ public:
+  NS_INLINE_DECL_REFCOUNTING(HandlerServiceChild)
+  HandlerServiceChild() {}
+ private:
+  virtual ~HandlerServiceChild() {}
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/HandlerServiceParent.cpp
@@ -0,0 +1,246 @@
+#include "HandlerServiceParent.h"
+#include "nsIHandlerService.h"
+#include "nsIMIMEInfo.h"
+#include "ContentHandlerService.h"
+
+using mozilla::dom::HandlerInfo;
+using mozilla::dom::HandlerApp;
+using mozilla::dom::ContentHandlerService;
+
+namespace {
+
+class ProxyHandlerInfo : public nsIHandlerInfo {
+public:
+  explicit ProxyHandlerInfo(const HandlerInfo& aHandlerInfo) : mHandlerInfo(aHandlerInfo) {}
+  NS_DECL_ISUPPORTS;
+  NS_DECL_NSIHANDLERINFO;
+protected:
+  virtual ~ProxyHandlerInfo() {}
+  HandlerInfo mHandlerInfo;
+  nsHandlerInfoAction mPrefAction;
+};
+
+NS_IMPL_ISUPPORTS(ProxyHandlerInfo, nsIHandlerInfo)
+
+/* readonly attribute ACString type; */
+NS_IMETHODIMP ProxyHandlerInfo::GetType(nsACString & aType)
+{
+  aType.Assign(mHandlerInfo.type());
+  return NS_OK;
+}
+
+/* attribute AString description; */
+NS_IMETHODIMP ProxyHandlerInfo::GetDescription(nsAString & aDescription)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP ProxyHandlerInfo::SetDescription(const nsAString & aDescription)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute nsIHandlerApp preferredApplicationHandler; */
+NS_IMETHODIMP ProxyHandlerInfo::GetPreferredApplicationHandler(nsIHandlerApp * *aPreferredApplicationHandler)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP ProxyHandlerInfo::SetPreferredApplicationHandler(nsIHandlerApp *aApp)
+{
+  nsString name;
+  nsString detailedDescription;
+  if (aApp) {
+    aApp->GetName(name);
+    aApp->GetDetailedDescription(detailedDescription);
+  }
+  HandlerApp happ(name, detailedDescription);
+  mHandlerInfo = HandlerInfo(mHandlerInfo.type(),
+                             mHandlerInfo.isMIMEInfo(),
+                             mHandlerInfo.description(),
+                             mHandlerInfo.alwaysAskBeforeHandling(),
+                             happ,
+                             mHandlerInfo.preferredAction());
+  return NS_OK;
+}
+
+/* readonly attribute nsIMutableArray possibleApplicationHandlers; */
+NS_IMETHODIMP ProxyHandlerInfo::GetPossibleApplicationHandlers(nsIMutableArray * *aPossibleApplicationHandlers)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* readonly attribute boolean hasDefaultHandler; */
+NS_IMETHODIMP ProxyHandlerInfo::GetHasDefaultHandler(bool *aHasDefaultHandler)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* readonly attribute AString defaultDescription; */
+NS_IMETHODIMP ProxyHandlerInfo::GetDefaultDescription(nsAString & aDefaultDescription)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void launchWithURI (in nsIURI aURI, [optional] in nsIInterfaceRequestor aWindowContext); */
+NS_IMETHODIMP ProxyHandlerInfo::LaunchWithURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute ProxyHandlerInfoAction preferredAction; */
+NS_IMETHODIMP ProxyHandlerInfo::GetPreferredAction(nsHandlerInfoAction *aPreferredAction)
+{
+  *aPreferredAction = mPrefAction;
+  return NS_OK;
+}
+NS_IMETHODIMP ProxyHandlerInfo::SetPreferredAction(nsHandlerInfoAction aPreferredAction)
+{
+  mHandlerInfo = HandlerInfo(mHandlerInfo.type(),
+                             mHandlerInfo.isMIMEInfo(),
+                             mHandlerInfo.description(),
+                             mHandlerInfo.alwaysAskBeforeHandling(),
+                             mHandlerInfo.preferredApplicationHandler(),
+                             aPreferredAction);
+  return NS_OK;
+}
+
+/* attribute boolean alwaysAskBeforeHandling; */
+NS_IMETHODIMP ProxyHandlerInfo::GetAlwaysAskBeforeHandling(bool *aAlwaysAskBeforeHandling)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP ProxyHandlerInfo::SetAlwaysAskBeforeHandling(bool aAlwaysAskBeforeHandling)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+
+class ProxyMIMEInfo : public nsIMIMEInfo
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMIMEINFO
+  NS_FORWARD_NSIHANDLERINFO(mProxyHandlerInfo->);
+
+  explicit ProxyMIMEInfo(HandlerInfo aHandlerInfo) : mProxyHandlerInfo(new ProxyHandlerInfo(aHandlerInfo)) {}
+
+private:
+  virtual ~ProxyMIMEInfo() {}
+  nsCOMPtr<nsIHandlerInfo> mProxyHandlerInfo;
+
+protected:
+  /* additional members */
+};
+
+NS_IMPL_ISUPPORTS(ProxyMIMEInfo, nsIMIMEInfo, nsIHandlerInfo)
+
+/* nsIUTF8StringEnumerator getFileExtensions (); */
+NS_IMETHODIMP ProxyMIMEInfo::GetFileExtensions(nsIUTF8StringEnumerator * *_retval)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* 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;
+}
+
+/* void appendExtension (in AUTF8String aExtension); */
+NS_IMETHODIMP ProxyMIMEInfo::AppendExtension(const nsACString & aExtension)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute AUTF8String primaryExtension; */
+NS_IMETHODIMP ProxyMIMEInfo::GetPrimaryExtension(nsACString & aPrimaryExtension)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP ProxyMIMEInfo::SetPrimaryExtension(const nsACString & aPrimaryExtension)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* readonly attribute ACString MIMEType; */
+NS_IMETHODIMP ProxyMIMEInfo::GetMIMEType(nsACString & aMIMEType)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* boolean equals (in nsIMIMEInfo aMIMEInfo); */
+NS_IMETHODIMP ProxyMIMEInfo::Equals(nsIMIMEInfo *aMIMEInfo, bool *_retval)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* readonly attribute nsIArray possibleLocalHandlers; */
+NS_IMETHODIMP ProxyMIMEInfo::GetPossibleLocalHandlers(nsIArray * *aPossibleLocalHandlers)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void launchWithFile (in nsIFile aFile); */
+NS_IMETHODIMP ProxyMIMEInfo::LaunchWithFile(nsIFile *aFile)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static already_AddRefed<nsIHandlerInfo> WrapHandlerInfo(const HandlerInfo& aHandlerInfo) {
+  nsCOMPtr<nsIHandlerInfo> info;
+  if (aHandlerInfo.isMIMEInfo()) {
+    info = new ProxyMIMEInfo(aHandlerInfo);
+  } else {
+    info = new ProxyHandlerInfo(aHandlerInfo);
+  }
+  return info.forget();
+}
+
+} // anonymous namespace
+
+HandlerServiceParent::HandlerServiceParent()
+{
+}
+
+HandlerServiceParent::~HandlerServiceParent()
+{
+}
+
+bool HandlerServiceParent::RecvFillHandlerInfo(const HandlerInfo& aHandlerInfoData,
+                                               const nsCString& aOverrideType,
+                                               HandlerInfo* handlerInfoData)
+{
+  nsCOMPtr<nsIHandlerInfo> info(WrapHandlerInfo(aHandlerInfoData));
+  nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID);
+  handlerSvc->FillHandlerInfo(info, aOverrideType);
+  ContentHandlerService::nsIHandlerInfoToHandlerInfo(info, handlerInfoData);
+  return true;
+}
+
+bool HandlerServiceParent::RecvExists(const HandlerInfo& aHandlerInfo,
+                                      bool* exists)
+{
+  nsCOMPtr<nsIHandlerInfo> info(WrapHandlerInfo(aHandlerInfo));
+  nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID);
+  handlerSvc->Exists(info, exists);
+  return true;
+}
+
+bool HandlerServiceParent::RecvGetTypeFromExtension(const nsCString& aFileExtension,
+                                                    nsCString* type)
+{
+  nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID);
+  handlerSvc->GetTypeFromExtension(aFileExtension, *type);
+  return true;
+}
+
+void HandlerServiceParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+}
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/HandlerServiceParent.h
@@ -0,0 +1,31 @@
+#ifndef handler_service_parent_h
+#define handler_service_parent_h
+
+#include "mozilla/dom/PHandlerServiceParent.h"
+#include "nsIMIMEInfo.h"
+
+class nsIHandlerApp;
+
+class HandlerServiceParent final : public mozilla::dom::PHandlerServiceParent
+{
+ public:
+  HandlerServiceParent();
+  NS_INLINE_DECL_REFCOUNTING(HandlerServiceParent)
+
+ private:
+  virtual ~HandlerServiceParent();
+  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+
+  virtual bool RecvFillHandlerInfo(const HandlerInfo& aHandlerInfoData,
+                                   const nsCString& aOverrideType,
+                                   HandlerInfo* handlerInfoData) override;
+  virtual bool RecvExists(const HandlerInfo& aHandlerInfo,
+                          bool* exits) override;
+
+  virtual bool RecvGetTypeFromExtension(const nsCString& aFileExtension,
+                                        nsCString* type) override;
+
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/PHandlerService.ipdl
@@ -0,0 +1,41 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PContent;
+
+namespace mozilla {
+namespace dom {
+
+struct HandlerApp {
+  nsString name;
+  nsString detailedDescription;
+};
+
+struct HandlerInfo {
+  nsCString type;
+  bool isMIMEInfo;
+  nsString description;
+  bool alwaysAskBeforeHandling;
+  HandlerApp preferredApplicationHandler;
+  long preferredAction;
+};
+
+sync protocol PHandlerService
+{
+  manager PContent;
+
+parent:
+  sync FillHandlerInfo(HandlerInfo aHandlerInfoData,
+                       nsCString aOverrideType)
+      returns (HandlerInfo handlerInfoData);
+  sync Exists(HandlerInfo aHandlerInfo)
+      returns (bool exists);
+  sync GetTypeFromExtension(nsCString aFileExtension)
+      returns (nsCString type);
+  __delete__();
+};
+
+
+} // namespace dom
+} // namespace mozilla
--- a/uriloader/exthandler/moz.build
+++ b/uriloader/exthandler/moz.build
@@ -29,33 +29,36 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] in ('a
 else:
     osdir = 'unix'
 
 EXPORTS += [
     osdir + '/nsOSHelperAppService.h'
 ]
 
 EXPORTS += [
+    'ContentHandlerService.h',
     'nsExternalHelperAppService.h',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     EXPORTS += [ '%s/%s' % (osdir, f) for f in [
         'nsExternalSharingAppService.h',
         'nsExternalURLHandlerService.h',
     ]]
 
 EXPORTS.mozilla.dom += [
     'ExternalHelperAppChild.h',
     'ExternalHelperAppParent.h',
 ]
 
 UNIFIED_SOURCES += [
+    'ContentHandlerService.cpp',
     'ExternalHelperAppChild.cpp',
     'ExternalHelperAppParent.cpp',
+    'HandlerServiceParent.cpp',
     'nsExternalHelperAppService.cpp',
     'nsExternalProtocolHandler.cpp',
     'nsLocalHandlerApp.cpp',
     'nsMIMEInfoImpl.cpp',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     UNIFIED_SOURCES += [
@@ -114,16 +117,17 @@ EXTRA_COMPONENTS += [
     'nsHandlerService.js',
     'nsHandlerService.manifest',
     'nsWebHandlerApp.js',
     'nsWebHandlerApp.manifest',
 ]
 
 IPDL_SOURCES += [
     'PExternalHelperApp.ipdl',
+    'PHandlerService.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/dom/base',
--- a/uriloader/exthandler/nsHandlerService.manifest
+++ b/uriloader/exthandler/nsHandlerService.manifest
@@ -1,2 +1,2 @@
 component {32314cc8-22f7-4f7f-a645-1a45453ba6a6} nsHandlerService.js
-contract @mozilla.org/uriloader/handler-service;1 {32314cc8-22f7-4f7f-a645-1a45453ba6a6}
\ No newline at end of file
+contract @mozilla.org/uriloader/handler-service;1 {32314cc8-22f7-4f7f-a645-1a45453ba6a6} process=main
\ No newline at end of file