Wed, 31 Dec 2014 07:53:36 +0100
Correct small whitespace inconsistency, lost while renaming variables.
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:
3 *
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 ////////////////////////////////////////////////////////////////////////
29 // a stub channel implemenation which will map calls to AsyncRead and OpenInputStream
30 // to calls in the OS for loading the url.
31 ////////////////////////////////////////////////////////////////////////
33 class nsExtProtocolChannel : public nsIChannel
34 {
35 public:
36 NS_DECL_THREADSAFE_ISUPPORTS
37 NS_DECL_NSICHANNEL
38 NS_DECL_NSIREQUEST
40 nsExtProtocolChannel();
41 virtual ~nsExtProtocolChannel();
43 nsresult SetURI(nsIURI*);
45 private:
46 nsresult OpenURL();
47 void Finish(nsresult aResult);
49 nsCOMPtr<nsIURI> mUrl;
50 nsCOMPtr<nsIURI> mOriginalURI;
51 nsresult mStatus;
52 nsLoadFlags mLoadFlags;
53 bool mWasOpened;
55 nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
56 nsCOMPtr<nsILoadGroup> mLoadGroup;
57 };
59 NS_IMPL_ADDREF(nsExtProtocolChannel)
60 NS_IMPL_RELEASE(nsExtProtocolChannel)
62 NS_INTERFACE_MAP_BEGIN(nsExtProtocolChannel)
63 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel)
64 NS_INTERFACE_MAP_ENTRY(nsIChannel)
65 NS_INTERFACE_MAP_ENTRY(nsIRequest)
66 NS_INTERFACE_MAP_END_THREADSAFE
68 nsExtProtocolChannel::nsExtProtocolChannel() : mStatus(NS_OK),
69 mWasOpened(false)
70 {
71 }
73 nsExtProtocolChannel::~nsExtProtocolChannel()
74 {}
76 NS_IMETHODIMP nsExtProtocolChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
77 {
78 NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
79 return NS_OK;
80 }
82 NS_IMETHODIMP nsExtProtocolChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
83 {
84 mLoadGroup = aLoadGroup;
85 return NS_OK;
86 }
88 NS_IMETHODIMP nsExtProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
89 {
90 NS_IF_ADDREF(*aCallbacks = mCallbacks);
91 return NS_OK;
92 }
94 NS_IMETHODIMP nsExtProtocolChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
95 {
96 mCallbacks = aCallbacks;
97 return NS_OK;
98 }
100 NS_IMETHODIMP
101 nsExtProtocolChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
102 {
103 *aSecurityInfo = nullptr;
104 return NS_OK;
105 }
107 NS_IMETHODIMP nsExtProtocolChannel::GetOriginalURI(nsIURI* *aURI)
108 {
109 NS_ADDREF(*aURI = mOriginalURI);
110 return NS_OK;
111 }
113 NS_IMETHODIMP nsExtProtocolChannel::SetOriginalURI(nsIURI* aURI)
114 {
115 NS_ENSURE_ARG_POINTER(aURI);
116 mOriginalURI = aURI;
117 return NS_OK;
118 }
120 NS_IMETHODIMP nsExtProtocolChannel::GetURI(nsIURI* *aURI)
121 {
122 *aURI = mUrl;
123 NS_IF_ADDREF(*aURI);
124 return NS_OK;
125 }
127 nsresult nsExtProtocolChannel::SetURI(nsIURI* aURI)
128 {
129 mUrl = aURI;
130 return NS_OK;
131 }
133 nsresult nsExtProtocolChannel::OpenURL()
134 {
135 nsresult rv = NS_ERROR_FAILURE;
136 nsCOMPtr<nsIExternalProtocolService> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
138 if (extProtService)
139 {
140 #ifdef DEBUG
141 nsAutoCString urlScheme;
142 mUrl->GetScheme(urlScheme);
143 bool haveHandler = false;
144 extProtService->ExternalProtocolHandlerExists(urlScheme.get(), &haveHandler);
145 NS_ASSERTION(haveHandler, "Why do we have a channel for this url if we don't support the protocol?");
146 #endif
148 nsCOMPtr<nsIInterfaceRequestor> aggCallbacks;
149 rv = NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
150 getter_AddRefs(aggCallbacks));
151 if (NS_FAILED(rv)) {
152 goto finish;
153 }
155 rv = extProtService->LoadURI(mUrl, aggCallbacks);
156 if (NS_SUCCEEDED(rv)) {
157 // despite success, we need to abort this channel, at the very least
158 // to make it clear to the caller that no on{Start,Stop}Request
159 // should be expected.
160 rv = NS_ERROR_NO_CONTENT;
161 }
162 }
164 finish:
165 mCallbacks = 0;
166 return rv;
167 }
169 NS_IMETHODIMP nsExtProtocolChannel::Open(nsIInputStream **_retval)
170 {
171 return OpenURL();
172 }
174 NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
175 {
176 NS_ENSURE_ARG_POINTER(listener);
177 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
179 mWasOpened = true;
181 return OpenURL();
182 }
184 NS_IMETHODIMP nsExtProtocolChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
185 {
186 *aLoadFlags = mLoadFlags;
187 return NS_OK;
188 }
190 NS_IMETHODIMP nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
191 {
192 mLoadFlags = aLoadFlags;
193 return NS_OK;
194 }
196 NS_IMETHODIMP nsExtProtocolChannel::GetContentType(nsACString &aContentType)
197 {
198 return NS_ERROR_NOT_IMPLEMENTED;
199 }
201 NS_IMETHODIMP nsExtProtocolChannel::SetContentType(const nsACString &aContentType)
202 {
203 return NS_ERROR_FAILURE;
204 }
206 NS_IMETHODIMP nsExtProtocolChannel::GetContentCharset(nsACString &aContentCharset)
207 {
208 return NS_ERROR_NOT_IMPLEMENTED;
209 }
211 NS_IMETHODIMP nsExtProtocolChannel::SetContentCharset(const nsACString &aContentCharset)
212 {
213 return NS_ERROR_NOT_IMPLEMENTED;
214 }
216 NS_IMETHODIMP nsExtProtocolChannel::GetContentDisposition(uint32_t *aContentDisposition)
217 {
218 return NS_ERROR_NOT_AVAILABLE;
219 }
221 NS_IMETHODIMP nsExtProtocolChannel::SetContentDisposition(uint32_t aContentDisposition)
222 {
223 return NS_ERROR_NOT_AVAILABLE;
224 }
226 NS_IMETHODIMP nsExtProtocolChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
227 {
228 return NS_ERROR_NOT_AVAILABLE;
229 }
231 NS_IMETHODIMP nsExtProtocolChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
232 {
233 return NS_ERROR_NOT_AVAILABLE;
234 }
236 NS_IMETHODIMP nsExtProtocolChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
237 {
238 return NS_ERROR_NOT_AVAILABLE;
239 }
241 NS_IMETHODIMP nsExtProtocolChannel::GetContentLength(int64_t * aContentLength)
242 {
243 *aContentLength = -1;
244 return NS_OK;
245 }
247 NS_IMETHODIMP
248 nsExtProtocolChannel::SetContentLength(int64_t aContentLength)
249 {
250 NS_NOTREACHED("SetContentLength");
251 return NS_ERROR_NOT_IMPLEMENTED;
252 }
254 NS_IMETHODIMP nsExtProtocolChannel::GetOwner(nsISupports * *aPrincipal)
255 {
256 NS_NOTREACHED("GetOwner");
257 return NS_ERROR_NOT_IMPLEMENTED;
258 }
260 NS_IMETHODIMP nsExtProtocolChannel::SetOwner(nsISupports * aPrincipal)
261 {
262 NS_NOTREACHED("SetOwner");
263 return NS_ERROR_NOT_IMPLEMENTED;
264 }
266 ////////////////////////////////////////////////////////////////////////////////
267 // From nsIRequest
268 ////////////////////////////////////////////////////////////////////////////////
270 NS_IMETHODIMP nsExtProtocolChannel::GetName(nsACString &result)
271 {
272 return mUrl->GetSpec(result);
273 }
275 NS_IMETHODIMP nsExtProtocolChannel::IsPending(bool *result)
276 {
277 *result = false;
278 return NS_OK;
279 }
281 NS_IMETHODIMP nsExtProtocolChannel::GetStatus(nsresult *status)
282 {
283 *status = mStatus;
284 return NS_OK;
285 }
287 NS_IMETHODIMP nsExtProtocolChannel::Cancel(nsresult status)
288 {
289 mStatus = status;
290 return NS_OK;
291 }
293 NS_IMETHODIMP nsExtProtocolChannel::Suspend()
294 {
295 NS_NOTREACHED("Suspend");
296 return NS_ERROR_NOT_IMPLEMENTED;
297 }
299 NS_IMETHODIMP nsExtProtocolChannel::Resume()
300 {
301 NS_NOTREACHED("Resume");
302 return NS_ERROR_NOT_IMPLEMENTED;
303 }
305 ///////////////////////////////////////////////////////////////////////
306 // the default protocol handler implementation
307 //////////////////////////////////////////////////////////////////////
309 nsExternalProtocolHandler::nsExternalProtocolHandler()
310 {
311 m_schemeName = "default";
312 }
315 nsExternalProtocolHandler::~nsExternalProtocolHandler()
316 {}
318 NS_IMPL_ADDREF(nsExternalProtocolHandler)
319 NS_IMPL_RELEASE(nsExternalProtocolHandler)
321 NS_INTERFACE_MAP_BEGIN(nsExternalProtocolHandler)
322 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIProtocolHandler)
323 NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler)
324 NS_INTERFACE_MAP_ENTRY(nsIExternalProtocolHandler)
325 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
326 NS_INTERFACE_MAP_END_THREADSAFE
328 NS_IMETHODIMP nsExternalProtocolHandler::GetScheme(nsACString &aScheme)
329 {
330 aScheme = m_schemeName;
331 return NS_OK;
332 }
334 NS_IMETHODIMP nsExternalProtocolHandler::GetDefaultPort(int32_t *aDefaultPort)
335 {
336 *aDefaultPort = 0;
337 return NS_OK;
338 }
340 NS_IMETHODIMP
341 nsExternalProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
342 {
343 // don't override anything.
344 *_retval = false;
345 return NS_OK;
346 }
347 // returns TRUE if the OS can handle this protocol scheme and false otherwise.
348 bool nsExternalProtocolHandler::HaveExternalProtocolHandler(nsIURI * aURI)
349 {
350 bool haveHandler = false;
351 if (aURI)
352 {
353 nsAutoCString scheme;
354 aURI->GetScheme(scheme);
355 nsCOMPtr<nsIExternalProtocolService> extProtSvc(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
356 if (extProtSvc)
357 extProtSvc->ExternalProtocolHandlerExists(scheme.get(), &haveHandler);
358 }
360 return haveHandler;
361 }
363 NS_IMETHODIMP nsExternalProtocolHandler::GetProtocolFlags(uint32_t *aUritype)
364 {
365 // Make it norelative since it is a simple uri
366 *aUritype = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE |
367 URI_NON_PERSISTABLE | URI_DOES_NOT_RETURN_DATA;
368 return NS_OK;
369 }
371 NS_IMETHODIMP nsExternalProtocolHandler::NewURI(const nsACString &aSpec,
372 const char *aCharset, // ignore charset info
373 nsIURI *aBaseURI,
374 nsIURI **_retval)
375 {
376 nsresult rv;
377 nsCOMPtr<nsIURI> uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv);
378 NS_ENSURE_SUCCESS(rv, rv);
380 rv = uri->SetSpec(aSpec);
381 NS_ENSURE_SUCCESS(rv, rv);
383 NS_ADDREF(*_retval = uri);
384 return NS_OK;
385 }
387 NS_IMETHODIMP nsExternalProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
388 {
389 // Only try to return a channel if we have a protocol handler for the url.
390 // nsOSHelperAppService::LoadUriInternal relies on this to check trustedness
391 // for some platforms at least. (win uses ::ShellExecute and unix uses
392 // gnome_url_show.)
393 bool haveExternalHandler = HaveExternalProtocolHandler(aURI);
394 if (haveExternalHandler)
395 {
396 nsCOMPtr<nsIChannel> channel = new nsExtProtocolChannel();
397 if (!channel) return NS_ERROR_OUT_OF_MEMORY;
399 ((nsExtProtocolChannel*) channel.get())->SetURI(aURI);
400 channel->SetOriginalURI(aURI);
402 if (_retval)
403 {
404 *_retval = channel;
405 NS_IF_ADDREF(*_retval);
406 return NS_OK;
407 }
408 }
410 return NS_ERROR_UNKNOWN_PROTOCOL;
411 }
413 ///////////////////////////////////////////////////////////////////////
414 // External protocol handler interface implementation
415 //////////////////////////////////////////////////////////////////////
416 NS_IMETHODIMP nsExternalProtocolHandler::ExternalAppExistsForScheme(const nsACString& aScheme, bool *_retval)
417 {
418 nsCOMPtr<nsIExternalProtocolService> extProtSvc(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
419 if (extProtSvc)
420 return extProtSvc->ExternalProtocolHandlerExists(
421 PromiseFlatCString(aScheme).get(), _retval);
423 // In case we don't have external protocol service.
424 *_retval = false;
425 return NS_OK;
426 }