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 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is mozilla.org Code.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
25 * Scott MacGregor <mscott@netscape.com>
26 * Dan Mosedale <dmose@mozilla.org>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
44 #include "nsExternalProtocolHandler.h"
45 #include "nsXPIDLString.h"
46 #include "nsReadableUtils.h"
48 #include "nsIServiceManager.h"
49 #include "nsServiceManagerUtils.h"
50 #include "nsIInterfaceRequestor.h"
51 #include "nsIInterfaceRequestorUtils.h"
52 #include "nsIStringBundle.h"
53 #include "nsIPrefService.h"
54 #include "nsIPrompt.h"
55 #include "nsNetUtil.h"
56 #include "nsExternalHelperAppService.h"
58 // used to dispatch urls to default protocol handlers
59 #include "nsCExternalHandlerService.h"
60 #include "nsIExternalProtocolService.h"
62 ////////////////////////////////////////////////////////////////////////
63 // a stub channel implemenation which will map calls to AsyncRead and OpenInputStream
64 // to calls in the OS for loading the url.
65 ////////////////////////////////////////////////////////////////////////
67 class nsExtProtocolChannel
: public nsIChannel
74 nsExtProtocolChannel();
75 virtual ~nsExtProtocolChannel();
77 nsresult
SetURI(nsIURI
*);
81 void Finish(nsresult aResult
);
83 nsCOMPtr
<nsIURI
> mUrl
;
84 nsCOMPtr
<nsIURI
> mOriginalURI
;
86 nsLoadFlags mLoadFlags
;
89 nsCOMPtr
<nsIInterfaceRequestor
> mCallbacks
;
90 nsCOMPtr
<nsILoadGroup
> mLoadGroup
;
93 NS_IMPL_THREADSAFE_ADDREF(nsExtProtocolChannel
)
94 NS_IMPL_THREADSAFE_RELEASE(nsExtProtocolChannel
)
96 NS_INTERFACE_MAP_BEGIN(nsExtProtocolChannel
)
97 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIChannel
)
98 NS_INTERFACE_MAP_ENTRY(nsIChannel
)
99 NS_INTERFACE_MAP_ENTRY(nsIRequest
)
100 NS_INTERFACE_MAP_END_THREADSAFE
102 nsExtProtocolChannel::nsExtProtocolChannel() : mStatus(NS_OK
),
107 nsExtProtocolChannel::~nsExtProtocolChannel()
110 NS_IMETHODIMP
nsExtProtocolChannel::GetLoadGroup(nsILoadGroup
* *aLoadGroup
)
112 NS_IF_ADDREF(*aLoadGroup
= mLoadGroup
);
116 NS_IMETHODIMP
nsExtProtocolChannel::SetLoadGroup(nsILoadGroup
* aLoadGroup
)
118 mLoadGroup
= aLoadGroup
;
122 NS_IMETHODIMP
nsExtProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor
* *aCallbacks
)
124 NS_IF_ADDREF(*aCallbacks
= mCallbacks
);
128 NS_IMETHODIMP
nsExtProtocolChannel::SetNotificationCallbacks(nsIInterfaceRequestor
* aCallbacks
)
130 mCallbacks
= aCallbacks
;
135 nsExtProtocolChannel::GetSecurityInfo(nsISupports
* *aSecurityInfo
)
137 *aSecurityInfo
= nsnull
;
141 NS_IMETHODIMP
nsExtProtocolChannel::GetOriginalURI(nsIURI
* *aURI
)
143 NS_ADDREF(*aURI
= mOriginalURI
);
147 NS_IMETHODIMP
nsExtProtocolChannel::SetOriginalURI(nsIURI
* aURI
)
149 NS_ENSURE_ARG_POINTER(aURI
);
154 NS_IMETHODIMP
nsExtProtocolChannel::GetURI(nsIURI
* *aURI
)
161 nsresult
nsExtProtocolChannel::SetURI(nsIURI
* aURI
)
167 nsresult
nsExtProtocolChannel::OpenURL()
169 nsresult rv
= NS_ERROR_FAILURE
;
170 nsCOMPtr
<nsIExternalProtocolService
> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID
));
175 nsCAutoString urlScheme
;
176 mUrl
->GetScheme(urlScheme
);
177 PRBool haveHandler
= PR_FALSE
;
178 extProtService
->ExternalProtocolHandlerExists(urlScheme
.get(), &haveHandler
);
179 NS_ASSERTION(haveHandler
, "Why do we have a channel for this url if we don't support the protocol?");
182 nsCOMPtr
<nsIInterfaceRequestor
> aggCallbacks
;
183 rv
= NS_NewNotificationCallbacksAggregation(mCallbacks
, mLoadGroup
,
184 getter_AddRefs(aggCallbacks
));
189 rv
= extProtService
->LoadURI(mUrl
, aggCallbacks
);
190 if (NS_SUCCEEDED(rv
)) {
191 // despite success, we need to abort this channel, at the very least
192 // to make it clear to the caller that no on{Start,Stop}Request
193 // should be expected.
194 rv
= NS_ERROR_NO_CONTENT
;
203 NS_IMETHODIMP
nsExtProtocolChannel::Open(nsIInputStream
**_retval
)
208 NS_IMETHODIMP
nsExtProtocolChannel::AsyncOpen(nsIStreamListener
*listener
, nsISupports
*ctxt
)
210 NS_ENSURE_ARG_POINTER(listener
);
211 NS_ENSURE_TRUE(!mWasOpened
, NS_ERROR_ALREADY_OPENED
);
213 mWasOpened
= PR_TRUE
;
218 NS_IMETHODIMP
nsExtProtocolChannel::GetLoadFlags(nsLoadFlags
*aLoadFlags
)
220 *aLoadFlags
= mLoadFlags
;
224 NS_IMETHODIMP
nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags
)
226 mLoadFlags
= aLoadFlags
;
230 NS_IMETHODIMP
nsExtProtocolChannel::GetContentType(nsACString
&aContentType
)
232 return NS_ERROR_NOT_IMPLEMENTED
;
235 NS_IMETHODIMP
nsExtProtocolChannel::SetContentType(const nsACString
&aContentType
)
237 return NS_ERROR_FAILURE
;
240 NS_IMETHODIMP
nsExtProtocolChannel::GetContentCharset(nsACString
&aContentCharset
)
242 return NS_ERROR_NOT_IMPLEMENTED
;
245 NS_IMETHODIMP
nsExtProtocolChannel::SetContentCharset(const nsACString
&aContentCharset
)
247 return NS_ERROR_NOT_IMPLEMENTED
;
250 NS_IMETHODIMP
nsExtProtocolChannel::GetContentLength(PRInt32
* aContentLength
)
252 *aContentLength
= -1;
257 nsExtProtocolChannel::SetContentLength(PRInt32 aContentLength
)
259 NS_NOTREACHED("SetContentLength");
260 return NS_ERROR_NOT_IMPLEMENTED
;
263 NS_IMETHODIMP
nsExtProtocolChannel::GetOwner(nsISupports
* *aPrincipal
)
265 NS_NOTREACHED("GetOwner");
266 return NS_ERROR_NOT_IMPLEMENTED
;
269 NS_IMETHODIMP
nsExtProtocolChannel::SetOwner(nsISupports
* aPrincipal
)
271 NS_NOTREACHED("SetOwner");
272 return NS_ERROR_NOT_IMPLEMENTED
;
275 ////////////////////////////////////////////////////////////////////////////////
277 ////////////////////////////////////////////////////////////////////////////////
279 NS_IMETHODIMP
nsExtProtocolChannel::GetName(nsACString
&result
)
281 return mUrl
->GetSpec(result
);
284 NS_IMETHODIMP
nsExtProtocolChannel::IsPending(PRBool
*result
)
290 NS_IMETHODIMP
nsExtProtocolChannel::GetStatus(nsresult
*status
)
296 NS_IMETHODIMP
nsExtProtocolChannel::Cancel(nsresult status
)
302 NS_IMETHODIMP
nsExtProtocolChannel::Suspend()
304 NS_NOTREACHED("Suspend");
305 return NS_ERROR_NOT_IMPLEMENTED
;
308 NS_IMETHODIMP
nsExtProtocolChannel::Resume()
310 NS_NOTREACHED("Resume");
311 return NS_ERROR_NOT_IMPLEMENTED
;
314 ///////////////////////////////////////////////////////////////////////
315 // the default protocol handler implementation
316 //////////////////////////////////////////////////////////////////////
318 nsExternalProtocolHandler::nsExternalProtocolHandler()
320 m_schemeName
= "default";
324 nsExternalProtocolHandler::~nsExternalProtocolHandler()
327 NS_IMPL_THREADSAFE_ADDREF(nsExternalProtocolHandler
)
328 NS_IMPL_THREADSAFE_RELEASE(nsExternalProtocolHandler
)
330 NS_INTERFACE_MAP_BEGIN(nsExternalProtocolHandler
)
331 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIProtocolHandler
)
332 NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler
)
333 NS_INTERFACE_MAP_ENTRY(nsIExternalProtocolHandler
)
334 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
335 NS_INTERFACE_MAP_END_THREADSAFE
337 NS_IMETHODIMP
nsExternalProtocolHandler::GetScheme(nsACString
&aScheme
)
339 aScheme
= m_schemeName
;
343 NS_IMETHODIMP
nsExternalProtocolHandler::GetDefaultPort(PRInt32
*aDefaultPort
)
350 nsExternalProtocolHandler::AllowPort(PRInt32 port
, const char *scheme
, PRBool
*_retval
)
352 // don't override anything.
356 // returns TRUE if the OS can handle this protocol scheme and false otherwise.
357 PRBool
nsExternalProtocolHandler::HaveExternalProtocolHandler(nsIURI
* aURI
)
359 PRBool haveHandler
= PR_FALSE
;
362 nsCAutoString scheme
;
363 aURI
->GetScheme(scheme
);
365 gExtProtSvc
->ExternalProtocolHandlerExists(scheme
.get(), &haveHandler
);
371 NS_IMETHODIMP
nsExternalProtocolHandler::GetProtocolFlags(PRUint32
*aUritype
)
373 // Make it norelative since it is a simple uri
374 *aUritype
= URI_NORELATIVE
| URI_NOAUTH
| URI_LOADABLE_BY_ANYONE
|
375 URI_NON_PERSISTABLE
| URI_DOES_NOT_RETURN_DATA
;
379 NS_IMETHODIMP
nsExternalProtocolHandler::NewURI(const nsACString
&aSpec
,
380 const char *aCharset
, // ignore charset info
385 nsCOMPtr
<nsIURI
> uri
= do_CreateInstance(NS_SIMPLEURI_CONTRACTID
, &rv
);
386 NS_ENSURE_SUCCESS(rv
, rv
);
388 rv
= uri
->SetSpec(aSpec
);
389 NS_ENSURE_SUCCESS(rv
, rv
);
391 NS_ADDREF(*_retval
= uri
);
395 NS_IMETHODIMP
nsExternalProtocolHandler::NewChannel(nsIURI
*aURI
, nsIChannel
**_retval
)
397 // Only try to return a channel if we have a protocol handler for the url.
398 // nsOSHelperAppService::LoadUriInternal relies on this to check trustedness
399 // for some platforms at least. (win uses ::ShellExecute and unix uses
401 PRBool haveExternalHandler
= HaveExternalProtocolHandler(aURI
);
402 if (haveExternalHandler
)
404 nsCOMPtr
<nsIChannel
> channel
= new nsExtProtocolChannel();
405 if (!channel
) return NS_ERROR_OUT_OF_MEMORY
;
407 ((nsExtProtocolChannel
*) channel
.get())->SetURI(aURI
);
408 channel
->SetOriginalURI(aURI
);
413 NS_IF_ADDREF(*_retval
);
418 return NS_ERROR_UNKNOWN_PROTOCOL
;
421 ///////////////////////////////////////////////////////////////////////
422 // External protocol handler interface implementation
423 //////////////////////////////////////////////////////////////////////
424 NS_IMETHODIMP
nsExternalProtocolHandler::ExternalAppExistsForScheme(const nsACString
& aScheme
, PRBool
*_retval
)
427 return gExtProtSvc
->ExternalProtocolHandlerExists(
428 PromiseFlatCString(aScheme
).get(), _retval
);
430 // In case we don't have external protocol service.