Bumping manifests a=b2g-bump
[gecko.git] / uriloader / exthandler / nsExternalProtocolHandler.cpp
blobbaaee370c80daf321c6c7135439560bde443fd3a
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/. */
8 #include "nsIURI.h"
9 #include "nsIURL.h"
10 #include "nsExternalProtocolHandler.h"
11 #include "nsXPIDLString.h"
12 #include "nsReadableUtils.h"
13 #include "nsCOMPtr.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"
28 class nsILoadInfo;
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
37 public:
38 NS_DECL_THREADSAFE_ISUPPORTS
39 NS_DECL_NSICHANNEL
40 NS_DECL_NSIREQUEST
42 nsExtProtocolChannel();
44 nsresult SetURI(nsIURI*);
46 private:
47 virtual ~nsExtProtocolChannel();
49 nsresult OpenURL();
50 void Finish(nsresult aResult);
52 nsCOMPtr<nsIURI> mUrl;
53 nsCOMPtr<nsIURI> mOriginalURI;
54 nsresult mStatus;
55 nsLoadFlags mLoadFlags;
56 bool mWasOpened;
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),
72 mWasOpened(false)
76 nsExtProtocolChannel::~nsExtProtocolChannel()
79 NS_IMETHODIMP nsExtProtocolChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
81 NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
82 return NS_OK;
85 NS_IMETHODIMP nsExtProtocolChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
87 mLoadGroup = aLoadGroup;
88 return NS_OK;
91 NS_IMETHODIMP nsExtProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
93 NS_IF_ADDREF(*aCallbacks = mCallbacks);
94 return NS_OK;
97 NS_IMETHODIMP nsExtProtocolChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
99 mCallbacks = aCallbacks;
100 return NS_OK;
103 NS_IMETHODIMP
104 nsExtProtocolChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
106 *aSecurityInfo = nullptr;
107 return NS_OK;
110 NS_IMETHODIMP nsExtProtocolChannel::GetOriginalURI(nsIURI* *aURI)
112 NS_ADDREF(*aURI = mOriginalURI);
113 return NS_OK;
116 NS_IMETHODIMP nsExtProtocolChannel::SetOriginalURI(nsIURI* aURI)
118 NS_ENSURE_ARG_POINTER(aURI);
119 mOriginalURI = aURI;
120 return NS_OK;
123 NS_IMETHODIMP nsExtProtocolChannel::GetURI(nsIURI* *aURI)
125 *aURI = mUrl;
126 NS_IF_ADDREF(*aURI);
127 return NS_OK;
130 nsresult nsExtProtocolChannel::SetURI(nsIURI* aURI)
132 mUrl = aURI;
133 return NS_OK;
136 nsresult nsExtProtocolChannel::OpenURL()
138 nsresult rv = NS_ERROR_FAILURE;
139 nsCOMPtr<nsIExternalProtocolService> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
141 if (extProtService)
143 #ifdef DEBUG
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?");
149 #endif
151 nsCOMPtr<nsIInterfaceRequestor> aggCallbacks;
152 rv = NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
153 getter_AddRefs(aggCallbacks));
154 if (NS_FAILED(rv)) {
155 goto finish;
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;
167 finish:
168 mCallbacks = 0;
169 return rv;
172 NS_IMETHODIMP nsExtProtocolChannel::Open(nsIInputStream **_retval)
174 return OpenURL();
177 NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
179 NS_ENSURE_ARG_POINTER(listener);
180 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
182 mWasOpened = true;
184 return OpenURL();
187 NS_IMETHODIMP nsExtProtocolChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
189 *aLoadFlags = mLoadFlags;
190 return NS_OK;
193 NS_IMETHODIMP nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
195 mLoadFlags = aLoadFlags;
196 return NS_OK;
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;
247 return NS_OK;
250 NS_IMETHODIMP
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 ////////////////////////////////////////////////////////////////////////////////
278 // From nsIRequest
279 ////////////////////////////////////////////////////////////////////////////////
281 NS_IMETHODIMP nsExtProtocolChannel::GetName(nsACString &result)
283 return mUrl->GetSpec(result);
286 NS_IMETHODIMP nsExtProtocolChannel::IsPending(bool *result)
288 *result = false;
289 return NS_OK;
292 NS_IMETHODIMP nsExtProtocolChannel::GetStatus(nsresult *status)
294 *status = mStatus;
295 return NS_OK;
298 NS_IMETHODIMP nsExtProtocolChannel::Cancel(nsresult status)
300 mStatus = status;
301 return NS_OK;
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;
342 return NS_OK;
345 NS_IMETHODIMP nsExternalProtocolHandler::GetDefaultPort(int32_t *aDefaultPort)
347 *aDefaultPort = 0;
348 return NS_OK;
351 NS_IMETHODIMP
352 nsExternalProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
354 // don't override anything.
355 *_retval = false;
356 return NS_OK;
358 // returns TRUE if the OS can handle this protocol scheme and false otherwise.
359 bool nsExternalProtocolHandler::HaveExternalProtocolHandler(nsIURI * aURI)
361 bool haveHandler = false;
362 if (aURI)
364 nsAutoCString scheme;
365 aURI->GetScheme(scheme);
366 nsCOMPtr<nsIExternalProtocolService> extProtSvc(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
367 if (extProtSvc)
368 extProtSvc->ExternalProtocolHandlerExists(scheme.get(), &haveHandler);
371 return 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;
379 return NS_OK;
382 NS_IMETHODIMP nsExternalProtocolHandler::NewURI(const nsACString &aSpec,
383 const char *aCharset, // ignore charset info
384 nsIURI *aBaseURI,
385 nsIURI **_retval)
387 nsresult rv;
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);
395 return NS_OK;
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
403 // gnome_url_show.)
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);
413 if (_retval)
415 *_retval = channel;
416 NS_IF_ADDREF(*_retval);
417 return NS_OK;
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));
430 if (extProtSvc)
431 return extProtSvc->ExternalProtocolHandlerExists(
432 PromiseFlatCString(aScheme).get(), _retval);
434 // In case we don't have external protocol service.
435 *_retval = false;
436 return NS_OK;