uriloader/exthandler/nsExternalProtocolHandler.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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 }

mercurial