1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim:set ts=2 sts=2 sw=2 et cin:
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include "nsExternalProtocolHandler.h"
11 #include "nsXPIDLString.h"
12 #include "nsReadableUtils.h"
14 #include "nsIServiceManager.h"
15 #include "nsServiceManagerUtils.h"
16 #include "nsIInterfaceRequestor.h"
17 #include "nsIInterfaceRequestorUtils.h"
18 #include "nsIStringBundle.h"
19 #include "nsIPrefService.h"
20 #include "nsIPrompt.h"
21 #include "nsNetUtil.h"
22 #include "nsExternalHelperAppService.h"
24 // used to dispatch urls to default protocol handlers
25 #include "nsCExternalHandlerService.h"
26 #include "nsIExternalProtocolService.h"
30 ////////////////////////////////////////////////////////////////////////
31 // a stub channel implemenation which will map calls to AsyncRead and OpenInputStream
32 // to calls in the OS for loading the url.
33 ////////////////////////////////////////////////////////////////////////
35 class nsExtProtocolChannel
: public nsIChannel
38 NS_DECL_THREADSAFE_ISUPPORTS
42 nsExtProtocolChannel();
44 nsresult
SetURI(nsIURI
*);
47 virtual ~nsExtProtocolChannel();
50 void Finish(nsresult aResult
);
52 nsCOMPtr
<nsIURI
> mUrl
;
53 nsCOMPtr
<nsIURI
> mOriginalURI
;
55 nsLoadFlags mLoadFlags
;
58 nsCOMPtr
<nsIInterfaceRequestor
> mCallbacks
;
59 nsCOMPtr
<nsILoadGroup
> mLoadGroup
;
62 NS_IMPL_ADDREF(nsExtProtocolChannel
)
63 NS_IMPL_RELEASE(nsExtProtocolChannel
)
65 NS_INTERFACE_MAP_BEGIN(nsExtProtocolChannel
)
66 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIChannel
)
67 NS_INTERFACE_MAP_ENTRY(nsIChannel
)
68 NS_INTERFACE_MAP_ENTRY(nsIRequest
)
69 NS_INTERFACE_MAP_END_THREADSAFE
71 nsExtProtocolChannel::nsExtProtocolChannel() : mStatus(NS_OK
),
76 nsExtProtocolChannel::~nsExtProtocolChannel()
79 NS_IMETHODIMP
nsExtProtocolChannel::GetLoadGroup(nsILoadGroup
* *aLoadGroup
)
81 NS_IF_ADDREF(*aLoadGroup
= mLoadGroup
);
85 NS_IMETHODIMP
nsExtProtocolChannel::SetLoadGroup(nsILoadGroup
* aLoadGroup
)
87 mLoadGroup
= aLoadGroup
;
91 NS_IMETHODIMP
nsExtProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor
* *aCallbacks
)
93 NS_IF_ADDREF(*aCallbacks
= mCallbacks
);
97 NS_IMETHODIMP
nsExtProtocolChannel::SetNotificationCallbacks(nsIInterfaceRequestor
* aCallbacks
)
99 mCallbacks
= aCallbacks
;
104 nsExtProtocolChannel::GetSecurityInfo(nsISupports
* *aSecurityInfo
)
106 *aSecurityInfo
= nullptr;
110 NS_IMETHODIMP
nsExtProtocolChannel::GetOriginalURI(nsIURI
* *aURI
)
112 NS_ADDREF(*aURI
= mOriginalURI
);
116 NS_IMETHODIMP
nsExtProtocolChannel::SetOriginalURI(nsIURI
* aURI
)
118 NS_ENSURE_ARG_POINTER(aURI
);
123 NS_IMETHODIMP
nsExtProtocolChannel::GetURI(nsIURI
* *aURI
)
130 nsresult
nsExtProtocolChannel::SetURI(nsIURI
* aURI
)
136 nsresult
nsExtProtocolChannel::OpenURL()
138 nsresult rv
= NS_ERROR_FAILURE
;
139 nsCOMPtr
<nsIExternalProtocolService
> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID
));
144 nsAutoCString urlScheme
;
145 mUrl
->GetScheme(urlScheme
);
146 bool haveHandler
= false;
147 extProtService
->ExternalProtocolHandlerExists(urlScheme
.get(), &haveHandler
);
148 NS_ASSERTION(haveHandler
, "Why do we have a channel for this url if we don't support the protocol?");
151 nsCOMPtr
<nsIInterfaceRequestor
> aggCallbacks
;
152 rv
= NS_NewNotificationCallbacksAggregation(mCallbacks
, mLoadGroup
,
153 getter_AddRefs(aggCallbacks
));
158 rv
= extProtService
->LoadURI(mUrl
, aggCallbacks
);
159 if (NS_SUCCEEDED(rv
)) {
160 // despite success, we need to abort this channel, at the very least
161 // to make it clear to the caller that no on{Start,Stop}Request
162 // should be expected.
163 rv
= NS_ERROR_NO_CONTENT
;
172 NS_IMETHODIMP
nsExtProtocolChannel::Open(nsIInputStream
**_retval
)
177 NS_IMETHODIMP
nsExtProtocolChannel::AsyncOpen(nsIStreamListener
*listener
, nsISupports
*ctxt
)
179 NS_ENSURE_ARG_POINTER(listener
);
180 NS_ENSURE_TRUE(!mWasOpened
, NS_ERROR_ALREADY_OPENED
);
187 NS_IMETHODIMP
nsExtProtocolChannel::GetLoadFlags(nsLoadFlags
*aLoadFlags
)
189 *aLoadFlags
= mLoadFlags
;
193 NS_IMETHODIMP
nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags
)
195 mLoadFlags
= aLoadFlags
;
199 NS_IMETHODIMP
nsExtProtocolChannel::GetContentType(nsACString
&aContentType
)
201 return NS_ERROR_NOT_IMPLEMENTED
;
204 NS_IMETHODIMP
nsExtProtocolChannel::SetContentType(const nsACString
&aContentType
)
206 return NS_ERROR_FAILURE
;
209 NS_IMETHODIMP
nsExtProtocolChannel::GetContentCharset(nsACString
&aContentCharset
)
211 return NS_ERROR_NOT_IMPLEMENTED
;
214 NS_IMETHODIMP
nsExtProtocolChannel::SetContentCharset(const nsACString
&aContentCharset
)
216 return NS_ERROR_NOT_IMPLEMENTED
;
219 NS_IMETHODIMP
nsExtProtocolChannel::GetContentDisposition(uint32_t *aContentDisposition
)
221 return NS_ERROR_NOT_AVAILABLE
;
224 NS_IMETHODIMP
nsExtProtocolChannel::SetContentDisposition(uint32_t aContentDisposition
)
226 return NS_ERROR_NOT_AVAILABLE
;
229 NS_IMETHODIMP
nsExtProtocolChannel::GetContentDispositionFilename(nsAString
&aContentDispositionFilename
)
231 return NS_ERROR_NOT_AVAILABLE
;
234 NS_IMETHODIMP
nsExtProtocolChannel::SetContentDispositionFilename(const nsAString
&aContentDispositionFilename
)
236 return NS_ERROR_NOT_AVAILABLE
;
239 NS_IMETHODIMP
nsExtProtocolChannel::GetContentDispositionHeader(nsACString
&aContentDispositionHeader
)
241 return NS_ERROR_NOT_AVAILABLE
;
244 NS_IMETHODIMP
nsExtProtocolChannel::GetContentLength(int64_t * aContentLength
)
246 *aContentLength
= -1;
251 nsExtProtocolChannel::SetContentLength(int64_t aContentLength
)
253 NS_NOTREACHED("SetContentLength");
254 return NS_ERROR_NOT_IMPLEMENTED
;
257 NS_IMETHODIMP
nsExtProtocolChannel::GetOwner(nsISupports
* *aPrincipal
)
259 return NS_ERROR_NOT_IMPLEMENTED
;
262 NS_IMETHODIMP
nsExtProtocolChannel::SetOwner(nsISupports
* aPrincipal
)
264 return NS_ERROR_NOT_IMPLEMENTED
;
267 NS_IMETHODIMP
nsExtProtocolChannel::GetLoadInfo(nsILoadInfo
* *aLoadInfo
)
269 return NS_ERROR_NOT_IMPLEMENTED
;
272 NS_IMETHODIMP
nsExtProtocolChannel::SetLoadInfo(nsILoadInfo
* aLoadInfo
)
274 return NS_ERROR_NOT_IMPLEMENTED
;
277 ////////////////////////////////////////////////////////////////////////////////
279 ////////////////////////////////////////////////////////////////////////////////
281 NS_IMETHODIMP
nsExtProtocolChannel::GetName(nsACString
&result
)
283 return mUrl
->GetSpec(result
);
286 NS_IMETHODIMP
nsExtProtocolChannel::IsPending(bool *result
)
292 NS_IMETHODIMP
nsExtProtocolChannel::GetStatus(nsresult
*status
)
298 NS_IMETHODIMP
nsExtProtocolChannel::Cancel(nsresult status
)
304 NS_IMETHODIMP
nsExtProtocolChannel::Suspend()
306 NS_NOTREACHED("Suspend");
307 return NS_ERROR_NOT_IMPLEMENTED
;
310 NS_IMETHODIMP
nsExtProtocolChannel::Resume()
312 NS_NOTREACHED("Resume");
313 return NS_ERROR_NOT_IMPLEMENTED
;
316 ///////////////////////////////////////////////////////////////////////
317 // the default protocol handler implementation
318 //////////////////////////////////////////////////////////////////////
320 nsExternalProtocolHandler::nsExternalProtocolHandler()
322 m_schemeName
= "default";
326 nsExternalProtocolHandler::~nsExternalProtocolHandler()
329 NS_IMPL_ADDREF(nsExternalProtocolHandler
)
330 NS_IMPL_RELEASE(nsExternalProtocolHandler
)
332 NS_INTERFACE_MAP_BEGIN(nsExternalProtocolHandler
)
333 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIProtocolHandler
)
334 NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler
)
335 NS_INTERFACE_MAP_ENTRY(nsIExternalProtocolHandler
)
336 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
337 NS_INTERFACE_MAP_END_THREADSAFE
339 NS_IMETHODIMP
nsExternalProtocolHandler::GetScheme(nsACString
&aScheme
)
341 aScheme
= m_schemeName
;
345 NS_IMETHODIMP
nsExternalProtocolHandler::GetDefaultPort(int32_t *aDefaultPort
)
352 nsExternalProtocolHandler::AllowPort(int32_t port
, const char *scheme
, bool *_retval
)
354 // don't override anything.
358 // returns TRUE if the OS can handle this protocol scheme and false otherwise.
359 bool nsExternalProtocolHandler::HaveExternalProtocolHandler(nsIURI
* aURI
)
361 bool haveHandler
= false;
364 nsAutoCString scheme
;
365 aURI
->GetScheme(scheme
);
366 nsCOMPtr
<nsIExternalProtocolService
> extProtSvc(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID
));
368 extProtSvc
->ExternalProtocolHandlerExists(scheme
.get(), &haveHandler
);
374 NS_IMETHODIMP
nsExternalProtocolHandler::GetProtocolFlags(uint32_t *aUritype
)
376 // Make it norelative since it is a simple uri
377 *aUritype
= URI_NORELATIVE
| URI_NOAUTH
| URI_LOADABLE_BY_ANYONE
|
378 URI_NON_PERSISTABLE
| URI_DOES_NOT_RETURN_DATA
;
382 NS_IMETHODIMP
nsExternalProtocolHandler::NewURI(const nsACString
&aSpec
,
383 const char *aCharset
, // ignore charset info
388 nsCOMPtr
<nsIURI
> uri
= do_CreateInstance(NS_SIMPLEURI_CONTRACTID
, &rv
);
389 NS_ENSURE_SUCCESS(rv
, rv
);
391 rv
= uri
->SetSpec(aSpec
);
392 NS_ENSURE_SUCCESS(rv
, rv
);
394 NS_ADDREF(*_retval
= uri
);
398 NS_IMETHODIMP
nsExternalProtocolHandler::NewChannel(nsIURI
*aURI
, nsIChannel
**_retval
)
400 // Only try to return a channel if we have a protocol handler for the url.
401 // nsOSHelperAppService::LoadUriInternal relies on this to check trustedness
402 // for some platforms at least. (win uses ::ShellExecute and unix uses
404 bool haveExternalHandler
= HaveExternalProtocolHandler(aURI
);
405 if (haveExternalHandler
)
407 nsCOMPtr
<nsIChannel
> channel
= new nsExtProtocolChannel();
408 if (!channel
) return NS_ERROR_OUT_OF_MEMORY
;
410 ((nsExtProtocolChannel
*) channel
.get())->SetURI(aURI
);
411 channel
->SetOriginalURI(aURI
);
416 NS_IF_ADDREF(*_retval
);
421 return NS_ERROR_UNKNOWN_PROTOCOL
;
424 ///////////////////////////////////////////////////////////////////////
425 // External protocol handler interface implementation
426 //////////////////////////////////////////////////////////////////////
427 NS_IMETHODIMP
nsExternalProtocolHandler::ExternalAppExistsForScheme(const nsACString
& aScheme
, bool *_retval
)
429 nsCOMPtr
<nsIExternalProtocolService
> extProtSvc(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID
));
431 return extProtSvc
->ExternalProtocolHandlerExists(
432 PromiseFlatCString(aScheme
).get(), _retval
);
434 // In case we don't have external protocol service.