diff options
Diffstat (limited to '')
-rw-r--r-- | uriloader/exthandler/HandlerServiceParent.cpp | 381 |
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) {} |