1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/ipc/ProtocolUtils.h"
8 #include "mozilla/Logging.h"
9 #include "HandlerServiceParent.h"
10 #include "nsIHandlerService.h"
11 #include "nsIMIMEInfo.h"
12 #include "ContentHandlerService.h"
13 #include "nsStringEnumerator.h"
14 #ifdef MOZ_WIDGET_GTK
15 #  include "unix/nsGNOMERegistry.h"
16 #endif
17 
18 using mozilla::dom::ContentHandlerService;
19 using mozilla::dom::HandlerApp;
20 using mozilla::dom::HandlerInfo;
21 using mozilla::dom::RemoteHandlerApp;
22 
23 namespace {
24 
25 class ProxyHandlerInfo final : public nsIHandlerInfo {
26  public:
27   explicit ProxyHandlerInfo(const HandlerInfo& aHandlerInfo);
28   NS_DECL_ISUPPORTS;
29   NS_DECL_NSIHANDLERINFO;
30 
Extensions()31   nsTArray<nsCString>& Extensions() { return mHandlerInfo.extensions(); }
32 
33  protected:
~ProxyHandlerInfo()34   ~ProxyHandlerInfo() {}
35   HandlerInfo mHandlerInfo;
36   nsHandlerInfoAction mPrefAction;
37   nsCOMPtr<nsIMutableArray> mPossibleApps;
38 };
39 
NS_IMPL_ISUPPORTS(ProxyHandlerInfo,nsIHandlerInfo)40 NS_IMPL_ISUPPORTS(ProxyHandlerInfo, nsIHandlerInfo)
41 
42 ProxyHandlerInfo::ProxyHandlerInfo(const HandlerInfo& aHandlerInfo)
43     : mHandlerInfo(aHandlerInfo),
44       mPrefAction(nsIHandlerInfo::alwaysAsk),
45       mPossibleApps(do_CreateInstance(NS_ARRAY_CONTRACTID)) {
46   for (auto& happ : aHandlerInfo.possibleApplicationHandlers()) {
47     mPossibleApps->AppendElement(new RemoteHandlerApp(happ));
48   }
49 }
50 
51 /* readonly attribute ACString type; */
GetType(nsACString & aType)52 NS_IMETHODIMP ProxyHandlerInfo::GetType(nsACString& aType) {
53   aType.Assign(mHandlerInfo.type());
54   return NS_OK;
55 }
56 
57 /* attribute AString description; */
GetDescription(nsAString & aDescription)58 NS_IMETHODIMP ProxyHandlerInfo::GetDescription(nsAString& aDescription) {
59   return NS_ERROR_NOT_IMPLEMENTED;
60 }
SetDescription(const nsAString & aDescription)61 NS_IMETHODIMP ProxyHandlerInfo::SetDescription(const nsAString& aDescription) {
62   return NS_ERROR_NOT_IMPLEMENTED;
63 }
64 
65 /* attribute nsIHandlerApp preferredApplicationHandler; */
GetPreferredApplicationHandler(nsIHandlerApp ** aPreferredApplicationHandler)66 NS_IMETHODIMP ProxyHandlerInfo::GetPreferredApplicationHandler(
67     nsIHandlerApp** aPreferredApplicationHandler) {
68   *aPreferredApplicationHandler =
69       new RemoteHandlerApp(mHandlerInfo.preferredApplicationHandler());
70   NS_IF_ADDREF(*aPreferredApplicationHandler);
71   return NS_OK;
72 }
73 
SetPreferredApplicationHandler(nsIHandlerApp * aApp)74 NS_IMETHODIMP ProxyHandlerInfo::SetPreferredApplicationHandler(
75     nsIHandlerApp* aApp) {
76   nsString name;
77   nsString detailedDescription;
78   if (aApp) {
79     aApp->GetName(name);
80     aApp->GetDetailedDescription(detailedDescription);
81   }
82 
83   mHandlerInfo.preferredApplicationHandler() =
84       HandlerApp(name, detailedDescription);
85   return NS_OK;
86 }
87 
88 /* readonly attribute nsIMutableArray possibleApplicationHandlers; */
GetPossibleApplicationHandlers(nsIMutableArray ** aPossibleApplicationHandlers)89 NS_IMETHODIMP ProxyHandlerInfo::GetPossibleApplicationHandlers(
90     nsIMutableArray** aPossibleApplicationHandlers) {
91   *aPossibleApplicationHandlers = mPossibleApps;
92   NS_IF_ADDREF(*aPossibleApplicationHandlers);
93   return NS_OK;
94 }
95 
96 /* readonly attribute boolean hasDefaultHandler; */
GetHasDefaultHandler(bool * aHasDefaultHandler)97 NS_IMETHODIMP ProxyHandlerInfo::GetHasDefaultHandler(bool* aHasDefaultHandler) {
98   return NS_ERROR_NOT_IMPLEMENTED;
99 }
100 
101 /* readonly attribute AString defaultDescription; */
GetDefaultDescription(nsAString & aDefaultDescription)102 NS_IMETHODIMP ProxyHandlerInfo::GetDefaultDescription(
103     nsAString& aDefaultDescription) {
104   return NS_ERROR_NOT_IMPLEMENTED;
105 }
106 
107 /* void launchWithURI (in nsIURI aURI,
108                        [optional] in BrowsingContext aBrowsingContext); */
LaunchWithURI(nsIURI * aURI,mozilla::dom::BrowsingContext * aBrowsingContext)109 NS_IMETHODIMP ProxyHandlerInfo::LaunchWithURI(
110     nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
111   return NS_ERROR_NOT_IMPLEMENTED;
112 }
113 
114 /* attribute ProxyHandlerInfoAction preferredAction; */
GetPreferredAction(nsHandlerInfoAction * aPreferredAction)115 NS_IMETHODIMP ProxyHandlerInfo::GetPreferredAction(
116     nsHandlerInfoAction* aPreferredAction) {
117   *aPreferredAction = mPrefAction;
118   return NS_OK;
119 }
SetPreferredAction(nsHandlerInfoAction aPreferredAction)120 NS_IMETHODIMP ProxyHandlerInfo::SetPreferredAction(
121     nsHandlerInfoAction aPreferredAction) {
122   mHandlerInfo.preferredAction() = aPreferredAction;
123   mPrefAction = aPreferredAction;
124   return NS_OK;
125 }
126 
127 /* attribute boolean alwaysAskBeforeHandling; */
GetAlwaysAskBeforeHandling(bool * aAlwaysAskBeforeHandling)128 NS_IMETHODIMP ProxyHandlerInfo::GetAlwaysAskBeforeHandling(
129     bool* aAlwaysAskBeforeHandling) {
130   *aAlwaysAskBeforeHandling = mHandlerInfo.alwaysAskBeforeHandling();
131   return NS_OK;
132 }
SetAlwaysAskBeforeHandling(bool aAlwaysAskBeforeHandling)133 NS_IMETHODIMP ProxyHandlerInfo::SetAlwaysAskBeforeHandling(
134     bool aAlwaysAskBeforeHandling) {
135   mHandlerInfo.alwaysAskBeforeHandling() = aAlwaysAskBeforeHandling;
136   return NS_OK;
137 }
138 
139 class ProxyMIMEInfo : public nsIMIMEInfo {
140  public:
141   NS_DECL_ISUPPORTS
142   NS_DECL_NSIMIMEINFO
143   NS_FORWARD_NSIHANDLERINFO(mProxyHandlerInfo->);
144 
ProxyMIMEInfo(const HandlerInfo & aHandlerInfo)145   explicit ProxyMIMEInfo(const HandlerInfo& aHandlerInfo)
146       : mProxyHandlerInfo(new ProxyHandlerInfo(aHandlerInfo)) {}
147 
148  private:
~ProxyMIMEInfo()149   virtual ~ProxyMIMEInfo() {}
150   RefPtr<ProxyHandlerInfo> mProxyHandlerInfo;
151 
152  protected:
153   /* additional members */
154 };
155 
NS_IMPL_ISUPPORTS(ProxyMIMEInfo,nsIMIMEInfo,nsIHandlerInfo)156 NS_IMPL_ISUPPORTS(ProxyMIMEInfo, nsIMIMEInfo, nsIHandlerInfo)
157 
158 /* nsIUTF8StringEnumerator getFileExtensions (); */
159 NS_IMETHODIMP ProxyMIMEInfo::GetFileExtensions(
160     nsIUTF8StringEnumerator** _retval) {
161   return NS_NewUTF8StringEnumerator(_retval, &mProxyHandlerInfo->Extensions(),
162                                     this);
163 }
164 
165 /* void setFileExtensions (in AUTF8String aExtensions); */
SetFileExtensions(const nsACString & aExtensions)166 NS_IMETHODIMP ProxyMIMEInfo::SetFileExtensions(const nsACString& aExtensions) {
167   return NS_ERROR_NOT_IMPLEMENTED;
168 }
169 
170 /* boolean extensionExists (in AUTF8String aExtension); */
ExtensionExists(const nsACString & aExtension,bool * _retval)171 NS_IMETHODIMP ProxyMIMEInfo::ExtensionExists(const nsACString& aExtension,
172                                              bool* _retval) {
173   *_retval = mProxyHandlerInfo->Extensions().Contains(
174       aExtension, nsCaseInsensitiveCStringArrayComparator());
175   return NS_OK;
176 }
177 
178 /* void appendExtension (in AUTF8String aExtension); */
AppendExtension(const nsACString & aExtension)179 NS_IMETHODIMP ProxyMIMEInfo::AppendExtension(const nsACString& aExtension) {
180   if (!aExtension.IsEmpty() &&
181       !mProxyHandlerInfo->Extensions().Contains(
182           aExtension, nsCaseInsensitiveCStringArrayComparator())) {
183     mProxyHandlerInfo->Extensions().AppendElement(aExtension);
184   }
185   return NS_OK;
186 }
187 
188 /* attribute AUTF8String primaryExtension; */
GetPrimaryExtension(nsACString & aPrimaryExtension)189 NS_IMETHODIMP ProxyMIMEInfo::GetPrimaryExtension(
190     nsACString& aPrimaryExtension) {
191   const auto& extensions = mProxyHandlerInfo->Extensions();
192   if (extensions.IsEmpty()) {
193     aPrimaryExtension.Truncate();
194     return NS_ERROR_FAILURE;
195   }
196   aPrimaryExtension = extensions[0];
197   return NS_OK;
198 }
199 
SetPrimaryExtension(const nsACString & aPrimaryExtension)200 NS_IMETHODIMP ProxyMIMEInfo::SetPrimaryExtension(
201     const nsACString& aPrimaryExtension) {
202   return NS_ERROR_NOT_IMPLEMENTED;
203 }
204 
205 /* readonly attribute ACString MIMEType; */
GetMIMEType(nsACString & aMIMEType)206 NS_IMETHODIMP ProxyMIMEInfo::GetMIMEType(nsACString& aMIMEType) {
207   return NS_ERROR_NOT_IMPLEMENTED;
208 }
209 
210 /* boolean equals (in nsIMIMEInfo aMIMEInfo); */
Equals(nsIMIMEInfo * aMIMEInfo,bool * _retval)211 NS_IMETHODIMP ProxyMIMEInfo::Equals(nsIMIMEInfo* aMIMEInfo, bool* _retval) {
212   return NS_ERROR_NOT_IMPLEMENTED;
213 }
214 
215 /* readonly attribute nsIArray possibleLocalHandlers; */
GetPossibleLocalHandlers(nsIArray ** aPossibleLocalHandlers)216 NS_IMETHODIMP ProxyMIMEInfo::GetPossibleLocalHandlers(
217     nsIArray** aPossibleLocalHandlers) {
218   return NS_ERROR_NOT_IMPLEMENTED;
219 }
220 
221 /* void launchWithFile (in nsIFile aFile); */
LaunchWithFile(nsIFile * aFile)222 NS_IMETHODIMP ProxyMIMEInfo::LaunchWithFile(nsIFile* aFile) {
223   return NS_ERROR_NOT_IMPLEMENTED;
224 }
225 
226 /* boolean isCurrentAppOSDefault(); */
IsCurrentAppOSDefault(bool * _retval)227 NS_IMETHODIMP ProxyMIMEInfo::IsCurrentAppOSDefault(bool* _retval) {
228   return NS_ERROR_NOT_IMPLEMENTED;
229 }
230 
WrapHandlerInfo(const HandlerInfo & aHandlerInfo)231 static already_AddRefed<nsIHandlerInfo> WrapHandlerInfo(
232     const HandlerInfo& aHandlerInfo) {
233   nsCOMPtr<nsIHandlerInfo> info;
234   if (aHandlerInfo.isMIMEInfo()) {
235     info = new ProxyMIMEInfo(aHandlerInfo);
236   } else {
237     info = new ProxyHandlerInfo(aHandlerInfo);
238   }
239   return info.forget();
240 }
241 
242 }  // anonymous namespace
243 
HandlerServiceParent()244 HandlerServiceParent::HandlerServiceParent() {}
245 
~HandlerServiceParent()246 HandlerServiceParent::~HandlerServiceParent() {}
247 
RecvFillHandlerInfo(const HandlerInfo & aHandlerInfoData,const nsCString & aOverrideType,HandlerInfo * handlerInfoData)248 mozilla::ipc::IPCResult HandlerServiceParent::RecvFillHandlerInfo(
249     const HandlerInfo& aHandlerInfoData, const nsCString& aOverrideType,
250     HandlerInfo* handlerInfoData) {
251   nsCOMPtr<nsIHandlerInfo> info(WrapHandlerInfo(aHandlerInfoData));
252   nsCOMPtr<nsIHandlerService> handlerSvc =
253       do_GetService(NS_HANDLERSERVICE_CONTRACTID);
254   handlerSvc->FillHandlerInfo(info, aOverrideType);
255   ContentHandlerService::nsIHandlerInfoToHandlerInfo(info, handlerInfoData);
256   return IPC_OK();
257 }
258 
RecvGetMIMEInfoFromOS(const nsCString & aMIMEType,const nsCString & aExtension,nsresult * aRv,HandlerInfo * aHandlerInfoData,bool * aFound)259 mozilla::ipc::IPCResult HandlerServiceParent::RecvGetMIMEInfoFromOS(
260     const nsCString& aMIMEType, const nsCString& aExtension, nsresult* aRv,
261     HandlerInfo* aHandlerInfoData, bool* aFound) {
262   *aFound = false;
263   if (aMIMEType.Length() > MAX_MIMETYPE_LENGTH ||
264       aExtension.Length() > MAX_EXT_LENGTH) {
265     *aRv = NS_OK;
266     return IPC_OK();
267   }
268 
269   nsCOMPtr<nsIMIMEService> mimeService =
270       do_GetService(NS_MIMESERVICE_CONTRACTID, aRv);
271   if (NS_WARN_IF(NS_FAILED(*aRv))) {
272     return IPC_OK();
273   }
274 
275   nsCOMPtr<nsIMIMEInfo> mimeInfo;
276   *aRv = mimeService->GetMIMEInfoFromOS(aMIMEType, aExtension, aFound,
277                                         getter_AddRefs(mimeInfo));
278   if (NS_WARN_IF(NS_FAILED(*aRv))) {
279     return IPC_OK();
280   }
281 
282   if (mimeInfo) {
283     ContentHandlerService::nsIHandlerInfoToHandlerInfo(mimeInfo,
284                                                        aHandlerInfoData);
285   }
286 
287   return IPC_OK();
288 }
289 
RecvExists(const HandlerInfo & aHandlerInfo,bool * exists)290 mozilla::ipc::IPCResult HandlerServiceParent::RecvExists(
291     const HandlerInfo& aHandlerInfo, bool* exists) {
292   nsCOMPtr<nsIHandlerInfo> info(WrapHandlerInfo(aHandlerInfo));
293   nsCOMPtr<nsIHandlerService> handlerSvc =
294       do_GetService(NS_HANDLERSERVICE_CONTRACTID);
295   handlerSvc->Exists(info, exists);
296   return IPC_OK();
297 }
298 
RecvExistsForProtocolOS(const nsCString & aProtocolScheme,bool * aHandlerExists)299 mozilla::ipc::IPCResult HandlerServiceParent::RecvExistsForProtocolOS(
300     const nsCString& aProtocolScheme, bool* aHandlerExists) {
301   if (aProtocolScheme.Length() > MAX_SCHEME_LENGTH) {
302     *aHandlerExists = false;
303     return IPC_OK();
304   }
305 #ifdef MOZ_WIDGET_GTK
306   // Check the GNOME registry for a protocol handler
307   *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme.get());
308 #else
309   *aHandlerExists = false;
310 #endif
311   return IPC_OK();
312 }
313 
314 /*
315  * Check if a handler exists for the provided protocol. Check the datastore
316  * first and then fallback to checking the OS for a handler.
317  */
RecvExistsForProtocol(const nsCString & aProtocolScheme,bool * aHandlerExists)318 mozilla::ipc::IPCResult HandlerServiceParent::RecvExistsForProtocol(
319     const nsCString& aProtocolScheme, bool* aHandlerExists) {
320   if (aProtocolScheme.Length() > MAX_SCHEME_LENGTH) {
321     *aHandlerExists = false;
322     return IPC_OK();
323   }
324 #if defined(XP_MACOSX)
325   // Check the datastore and fallback to an OS check.
326   // ExternalProcotolHandlerExists() does the fallback.
327   nsresult rv;
328   nsCOMPtr<nsIExternalProtocolService> protoSvc =
329       do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &rv);
330   if (NS_WARN_IF(NS_FAILED(rv))) {
331     *aHandlerExists = false;
332     return IPC_OK();
333   }
334   rv = protoSvc->ExternalProtocolHandlerExists(aProtocolScheme.get(),
335                                                aHandlerExists);
336 
337   if (NS_WARN_IF(NS_FAILED(rv))) {
338     *aHandlerExists = false;
339   }
340 #else
341   MOZ_RELEASE_ASSERT(false, "No implementation on this platform.");
342   *aHandlerExists = false;
343 #endif
344   return IPC_OK();
345 }
346 
RecvGetTypeFromExtension(const nsCString & aFileExtension,nsCString * type)347 mozilla::ipc::IPCResult HandlerServiceParent::RecvGetTypeFromExtension(
348     const nsCString& aFileExtension, nsCString* type) {
349   if (aFileExtension.Length() > MAX_EXT_LENGTH) {
350     return IPC_OK();
351   }
352 
353   nsresult rv;
354   nsCOMPtr<nsIHandlerService> handlerSvc =
355       do_GetService(NS_HANDLERSERVICE_CONTRACTID, &rv);
356   if (NS_WARN_IF(NS_FAILED(rv))) {
357     return IPC_OK();
358   }
359 
360   rv = handlerSvc->GetTypeFromExtension(aFileExtension, *type);
361   mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
362 
363   return IPC_OK();
364 }
365 
RecvGetApplicationDescription(const nsCString & aScheme,nsresult * aRv,nsString * aDescription)366 mozilla::ipc::IPCResult HandlerServiceParent::RecvGetApplicationDescription(
367     const nsCString& aScheme, nsresult* aRv, nsString* aDescription) {
368   if (aScheme.Length() > MAX_SCHEME_LENGTH) {
369     *aRv = NS_ERROR_NOT_AVAILABLE;
370     return IPC_OK();
371   }
372   nsCOMPtr<nsIExternalProtocolService> protoSvc =
373       do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
374   NS_ASSERTION(protoSvc, "No Helper App Service!");
375   *aRv = protoSvc->GetApplicationDescription(aScheme, *aDescription);
376   return IPC_OK();
377 }
378 
ActorDestroy(ActorDestroyReason aWhy)379 void HandlerServiceParent::ActorDestroy(ActorDestroyReason aWhy) {}
380