summaryrefslogtreecommitdiffstats
path: root/uriloader/exthandler/HandlerServiceParent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'uriloader/exthandler/HandlerServiceParent.cpp')
-rw-r--r--uriloader/exthandler/HandlerServiceParent.cpp381
1 files changed, 381 insertions, 0 deletions
diff --git a/uriloader/exthandler/HandlerServiceParent.cpp b/uriloader/exthandler/HandlerServiceParent.cpp
new file mode 100644
index 0000000000..ab77657dd5
--- /dev/null
+++ b/uriloader/exthandler/HandlerServiceParent.cpp
@@ -0,0 +1,381 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/Logging.h"
+#include "HandlerServiceParent.h"
+#include "nsIHandlerService.h"
+#include "nsIMIMEInfo.h"
+#include "nsIMIMEService.h"
+#include "ContentHandlerService.h"
+#include "nsIExternalProtocolService.h"
+#include "nsStringEnumerator.h"
+#include "nsIMutableArray.h"
+#include "nsCExternalHandlerService.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#ifdef MOZ_WIDGET_GTK
+# include "unix/nsGNOMERegistry.h"
+#endif
+
+using mozilla::dom::ContentHandlerService;
+using mozilla::dom::HandlerApp;
+using mozilla::dom::HandlerInfo;
+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),
+ mPrefAction(nsIHandlerInfo::alwaysAsk),
+ 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) {
+ 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) {
+ *aPreferredApplicationHandler =
+ new RemoteHandlerApp(mHandlerInfo.preferredApplicationHandler());
+ NS_IF_ADDREF(*aPreferredApplicationHandler);
+ return NS_OK;
+}
+
+NS_IMETHODIMP ProxyHandlerInfo::SetPreferredApplicationHandler(
+ nsIHandlerApp* aApp) {
+ nsString name;
+ nsString detailedDescription;
+ if (aApp) {
+ aApp->GetName(name);
+ aApp->GetDetailedDescription(detailedDescription);
+ }
+
+ mHandlerInfo.preferredApplicationHandler() =
+ HandlerApp(name, detailedDescription);
+ return NS_OK;
+}
+
+/* readonly attribute nsIMutableArray possibleApplicationHandlers; */
+NS_IMETHODIMP ProxyHandlerInfo::GetPossibleApplicationHandlers(
+ nsIMutableArray** aPossibleApplicationHandlers) {
+ *aPossibleApplicationHandlers = mPossibleApps;
+ NS_IF_ADDREF(*aPossibleApplicationHandlers);
+ return NS_OK;
+}
+
+/* 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 BrowsingContext aBrowsingContext); */
+NS_IMETHODIMP ProxyHandlerInfo::LaunchWithURI(
+ nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
+ 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.preferredAction() = aPreferredAction;
+ mPrefAction = aPreferredAction;
+ return NS_OK;
+}
+
+/* attribute boolean alwaysAskBeforeHandling; */
+NS_IMETHODIMP ProxyHandlerInfo::GetAlwaysAskBeforeHandling(
+ bool* aAlwaysAskBeforeHandling) {
+ *aAlwaysAskBeforeHandling = mHandlerInfo.alwaysAskBeforeHandling();
+ return NS_OK;
+}
+NS_IMETHODIMP ProxyHandlerInfo::SetAlwaysAskBeforeHandling(
+ bool aAlwaysAskBeforeHandling) {
+ mHandlerInfo.alwaysAskBeforeHandling() = aAlwaysAskBeforeHandling;
+ return NS_OK;
+}
+
+class ProxyMIMEInfo : public nsIMIMEInfo {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIMIMEINFO
+ NS_FORWARD_NSIHANDLERINFO(mProxyHandlerInfo->);
+
+ explicit ProxyMIMEInfo(const HandlerInfo& aHandlerInfo)
+ : mProxyHandlerInfo(new ProxyHandlerInfo(aHandlerInfo)) {}
+
+ private:
+ virtual ~ProxyMIMEInfo() {}
+ RefPtr<ProxyHandlerInfo> mProxyHandlerInfo;
+
+ protected:
+ /* additional members */
+};
+
+NS_IMPL_ISUPPORTS(ProxyMIMEInfo, nsIMIMEInfo, nsIHandlerInfo)
+
+/* nsIUTF8StringEnumerator getFileExtensions (); */
+NS_IMETHODIMP ProxyMIMEInfo::GetFileExtensions(
+ nsIUTF8StringEnumerator** _retval) {
+ 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) {
+ *_retval = mProxyHandlerInfo->Extensions().Contains(
+ aExtension, nsCaseInsensitiveCStringArrayComparator());
+ return NS_OK;
+}
+
+/* void appendExtension (in AUTF8String aExtension); */
+NS_IMETHODIMP ProxyMIMEInfo::AppendExtension(const nsACString& aExtension) {
+ if (!aExtension.IsEmpty() &&
+ !mProxyHandlerInfo->Extensions().Contains(
+ aExtension, nsCaseInsensitiveCStringArrayComparator())) {
+ mProxyHandlerInfo->Extensions().AppendElement(aExtension);
+ }
+ return NS_OK;
+}
+
+/* attribute AUTF8String primaryExtension; */
+NS_IMETHODIMP ProxyMIMEInfo::GetPrimaryExtension(
+ nsACString& aPrimaryExtension) {
+ const auto& extensions = mProxyHandlerInfo->Extensions();
+ if (extensions.IsEmpty()) {
+ aPrimaryExtension.Truncate();
+ 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; */
+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;
+}
+
+/* boolean isCurrentAppOSDefault(); */
+NS_IMETHODIMP ProxyMIMEInfo::IsCurrentAppOSDefault(bool* _retval) {
+ 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() {}
+
+mozilla::ipc::IPCResult HandlerServiceParent::RecvFillHandlerInfo(
+ const HandlerInfo& aHandlerInfoData, const nsACString& 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 IPC_OK();
+}
+
+mozilla::ipc::IPCResult HandlerServiceParent::RecvGetMIMEInfoFromOS(
+ const nsACString& aMIMEType, const nsACString& aExtension, nsresult* aRv,
+ HandlerInfo* aHandlerInfoData, bool* aFound) {
+ *aFound = false;
+ if (aMIMEType.Length() > MAX_MIMETYPE_LENGTH ||
+ aExtension.Length() > MAX_EXT_LENGTH) {
+ *aRv = NS_OK;
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIMIMEService> mimeService =
+ do_GetService(NS_MIMESERVICE_CONTRACTID, aRv);
+ if (NS_WARN_IF(NS_FAILED(*aRv))) {
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIMIMEInfo> mimeInfo;
+ *aRv = mimeService->GetMIMEInfoFromOS(aMIMEType, aExtension, aFound,
+ getter_AddRefs(mimeInfo));
+ if (NS_WARN_IF(NS_FAILED(*aRv))) {
+ return IPC_OK();
+ }
+
+ if (mimeInfo) {
+ ContentHandlerService::nsIHandlerInfoToHandlerInfo(mimeInfo,
+ aHandlerInfoData);
+ }
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult 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 IPC_OK();
+}
+
+mozilla::ipc::IPCResult HandlerServiceParent::RecvExistsForProtocolOS(
+ const nsACString& aProtocolScheme, bool* aHandlerExists) {
+ if (aProtocolScheme.Length() > MAX_SCHEME_LENGTH) {
+ *aHandlerExists = false;
+ return IPC_OK();
+ }
+#ifdef MOZ_WIDGET_GTK
+ // Check the GNOME registry for a protocol handler
+ *aHandlerExists =
+ nsGNOMERegistry::HandlerExists(PromiseFlatCString(aProtocolScheme).get());
+#else
+ *aHandlerExists = false;
+#endif
+ return IPC_OK();
+}
+
+/*
+ * Check if a handler exists for the provided protocol. Check the datastore
+ * first and then fallback to checking the OS for a handler.
+ */
+mozilla::ipc::IPCResult HandlerServiceParent::RecvExistsForProtocol(
+ const nsACString& aProtocolScheme, bool* aHandlerExists) {
+ if (aProtocolScheme.Length() > MAX_SCHEME_LENGTH) {
+ *aHandlerExists = false;
+ return IPC_OK();
+ }
+ // Check the datastore and fallback to an OS check.
+ // ExternalProcotolHandlerExists() does the fallback.
+ nsresult rv;
+ nsCOMPtr<nsIExternalProtocolService> protoSvc =
+ do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ *aHandlerExists = false;
+ return IPC_OK();
+ }
+ rv = protoSvc->ExternalProtocolHandlerExists(
+ PromiseFlatCString(aProtocolScheme).get(), aHandlerExists);
+
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ *aHandlerExists = false;
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult HandlerServiceParent::RecvGetTypeFromExtension(
+ const nsACString& aFileExtension, nsCString* type) {
+ if (aFileExtension.Length() > MAX_EXT_LENGTH) {
+ return IPC_OK();
+ }
+
+ nsresult rv;
+ nsCOMPtr<nsIHandlerService> handlerSvc =
+ do_GetService(NS_HANDLERSERVICE_CONTRACTID, &rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return IPC_OK();
+ }
+
+ rv = handlerSvc->GetTypeFromExtension(aFileExtension, *type);
+ mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult HandlerServiceParent::RecvGetApplicationDescription(
+ const nsACString& aScheme, nsresult* aRv, nsString* aDescription) {
+ if (aScheme.Length() > MAX_SCHEME_LENGTH) {
+ *aRv = NS_ERROR_NOT_AVAILABLE;
+ return IPC_OK();
+ }
+ nsCOMPtr<nsIExternalProtocolService> protoSvc =
+ do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
+ NS_ASSERTION(protoSvc, "No Helper App Service!");
+ *aRv = protoSvc->GetApplicationDescription(aScheme, *aDescription);
+ return IPC_OK();
+}
+
+void HandlerServiceParent::ActorDestroy(ActorDestroyReason aWhy) {}