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