uriloader/exthandler/nsExternalProtocolHandler.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 * vim:set ts=2 sts=2 sw=2 et cin:
michael@0 3 *
michael@0 4 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 5 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 7
michael@0 8 #include "nsIURI.h"
michael@0 9 #include "nsIURL.h"
michael@0 10 #include "nsExternalProtocolHandler.h"
michael@0 11 #include "nsXPIDLString.h"
michael@0 12 #include "nsReadableUtils.h"
michael@0 13 #include "nsCOMPtr.h"
michael@0 14 #include "nsIServiceManager.h"
michael@0 15 #include "nsServiceManagerUtils.h"
michael@0 16 #include "nsIInterfaceRequestor.h"
michael@0 17 #include "nsIInterfaceRequestorUtils.h"
michael@0 18 #include "nsIStringBundle.h"
michael@0 19 #include "nsIPrefService.h"
michael@0 20 #include "nsIPrompt.h"
michael@0 21 #include "nsNetUtil.h"
michael@0 22 #include "nsExternalHelperAppService.h"
michael@0 23
michael@0 24 // used to dispatch urls to default protocol handlers
michael@0 25 #include "nsCExternalHandlerService.h"
michael@0 26 #include "nsIExternalProtocolService.h"
michael@0 27
michael@0 28 ////////////////////////////////////////////////////////////////////////
michael@0 29 // a stub channel implemenation which will map calls to AsyncRead and OpenInputStream
michael@0 30 // to calls in the OS for loading the url.
michael@0 31 ////////////////////////////////////////////////////////////////////////
michael@0 32
michael@0 33 class nsExtProtocolChannel : public nsIChannel
michael@0 34 {
michael@0 35 public:
michael@0 36 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 37 NS_DECL_NSICHANNEL
michael@0 38 NS_DECL_NSIREQUEST
michael@0 39
michael@0 40 nsExtProtocolChannel();
michael@0 41 virtual ~nsExtProtocolChannel();
michael@0 42
michael@0 43 nsresult SetURI(nsIURI*);
michael@0 44
michael@0 45 private:
michael@0 46 nsresult OpenURL();
michael@0 47 void Finish(nsresult aResult);
michael@0 48
michael@0 49 nsCOMPtr<nsIURI> mUrl;
michael@0 50 nsCOMPtr<nsIURI> mOriginalURI;
michael@0 51 nsresult mStatus;
michael@0 52 nsLoadFlags mLoadFlags;
michael@0 53 bool mWasOpened;
michael@0 54
michael@0 55 nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
michael@0 56 nsCOMPtr<nsILoadGroup> mLoadGroup;
michael@0 57 };
michael@0 58
michael@0 59 NS_IMPL_ADDREF(nsExtProtocolChannel)
michael@0 60 NS_IMPL_RELEASE(nsExtProtocolChannel)
michael@0 61
michael@0 62 NS_INTERFACE_MAP_BEGIN(nsExtProtocolChannel)
michael@0 63 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel)
michael@0 64 NS_INTERFACE_MAP_ENTRY(nsIChannel)
michael@0 65 NS_INTERFACE_MAP_ENTRY(nsIRequest)
michael@0 66 NS_INTERFACE_MAP_END_THREADSAFE
michael@0 67
michael@0 68 nsExtProtocolChannel::nsExtProtocolChannel() : mStatus(NS_OK),
michael@0 69 mWasOpened(false)
michael@0 70 {
michael@0 71 }
michael@0 72
michael@0 73 nsExtProtocolChannel::~nsExtProtocolChannel()
michael@0 74 {}
michael@0 75
michael@0 76 NS_IMETHODIMP nsExtProtocolChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
michael@0 77 {
michael@0 78 NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
michael@0 79 return NS_OK;
michael@0 80 }
michael@0 81
michael@0 82 NS_IMETHODIMP nsExtProtocolChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
michael@0 83 {
michael@0 84 mLoadGroup = aLoadGroup;
michael@0 85 return NS_OK;
michael@0 86 }
michael@0 87
michael@0 88 NS_IMETHODIMP nsExtProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
michael@0 89 {
michael@0 90 NS_IF_ADDREF(*aCallbacks = mCallbacks);
michael@0 91 return NS_OK;
michael@0 92 }
michael@0 93
michael@0 94 NS_IMETHODIMP nsExtProtocolChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
michael@0 95 {
michael@0 96 mCallbacks = aCallbacks;
michael@0 97 return NS_OK;
michael@0 98 }
michael@0 99
michael@0 100 NS_IMETHODIMP
michael@0 101 nsExtProtocolChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
michael@0 102 {
michael@0 103 *aSecurityInfo = nullptr;
michael@0 104 return NS_OK;
michael@0 105 }
michael@0 106
michael@0 107 NS_IMETHODIMP nsExtProtocolChannel::GetOriginalURI(nsIURI* *aURI)
michael@0 108 {
michael@0 109 NS_ADDREF(*aURI = mOriginalURI);
michael@0 110 return NS_OK;
michael@0 111 }
michael@0 112
michael@0 113 NS_IMETHODIMP nsExtProtocolChannel::SetOriginalURI(nsIURI* aURI)
michael@0 114 {
michael@0 115 NS_ENSURE_ARG_POINTER(aURI);
michael@0 116 mOriginalURI = aURI;
michael@0 117 return NS_OK;
michael@0 118 }
michael@0 119
michael@0 120 NS_IMETHODIMP nsExtProtocolChannel::GetURI(nsIURI* *aURI)
michael@0 121 {
michael@0 122 *aURI = mUrl;
michael@0 123 NS_IF_ADDREF(*aURI);
michael@0 124 return NS_OK;
michael@0 125 }
michael@0 126
michael@0 127 nsresult nsExtProtocolChannel::SetURI(nsIURI* aURI)
michael@0 128 {
michael@0 129 mUrl = aURI;
michael@0 130 return NS_OK;
michael@0 131 }
michael@0 132
michael@0 133 nsresult nsExtProtocolChannel::OpenURL()
michael@0 134 {
michael@0 135 nsresult rv = NS_ERROR_FAILURE;
michael@0 136 nsCOMPtr<nsIExternalProtocolService> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
michael@0 137
michael@0 138 if (extProtService)
michael@0 139 {
michael@0 140 #ifdef DEBUG
michael@0 141 nsAutoCString urlScheme;
michael@0 142 mUrl->GetScheme(urlScheme);
michael@0 143 bool haveHandler = false;
michael@0 144 extProtService->ExternalProtocolHandlerExists(urlScheme.get(), &haveHandler);
michael@0 145 NS_ASSERTION(haveHandler, "Why do we have a channel for this url if we don't support the protocol?");
michael@0 146 #endif
michael@0 147
michael@0 148 nsCOMPtr<nsIInterfaceRequestor> aggCallbacks;
michael@0 149 rv = NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
michael@0 150 getter_AddRefs(aggCallbacks));
michael@0 151 if (NS_FAILED(rv)) {
michael@0 152 goto finish;
michael@0 153 }
michael@0 154
michael@0 155 rv = extProtService->LoadURI(mUrl, aggCallbacks);
michael@0 156 if (NS_SUCCEEDED(rv)) {
michael@0 157 // despite success, we need to abort this channel, at the very least
michael@0 158 // to make it clear to the caller that no on{Start,Stop}Request
michael@0 159 // should be expected.
michael@0 160 rv = NS_ERROR_NO_CONTENT;
michael@0 161 }
michael@0 162 }
michael@0 163
michael@0 164 finish:
michael@0 165 mCallbacks = 0;
michael@0 166 return rv;
michael@0 167 }
michael@0 168
michael@0 169 NS_IMETHODIMP nsExtProtocolChannel::Open(nsIInputStream **_retval)
michael@0 170 {
michael@0 171 return OpenURL();
michael@0 172 }
michael@0 173
michael@0 174 NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
michael@0 175 {
michael@0 176 NS_ENSURE_ARG_POINTER(listener);
michael@0 177 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
michael@0 178
michael@0 179 mWasOpened = true;
michael@0 180
michael@0 181 return OpenURL();
michael@0 182 }
michael@0 183
michael@0 184 NS_IMETHODIMP nsExtProtocolChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
michael@0 185 {
michael@0 186 *aLoadFlags = mLoadFlags;
michael@0 187 return NS_OK;
michael@0 188 }
michael@0 189
michael@0 190 NS_IMETHODIMP nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
michael@0 191 {
michael@0 192 mLoadFlags = aLoadFlags;
michael@0 193 return NS_OK;
michael@0 194 }
michael@0 195
michael@0 196 NS_IMETHODIMP nsExtProtocolChannel::GetContentType(nsACString &aContentType)
michael@0 197 {
michael@0 198 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 199 }
michael@0 200
michael@0 201 NS_IMETHODIMP nsExtProtocolChannel::SetContentType(const nsACString &aContentType)
michael@0 202 {
michael@0 203 return NS_ERROR_FAILURE;
michael@0 204 }
michael@0 205
michael@0 206 NS_IMETHODIMP nsExtProtocolChannel::GetContentCharset(nsACString &aContentCharset)
michael@0 207 {
michael@0 208 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 209 }
michael@0 210
michael@0 211 NS_IMETHODIMP nsExtProtocolChannel::SetContentCharset(const nsACString &aContentCharset)
michael@0 212 {
michael@0 213 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 214 }
michael@0 215
michael@0 216 NS_IMETHODIMP nsExtProtocolChannel::GetContentDisposition(uint32_t *aContentDisposition)
michael@0 217 {
michael@0 218 return NS_ERROR_NOT_AVAILABLE;
michael@0 219 }
michael@0 220
michael@0 221 NS_IMETHODIMP nsExtProtocolChannel::SetContentDisposition(uint32_t aContentDisposition)
michael@0 222 {
michael@0 223 return NS_ERROR_NOT_AVAILABLE;
michael@0 224 }
michael@0 225
michael@0 226 NS_IMETHODIMP nsExtProtocolChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
michael@0 227 {
michael@0 228 return NS_ERROR_NOT_AVAILABLE;
michael@0 229 }
michael@0 230
michael@0 231 NS_IMETHODIMP nsExtProtocolChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
michael@0 232 {
michael@0 233 return NS_ERROR_NOT_AVAILABLE;
michael@0 234 }
michael@0 235
michael@0 236 NS_IMETHODIMP nsExtProtocolChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
michael@0 237 {
michael@0 238 return NS_ERROR_NOT_AVAILABLE;
michael@0 239 }
michael@0 240
michael@0 241 NS_IMETHODIMP nsExtProtocolChannel::GetContentLength(int64_t * aContentLength)
michael@0 242 {
michael@0 243 *aContentLength = -1;
michael@0 244 return NS_OK;
michael@0 245 }
michael@0 246
michael@0 247 NS_IMETHODIMP
michael@0 248 nsExtProtocolChannel::SetContentLength(int64_t aContentLength)
michael@0 249 {
michael@0 250 NS_NOTREACHED("SetContentLength");
michael@0 251 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 252 }
michael@0 253
michael@0 254 NS_IMETHODIMP nsExtProtocolChannel::GetOwner(nsISupports * *aPrincipal)
michael@0 255 {
michael@0 256 NS_NOTREACHED("GetOwner");
michael@0 257 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 258 }
michael@0 259
michael@0 260 NS_IMETHODIMP nsExtProtocolChannel::SetOwner(nsISupports * aPrincipal)
michael@0 261 {
michael@0 262 NS_NOTREACHED("SetOwner");
michael@0 263 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 264 }
michael@0 265
michael@0 266 ////////////////////////////////////////////////////////////////////////////////
michael@0 267 // From nsIRequest
michael@0 268 ////////////////////////////////////////////////////////////////////////////////
michael@0 269
michael@0 270 NS_IMETHODIMP nsExtProtocolChannel::GetName(nsACString &result)
michael@0 271 {
michael@0 272 return mUrl->GetSpec(result);
michael@0 273 }
michael@0 274
michael@0 275 NS_IMETHODIMP nsExtProtocolChannel::IsPending(bool *result)
michael@0 276 {
michael@0 277 *result = false;
michael@0 278 return NS_OK;
michael@0 279 }
michael@0 280
michael@0 281 NS_IMETHODIMP nsExtProtocolChannel::GetStatus(nsresult *status)
michael@0 282 {
michael@0 283 *status = mStatus;
michael@0 284 return NS_OK;
michael@0 285 }
michael@0 286
michael@0 287 NS_IMETHODIMP nsExtProtocolChannel::Cancel(nsresult status)
michael@0 288 {
michael@0 289 mStatus = status;
michael@0 290 return NS_OK;
michael@0 291 }
michael@0 292
michael@0 293 NS_IMETHODIMP nsExtProtocolChannel::Suspend()
michael@0 294 {
michael@0 295 NS_NOTREACHED("Suspend");
michael@0 296 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 297 }
michael@0 298
michael@0 299 NS_IMETHODIMP nsExtProtocolChannel::Resume()
michael@0 300 {
michael@0 301 NS_NOTREACHED("Resume");
michael@0 302 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 303 }
michael@0 304
michael@0 305 ///////////////////////////////////////////////////////////////////////
michael@0 306 // the default protocol handler implementation
michael@0 307 //////////////////////////////////////////////////////////////////////
michael@0 308
michael@0 309 nsExternalProtocolHandler::nsExternalProtocolHandler()
michael@0 310 {
michael@0 311 m_schemeName = "default";
michael@0 312 }
michael@0 313
michael@0 314
michael@0 315 nsExternalProtocolHandler::~nsExternalProtocolHandler()
michael@0 316 {}
michael@0 317
michael@0 318 NS_IMPL_ADDREF(nsExternalProtocolHandler)
michael@0 319 NS_IMPL_RELEASE(nsExternalProtocolHandler)
michael@0 320
michael@0 321 NS_INTERFACE_MAP_BEGIN(nsExternalProtocolHandler)
michael@0 322 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIProtocolHandler)
michael@0 323 NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler)
michael@0 324 NS_INTERFACE_MAP_ENTRY(nsIExternalProtocolHandler)
michael@0 325 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
michael@0 326 NS_INTERFACE_MAP_END_THREADSAFE
michael@0 327
michael@0 328 NS_IMETHODIMP nsExternalProtocolHandler::GetScheme(nsACString &aScheme)
michael@0 329 {
michael@0 330 aScheme = m_schemeName;
michael@0 331 return NS_OK;
michael@0 332 }
michael@0 333
michael@0 334 NS_IMETHODIMP nsExternalProtocolHandler::GetDefaultPort(int32_t *aDefaultPort)
michael@0 335 {
michael@0 336 *aDefaultPort = 0;
michael@0 337 return NS_OK;
michael@0 338 }
michael@0 339
michael@0 340 NS_IMETHODIMP
michael@0 341 nsExternalProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
michael@0 342 {
michael@0 343 // don't override anything.
michael@0 344 *_retval = false;
michael@0 345 return NS_OK;
michael@0 346 }
michael@0 347 // returns TRUE if the OS can handle this protocol scheme and false otherwise.
michael@0 348 bool nsExternalProtocolHandler::HaveExternalProtocolHandler(nsIURI * aURI)
michael@0 349 {
michael@0 350 bool haveHandler = false;
michael@0 351 if (aURI)
michael@0 352 {
michael@0 353 nsAutoCString scheme;
michael@0 354 aURI->GetScheme(scheme);
michael@0 355 nsCOMPtr<nsIExternalProtocolService> extProtSvc(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
michael@0 356 if (extProtSvc)
michael@0 357 extProtSvc->ExternalProtocolHandlerExists(scheme.get(), &haveHandler);
michael@0 358 }
michael@0 359
michael@0 360 return haveHandler;
michael@0 361 }
michael@0 362
michael@0 363 NS_IMETHODIMP nsExternalProtocolHandler::GetProtocolFlags(uint32_t *aUritype)
michael@0 364 {
michael@0 365 // Make it norelative since it is a simple uri
michael@0 366 *aUritype = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE |
michael@0 367 URI_NON_PERSISTABLE | URI_DOES_NOT_RETURN_DATA;
michael@0 368 return NS_OK;
michael@0 369 }
michael@0 370
michael@0 371 NS_IMETHODIMP nsExternalProtocolHandler::NewURI(const nsACString &aSpec,
michael@0 372 const char *aCharset, // ignore charset info
michael@0 373 nsIURI *aBaseURI,
michael@0 374 nsIURI **_retval)
michael@0 375 {
michael@0 376 nsresult rv;
michael@0 377 nsCOMPtr<nsIURI> uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv);
michael@0 378 NS_ENSURE_SUCCESS(rv, rv);
michael@0 379
michael@0 380 rv = uri->SetSpec(aSpec);
michael@0 381 NS_ENSURE_SUCCESS(rv, rv);
michael@0 382
michael@0 383 NS_ADDREF(*_retval = uri);
michael@0 384 return NS_OK;
michael@0 385 }
michael@0 386
michael@0 387 NS_IMETHODIMP nsExternalProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
michael@0 388 {
michael@0 389 // Only try to return a channel if we have a protocol handler for the url.
michael@0 390 // nsOSHelperAppService::LoadUriInternal relies on this to check trustedness
michael@0 391 // for some platforms at least. (win uses ::ShellExecute and unix uses
michael@0 392 // gnome_url_show.)
michael@0 393 bool haveExternalHandler = HaveExternalProtocolHandler(aURI);
michael@0 394 if (haveExternalHandler)
michael@0 395 {
michael@0 396 nsCOMPtr<nsIChannel> channel = new nsExtProtocolChannel();
michael@0 397 if (!channel) return NS_ERROR_OUT_OF_MEMORY;
michael@0 398
michael@0 399 ((nsExtProtocolChannel*) channel.get())->SetURI(aURI);
michael@0 400 channel->SetOriginalURI(aURI);
michael@0 401
michael@0 402 if (_retval)
michael@0 403 {
michael@0 404 *_retval = channel;
michael@0 405 NS_IF_ADDREF(*_retval);
michael@0 406 return NS_OK;
michael@0 407 }
michael@0 408 }
michael@0 409
michael@0 410 return NS_ERROR_UNKNOWN_PROTOCOL;
michael@0 411 }
michael@0 412
michael@0 413 ///////////////////////////////////////////////////////////////////////
michael@0 414 // External protocol handler interface implementation
michael@0 415 //////////////////////////////////////////////////////////////////////
michael@0 416 NS_IMETHODIMP nsExternalProtocolHandler::ExternalAppExistsForScheme(const nsACString& aScheme, bool *_retval)
michael@0 417 {
michael@0 418 nsCOMPtr<nsIExternalProtocolService> extProtSvc(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
michael@0 419 if (extProtSvc)
michael@0 420 return extProtSvc->ExternalProtocolHandlerExists(
michael@0 421 PromiseFlatCString(aScheme).get(), _retval);
michael@0 422
michael@0 423 // In case we don't have external protocol service.
michael@0 424 *_retval = false;
michael@0 425 return NS_OK;
michael@0 426 }

mercurial