Back to index

lightning-sunbird  0.9+nobinonly
nsExternalProtocolHandler.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  * vim:set ts=2 sts=2 sw=2 et cin:
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is mozilla.org Code.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   Scott MacGregor <mscott@netscape.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nsIURI.h"
00042 #include "nsIURL.h"
00043 #include "nsExternalProtocolHandler.h"
00044 #include "nsXPIDLString.h"
00045 #include "nsReadableUtils.h"
00046 #include "nsCOMPtr.h"
00047 #include "nsIServiceManager.h"
00048 #include "nsServiceManagerUtils.h"
00049 #include "nsIInterfaceRequestor.h"
00050 #include "nsIInterfaceRequestorUtils.h"
00051 #include "nsIStringBundle.h"
00052 #include "nsIPrefService.h"
00053 #include "nsIPrompt.h"
00054 #include "nsEventQueueUtils.h"
00055 #include "nsNetUtil.h"
00056 
00057 // used to dispatch urls to default protocol handlers
00058 #include "nsCExternalHandlerService.h"
00059 #include "nsIExternalProtocolService.h"
00060 
00061 static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
00062 
00063 
00064 
00066 // a stub channel implemenation which will map calls to AsyncRead and OpenInputStream
00067 // to calls in the OS for loading the url.
00069 
00070 class nsExtProtocolChannel : public nsIChannel
00071 {
00072 public:
00073 
00074     NS_DECL_ISUPPORTS
00075     NS_DECL_NSICHANNEL
00076     NS_DECL_NSIREQUEST
00077 
00078     nsExtProtocolChannel();
00079     virtual ~nsExtProtocolChannel();
00080 
00081     nsresult SetURI(nsIURI*);
00082 
00083 private:
00084     nsresult OpenURL();
00085 
00086     nsCOMPtr<nsIURI> mUrl;
00087     nsCOMPtr<nsIURI> mOriginalURI;
00088     nsresult mStatus;
00089 
00090     nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
00091     nsCOMPtr<nsILoadGroup> mLoadGroup;
00092 };
00093 
00094 NS_IMPL_THREADSAFE_ADDREF(nsExtProtocolChannel)
00095 NS_IMPL_THREADSAFE_RELEASE(nsExtProtocolChannel)
00096 
00097 NS_INTERFACE_MAP_BEGIN(nsExtProtocolChannel)
00098    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel)
00099    NS_INTERFACE_MAP_ENTRY(nsIChannel)
00100    NS_INTERFACE_MAP_ENTRY(nsIRequest)
00101 NS_INTERFACE_MAP_END_THREADSAFE
00102 
00103 nsExtProtocolChannel::nsExtProtocolChannel() : mStatus(NS_OK)
00104 {
00105 }
00106 
00107 nsExtProtocolChannel::~nsExtProtocolChannel()
00108 {}
00109 
00110 NS_IMETHODIMP nsExtProtocolChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
00111 {
00112   NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
00113   return NS_OK;
00114 }
00115 
00116 NS_IMETHODIMP nsExtProtocolChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
00117 {
00118   mLoadGroup = aLoadGroup;
00119   return NS_OK;
00120 }
00121 
00122 NS_IMETHODIMP nsExtProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
00123 {
00124   NS_IF_ADDREF(*aCallbacks = mCallbacks);
00125   return NS_OK;
00126 }
00127 
00128 NS_IMETHODIMP nsExtProtocolChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
00129 {
00130   mCallbacks = aCallbacks;
00131   return NS_OK;
00132 }
00133 
00134 NS_IMETHODIMP 
00135 nsExtProtocolChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
00136 {
00137   *aSecurityInfo = nsnull;
00138   return NS_OK;
00139 }
00140 
00141 NS_IMETHODIMP nsExtProtocolChannel::GetOriginalURI(nsIURI* *aURI)
00142 {
00143   NS_IF_ADDREF(*aURI = mOriginalURI);
00144   return NS_OK; 
00145 }
00146  
00147 NS_IMETHODIMP nsExtProtocolChannel::SetOriginalURI(nsIURI* aURI)
00148 {
00149   NS_ENSURE_ARG_POINTER(aURI);
00150   mOriginalURI = aURI;
00151   return NS_OK;
00152 }
00153  
00154 NS_IMETHODIMP nsExtProtocolChannel::GetURI(nsIURI* *aURI)
00155 {
00156   *aURI = mUrl;
00157   NS_IF_ADDREF(*aURI);
00158   return NS_OK; 
00159 }
00160  
00161 nsresult nsExtProtocolChannel::SetURI(nsIURI* aURI)
00162 {
00163   mUrl = aURI;
00164   return NS_OK; 
00165 }
00166  
00167 nsresult nsExtProtocolChannel::OpenURL()
00168 {
00169   nsresult rv = NS_ERROR_FAILURE;
00170   nsCOMPtr<nsIExternalProtocolService> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
00171 
00172   if (extProtService)
00173   {
00174 #ifdef DEBUG
00175     nsCAutoString urlScheme;
00176     mUrl->GetScheme(urlScheme);
00177     PRBool haveHandler = PR_FALSE;
00178     extProtService->ExternalProtocolHandlerExists(urlScheme.get(), &haveHandler);
00179     NS_ASSERTION(haveHandler, "Why do we have a channel for this url if we don't support the protocol?");
00180 #endif
00181 
00182     // get an nsIPrompt from the channel if we can
00183     nsCOMPtr<nsIPrompt> prompt;
00184     NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, prompt);
00185     rv = extProtService->LoadURI(mUrl, prompt);
00186   }
00187 
00188   // Drop notification callbacks to prevent cycles.
00189   mCallbacks = 0;
00190 
00191   return rv;
00192 }
00193 
00194 NS_IMETHODIMP nsExtProtocolChannel::Open(nsIInputStream **_retval)
00195 {
00196   OpenURL();
00197   return NS_ERROR_NO_CONTENT; // force caller to abort.
00198 }
00199 
00200 NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
00201 {
00202   OpenURL();
00203   return NS_ERROR_NO_CONTENT; // force caller to abort.
00204 }
00205 
00206 NS_IMETHODIMP nsExtProtocolChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
00207 {
00208   *aLoadFlags = 0;
00209   return NS_OK;
00210 }
00211 
00212 NS_IMETHODIMP nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
00213 {
00214   return NS_OK;
00215 }
00216 
00217 NS_IMETHODIMP nsExtProtocolChannel::GetContentType(nsACString &aContentType)
00218 {
00219   return NS_ERROR_NOT_IMPLEMENTED;
00220 }
00221 
00222 NS_IMETHODIMP nsExtProtocolChannel::SetContentType(const nsACString &aContentType)
00223 {
00224   return NS_ERROR_FAILURE;
00225 }
00226 
00227 NS_IMETHODIMP nsExtProtocolChannel::GetContentCharset(nsACString &aContentCharset)
00228 {
00229   return NS_ERROR_NOT_IMPLEMENTED;
00230 }
00231 
00232 NS_IMETHODIMP nsExtProtocolChannel::SetContentCharset(const nsACString &aContentCharset)
00233 {
00234   return NS_ERROR_NOT_IMPLEMENTED;
00235 }
00236 
00237 NS_IMETHODIMP nsExtProtocolChannel::GetContentLength(PRInt32 * aContentLength)
00238 {
00239   *aContentLength = -1;
00240   return NS_OK;
00241 }
00242 
00243 NS_IMETHODIMP
00244 nsExtProtocolChannel::SetContentLength(PRInt32 aContentLength)
00245 {
00246   NS_NOTREACHED("SetContentLength");
00247   return NS_ERROR_NOT_IMPLEMENTED;
00248 }
00249 
00250 NS_IMETHODIMP nsExtProtocolChannel::GetOwner(nsISupports * *aPrincipal)
00251 {
00252   NS_NOTREACHED("GetOwner");
00253   return NS_ERROR_NOT_IMPLEMENTED;
00254 }
00255 
00256 NS_IMETHODIMP nsExtProtocolChannel::SetOwner(nsISupports * aPrincipal)
00257 {
00258   NS_NOTREACHED("SetOwner");
00259   return NS_ERROR_NOT_IMPLEMENTED;
00260 }
00261 
00263 // From nsIRequest
00265 
00266 NS_IMETHODIMP nsExtProtocolChannel::GetName(nsACString &result)
00267 {
00268   NS_NOTREACHED("nsExtProtocolChannel::GetName");
00269   return NS_ERROR_NOT_IMPLEMENTED;
00270 }
00271 
00272 NS_IMETHODIMP nsExtProtocolChannel::IsPending(PRBool *result)
00273 {
00274   *result = PR_TRUE;
00275   return NS_OK; 
00276 }
00277 
00278 NS_IMETHODIMP nsExtProtocolChannel::GetStatus(nsresult *status)
00279 {
00280   *status = mStatus;
00281   return NS_OK;
00282 }
00283 
00284 NS_IMETHODIMP nsExtProtocolChannel::Cancel(nsresult status)
00285 {
00286   mStatus = status;
00287   return NS_OK;
00288 }
00289 
00290 NS_IMETHODIMP nsExtProtocolChannel::Suspend()
00291 {
00292   NS_NOTREACHED("Suspend");
00293   return NS_ERROR_NOT_IMPLEMENTED;
00294 }
00295 
00296 NS_IMETHODIMP nsExtProtocolChannel::Resume()
00297 {
00298   NS_NOTREACHED("Resume");
00299   return NS_ERROR_NOT_IMPLEMENTED;
00300 }
00301 
00303 // the default protocol handler implementation
00305 
00306 nsExternalProtocolHandler::nsExternalProtocolHandler()
00307 {
00308   m_schemeName = "default";
00309   m_extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
00310 }
00311 
00312 
00313 nsExternalProtocolHandler::~nsExternalProtocolHandler()
00314 {}
00315 
00316 NS_IMPL_THREADSAFE_ADDREF(nsExternalProtocolHandler)
00317 NS_IMPL_THREADSAFE_RELEASE(nsExternalProtocolHandler)
00318 
00319 NS_INTERFACE_MAP_BEGIN(nsExternalProtocolHandler)
00320    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIProtocolHandler)
00321    NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler)
00322    NS_INTERFACE_MAP_ENTRY(nsIExternalProtocolHandler)
00323    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00324 NS_INTERFACE_MAP_END_THREADSAFE
00325 
00326 NS_IMETHODIMP nsExternalProtocolHandler::GetScheme(nsACString &aScheme)
00327 {
00328   aScheme = m_schemeName;
00329   return NS_OK;
00330 }
00331 
00332 NS_IMETHODIMP nsExternalProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
00333 {
00334   *aDefaultPort = 0;
00335     return NS_OK;
00336 }
00337 
00338 NS_IMETHODIMP 
00339 nsExternalProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
00340 {
00341     // don't override anything.  
00342     *_retval = PR_FALSE;
00343     return NS_OK;
00344 }
00345 // returns TRUE if the OS can handle this protocol scheme and false otherwise.
00346 PRBool nsExternalProtocolHandler::HaveProtocolHandler(nsIURI * aURI)
00347 {
00348   PRBool haveHandler = PR_FALSE;
00349   if (aURI)
00350   {
00351     nsCAutoString scheme;
00352     aURI->GetScheme(scheme);
00353     if (m_extProtService)
00354       m_extProtService->ExternalProtocolHandlerExists(scheme.get(), &haveHandler);
00355   }
00356 
00357   return haveHandler;
00358 }
00359 
00360 NS_IMETHODIMP nsExternalProtocolHandler::GetProtocolFlags(PRUint32 *aUritype)
00361 {
00362     // Make it norelative since it is a simple uri
00363     *aUritype = URI_NORELATIVE;
00364     return NS_OK;
00365 }
00366 
00367 NS_IMETHODIMP nsExternalProtocolHandler::NewURI(const nsACString &aSpec,
00368                                                 const char *aCharset, // ignore charset info
00369                                                 nsIURI *aBaseURI,
00370                                                 nsIURI **_retval)
00371 {
00372   nsresult rv;
00373   nsCOMPtr<nsIURI> uri = do_CreateInstance(kSimpleURICID, &rv);
00374   NS_ENSURE_SUCCESS(rv, rv);
00375   
00376   rv = uri->SetSpec(aSpec);
00377   NS_ENSURE_SUCCESS(rv, rv);
00378 
00379   NS_ADDREF(*_retval = uri);
00380   return NS_OK;
00381 }
00382 
00383 NS_IMETHODIMP nsExternalProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
00384 {
00385   // only try to return a channel if we have a protocol handler for the url
00386 
00387   PRBool haveHandler = HaveProtocolHandler(aURI);
00388   if (haveHandler)
00389   {
00390     nsCOMPtr<nsIChannel> channel;
00391     NS_NEWXPCOM(channel, nsExtProtocolChannel);
00392     if (!channel) return NS_ERROR_OUT_OF_MEMORY;
00393 
00394     ((nsExtProtocolChannel*) channel.get())->SetURI(aURI);
00395     channel->SetOriginalURI(aURI);
00396 
00397     if (_retval)
00398     {
00399       *_retval = channel;
00400       NS_IF_ADDREF(*_retval);
00401       return NS_OK;
00402     }
00403   }
00404 
00405   return NS_ERROR_UNKNOWN_PROTOCOL;
00406 }
00407 
00409 // External protocol handler interface implementation
00411 NS_IMETHODIMP nsExternalProtocolHandler::ExternalAppExistsForScheme(const nsACString& aScheme, PRBool *_retval)
00412 {
00413   if (m_extProtService)
00414     return m_extProtService->ExternalProtocolHandlerExists(PromiseFlatCString(aScheme).get(), _retval);
00415 
00416   // In case we don't have external protocol service.
00417   *_retval = PR_FALSE;
00418   return NS_OK;
00419 }
00420 
00421 nsBlockedExternalProtocolHandler::nsBlockedExternalProtocolHandler()
00422 {
00423     m_schemeName = "default-blocked";
00424 }
00425 
00426 NS_IMETHODIMP
00427 nsBlockedExternalProtocolHandler::NewChannel(nsIURI *aURI,
00428                                              nsIChannel **_retval)
00429 {
00430     *_retval = nsnull;
00431     return NS_ERROR_UNKNOWN_PROTOCOL;
00432 }