netwerk/base/public/nsNetUtil.h

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

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim:set ts=4 sw=4 sts=4 et cin: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef nsNetUtil_h__
michael@0 8 #define nsNetUtil_h__
michael@0 9
michael@0 10 #include "nsError.h"
michael@0 11 #include "nsNetCID.h"
michael@0 12 #include "nsStringGlue.h"
michael@0 13 #include "nsMemory.h"
michael@0 14 #include "nsCOMPtr.h"
michael@0 15 #include "prio.h" // for read/write flags, permissions, etc.
michael@0 16 #include "nsHashKeys.h"
michael@0 17
michael@0 18 #include "plstr.h"
michael@0 19 #include "nsIURI.h"
michael@0 20 #include "nsIStandardURL.h"
michael@0 21 #include "nsIURLParser.h"
michael@0 22 #include "nsIUUIDGenerator.h"
michael@0 23 #include "nsIInputStream.h"
michael@0 24 #include "nsIOutputStream.h"
michael@0 25 #include "nsISafeOutputStream.h"
michael@0 26 #include "nsIStreamListener.h"
michael@0 27 #include "nsIRequestObserverProxy.h"
michael@0 28 #include "nsISimpleStreamListener.h"
michael@0 29 #include "nsILoadGroup.h"
michael@0 30 #include "nsIInterfaceRequestor.h"
michael@0 31 #include "nsIInterfaceRequestorUtils.h"
michael@0 32 #include "nsIIOService.h"
michael@0 33 #include "nsIServiceManager.h"
michael@0 34 #include "nsIChannel.h"
michael@0 35 #include "nsChannelProperties.h"
michael@0 36 #include "nsIInputStreamChannel.h"
michael@0 37 #include "nsITransport.h"
michael@0 38 #include "nsIStreamTransportService.h"
michael@0 39 #include "nsIHttpChannel.h"
michael@0 40 #include "nsIDownloader.h"
michael@0 41 #include "nsIStreamLoader.h"
michael@0 42 #include "nsIUnicharStreamLoader.h"
michael@0 43 #include "nsIPipe.h"
michael@0 44 #include "nsIProtocolHandler.h"
michael@0 45 #include "nsIFileProtocolHandler.h"
michael@0 46 #include "nsIStringStream.h"
michael@0 47 #include "nsIFile.h"
michael@0 48 #include "nsIFileStreams.h"
michael@0 49 #include "nsIFileURL.h"
michael@0 50 #include "nsIProtocolProxyService.h"
michael@0 51 #include "nsIProxyInfo.h"
michael@0 52 #include "nsIFileStreams.h"
michael@0 53 #include "nsIBufferedStreams.h"
michael@0 54 #include "nsIInputStreamPump.h"
michael@0 55 #include "nsIAsyncStreamCopier.h"
michael@0 56 #include "nsIPersistentProperties2.h"
michael@0 57 #include "nsISyncStreamListener.h"
michael@0 58 #include "nsInterfaceRequestorAgg.h"
michael@0 59 #include "nsINetUtil.h"
michael@0 60 #include "nsIURIWithPrincipal.h"
michael@0 61 #include "nsIAuthPrompt.h"
michael@0 62 #include "nsIAuthPrompt2.h"
michael@0 63 #include "nsIAuthPromptAdapterFactory.h"
michael@0 64 #include "nsComponentManagerUtils.h"
michael@0 65 #include "nsServiceManagerUtils.h"
michael@0 66 #include "nsINestedURI.h"
michael@0 67 #include "nsIMutable.h"
michael@0 68 #include "nsIPropertyBag2.h"
michael@0 69 #include "nsIWritablePropertyBag2.h"
michael@0 70 #include "nsIIDNService.h"
michael@0 71 #include "nsIChannelEventSink.h"
michael@0 72 #include "nsIChannelPolicy.h"
michael@0 73 #include "nsISocketProviderService.h"
michael@0 74 #include "nsISocketProvider.h"
michael@0 75 #include "nsIRedirectChannelRegistrar.h"
michael@0 76 #include "nsIMIMEHeaderParam.h"
michael@0 77 #include "nsILoadContext.h"
michael@0 78 #include "mozilla/Services.h"
michael@0 79 #include "nsIPrivateBrowsingChannel.h"
michael@0 80 #include "mozIApplicationClearPrivateDataParams.h"
michael@0 81 #include "nsIOfflineCacheUpdate.h"
michael@0 82 #include "nsIContentSniffer.h"
michael@0 83 #include "nsCategoryCache.h"
michael@0 84 #include "nsStringStream.h"
michael@0 85 #include "nsIViewSourceChannel.h"
michael@0 86
michael@0 87 #include <limits>
michael@0 88
michael@0 89 #ifdef MOZILLA_INTERNAL_API
michael@0 90
michael@0 91 #include "nsReadableUtils.h"
michael@0 92
michael@0 93 inline already_AddRefed<nsIIOService>
michael@0 94 do_GetIOService(nsresult* error = 0)
michael@0 95 {
michael@0 96 nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
michael@0 97 if (error)
michael@0 98 *error = io ? NS_OK : NS_ERROR_FAILURE;
michael@0 99 return io.forget();
michael@0 100 }
michael@0 101
michael@0 102 inline already_AddRefed<nsINetUtil>
michael@0 103 do_GetNetUtil(nsresult *error = 0)
michael@0 104 {
michael@0 105 nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
michael@0 106 nsCOMPtr<nsINetUtil> util;
michael@0 107 if (io)
michael@0 108 util = do_QueryInterface(io);
michael@0 109
michael@0 110 if (error)
michael@0 111 *error = !!util ? NS_OK : NS_ERROR_FAILURE;
michael@0 112 return util.forget();
michael@0 113 }
michael@0 114 #else
michael@0 115 // Helper, to simplify getting the I/O service.
michael@0 116 inline const nsGetServiceByContractIDWithError
michael@0 117 do_GetIOService(nsresult* error = 0)
michael@0 118 {
michael@0 119 return nsGetServiceByContractIDWithError(NS_IOSERVICE_CONTRACTID, error);
michael@0 120 }
michael@0 121
michael@0 122 // An alias to do_GetIOService
michael@0 123 inline const nsGetServiceByContractIDWithError
michael@0 124 do_GetNetUtil(nsresult* error = 0)
michael@0 125 {
michael@0 126 return do_GetIOService(error);
michael@0 127 }
michael@0 128 #endif
michael@0 129
michael@0 130 // private little helper function... don't call this directly!
michael@0 131 inline nsresult
michael@0 132 net_EnsureIOService(nsIIOService **ios, nsCOMPtr<nsIIOService> &grip)
michael@0 133 {
michael@0 134 nsresult rv = NS_OK;
michael@0 135 if (!*ios) {
michael@0 136 grip = do_GetIOService(&rv);
michael@0 137 *ios = grip;
michael@0 138 }
michael@0 139 return rv;
michael@0 140 }
michael@0 141
michael@0 142 inline nsresult
michael@0 143 NS_NewURI(nsIURI **result,
michael@0 144 const nsACString &spec,
michael@0 145 const char *charset = nullptr,
michael@0 146 nsIURI *baseURI = nullptr,
michael@0 147 nsIIOService *ioService = nullptr) // pass in nsIIOService to optimize callers
michael@0 148 {
michael@0 149 nsresult rv;
michael@0 150 nsCOMPtr<nsIIOService> grip;
michael@0 151 rv = net_EnsureIOService(&ioService, grip);
michael@0 152 if (ioService)
michael@0 153 rv = ioService->NewURI(spec, charset, baseURI, result);
michael@0 154 return rv;
michael@0 155 }
michael@0 156
michael@0 157 inline nsresult
michael@0 158 NS_NewURI(nsIURI* *result,
michael@0 159 const nsAString& spec,
michael@0 160 const char *charset = nullptr,
michael@0 161 nsIURI* baseURI = nullptr,
michael@0 162 nsIIOService* ioService = nullptr) // pass in nsIIOService to optimize callers
michael@0 163 {
michael@0 164 return NS_NewURI(result, NS_ConvertUTF16toUTF8(spec), charset, baseURI, ioService);
michael@0 165 }
michael@0 166
michael@0 167 inline nsresult
michael@0 168 NS_NewURI(nsIURI* *result,
michael@0 169 const char *spec,
michael@0 170 nsIURI* baseURI = nullptr,
michael@0 171 nsIIOService* ioService = nullptr) // pass in nsIIOService to optimize callers
michael@0 172 {
michael@0 173 return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI, ioService);
michael@0 174 }
michael@0 175
michael@0 176 inline nsresult
michael@0 177 NS_NewFileURI(nsIURI* *result,
michael@0 178 nsIFile* spec,
michael@0 179 nsIIOService* ioService = nullptr) // pass in nsIIOService to optimize callers
michael@0 180 {
michael@0 181 nsresult rv;
michael@0 182 nsCOMPtr<nsIIOService> grip;
michael@0 183 rv = net_EnsureIOService(&ioService, grip);
michael@0 184 if (ioService)
michael@0 185 rv = ioService->NewFileURI(spec, result);
michael@0 186 return rv;
michael@0 187 }
michael@0 188
michael@0 189 inline nsresult
michael@0 190 NS_NewChannel(nsIChannel **result,
michael@0 191 nsIURI *uri,
michael@0 192 nsIIOService *ioService = nullptr, // pass in nsIIOService to optimize callers
michael@0 193 nsILoadGroup *loadGroup = nullptr,
michael@0 194 nsIInterfaceRequestor *callbacks = nullptr,
michael@0 195 uint32_t loadFlags = nsIRequest::LOAD_NORMAL,
michael@0 196 nsIChannelPolicy *channelPolicy = nullptr)
michael@0 197 {
michael@0 198 nsresult rv;
michael@0 199 nsCOMPtr<nsIIOService> grip;
michael@0 200 rv = net_EnsureIOService(&ioService, grip);
michael@0 201 if (ioService) {
michael@0 202 nsCOMPtr<nsIChannel> chan;
michael@0 203 rv = ioService->NewChannelFromURI(uri, getter_AddRefs(chan));
michael@0 204 if (NS_SUCCEEDED(rv)) {
michael@0 205 if (loadGroup) {
michael@0 206 rv = chan->SetLoadGroup(loadGroup);
michael@0 207 }
michael@0 208 if (callbacks) {
michael@0 209 nsresult tmp = chan->SetNotificationCallbacks(callbacks);
michael@0 210 if (NS_FAILED(tmp)) {
michael@0 211 rv = tmp;
michael@0 212 }
michael@0 213 }
michael@0 214 if (loadFlags != nsIRequest::LOAD_NORMAL) {
michael@0 215 // Retain the LOAD_REPLACE load flag if set.
michael@0 216 nsLoadFlags normalLoadFlags = 0;
michael@0 217 chan->GetLoadFlags(&normalLoadFlags);
michael@0 218 nsresult tmp = chan->SetLoadFlags(loadFlags |
michael@0 219 (normalLoadFlags &
michael@0 220 nsIChannel::LOAD_REPLACE));
michael@0 221 if (NS_FAILED(tmp)) {
michael@0 222 rv = tmp;
michael@0 223 }
michael@0 224 }
michael@0 225 if (channelPolicy) {
michael@0 226 nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(chan);
michael@0 227 if (props) {
michael@0 228 props->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
michael@0 229 channelPolicy);
michael@0 230 }
michael@0 231 }
michael@0 232 if (NS_SUCCEEDED(rv))
michael@0 233 chan.forget(result);
michael@0 234 }
michael@0 235 }
michael@0 236 return rv;
michael@0 237 }
michael@0 238
michael@0 239 // Use this function with CAUTION. It creates a stream that blocks when you
michael@0 240 // Read() from it and blocking the UI thread is a bad idea. If you don't want
michael@0 241 // to implement a full blown asynchronous consumer (via nsIStreamListener) look
michael@0 242 // at nsIStreamLoader instead.
michael@0 243 inline nsresult
michael@0 244 NS_OpenURI(nsIInputStream **result,
michael@0 245 nsIURI *uri,
michael@0 246 nsIIOService *ioService = nullptr, // pass in nsIIOService to optimize callers
michael@0 247 nsILoadGroup *loadGroup = nullptr,
michael@0 248 nsIInterfaceRequestor *callbacks = nullptr,
michael@0 249 uint32_t loadFlags = nsIRequest::LOAD_NORMAL,
michael@0 250 nsIChannel **channelOut = nullptr)
michael@0 251 {
michael@0 252 nsresult rv;
michael@0 253 nsCOMPtr<nsIChannel> channel;
michael@0 254 rv = NS_NewChannel(getter_AddRefs(channel), uri, ioService,
michael@0 255 loadGroup, callbacks, loadFlags);
michael@0 256 if (NS_SUCCEEDED(rv)) {
michael@0 257 nsIInputStream *stream;
michael@0 258 rv = channel->Open(&stream);
michael@0 259 if (NS_SUCCEEDED(rv)) {
michael@0 260 *result = stream;
michael@0 261 if (channelOut) {
michael@0 262 *channelOut = nullptr;
michael@0 263 channel.swap(*channelOut);
michael@0 264 }
michael@0 265 }
michael@0 266 }
michael@0 267 return rv;
michael@0 268 }
michael@0 269
michael@0 270 inline nsresult
michael@0 271 NS_OpenURI(nsIStreamListener *listener,
michael@0 272 nsISupports *context,
michael@0 273 nsIURI *uri,
michael@0 274 nsIIOService *ioService = nullptr, // pass in nsIIOService to optimize callers
michael@0 275 nsILoadGroup *loadGroup = nullptr,
michael@0 276 nsIInterfaceRequestor *callbacks = nullptr,
michael@0 277 uint32_t loadFlags = nsIRequest::LOAD_NORMAL)
michael@0 278 {
michael@0 279 nsresult rv;
michael@0 280 nsCOMPtr<nsIChannel> channel;
michael@0 281 rv = NS_NewChannel(getter_AddRefs(channel), uri, ioService,
michael@0 282 loadGroup, callbacks, loadFlags);
michael@0 283 if (NS_SUCCEEDED(rv))
michael@0 284 rv = channel->AsyncOpen(listener, context);
michael@0 285 return rv;
michael@0 286 }
michael@0 287
michael@0 288 inline nsresult
michael@0 289 NS_MakeAbsoluteURI(nsACString &result,
michael@0 290 const nsACString &spec,
michael@0 291 nsIURI *baseURI)
michael@0 292 {
michael@0 293 nsresult rv;
michael@0 294 if (!baseURI) {
michael@0 295 NS_WARNING("It doesn't make sense to not supply a base URI");
michael@0 296 result = spec;
michael@0 297 rv = NS_OK;
michael@0 298 }
michael@0 299 else if (spec.IsEmpty())
michael@0 300 rv = baseURI->GetSpec(result);
michael@0 301 else
michael@0 302 rv = baseURI->Resolve(spec, result);
michael@0 303 return rv;
michael@0 304 }
michael@0 305
michael@0 306 inline nsresult
michael@0 307 NS_MakeAbsoluteURI(char **result,
michael@0 308 const char *spec,
michael@0 309 nsIURI *baseURI)
michael@0 310 {
michael@0 311 nsresult rv;
michael@0 312 nsAutoCString resultBuf;
michael@0 313 rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI);
michael@0 314 if (NS_SUCCEEDED(rv)) {
michael@0 315 *result = ToNewCString(resultBuf);
michael@0 316 if (!*result)
michael@0 317 rv = NS_ERROR_OUT_OF_MEMORY;
michael@0 318 }
michael@0 319 return rv;
michael@0 320 }
michael@0 321
michael@0 322 inline nsresult
michael@0 323 NS_MakeAbsoluteURI(nsAString &result,
michael@0 324 const nsAString &spec,
michael@0 325 nsIURI *baseURI)
michael@0 326 {
michael@0 327 nsresult rv;
michael@0 328 if (!baseURI) {
michael@0 329 NS_WARNING("It doesn't make sense to not supply a base URI");
michael@0 330 result = spec;
michael@0 331 rv = NS_OK;
michael@0 332 }
michael@0 333 else {
michael@0 334 nsAutoCString resultBuf;
michael@0 335 if (spec.IsEmpty())
michael@0 336 rv = baseURI->GetSpec(resultBuf);
michael@0 337 else
michael@0 338 rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf);
michael@0 339 if (NS_SUCCEEDED(rv))
michael@0 340 CopyUTF8toUTF16(resultBuf, result);
michael@0 341 }
michael@0 342 return rv;
michael@0 343 }
michael@0 344
michael@0 345 /**
michael@0 346 * This function is a helper function to get a scheme's default port.
michael@0 347 */
michael@0 348 inline int32_t
michael@0 349 NS_GetDefaultPort(const char *scheme,
michael@0 350 nsIIOService* ioService = nullptr)
michael@0 351 {
michael@0 352 nsresult rv;
michael@0 353
michael@0 354 nsCOMPtr<nsIIOService> grip;
michael@0 355 net_EnsureIOService(&ioService, grip);
michael@0 356 if (!ioService)
michael@0 357 return -1;
michael@0 358
michael@0 359 nsCOMPtr<nsIProtocolHandler> handler;
michael@0 360 rv = ioService->GetProtocolHandler(scheme, getter_AddRefs(handler));
michael@0 361 if (NS_FAILED(rv))
michael@0 362 return -1;
michael@0 363 int32_t port;
michael@0 364 rv = handler->GetDefaultPort(&port);
michael@0 365 return NS_SUCCEEDED(rv) ? port : -1;
michael@0 366 }
michael@0 367
michael@0 368 /**
michael@0 369 * This function is a helper function to apply the ToAscii conversion
michael@0 370 * to a string
michael@0 371 */
michael@0 372 inline bool
michael@0 373 NS_StringToACE(const nsACString &idn, nsACString &result)
michael@0 374 {
michael@0 375 nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
michael@0 376 if (!idnSrv)
michael@0 377 return false;
michael@0 378 nsresult rv = idnSrv->ConvertUTF8toACE(idn, result);
michael@0 379 if (NS_FAILED(rv))
michael@0 380 return false;
michael@0 381
michael@0 382 return true;
michael@0 383 }
michael@0 384
michael@0 385 /**
michael@0 386 * This function is a helper function to get a protocol's default port if the
michael@0 387 * URI does not specify a port explicitly. Returns -1 if this protocol has no
michael@0 388 * concept of ports or if there was an error getting the port.
michael@0 389 */
michael@0 390 inline int32_t
michael@0 391 NS_GetRealPort(nsIURI* aURI)
michael@0 392 {
michael@0 393 int32_t port;
michael@0 394 nsresult rv = aURI->GetPort(&port);
michael@0 395 if (NS_FAILED(rv))
michael@0 396 return -1;
michael@0 397
michael@0 398 if (port != -1)
michael@0 399 return port; // explicitly specified
michael@0 400
michael@0 401 // Otherwise, we have to get the default port from the protocol handler
michael@0 402
michael@0 403 // Need the scheme first
michael@0 404 nsAutoCString scheme;
michael@0 405 rv = aURI->GetScheme(scheme);
michael@0 406 if (NS_FAILED(rv))
michael@0 407 return -1;
michael@0 408
michael@0 409 return NS_GetDefaultPort(scheme.get());
michael@0 410 }
michael@0 411
michael@0 412 inline nsresult
michael@0 413 NS_NewInputStreamChannel(nsIChannel **result,
michael@0 414 nsIURI *uri,
michael@0 415 nsIInputStream *stream,
michael@0 416 const nsACString &contentType,
michael@0 417 const nsACString *contentCharset)
michael@0 418 {
michael@0 419 nsresult rv;
michael@0 420 nsCOMPtr<nsIInputStreamChannel> isc =
michael@0 421 do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
michael@0 422 if (NS_FAILED(rv))
michael@0 423 return rv;
michael@0 424 rv = isc->SetURI(uri);
michael@0 425 nsresult tmp = isc->SetContentStream(stream);
michael@0 426 if (NS_FAILED(tmp)) {
michael@0 427 rv = tmp;
michael@0 428 }
michael@0 429 if (NS_FAILED(rv))
michael@0 430 return rv;
michael@0 431 nsCOMPtr<nsIChannel> chan = do_QueryInterface(isc, &rv);
michael@0 432 if (NS_FAILED(rv))
michael@0 433 return rv;
michael@0 434 if (!contentType.IsEmpty())
michael@0 435 rv = chan->SetContentType(contentType);
michael@0 436 if (contentCharset && !contentCharset->IsEmpty()) {
michael@0 437 tmp = chan->SetContentCharset(*contentCharset);
michael@0 438 if (NS_FAILED(tmp)) {
michael@0 439 rv = tmp;
michael@0 440 }
michael@0 441 }
michael@0 442 if (NS_SUCCEEDED(rv)) {
michael@0 443 *result = nullptr;
michael@0 444 chan.swap(*result);
michael@0 445 }
michael@0 446 return rv;
michael@0 447 }
michael@0 448
michael@0 449 inline nsresult
michael@0 450 NS_NewInputStreamChannel(nsIChannel **result,
michael@0 451 nsIURI *uri,
michael@0 452 nsIInputStream *stream,
michael@0 453 const nsACString &contentType = EmptyCString())
michael@0 454 {
michael@0 455 return NS_NewInputStreamChannel(result, uri, stream, contentType, nullptr);
michael@0 456 }
michael@0 457
michael@0 458 inline nsresult
michael@0 459 NS_NewInputStreamChannel(nsIChannel **result,
michael@0 460 nsIURI *uri,
michael@0 461 nsIInputStream *stream,
michael@0 462 const nsACString &contentType,
michael@0 463 const nsACString &contentCharset)
michael@0 464 {
michael@0 465 return NS_NewInputStreamChannel(result, uri, stream, contentType,
michael@0 466 &contentCharset);
michael@0 467 }
michael@0 468
michael@0 469 inline nsresult
michael@0 470 NS_NewInputStreamChannel(nsIChannel **result,
michael@0 471 nsIURI *uri,
michael@0 472 const nsAString &data,
michael@0 473 const nsACString &contentType,
michael@0 474 bool isSrcdocChannel = false)
michael@0 475 {
michael@0 476
michael@0 477 nsresult rv;
michael@0 478
michael@0 479 nsCOMPtr<nsIStringInputStream> stream;
michael@0 480 stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
michael@0 481 NS_ENSURE_SUCCESS(rv, rv);
michael@0 482
michael@0 483 #ifdef MOZILLA_INTERNAL_API
michael@0 484 uint32_t len;
michael@0 485 char* utf8Bytes = ToNewUTF8String(data, &len);
michael@0 486 rv = stream->AdoptData(utf8Bytes, len);
michael@0 487 #else
michael@0 488 char* utf8Bytes = ToNewUTF8String(data);
michael@0 489 rv = stream->AdoptData(utf8Bytes, strlen(utf8Bytes));
michael@0 490 #endif
michael@0 491
michael@0 492 nsCOMPtr<nsIChannel> chan;
michael@0 493
michael@0 494 rv = NS_NewInputStreamChannel(getter_AddRefs(chan), uri, stream,
michael@0 495 contentType, NS_LITERAL_CSTRING("UTF-8"));
michael@0 496 NS_ENSURE_SUCCESS(rv, rv);
michael@0 497
michael@0 498 if (isSrcdocChannel) {
michael@0 499 nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(chan);
michael@0 500 NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE);
michael@0 501 inStrmChan->SetSrcdocData(data);
michael@0 502 }
michael@0 503
michael@0 504 *result = nullptr;
michael@0 505 chan.swap(*result);
michael@0 506
michael@0 507 return NS_OK;
michael@0 508 }
michael@0 509
michael@0 510 inline nsresult
michael@0 511 NS_NewInputStreamPump(nsIInputStreamPump **result,
michael@0 512 nsIInputStream *stream,
michael@0 513 int64_t streamPos = int64_t(-1),
michael@0 514 int64_t streamLen = int64_t(-1),
michael@0 515 uint32_t segsize = 0,
michael@0 516 uint32_t segcount = 0,
michael@0 517 bool closeWhenDone = false)
michael@0 518 {
michael@0 519 nsresult rv;
michael@0 520 nsCOMPtr<nsIInputStreamPump> pump =
michael@0 521 do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
michael@0 522 if (NS_SUCCEEDED(rv)) {
michael@0 523 rv = pump->Init(stream, streamPos, streamLen,
michael@0 524 segsize, segcount, closeWhenDone);
michael@0 525 if (NS_SUCCEEDED(rv)) {
michael@0 526 *result = nullptr;
michael@0 527 pump.swap(*result);
michael@0 528 }
michael@0 529 }
michael@0 530 return rv;
michael@0 531 }
michael@0 532
michael@0 533 // NOTE: you will need to specify whether or not your streams are buffered
michael@0 534 // (i.e., do they implement ReadSegments/WriteSegments). the default
michael@0 535 // assumption of TRUE for both streams might not be right for you!
michael@0 536 inline nsresult
michael@0 537 NS_NewAsyncStreamCopier(nsIAsyncStreamCopier **result,
michael@0 538 nsIInputStream *source,
michael@0 539 nsIOutputStream *sink,
michael@0 540 nsIEventTarget *target,
michael@0 541 bool sourceBuffered = true,
michael@0 542 bool sinkBuffered = true,
michael@0 543 uint32_t chunkSize = 0,
michael@0 544 bool closeSource = true,
michael@0 545 bool closeSink = true)
michael@0 546 {
michael@0 547 nsresult rv;
michael@0 548 nsCOMPtr<nsIAsyncStreamCopier> copier =
michael@0 549 do_CreateInstance(NS_ASYNCSTREAMCOPIER_CONTRACTID, &rv);
michael@0 550 if (NS_SUCCEEDED(rv)) {
michael@0 551 rv = copier->Init(source, sink, target, sourceBuffered, sinkBuffered,
michael@0 552 chunkSize, closeSource, closeSink);
michael@0 553 if (NS_SUCCEEDED(rv)) {
michael@0 554 *result = nullptr;
michael@0 555 copier.swap(*result);
michael@0 556 }
michael@0 557 }
michael@0 558 return rv;
michael@0 559 }
michael@0 560
michael@0 561 inline nsresult
michael@0 562 NS_NewLoadGroup(nsILoadGroup **result,
michael@0 563 nsIRequestObserver *obs)
michael@0 564 {
michael@0 565 nsresult rv;
michael@0 566 nsCOMPtr<nsILoadGroup> group =
michael@0 567 do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
michael@0 568 if (NS_SUCCEEDED(rv)) {
michael@0 569 rv = group->SetGroupObserver(obs);
michael@0 570 if (NS_SUCCEEDED(rv)) {
michael@0 571 *result = nullptr;
michael@0 572 group.swap(*result);
michael@0 573 }
michael@0 574 }
michael@0 575 return rv;
michael@0 576 }
michael@0 577
michael@0 578 inline nsresult
michael@0 579 NS_NewDownloader(nsIStreamListener **result,
michael@0 580 nsIDownloadObserver *observer,
michael@0 581 nsIFile *downloadLocation = nullptr)
michael@0 582 {
michael@0 583 nsresult rv;
michael@0 584 nsCOMPtr<nsIDownloader> downloader =
michael@0 585 do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv);
michael@0 586 if (NS_SUCCEEDED(rv)) {
michael@0 587 rv = downloader->Init(observer, downloadLocation);
michael@0 588 if (NS_SUCCEEDED(rv))
michael@0 589 NS_ADDREF(*result = downloader);
michael@0 590 }
michael@0 591 return rv;
michael@0 592 }
michael@0 593
michael@0 594 inline nsresult
michael@0 595 NS_NewStreamLoader(nsIStreamLoader **result,
michael@0 596 nsIStreamLoaderObserver *observer)
michael@0 597 {
michael@0 598 nsresult rv;
michael@0 599 nsCOMPtr<nsIStreamLoader> loader =
michael@0 600 do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv);
michael@0 601 if (NS_SUCCEEDED(rv)) {
michael@0 602 rv = loader->Init(observer);
michael@0 603 if (NS_SUCCEEDED(rv)) {
michael@0 604 *result = nullptr;
michael@0 605 loader.swap(*result);
michael@0 606 }
michael@0 607 }
michael@0 608 return rv;
michael@0 609 }
michael@0 610
michael@0 611 inline nsresult
michael@0 612 NS_NewStreamLoader(nsIStreamLoader **result,
michael@0 613 nsIURI *uri,
michael@0 614 nsIStreamLoaderObserver *observer,
michael@0 615 nsISupports *context = nullptr,
michael@0 616 nsILoadGroup *loadGroup = nullptr,
michael@0 617 nsIInterfaceRequestor *callbacks = nullptr,
michael@0 618 uint32_t loadFlags = nsIRequest::LOAD_NORMAL,
michael@0 619 nsIURI *referrer = nullptr)
michael@0 620 {
michael@0 621 nsresult rv;
michael@0 622 nsCOMPtr<nsIChannel> channel;
michael@0 623 rv = NS_NewChannel(getter_AddRefs(channel),
michael@0 624 uri,
michael@0 625 nullptr,
michael@0 626 loadGroup,
michael@0 627 callbacks,
michael@0 628 loadFlags);
michael@0 629 if (NS_SUCCEEDED(rv)) {
michael@0 630 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
michael@0 631 if (httpChannel)
michael@0 632 httpChannel->SetReferrer(referrer);
michael@0 633 rv = NS_NewStreamLoader(result, observer);
michael@0 634 if (NS_SUCCEEDED(rv))
michael@0 635 rv = channel->AsyncOpen(*result, context);
michael@0 636 }
michael@0 637 return rv;
michael@0 638 }
michael@0 639
michael@0 640 inline nsresult
michael@0 641 NS_NewUnicharStreamLoader(nsIUnicharStreamLoader **result,
michael@0 642 nsIUnicharStreamLoaderObserver *observer)
michael@0 643 {
michael@0 644 nsresult rv;
michael@0 645 nsCOMPtr<nsIUnicharStreamLoader> loader =
michael@0 646 do_CreateInstance(NS_UNICHARSTREAMLOADER_CONTRACTID, &rv);
michael@0 647 if (NS_SUCCEEDED(rv)) {
michael@0 648 rv = loader->Init(observer);
michael@0 649 if (NS_SUCCEEDED(rv)) {
michael@0 650 *result = nullptr;
michael@0 651 loader.swap(*result);
michael@0 652 }
michael@0 653 }
michael@0 654 return rv;
michael@0 655 }
michael@0 656
michael@0 657 inline nsresult
michael@0 658 NS_NewSyncStreamListener(nsIStreamListener **result,
michael@0 659 nsIInputStream **stream)
michael@0 660 {
michael@0 661 nsresult rv;
michael@0 662 nsCOMPtr<nsISyncStreamListener> listener =
michael@0 663 do_CreateInstance(NS_SYNCSTREAMLISTENER_CONTRACTID, &rv);
michael@0 664 if (NS_SUCCEEDED(rv)) {
michael@0 665 rv = listener->GetInputStream(stream);
michael@0 666 if (NS_SUCCEEDED(rv))
michael@0 667 NS_ADDREF(*result = listener); // cannot use nsCOMPtr::swap
michael@0 668 }
michael@0 669 return rv;
michael@0 670 }
michael@0 671
michael@0 672 /**
michael@0 673 * Implement the nsIChannel::Open(nsIInputStream**) method using the channel's
michael@0 674 * AsyncOpen method.
michael@0 675 *
michael@0 676 * NOTE: Reading from the returned nsIInputStream may spin the current
michael@0 677 * thread's event queue, which could result in any event being processed.
michael@0 678 */
michael@0 679 inline nsresult
michael@0 680 NS_ImplementChannelOpen(nsIChannel *channel,
michael@0 681 nsIInputStream **result)
michael@0 682 {
michael@0 683 nsCOMPtr<nsIStreamListener> listener;
michael@0 684 nsCOMPtr<nsIInputStream> stream;
michael@0 685 nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener),
michael@0 686 getter_AddRefs(stream));
michael@0 687 if (NS_SUCCEEDED(rv)) {
michael@0 688 rv = channel->AsyncOpen(listener, nullptr);
michael@0 689 if (NS_SUCCEEDED(rv)) {
michael@0 690 uint64_t n;
michael@0 691 // block until the initial response is received or an error occurs.
michael@0 692 rv = stream->Available(&n);
michael@0 693 if (NS_SUCCEEDED(rv)) {
michael@0 694 *result = nullptr;
michael@0 695 stream.swap(*result);
michael@0 696 }
michael@0 697 }
michael@0 698 }
michael@0 699 return rv;
michael@0 700 }
michael@0 701
michael@0 702 inline nsresult
michael@0 703 NS_NewRequestObserverProxy(nsIRequestObserver **result,
michael@0 704 nsIRequestObserver *observer,
michael@0 705 nsISupports *context)
michael@0 706 {
michael@0 707 nsresult rv;
michael@0 708 nsCOMPtr<nsIRequestObserverProxy> proxy =
michael@0 709 do_CreateInstance(NS_REQUESTOBSERVERPROXY_CONTRACTID, &rv);
michael@0 710 if (NS_SUCCEEDED(rv)) {
michael@0 711 rv = proxy->Init(observer, context);
michael@0 712 if (NS_SUCCEEDED(rv))
michael@0 713 NS_ADDREF(*result = proxy); // cannot use nsCOMPtr::swap
michael@0 714 }
michael@0 715 return rv;
michael@0 716 }
michael@0 717
michael@0 718 inline nsresult
michael@0 719 NS_NewSimpleStreamListener(nsIStreamListener **result,
michael@0 720 nsIOutputStream *sink,
michael@0 721 nsIRequestObserver *observer = nullptr)
michael@0 722 {
michael@0 723 nsresult rv;
michael@0 724 nsCOMPtr<nsISimpleStreamListener> listener =
michael@0 725 do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv);
michael@0 726 if (NS_SUCCEEDED(rv)) {
michael@0 727 rv = listener->Init(sink, observer);
michael@0 728 if (NS_SUCCEEDED(rv))
michael@0 729 NS_ADDREF(*result = listener); // cannot use nsCOMPtr::swap
michael@0 730 }
michael@0 731 return rv;
michael@0 732 }
michael@0 733
michael@0 734 inline nsresult
michael@0 735 NS_CheckPortSafety(int32_t port,
michael@0 736 const char *scheme,
michael@0 737 nsIIOService *ioService = nullptr)
michael@0 738 {
michael@0 739 nsresult rv;
michael@0 740 nsCOMPtr<nsIIOService> grip;
michael@0 741 rv = net_EnsureIOService(&ioService, grip);
michael@0 742 if (ioService) {
michael@0 743 bool allow;
michael@0 744 rv = ioService->AllowPort(port, scheme, &allow);
michael@0 745 if (NS_SUCCEEDED(rv) && !allow) {
michael@0 746 NS_WARNING("port blocked");
michael@0 747 rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED;
michael@0 748 }
michael@0 749 }
michael@0 750 return rv;
michael@0 751 }
michael@0 752
michael@0 753 // Determine if this URI is using a safe port.
michael@0 754 inline nsresult
michael@0 755 NS_CheckPortSafety(nsIURI *uri) {
michael@0 756 int32_t port;
michael@0 757 nsresult rv = uri->GetPort(&port);
michael@0 758 if (NS_FAILED(rv) || port == -1) // port undefined or default-valued
michael@0 759 return NS_OK;
michael@0 760 nsAutoCString scheme;
michael@0 761 uri->GetScheme(scheme);
michael@0 762 return NS_CheckPortSafety(port, scheme.get());
michael@0 763 }
michael@0 764
michael@0 765 inline nsresult
michael@0 766 NS_NewProxyInfo(const nsACString &type,
michael@0 767 const nsACString &host,
michael@0 768 int32_t port,
michael@0 769 uint32_t flags,
michael@0 770 nsIProxyInfo **result)
michael@0 771 {
michael@0 772 nsresult rv;
michael@0 773 nsCOMPtr<nsIProtocolProxyService> pps =
michael@0 774 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
michael@0 775 if (NS_SUCCEEDED(rv))
michael@0 776 rv = pps->NewProxyInfo(type, host, port, flags, UINT32_MAX, nullptr,
michael@0 777 result);
michael@0 778 return rv;
michael@0 779 }
michael@0 780
michael@0 781 inline nsresult
michael@0 782 NS_GetFileProtocolHandler(nsIFileProtocolHandler **result,
michael@0 783 nsIIOService *ioService = nullptr)
michael@0 784 {
michael@0 785 nsresult rv;
michael@0 786 nsCOMPtr<nsIIOService> grip;
michael@0 787 rv = net_EnsureIOService(&ioService, grip);
michael@0 788 if (ioService) {
michael@0 789 nsCOMPtr<nsIProtocolHandler> handler;
michael@0 790 rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler));
michael@0 791 if (NS_SUCCEEDED(rv))
michael@0 792 rv = CallQueryInterface(handler, result);
michael@0 793 }
michael@0 794 return rv;
michael@0 795 }
michael@0 796
michael@0 797 inline nsresult
michael@0 798 NS_GetFileFromURLSpec(const nsACString &inURL,
michael@0 799 nsIFile **result,
michael@0 800 nsIIOService *ioService = nullptr)
michael@0 801 {
michael@0 802 nsresult rv;
michael@0 803 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
michael@0 804 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
michael@0 805 if (NS_SUCCEEDED(rv))
michael@0 806 rv = fileHandler->GetFileFromURLSpec(inURL, result);
michael@0 807 return rv;
michael@0 808 }
michael@0 809
michael@0 810 inline nsresult
michael@0 811 NS_GetURLSpecFromFile(nsIFile *file,
michael@0 812 nsACString &url,
michael@0 813 nsIIOService *ioService = nullptr)
michael@0 814 {
michael@0 815 nsresult rv;
michael@0 816 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
michael@0 817 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
michael@0 818 if (NS_SUCCEEDED(rv))
michael@0 819 rv = fileHandler->GetURLSpecFromFile(file, url);
michael@0 820 return rv;
michael@0 821 }
michael@0 822
michael@0 823 /**
michael@0 824 * Converts the nsIFile to the corresponding URL string.
michael@0 825 * Should only be called on files which are not directories,
michael@0 826 * is otherwise identical to NS_GetURLSpecFromFile, but is
michael@0 827 * usually more efficient.
michael@0 828 * Warning: this restriction may not be enforced at runtime!
michael@0 829 */
michael@0 830 inline nsresult
michael@0 831 NS_GetURLSpecFromActualFile(nsIFile *file,
michael@0 832 nsACString &url,
michael@0 833 nsIIOService *ioService = nullptr)
michael@0 834 {
michael@0 835 nsresult rv;
michael@0 836 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
michael@0 837 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
michael@0 838 if (NS_SUCCEEDED(rv))
michael@0 839 rv = fileHandler->GetURLSpecFromActualFile(file, url);
michael@0 840 return rv;
michael@0 841 }
michael@0 842
michael@0 843 /**
michael@0 844 * Converts the nsIFile to the corresponding URL string.
michael@0 845 * Should only be called on files which are directories,
michael@0 846 * is otherwise identical to NS_GetURLSpecFromFile, but is
michael@0 847 * usually more efficient.
michael@0 848 * Warning: this restriction may not be enforced at runtime!
michael@0 849 */
michael@0 850 inline nsresult
michael@0 851 NS_GetURLSpecFromDir(nsIFile *file,
michael@0 852 nsACString &url,
michael@0 853 nsIIOService *ioService = nullptr)
michael@0 854 {
michael@0 855 nsresult rv;
michael@0 856 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
michael@0 857 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
michael@0 858 if (NS_SUCCEEDED(rv))
michael@0 859 rv = fileHandler->GetURLSpecFromDir(file, url);
michael@0 860 return rv;
michael@0 861 }
michael@0 862
michael@0 863 /**
michael@0 864 * Obtains the referrer for a given channel. This first tries to obtain the
michael@0 865 * referrer from the property docshell.internalReferrer, and if that doesn't
michael@0 866 * work and the channel is an nsIHTTPChannel, we check it's referrer property.
michael@0 867 *
michael@0 868 * @returns NS_ERROR_NOT_AVAILABLE if no referrer is available.
michael@0 869 */
michael@0 870 inline nsresult
michael@0 871 NS_GetReferrerFromChannel(nsIChannel *channel,
michael@0 872 nsIURI **referrer)
michael@0 873 {
michael@0 874 nsresult rv = NS_ERROR_NOT_AVAILABLE;
michael@0 875 *referrer = nullptr;
michael@0 876
michael@0 877 nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel));
michael@0 878 if (props) {
michael@0 879 // We have to check for a property on a property bag because the
michael@0 880 // referrer may be empty for security reasons (for example, when loading
michael@0 881 // an http page with an https referrer).
michael@0 882 rv = props->GetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
michael@0 883 NS_GET_IID(nsIURI),
michael@0 884 reinterpret_cast<void **>(referrer));
michael@0 885 if (NS_FAILED(rv))
michael@0 886 *referrer = nullptr;
michael@0 887 }
michael@0 888
michael@0 889 // if that didn't work, we can still try to get the referrer from the
michael@0 890 // nsIHttpChannel (if we can QI to it)
michael@0 891 if (!(*referrer)) {
michael@0 892 nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel));
michael@0 893 if (chan) {
michael@0 894 rv = chan->GetReferrer(referrer);
michael@0 895 if (NS_FAILED(rv))
michael@0 896 *referrer = nullptr;
michael@0 897 }
michael@0 898 }
michael@0 899 return rv;
michael@0 900 }
michael@0 901
michael@0 902 inline nsresult
michael@0 903 NS_ParseContentType(const nsACString &rawContentType,
michael@0 904 nsCString &contentType,
michael@0 905 nsCString &contentCharset)
michael@0 906 {
michael@0 907 // contentCharset is left untouched if not present in rawContentType
michael@0 908 nsresult rv;
michael@0 909 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
michael@0 910 NS_ENSURE_SUCCESS(rv, rv);
michael@0 911 nsCString charset;
michael@0 912 bool hadCharset;
michael@0 913 rv = util->ParseContentType(rawContentType, charset, &hadCharset,
michael@0 914 contentType);
michael@0 915 if (NS_SUCCEEDED(rv) && hadCharset)
michael@0 916 contentCharset = charset;
michael@0 917 return rv;
michael@0 918 }
michael@0 919
michael@0 920 inline nsresult
michael@0 921 NS_ExtractCharsetFromContentType(const nsACString &rawContentType,
michael@0 922 nsCString &contentCharset,
michael@0 923 bool *hadCharset,
michael@0 924 int32_t *charsetStart,
michael@0 925 int32_t *charsetEnd)
michael@0 926 {
michael@0 927 // contentCharset is left untouched if not present in rawContentType
michael@0 928 nsresult rv;
michael@0 929 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
michael@0 930 NS_ENSURE_SUCCESS(rv, rv);
michael@0 931
michael@0 932 return util->ExtractCharsetFromContentType(rawContentType,
michael@0 933 contentCharset,
michael@0 934 charsetStart,
michael@0 935 charsetEnd,
michael@0 936 hadCharset);
michael@0 937 }
michael@0 938
michael@0 939 inline nsresult
michael@0 940 NS_NewLocalFileInputStream(nsIInputStream **result,
michael@0 941 nsIFile *file,
michael@0 942 int32_t ioFlags = -1,
michael@0 943 int32_t perm = -1,
michael@0 944 int32_t behaviorFlags = 0)
michael@0 945 {
michael@0 946 nsresult rv;
michael@0 947 nsCOMPtr<nsIFileInputStream> in =
michael@0 948 do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
michael@0 949 if (NS_SUCCEEDED(rv)) {
michael@0 950 rv = in->Init(file, ioFlags, perm, behaviorFlags);
michael@0 951 if (NS_SUCCEEDED(rv))
michael@0 952 in.forget(result);
michael@0 953 }
michael@0 954 return rv;
michael@0 955 }
michael@0 956
michael@0 957 inline nsresult
michael@0 958 NS_NewPartialLocalFileInputStream(nsIInputStream **result,
michael@0 959 nsIFile *file,
michael@0 960 uint64_t offset,
michael@0 961 uint64_t length,
michael@0 962 int32_t ioFlags = -1,
michael@0 963 int32_t perm = -1,
michael@0 964 int32_t behaviorFlags = 0)
michael@0 965 {
michael@0 966 nsresult rv;
michael@0 967 nsCOMPtr<nsIPartialFileInputStream> in =
michael@0 968 do_CreateInstance(NS_PARTIALLOCALFILEINPUTSTREAM_CONTRACTID, &rv);
michael@0 969 if (NS_SUCCEEDED(rv)) {
michael@0 970 rv = in->Init(file, offset, length, ioFlags, perm, behaviorFlags);
michael@0 971 if (NS_SUCCEEDED(rv))
michael@0 972 rv = CallQueryInterface(in, result);
michael@0 973 }
michael@0 974 return rv;
michael@0 975 }
michael@0 976
michael@0 977 inline nsresult
michael@0 978 NS_NewLocalFileOutputStream(nsIOutputStream **result,
michael@0 979 nsIFile *file,
michael@0 980 int32_t ioFlags = -1,
michael@0 981 int32_t perm = -1,
michael@0 982 int32_t behaviorFlags = 0)
michael@0 983 {
michael@0 984 nsresult rv;
michael@0 985 nsCOMPtr<nsIFileOutputStream> out =
michael@0 986 do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
michael@0 987 if (NS_SUCCEEDED(rv)) {
michael@0 988 rv = out->Init(file, ioFlags, perm, behaviorFlags);
michael@0 989 if (NS_SUCCEEDED(rv))
michael@0 990 out.forget(result);
michael@0 991 }
michael@0 992 return rv;
michael@0 993 }
michael@0 994
michael@0 995 // returns a file output stream which can be QI'ed to nsISafeOutputStream.
michael@0 996 inline nsresult
michael@0 997 NS_NewAtomicFileOutputStream(nsIOutputStream **result,
michael@0 998 nsIFile *file,
michael@0 999 int32_t ioFlags = -1,
michael@0 1000 int32_t perm = -1,
michael@0 1001 int32_t behaviorFlags = 0)
michael@0 1002 {
michael@0 1003 nsresult rv;
michael@0 1004 nsCOMPtr<nsIFileOutputStream> out =
michael@0 1005 do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
michael@0 1006 if (NS_SUCCEEDED(rv)) {
michael@0 1007 rv = out->Init(file, ioFlags, perm, behaviorFlags);
michael@0 1008 if (NS_SUCCEEDED(rv))
michael@0 1009 out.forget(result);
michael@0 1010 }
michael@0 1011 return rv;
michael@0 1012 }
michael@0 1013
michael@0 1014 // returns a file output stream which can be QI'ed to nsISafeOutputStream.
michael@0 1015 inline nsresult
michael@0 1016 NS_NewSafeLocalFileOutputStream(nsIOutputStream **result,
michael@0 1017 nsIFile *file,
michael@0 1018 int32_t ioFlags = -1,
michael@0 1019 int32_t perm = -1,
michael@0 1020 int32_t behaviorFlags = 0)
michael@0 1021 {
michael@0 1022 nsresult rv;
michael@0 1023 nsCOMPtr<nsIFileOutputStream> out =
michael@0 1024 do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
michael@0 1025 if (NS_SUCCEEDED(rv)) {
michael@0 1026 rv = out->Init(file, ioFlags, perm, behaviorFlags);
michael@0 1027 if (NS_SUCCEEDED(rv))
michael@0 1028 out.forget(result);
michael@0 1029 }
michael@0 1030 return rv;
michael@0 1031 }
michael@0 1032
michael@0 1033 inline nsresult
michael@0 1034 NS_NewLocalFileStream(nsIFileStream **result,
michael@0 1035 nsIFile *file,
michael@0 1036 int32_t ioFlags = -1,
michael@0 1037 int32_t perm = -1,
michael@0 1038 int32_t behaviorFlags = 0)
michael@0 1039 {
michael@0 1040 nsresult rv;
michael@0 1041 nsCOMPtr<nsIFileStream> stream =
michael@0 1042 do_CreateInstance(NS_LOCALFILESTREAM_CONTRACTID, &rv);
michael@0 1043 if (NS_SUCCEEDED(rv)) {
michael@0 1044 rv = stream->Init(file, ioFlags, perm, behaviorFlags);
michael@0 1045 if (NS_SUCCEEDED(rv))
michael@0 1046 stream.forget(result);
michael@0 1047 }
michael@0 1048 return rv;
michael@0 1049 }
michael@0 1050
michael@0 1051 // returns the input end of a pipe. the output end of the pipe
michael@0 1052 // is attached to the original stream. data from the original
michael@0 1053 // stream is read into the pipe on a background thread.
michael@0 1054 inline nsresult
michael@0 1055 NS_BackgroundInputStream(nsIInputStream **result,
michael@0 1056 nsIInputStream *stream,
michael@0 1057 uint32_t segmentSize = 0,
michael@0 1058 uint32_t segmentCount = 0)
michael@0 1059 {
michael@0 1060 nsresult rv;
michael@0 1061 nsCOMPtr<nsIStreamTransportService> sts =
michael@0 1062 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
michael@0 1063 if (NS_SUCCEEDED(rv)) {
michael@0 1064 nsCOMPtr<nsITransport> inTransport;
michael@0 1065 rv = sts->CreateInputTransport(stream, int64_t(-1), int64_t(-1),
michael@0 1066 true, getter_AddRefs(inTransport));
michael@0 1067 if (NS_SUCCEEDED(rv))
michael@0 1068 rv = inTransport->OpenInputStream(nsITransport::OPEN_BLOCKING,
michael@0 1069 segmentSize, segmentCount,
michael@0 1070 result);
michael@0 1071 }
michael@0 1072 return rv;
michael@0 1073 }
michael@0 1074
michael@0 1075 // returns the output end of a pipe. the input end of the pipe
michael@0 1076 // is attached to the original stream. data written to the pipe
michael@0 1077 // is copied to the original stream on a background thread.
michael@0 1078 inline nsresult
michael@0 1079 NS_BackgroundOutputStream(nsIOutputStream **result,
michael@0 1080 nsIOutputStream *stream,
michael@0 1081 uint32_t segmentSize = 0,
michael@0 1082 uint32_t segmentCount = 0)
michael@0 1083 {
michael@0 1084 nsresult rv;
michael@0 1085 nsCOMPtr<nsIStreamTransportService> sts =
michael@0 1086 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
michael@0 1087 if (NS_SUCCEEDED(rv)) {
michael@0 1088 nsCOMPtr<nsITransport> inTransport;
michael@0 1089 rv = sts->CreateOutputTransport(stream, int64_t(-1), int64_t(-1),
michael@0 1090 true, getter_AddRefs(inTransport));
michael@0 1091 if (NS_SUCCEEDED(rv))
michael@0 1092 rv = inTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING,
michael@0 1093 segmentSize, segmentCount,
michael@0 1094 result);
michael@0 1095 }
michael@0 1096 return rv;
michael@0 1097 }
michael@0 1098
michael@0 1099 MOZ_WARN_UNUSED_RESULT inline nsresult
michael@0 1100 NS_NewBufferedInputStream(nsIInputStream **result,
michael@0 1101 nsIInputStream *str,
michael@0 1102 uint32_t bufferSize)
michael@0 1103 {
michael@0 1104 nsresult rv;
michael@0 1105 nsCOMPtr<nsIBufferedInputStream> in =
michael@0 1106 do_CreateInstance(NS_BUFFEREDINPUTSTREAM_CONTRACTID, &rv);
michael@0 1107 if (NS_SUCCEEDED(rv)) {
michael@0 1108 rv = in->Init(str, bufferSize);
michael@0 1109 if (NS_SUCCEEDED(rv))
michael@0 1110 NS_ADDREF(*result = in); // cannot use nsCOMPtr::swap
michael@0 1111 }
michael@0 1112 return rv;
michael@0 1113 }
michael@0 1114
michael@0 1115 // note: the resulting stream can be QI'ed to nsISafeOutputStream iff the
michael@0 1116 // provided stream supports it.
michael@0 1117 inline nsresult
michael@0 1118 NS_NewBufferedOutputStream(nsIOutputStream **result,
michael@0 1119 nsIOutputStream *str,
michael@0 1120 uint32_t bufferSize)
michael@0 1121 {
michael@0 1122 nsresult rv;
michael@0 1123 nsCOMPtr<nsIBufferedOutputStream> out =
michael@0 1124 do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
michael@0 1125 if (NS_SUCCEEDED(rv)) {
michael@0 1126 rv = out->Init(str, bufferSize);
michael@0 1127 if (NS_SUCCEEDED(rv))
michael@0 1128 NS_ADDREF(*result = out); // cannot use nsCOMPtr::swap
michael@0 1129 }
michael@0 1130 return rv;
michael@0 1131 }
michael@0 1132
michael@0 1133 /**
michael@0 1134 * Attempts to buffer a given output stream. If this fails, it returns the
michael@0 1135 * passed-in output stream.
michael@0 1136 *
michael@0 1137 * @param aOutputStream
michael@0 1138 * The output stream we want to buffer. This cannot be null.
michael@0 1139 * @param aBufferSize
michael@0 1140 * The size of the buffer for the buffered output stream.
michael@0 1141 * @returns an nsIOutputStream that is buffered with the specified buffer size,
michael@0 1142 * or is aOutputStream if creating the new buffered stream failed.
michael@0 1143 */
michael@0 1144 inline already_AddRefed<nsIOutputStream>
michael@0 1145 NS_BufferOutputStream(nsIOutputStream *aOutputStream,
michael@0 1146 uint32_t aBufferSize)
michael@0 1147 {
michael@0 1148 NS_ASSERTION(aOutputStream, "No output stream given!");
michael@0 1149
michael@0 1150 nsCOMPtr<nsIOutputStream> bos;
michael@0 1151 nsresult rv = NS_NewBufferedOutputStream(getter_AddRefs(bos), aOutputStream,
michael@0 1152 aBufferSize);
michael@0 1153 if (NS_SUCCEEDED(rv))
michael@0 1154 return bos.forget();
michael@0 1155
michael@0 1156 bos = aOutputStream;
michael@0 1157 return bos.forget();
michael@0 1158 }
michael@0 1159
michael@0 1160 // returns an input stream compatible with nsIUploadChannel::SetUploadStream()
michael@0 1161 inline nsresult
michael@0 1162 NS_NewPostDataStream(nsIInputStream **result,
michael@0 1163 bool isFile,
michael@0 1164 const nsACString &data)
michael@0 1165 {
michael@0 1166 nsresult rv;
michael@0 1167
michael@0 1168 if (isFile) {
michael@0 1169 nsCOMPtr<nsIFile> file;
michael@0 1170 nsCOMPtr<nsIInputStream> fileStream;
michael@0 1171
michael@0 1172 rv = NS_NewNativeLocalFile(data, false, getter_AddRefs(file));
michael@0 1173 if (NS_SUCCEEDED(rv)) {
michael@0 1174 rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file);
michael@0 1175 if (NS_SUCCEEDED(rv)) {
michael@0 1176 // wrap the file stream with a buffered input stream
michael@0 1177 rv = NS_NewBufferedInputStream(result, fileStream, 8192);
michael@0 1178 }
michael@0 1179 }
michael@0 1180 return rv;
michael@0 1181 }
michael@0 1182
michael@0 1183 // otherwise, create a string stream for the data (copies)
michael@0 1184 nsCOMPtr<nsIStringInputStream> stream
michael@0 1185 (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv));
michael@0 1186 if (NS_FAILED(rv))
michael@0 1187 return rv;
michael@0 1188
michael@0 1189 rv = stream->SetData(data.BeginReading(), data.Length());
michael@0 1190 if (NS_FAILED(rv))
michael@0 1191 return rv;
michael@0 1192
michael@0 1193 NS_ADDREF(*result = stream);
michael@0 1194 return NS_OK;
michael@0 1195 }
michael@0 1196
michael@0 1197 inline nsresult
michael@0 1198 NS_ReadInputStreamToBuffer(nsIInputStream *aInputStream,
michael@0 1199 void** aDest,
michael@0 1200 uint32_t aCount)
michael@0 1201 {
michael@0 1202 nsresult rv;
michael@0 1203
michael@0 1204 if (!*aDest) {
michael@0 1205 *aDest = malloc(aCount);
michael@0 1206 if (!*aDest)
michael@0 1207 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1208 }
michael@0 1209
michael@0 1210 char * p = reinterpret_cast<char*>(*aDest);
michael@0 1211 uint32_t bytesRead;
michael@0 1212 uint32_t totalRead = 0;
michael@0 1213 while (1) {
michael@0 1214 rv = aInputStream->Read(p + totalRead, aCount - totalRead, &bytesRead);
michael@0 1215 if (!NS_SUCCEEDED(rv))
michael@0 1216 return rv;
michael@0 1217 totalRead += bytesRead;
michael@0 1218 if (totalRead == aCount)
michael@0 1219 break;
michael@0 1220 // if Read reads 0 bytes, we've hit EOF
michael@0 1221 if (bytesRead == 0)
michael@0 1222 return NS_ERROR_UNEXPECTED;
michael@0 1223 }
michael@0 1224 return rv;
michael@0 1225 }
michael@0 1226
michael@0 1227 // external code can't see fallible_t
michael@0 1228 #ifdef MOZILLA_INTERNAL_API
michael@0 1229
michael@0 1230 inline nsresult
michael@0 1231 NS_ReadInputStreamToString(nsIInputStream *aInputStream,
michael@0 1232 nsACString &aDest,
michael@0 1233 uint32_t aCount)
michael@0 1234 {
michael@0 1235 if (!aDest.SetLength(aCount, mozilla::fallible_t()))
michael@0 1236 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1237 void* dest = aDest.BeginWriting();
michael@0 1238 return NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount);
michael@0 1239 }
michael@0 1240
michael@0 1241 #endif
michael@0 1242
michael@0 1243 inline nsresult
michael@0 1244 NS_LoadPersistentPropertiesFromURI(nsIPersistentProperties **result,
michael@0 1245 nsIURI *uri,
michael@0 1246 nsIIOService *ioService = nullptr)
michael@0 1247 {
michael@0 1248 nsCOMPtr<nsIInputStream> in;
michael@0 1249 nsresult rv = NS_OpenURI(getter_AddRefs(in), uri, ioService);
michael@0 1250 if (NS_SUCCEEDED(rv)) {
michael@0 1251 nsCOMPtr<nsIPersistentProperties> properties =
michael@0 1252 do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID, &rv);
michael@0 1253 if (NS_SUCCEEDED(rv)) {
michael@0 1254 rv = properties->Load(in);
michael@0 1255 if (NS_SUCCEEDED(rv)) {
michael@0 1256 *result = nullptr;
michael@0 1257 properties.swap(*result);
michael@0 1258 }
michael@0 1259 }
michael@0 1260 }
michael@0 1261 return rv;
michael@0 1262 }
michael@0 1263
michael@0 1264 inline nsresult
michael@0 1265 NS_LoadPersistentPropertiesFromURISpec(nsIPersistentProperties **result,
michael@0 1266 const nsACString &spec,
michael@0 1267 const char *charset = nullptr,
michael@0 1268 nsIURI *baseURI = nullptr,
michael@0 1269 nsIIOService *ioService = nullptr)
michael@0 1270 {
michael@0 1271 nsCOMPtr<nsIURI> uri;
michael@0 1272 nsresult rv =
michael@0 1273 NS_NewURI(getter_AddRefs(uri), spec, charset, baseURI, ioService);
michael@0 1274
michael@0 1275 if (NS_SUCCEEDED(rv))
michael@0 1276 rv = NS_LoadPersistentPropertiesFromURI(result, uri, ioService);
michael@0 1277
michael@0 1278 return rv;
michael@0 1279 }
michael@0 1280
michael@0 1281 /**
michael@0 1282 * NS_QueryNotificationCallbacks implements the canonical algorithm for
michael@0 1283 * querying interfaces from a channel's notification callbacks. It first
michael@0 1284 * searches the channel's notificationCallbacks attribute, and if the interface
michael@0 1285 * is not found there, then it inspects the notificationCallbacks attribute of
michael@0 1286 * the channel's loadGroup.
michael@0 1287 *
michael@0 1288 * Note: templatized only because nsIWebSocketChannel is currently not an
michael@0 1289 * nsIChannel.
michael@0 1290 */
michael@0 1291 template <class T> inline void
michael@0 1292 NS_QueryNotificationCallbacks(T *channel,
michael@0 1293 const nsIID &iid,
michael@0 1294 void **result)
michael@0 1295 {
michael@0 1296 NS_PRECONDITION(channel, "null channel");
michael@0 1297 *result = nullptr;
michael@0 1298
michael@0 1299 nsCOMPtr<nsIInterfaceRequestor> cbs;
michael@0 1300 channel->GetNotificationCallbacks(getter_AddRefs(cbs));
michael@0 1301 if (cbs)
michael@0 1302 cbs->GetInterface(iid, result);
michael@0 1303 if (!*result) {
michael@0 1304 // try load group's notification callbacks...
michael@0 1305 nsCOMPtr<nsILoadGroup> loadGroup;
michael@0 1306 channel->GetLoadGroup(getter_AddRefs(loadGroup));
michael@0 1307 if (loadGroup) {
michael@0 1308 loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
michael@0 1309 if (cbs)
michael@0 1310 cbs->GetInterface(iid, result);
michael@0 1311 }
michael@0 1312 }
michael@0 1313 }
michael@0 1314
michael@0 1315 // template helper:
michael@0 1316 // Note: "class C" templatized only because nsIWebSocketChannel is currently not
michael@0 1317 // an nsIChannel.
michael@0 1318
michael@0 1319 template <class C, class T> inline void
michael@0 1320 NS_QueryNotificationCallbacks(C *channel,
michael@0 1321 nsCOMPtr<T> &result)
michael@0 1322 {
michael@0 1323 NS_QueryNotificationCallbacks(channel, NS_GET_TEMPLATE_IID(T),
michael@0 1324 getter_AddRefs(result));
michael@0 1325 }
michael@0 1326
michael@0 1327 /**
michael@0 1328 * Alternate form of NS_QueryNotificationCallbacks designed for use by
michael@0 1329 * nsIChannel implementations.
michael@0 1330 */
michael@0 1331 inline void
michael@0 1332 NS_QueryNotificationCallbacks(nsIInterfaceRequestor *callbacks,
michael@0 1333 nsILoadGroup *loadGroup,
michael@0 1334 const nsIID &iid,
michael@0 1335 void **result)
michael@0 1336 {
michael@0 1337 *result = nullptr;
michael@0 1338
michael@0 1339 if (callbacks)
michael@0 1340 callbacks->GetInterface(iid, result);
michael@0 1341 if (!*result) {
michael@0 1342 // try load group's notification callbacks...
michael@0 1343 if (loadGroup) {
michael@0 1344 nsCOMPtr<nsIInterfaceRequestor> cbs;
michael@0 1345 loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
michael@0 1346 if (cbs)
michael@0 1347 cbs->GetInterface(iid, result);
michael@0 1348 }
michael@0 1349 }
michael@0 1350 }
michael@0 1351
michael@0 1352 /**
michael@0 1353 * Returns true if channel is using Private Browsing, or false if not.
michael@0 1354 * Returns false if channel's callbacks don't implement nsILoadContext.
michael@0 1355 */
michael@0 1356 inline bool
michael@0 1357 NS_UsePrivateBrowsing(nsIChannel *channel)
michael@0 1358 {
michael@0 1359 bool isPrivate = false;
michael@0 1360 bool isOverriden = false;
michael@0 1361 nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
michael@0 1362 if (pbChannel &&
michael@0 1363 NS_SUCCEEDED(pbChannel->IsPrivateModeOverriden(&isPrivate, &isOverriden)) &&
michael@0 1364 isOverriden) {
michael@0 1365 return isPrivate;
michael@0 1366 }
michael@0 1367 nsCOMPtr<nsILoadContext> loadContext;
michael@0 1368 NS_QueryNotificationCallbacks(channel, loadContext);
michael@0 1369 return loadContext && loadContext->UsePrivateBrowsing();
michael@0 1370 }
michael@0 1371
michael@0 1372 // Constants duplicated from nsIScriptSecurityManager so we avoid having necko
michael@0 1373 // know about script security manager.
michael@0 1374 #define NECKO_NO_APP_ID 0
michael@0 1375 #define NECKO_UNKNOWN_APP_ID UINT32_MAX
michael@0 1376 // special app id reserved for separating the safebrowsing cookie
michael@0 1377 #define NECKO_SAFEBROWSING_APP_ID UINT32_MAX - 1
michael@0 1378
michael@0 1379 /**
michael@0 1380 * Gets AppId and isInBrowserElement from channel's nsILoadContext.
michael@0 1381 * Returns false if error or channel's callbacks don't implement nsILoadContext.
michael@0 1382 */
michael@0 1383 inline bool
michael@0 1384 NS_GetAppInfo(nsIChannel *aChannel, uint32_t *aAppID, bool *aIsInBrowserElement)
michael@0 1385 {
michael@0 1386 nsCOMPtr<nsILoadContext> loadContext;
michael@0 1387 NS_QueryNotificationCallbacks(aChannel, loadContext);
michael@0 1388 if (!loadContext) {
michael@0 1389 return false;
michael@0 1390 }
michael@0 1391
michael@0 1392 nsresult rv = loadContext->GetAppId(aAppID);
michael@0 1393 NS_ENSURE_SUCCESS(rv, false);
michael@0 1394
michael@0 1395 rv = loadContext->GetIsInBrowserElement(aIsInBrowserElement);
michael@0 1396 NS_ENSURE_SUCCESS(rv, false);
michael@0 1397
michael@0 1398 return true;
michael@0 1399 }
michael@0 1400
michael@0 1401 /**
michael@0 1402 * Gets appId and browserOnly parameters from the TOPIC_WEB_APP_CLEAR_DATA
michael@0 1403 * nsIObserverService notification. Used when clearing user data or
michael@0 1404 * uninstalling web apps.
michael@0 1405 */
michael@0 1406 inline nsresult
michael@0 1407 NS_GetAppInfoFromClearDataNotification(nsISupports *aSubject,
michael@0 1408 uint32_t *aAppID, bool* aBrowserOnly)
michael@0 1409 {
michael@0 1410 nsresult rv;
michael@0 1411
michael@0 1412 nsCOMPtr<mozIApplicationClearPrivateDataParams>
michael@0 1413 clearParams(do_QueryInterface(aSubject));
michael@0 1414 MOZ_ASSERT(clearParams);
michael@0 1415 if (!clearParams) {
michael@0 1416 return NS_ERROR_UNEXPECTED;
michael@0 1417 }
michael@0 1418
michael@0 1419 uint32_t appId;
michael@0 1420 rv = clearParams->GetAppId(&appId);
michael@0 1421 MOZ_ASSERT(NS_SUCCEEDED(rv));
michael@0 1422 MOZ_ASSERT(appId != NECKO_UNKNOWN_APP_ID);
michael@0 1423 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1424 if (appId == NECKO_UNKNOWN_APP_ID) {
michael@0 1425 return NS_ERROR_UNEXPECTED;
michael@0 1426 }
michael@0 1427
michael@0 1428 bool browserOnly = false;
michael@0 1429 rv = clearParams->GetBrowserOnly(&browserOnly);
michael@0 1430 MOZ_ASSERT(NS_SUCCEEDED(rv));
michael@0 1431 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1432
michael@0 1433 *aAppID = appId;
michael@0 1434 *aBrowserOnly = browserOnly;
michael@0 1435 return NS_OK;
michael@0 1436 }
michael@0 1437
michael@0 1438 /**
michael@0 1439 * Determines whether appcache should be checked for a given URI.
michael@0 1440 */
michael@0 1441 inline bool
michael@0 1442 NS_ShouldCheckAppCache(nsIURI *aURI, bool usePrivateBrowsing)
michael@0 1443 {
michael@0 1444 if (usePrivateBrowsing) {
michael@0 1445 return false;
michael@0 1446 }
michael@0 1447
michael@0 1448 nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
michael@0 1449 do_GetService("@mozilla.org/offlinecacheupdate-service;1");
michael@0 1450 if (!offlineService) {
michael@0 1451 return false;
michael@0 1452 }
michael@0 1453
michael@0 1454 bool allowed;
michael@0 1455 nsresult rv = offlineService->OfflineAppAllowedForURI(aURI,
michael@0 1456 nullptr,
michael@0 1457 &allowed);
michael@0 1458 return NS_SUCCEEDED(rv) && allowed;
michael@0 1459 }
michael@0 1460
michael@0 1461 inline bool
michael@0 1462 NS_ShouldCheckAppCache(nsIPrincipal * aPrincipal, bool usePrivateBrowsing)
michael@0 1463 {
michael@0 1464 if (usePrivateBrowsing) {
michael@0 1465 return false;
michael@0 1466 }
michael@0 1467
michael@0 1468 nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
michael@0 1469 do_GetService("@mozilla.org/offlinecacheupdate-service;1");
michael@0 1470 if (!offlineService) {
michael@0 1471 return false;
michael@0 1472 }
michael@0 1473
michael@0 1474 bool allowed;
michael@0 1475 nsresult rv = offlineService->OfflineAppAllowed(aPrincipal,
michael@0 1476 nullptr,
michael@0 1477 &allowed);
michael@0 1478 return NS_SUCCEEDED(rv) && allowed;
michael@0 1479 }
michael@0 1480
michael@0 1481 /**
michael@0 1482 * Wraps an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2. This
michael@0 1483 * method is provided mainly for use by other methods in this file.
michael@0 1484 *
michael@0 1485 * *aAuthPrompt2 should be set to null before calling this function.
michael@0 1486 */
michael@0 1487 inline void
michael@0 1488 NS_WrapAuthPrompt(nsIAuthPrompt *aAuthPrompt, nsIAuthPrompt2** aAuthPrompt2)
michael@0 1489 {
michael@0 1490 nsCOMPtr<nsIAuthPromptAdapterFactory> factory =
michael@0 1491 do_GetService(NS_AUTHPROMPT_ADAPTER_FACTORY_CONTRACTID);
michael@0 1492 if (!factory)
michael@0 1493 return;
michael@0 1494
michael@0 1495 NS_WARNING("Using deprecated nsIAuthPrompt");
michael@0 1496 factory->CreateAdapter(aAuthPrompt, aAuthPrompt2);
michael@0 1497 }
michael@0 1498
michael@0 1499 /**
michael@0 1500 * Gets an auth prompt from an interface requestor. This takes care of wrapping
michael@0 1501 * an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2.
michael@0 1502 */
michael@0 1503 inline void
michael@0 1504 NS_QueryAuthPrompt2(nsIInterfaceRequestor *aCallbacks,
michael@0 1505 nsIAuthPrompt2 **aAuthPrompt)
michael@0 1506 {
michael@0 1507 CallGetInterface(aCallbacks, aAuthPrompt);
michael@0 1508 if (*aAuthPrompt)
michael@0 1509 return;
michael@0 1510
michael@0 1511 // Maybe only nsIAuthPrompt is provided and we have to wrap it.
michael@0 1512 nsCOMPtr<nsIAuthPrompt> prompt(do_GetInterface(aCallbacks));
michael@0 1513 if (!prompt)
michael@0 1514 return;
michael@0 1515
michael@0 1516 NS_WrapAuthPrompt(prompt, aAuthPrompt);
michael@0 1517 }
michael@0 1518
michael@0 1519 /**
michael@0 1520 * Gets an nsIAuthPrompt2 from a channel. Use this instead of
michael@0 1521 * NS_QueryNotificationCallbacks for better backwards compatibility.
michael@0 1522 */
michael@0 1523 inline void
michael@0 1524 NS_QueryAuthPrompt2(nsIChannel *aChannel,
michael@0 1525 nsIAuthPrompt2 **aAuthPrompt)
michael@0 1526 {
michael@0 1527 *aAuthPrompt = nullptr;
michael@0 1528
michael@0 1529 // We want to use any auth prompt we can find on the channel's callbacks,
michael@0 1530 // and if that fails use the loadgroup's prompt (if any)
michael@0 1531 // Therefore, we can't just use NS_QueryNotificationCallbacks, because
michael@0 1532 // that would prefer a loadgroup's nsIAuthPrompt2 over a channel's
michael@0 1533 // nsIAuthPrompt.
michael@0 1534 nsCOMPtr<nsIInterfaceRequestor> callbacks;
michael@0 1535 aChannel->GetNotificationCallbacks(getter_AddRefs(callbacks));
michael@0 1536 if (callbacks) {
michael@0 1537 NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
michael@0 1538 if (*aAuthPrompt)
michael@0 1539 return;
michael@0 1540 }
michael@0 1541
michael@0 1542 nsCOMPtr<nsILoadGroup> group;
michael@0 1543 aChannel->GetLoadGroup(getter_AddRefs(group));
michael@0 1544 if (!group)
michael@0 1545 return;
michael@0 1546
michael@0 1547 group->GetNotificationCallbacks(getter_AddRefs(callbacks));
michael@0 1548 if (!callbacks)
michael@0 1549 return;
michael@0 1550 NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
michael@0 1551 }
michael@0 1552
michael@0 1553 /* template helper */
michael@0 1554 template <class T> inline void
michael@0 1555 NS_QueryNotificationCallbacks(nsIInterfaceRequestor *callbacks,
michael@0 1556 nsILoadGroup *loadGroup,
michael@0 1557 nsCOMPtr<T> &result)
michael@0 1558 {
michael@0 1559 NS_QueryNotificationCallbacks(callbacks, loadGroup,
michael@0 1560 NS_GET_TEMPLATE_IID(T),
michael@0 1561 getter_AddRefs(result));
michael@0 1562 }
michael@0 1563
michael@0 1564 /* template helper */
michael@0 1565 template <class T> inline void
michael@0 1566 NS_QueryNotificationCallbacks(const nsCOMPtr<nsIInterfaceRequestor> &aCallbacks,
michael@0 1567 const nsCOMPtr<nsILoadGroup> &aLoadGroup,
michael@0 1568 nsCOMPtr<T> &aResult)
michael@0 1569 {
michael@0 1570 NS_QueryNotificationCallbacks(aCallbacks.get(), aLoadGroup.get(), aResult);
michael@0 1571 }
michael@0 1572
michael@0 1573 /* template helper */
michael@0 1574 template <class T> inline void
michael@0 1575 NS_QueryNotificationCallbacks(const nsCOMPtr<nsIChannel> &aChannel,
michael@0 1576 nsCOMPtr<T> &aResult)
michael@0 1577 {
michael@0 1578 NS_QueryNotificationCallbacks(aChannel.get(), aResult);
michael@0 1579 }
michael@0 1580
michael@0 1581 /**
michael@0 1582 * This function returns a nsIInterfaceRequestor instance that returns the
michael@0 1583 * same result as NS_QueryNotificationCallbacks when queried. It is useful
michael@0 1584 * as the value for nsISocketTransport::securityCallbacks.
michael@0 1585 */
michael@0 1586 inline nsresult
michael@0 1587 NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor *callbacks,
michael@0 1588 nsILoadGroup *loadGroup,
michael@0 1589 nsIEventTarget *target,
michael@0 1590 nsIInterfaceRequestor **result)
michael@0 1591 {
michael@0 1592 nsCOMPtr<nsIInterfaceRequestor> cbs;
michael@0 1593 if (loadGroup)
michael@0 1594 loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
michael@0 1595 return NS_NewInterfaceRequestorAggregation(callbacks, cbs, target, result);
michael@0 1596 }
michael@0 1597
michael@0 1598 inline nsresult
michael@0 1599 NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor *callbacks,
michael@0 1600 nsILoadGroup *loadGroup,
michael@0 1601 nsIInterfaceRequestor **result)
michael@0 1602 {
michael@0 1603 return NS_NewNotificationCallbacksAggregation(callbacks, loadGroup, nullptr, result);
michael@0 1604 }
michael@0 1605
michael@0 1606 /**
michael@0 1607 * Helper function for testing online/offline state of the browser.
michael@0 1608 */
michael@0 1609 inline bool
michael@0 1610 NS_IsOffline()
michael@0 1611 {
michael@0 1612 bool offline = true;
michael@0 1613 nsCOMPtr<nsIIOService> ios = do_GetIOService();
michael@0 1614 if (ios)
michael@0 1615 ios->GetOffline(&offline);
michael@0 1616 return offline;
michael@0 1617 }
michael@0 1618
michael@0 1619 /**
michael@0 1620 * Helper functions for implementing nsINestedURI::innermostURI.
michael@0 1621 *
michael@0 1622 * Note that NS_DoImplGetInnermostURI is "private" -- call
michael@0 1623 * NS_ImplGetInnermostURI instead.
michael@0 1624 */
michael@0 1625 inline nsresult
michael@0 1626 NS_DoImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result)
michael@0 1627 {
michael@0 1628 NS_PRECONDITION(nestedURI, "Must have a nested URI!");
michael@0 1629 NS_PRECONDITION(!*result, "Must have null *result");
michael@0 1630
michael@0 1631 nsCOMPtr<nsIURI> inner;
michael@0 1632 nsresult rv = nestedURI->GetInnerURI(getter_AddRefs(inner));
michael@0 1633 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1634
michael@0 1635 // We may need to loop here until we reach the innermost
michael@0 1636 // URI.
michael@0 1637 nsCOMPtr<nsINestedURI> nestedInner(do_QueryInterface(inner));
michael@0 1638 while (nestedInner) {
michael@0 1639 rv = nestedInner->GetInnerURI(getter_AddRefs(inner));
michael@0 1640 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1641 nestedInner = do_QueryInterface(inner);
michael@0 1642 }
michael@0 1643
michael@0 1644 // Found the innermost one if we reach here.
michael@0 1645 inner.swap(*result);
michael@0 1646
michael@0 1647 return rv;
michael@0 1648 }
michael@0 1649
michael@0 1650 inline nsresult
michael@0 1651 NS_ImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result)
michael@0 1652 {
michael@0 1653 // Make it safe to use swap()
michael@0 1654 *result = nullptr;
michael@0 1655
michael@0 1656 return NS_DoImplGetInnermostURI(nestedURI, result);
michael@0 1657 }
michael@0 1658
michael@0 1659 /**
michael@0 1660 * Helper function that ensures that |result| is a URI that's safe to
michael@0 1661 * return. If |uri| is immutable, just returns it, otherwise returns
michael@0 1662 * a clone. |uri| must not be null.
michael@0 1663 */
michael@0 1664 inline nsresult
michael@0 1665 NS_EnsureSafeToReturn(nsIURI* uri, nsIURI** result)
michael@0 1666 {
michael@0 1667 NS_PRECONDITION(uri, "Must have a URI");
michael@0 1668
michael@0 1669 // Assume mutable until told otherwise
michael@0 1670 bool isMutable = true;
michael@0 1671 nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(uri));
michael@0 1672 if (mutableObj) {
michael@0 1673 nsresult rv = mutableObj->GetMutable(&isMutable);
michael@0 1674 isMutable = NS_FAILED(rv) || isMutable;
michael@0 1675 }
michael@0 1676
michael@0 1677 if (!isMutable) {
michael@0 1678 NS_ADDREF(*result = uri);
michael@0 1679 return NS_OK;
michael@0 1680 }
michael@0 1681
michael@0 1682 nsresult rv = uri->Clone(result);
michael@0 1683 if (NS_SUCCEEDED(rv) && !*result) {
michael@0 1684 NS_ERROR("nsIURI.clone contract was violated");
michael@0 1685 return NS_ERROR_UNEXPECTED;
michael@0 1686 }
michael@0 1687
michael@0 1688 return rv;
michael@0 1689 }
michael@0 1690
michael@0 1691 /**
michael@0 1692 * Helper function that tries to set the argument URI to be immutable
michael@0 1693 */
michael@0 1694 inline void
michael@0 1695 NS_TryToSetImmutable(nsIURI* uri)
michael@0 1696 {
michael@0 1697 nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(uri));
michael@0 1698 if (mutableObj) {
michael@0 1699 mutableObj->SetMutable(false);
michael@0 1700 }
michael@0 1701 }
michael@0 1702
michael@0 1703 /**
michael@0 1704 * Helper function for calling ToImmutableURI. If all else fails, returns
michael@0 1705 * the input URI. The optional second arg indicates whether we had to fall
michael@0 1706 * back to the input URI. Passing in a null URI is ok.
michael@0 1707 */
michael@0 1708 inline already_AddRefed<nsIURI>
michael@0 1709 NS_TryToMakeImmutable(nsIURI* uri,
michael@0 1710 nsresult* outRv = nullptr)
michael@0 1711 {
michael@0 1712 nsresult rv;
michael@0 1713 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
michael@0 1714
michael@0 1715 nsCOMPtr<nsIURI> result;
michael@0 1716 if (NS_SUCCEEDED(rv)) {
michael@0 1717 NS_ASSERTION(util, "do_GetNetUtil lied");
michael@0 1718 rv = util->ToImmutableURI(uri, getter_AddRefs(result));
michael@0 1719 }
michael@0 1720
michael@0 1721 if (NS_FAILED(rv)) {
michael@0 1722 result = uri;
michael@0 1723 }
michael@0 1724
michael@0 1725 if (outRv) {
michael@0 1726 *outRv = rv;
michael@0 1727 }
michael@0 1728
michael@0 1729 return result.forget();
michael@0 1730 }
michael@0 1731
michael@0 1732 /**
michael@0 1733 * Helper function for testing whether the given URI, or any of its
michael@0 1734 * inner URIs, has all the given protocol flags.
michael@0 1735 */
michael@0 1736 inline nsresult
michael@0 1737 NS_URIChainHasFlags(nsIURI *uri,
michael@0 1738 uint32_t flags,
michael@0 1739 bool *result)
michael@0 1740 {
michael@0 1741 nsresult rv;
michael@0 1742 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
michael@0 1743 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1744
michael@0 1745 return util->URIChainHasFlags(uri, flags, result);
michael@0 1746 }
michael@0 1747
michael@0 1748 /**
michael@0 1749 * Helper function for getting the innermost URI for a given URI. The return
michael@0 1750 * value could be just the object passed in if it's not a nested URI.
michael@0 1751 */
michael@0 1752 inline already_AddRefed<nsIURI>
michael@0 1753 NS_GetInnermostURI(nsIURI* aURI)
michael@0 1754 {
michael@0 1755 NS_PRECONDITION(aURI, "Must have URI");
michael@0 1756
michael@0 1757 nsCOMPtr<nsIURI> uri = aURI;
michael@0 1758
michael@0 1759 nsCOMPtr<nsINestedURI> nestedURI(do_QueryInterface(uri));
michael@0 1760 if (!nestedURI) {
michael@0 1761 return uri.forget();
michael@0 1762 }
michael@0 1763
michael@0 1764 nsresult rv = nestedURI->GetInnermostURI(getter_AddRefs(uri));
michael@0 1765 if (NS_FAILED(rv)) {
michael@0 1766 return nullptr;
michael@0 1767 }
michael@0 1768
michael@0 1769 return uri.forget();
michael@0 1770 }
michael@0 1771
michael@0 1772 /**
michael@0 1773 * Get the "final" URI for a channel. This is either the same as GetURI or
michael@0 1774 * GetOriginalURI, depending on whether this channel has
michael@0 1775 * nsIChanel::LOAD_REPLACE set. For channels without that flag set, the final
michael@0 1776 * URI is the original URI, while for ones with the flag the final URI is the
michael@0 1777 * channel URI.
michael@0 1778 */
michael@0 1779 inline nsresult
michael@0 1780 NS_GetFinalChannelURI(nsIChannel* channel, nsIURI** uri)
michael@0 1781 {
michael@0 1782 *uri = nullptr;
michael@0 1783 nsLoadFlags loadFlags = 0;
michael@0 1784 nsresult rv = channel->GetLoadFlags(&loadFlags);
michael@0 1785 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1786
michael@0 1787 if (loadFlags & nsIChannel::LOAD_REPLACE) {
michael@0 1788 return channel->GetURI(uri);
michael@0 1789 }
michael@0 1790
michael@0 1791 return channel->GetOriginalURI(uri);
michael@0 1792 }
michael@0 1793
michael@0 1794 // NS_SecurityHashURI must return the same hash value for any two URIs that
michael@0 1795 // compare equal according to NS_SecurityCompareURIs. Unfortunately, in the
michael@0 1796 // case of files, it's not clear we can do anything better than returning
michael@0 1797 // the schemeHash, so hashing files degenerates to storing them in a list.
michael@0 1798 inline uint32_t
michael@0 1799 NS_SecurityHashURI(nsIURI* aURI)
michael@0 1800 {
michael@0 1801 nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
michael@0 1802
michael@0 1803 nsAutoCString scheme;
michael@0 1804 uint32_t schemeHash = 0;
michael@0 1805 if (NS_SUCCEEDED(baseURI->GetScheme(scheme)))
michael@0 1806 schemeHash = mozilla::HashString(scheme);
michael@0 1807
michael@0 1808 // TODO figure out how to hash file:// URIs
michael@0 1809 if (scheme.EqualsLiteral("file"))
michael@0 1810 return schemeHash; // sad face
michael@0 1811
michael@0 1812 if (scheme.EqualsLiteral("imap") ||
michael@0 1813 scheme.EqualsLiteral("mailbox") ||
michael@0 1814 scheme.EqualsLiteral("news"))
michael@0 1815 {
michael@0 1816 nsAutoCString spec;
michael@0 1817 uint32_t specHash;
michael@0 1818 nsresult res = baseURI->GetSpec(spec);
michael@0 1819 if (NS_SUCCEEDED(res))
michael@0 1820 specHash = mozilla::HashString(spec);
michael@0 1821 else
michael@0 1822 specHash = static_cast<uint32_t>(res);
michael@0 1823 return specHash;
michael@0 1824 }
michael@0 1825
michael@0 1826 nsAutoCString host;
michael@0 1827 uint32_t hostHash = 0;
michael@0 1828 if (NS_SUCCEEDED(baseURI->GetAsciiHost(host)))
michael@0 1829 hostHash = mozilla::HashString(host);
michael@0 1830
michael@0 1831 return mozilla::AddToHash(schemeHash, hostHash, NS_GetRealPort(baseURI));
michael@0 1832 }
michael@0 1833
michael@0 1834 inline bool
michael@0 1835 NS_SecurityCompareURIs(nsIURI* aSourceURI,
michael@0 1836 nsIURI* aTargetURI,
michael@0 1837 bool aStrictFileOriginPolicy)
michael@0 1838 {
michael@0 1839 // Note that this is not an Equals() test on purpose -- for URIs that don't
michael@0 1840 // support host/port, we want equality to basically be object identity, for
michael@0 1841 // security purposes. Otherwise, for example, two javascript: URIs that
michael@0 1842 // are otherwise unrelated could end up "same origin", which would be
michael@0 1843 // unfortunate.
michael@0 1844 if (aSourceURI && aSourceURI == aTargetURI)
michael@0 1845 {
michael@0 1846 return true;
michael@0 1847 }
michael@0 1848
michael@0 1849 if (!aTargetURI || !aSourceURI)
michael@0 1850 {
michael@0 1851 return false;
michael@0 1852 }
michael@0 1853
michael@0 1854 // If either URI is a nested URI, get the base URI
michael@0 1855 nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI);
michael@0 1856 nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
michael@0 1857
michael@0 1858 // If either uri is an nsIURIWithPrincipal
michael@0 1859 nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(sourceBaseURI);
michael@0 1860 if (uriPrinc) {
michael@0 1861 uriPrinc->GetPrincipalUri(getter_AddRefs(sourceBaseURI));
michael@0 1862 }
michael@0 1863
michael@0 1864 uriPrinc = do_QueryInterface(targetBaseURI);
michael@0 1865 if (uriPrinc) {
michael@0 1866 uriPrinc->GetPrincipalUri(getter_AddRefs(targetBaseURI));
michael@0 1867 }
michael@0 1868
michael@0 1869 if (!sourceBaseURI || !targetBaseURI)
michael@0 1870 return false;
michael@0 1871
michael@0 1872 // Compare schemes
michael@0 1873 nsAutoCString targetScheme;
michael@0 1874 bool sameScheme = false;
michael@0 1875 if (NS_FAILED( targetBaseURI->GetScheme(targetScheme) ) ||
michael@0 1876 NS_FAILED( sourceBaseURI->SchemeIs(targetScheme.get(), &sameScheme) ) ||
michael@0 1877 !sameScheme)
michael@0 1878 {
michael@0 1879 // Not same-origin if schemes differ
michael@0 1880 return false;
michael@0 1881 }
michael@0 1882
michael@0 1883 // For file scheme, reject unless the files are identical. See
michael@0 1884 // NS_RelaxStrictFileOriginPolicy for enforcing file same-origin checking
michael@0 1885 if (targetScheme.EqualsLiteral("file"))
michael@0 1886 {
michael@0 1887 // in traditional unsafe behavior all files are the same origin
michael@0 1888 if (!aStrictFileOriginPolicy)
michael@0 1889 return true;
michael@0 1890
michael@0 1891 nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(sourceBaseURI));
michael@0 1892 nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(targetBaseURI));
michael@0 1893
michael@0 1894 if (!sourceFileURL || !targetFileURL)
michael@0 1895 return false;
michael@0 1896
michael@0 1897 nsCOMPtr<nsIFile> sourceFile, targetFile;
michael@0 1898
michael@0 1899 sourceFileURL->GetFile(getter_AddRefs(sourceFile));
michael@0 1900 targetFileURL->GetFile(getter_AddRefs(targetFile));
michael@0 1901
michael@0 1902 if (!sourceFile || !targetFile)
michael@0 1903 return false;
michael@0 1904
michael@0 1905 // Otherwise they had better match
michael@0 1906 bool filesAreEqual = false;
michael@0 1907 nsresult rv = sourceFile->Equals(targetFile, &filesAreEqual);
michael@0 1908 return NS_SUCCEEDED(rv) && filesAreEqual;
michael@0 1909 }
michael@0 1910
michael@0 1911 // Special handling for mailnews schemes
michael@0 1912 if (targetScheme.EqualsLiteral("imap") ||
michael@0 1913 targetScheme.EqualsLiteral("mailbox") ||
michael@0 1914 targetScheme.EqualsLiteral("news"))
michael@0 1915 {
michael@0 1916 // Each message is a distinct trust domain; use the
michael@0 1917 // whole spec for comparison
michael@0 1918 nsAutoCString targetSpec;
michael@0 1919 nsAutoCString sourceSpec;
michael@0 1920 return ( NS_SUCCEEDED( targetBaseURI->GetSpec(targetSpec) ) &&
michael@0 1921 NS_SUCCEEDED( sourceBaseURI->GetSpec(sourceSpec) ) &&
michael@0 1922 targetSpec.Equals(sourceSpec) );
michael@0 1923 }
michael@0 1924
michael@0 1925 // Compare hosts
michael@0 1926 nsAutoCString targetHost;
michael@0 1927 nsAutoCString sourceHost;
michael@0 1928 if (NS_FAILED( targetBaseURI->GetAsciiHost(targetHost) ) ||
michael@0 1929 NS_FAILED( sourceBaseURI->GetAsciiHost(sourceHost) ))
michael@0 1930 {
michael@0 1931 return false;
michael@0 1932 }
michael@0 1933
michael@0 1934 nsCOMPtr<nsIStandardURL> targetURL(do_QueryInterface(targetBaseURI));
michael@0 1935 nsCOMPtr<nsIStandardURL> sourceURL(do_QueryInterface(sourceBaseURI));
michael@0 1936 if (!targetURL || !sourceURL)
michael@0 1937 {
michael@0 1938 return false;
michael@0 1939 }
michael@0 1940
michael@0 1941 #ifdef MOZILLA_INTERNAL_API
michael@0 1942 if (!targetHost.Equals(sourceHost, nsCaseInsensitiveCStringComparator() ))
michael@0 1943 #else
michael@0 1944 if (!targetHost.Equals(sourceHost, CaseInsensitiveCompare))
michael@0 1945 #endif
michael@0 1946 {
michael@0 1947 return false;
michael@0 1948 }
michael@0 1949
michael@0 1950 return NS_GetRealPort(targetBaseURI) == NS_GetRealPort(sourceBaseURI);
michael@0 1951 }
michael@0 1952
michael@0 1953 inline bool
michael@0 1954 NS_URIIsLocalFile(nsIURI *aURI)
michael@0 1955 {
michael@0 1956 nsCOMPtr<nsINetUtil> util = do_GetNetUtil();
michael@0 1957
michael@0 1958 bool isFile;
michael@0 1959 return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
michael@0 1960 nsIProtocolHandler::URI_IS_LOCAL_FILE,
michael@0 1961 &isFile)) &&
michael@0 1962 isFile;
michael@0 1963 }
michael@0 1964
michael@0 1965 // When strict file origin policy is enabled, SecurityCompareURIs will fail for
michael@0 1966 // file URIs that do not point to the same local file. This call provides an
michael@0 1967 // alternate file-specific origin check that allows target files that are
michael@0 1968 // contained in the same directory as the source.
michael@0 1969 //
michael@0 1970 // https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs
michael@0 1971 inline bool
michael@0 1972 NS_RelaxStrictFileOriginPolicy(nsIURI *aTargetURI,
michael@0 1973 nsIURI *aSourceURI,
michael@0 1974 bool aAllowDirectoryTarget = false)
michael@0 1975 {
michael@0 1976 if (!NS_URIIsLocalFile(aTargetURI)) {
michael@0 1977 // This is probably not what the caller intended
michael@0 1978 NS_NOTREACHED("NS_RelaxStrictFileOriginPolicy called with non-file URI");
michael@0 1979 return false;
michael@0 1980 }
michael@0 1981
michael@0 1982 if (!NS_URIIsLocalFile(aSourceURI)) {
michael@0 1983 // If the source is not also a file: uri then forget it
michael@0 1984 // (don't want resource: principals in a file: doc)
michael@0 1985 //
michael@0 1986 // note: we're not de-nesting jar: uris here, we want to
michael@0 1987 // keep archive content bottled up in its own little island
michael@0 1988 return false;
michael@0 1989 }
michael@0 1990
michael@0 1991 //
michael@0 1992 // pull out the internal files
michael@0 1993 //
michael@0 1994 nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(aTargetURI));
michael@0 1995 nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(aSourceURI));
michael@0 1996 nsCOMPtr<nsIFile> targetFile;
michael@0 1997 nsCOMPtr<nsIFile> sourceFile;
michael@0 1998 bool targetIsDir;
michael@0 1999
michael@0 2000 // Make sure targetFile is not a directory (bug 209234)
michael@0 2001 // and that it exists w/out unescaping (bug 395343)
michael@0 2002 if (!sourceFileURL || !targetFileURL ||
michael@0 2003 NS_FAILED(targetFileURL->GetFile(getter_AddRefs(targetFile))) ||
michael@0 2004 NS_FAILED(sourceFileURL->GetFile(getter_AddRefs(sourceFile))) ||
michael@0 2005 !targetFile || !sourceFile ||
michael@0 2006 NS_FAILED(targetFile->Normalize()) ||
michael@0 2007 #ifndef MOZ_WIDGET_ANDROID
michael@0 2008 NS_FAILED(sourceFile->Normalize()) ||
michael@0 2009 #endif
michael@0 2010 (!aAllowDirectoryTarget &&
michael@0 2011 (NS_FAILED(targetFile->IsDirectory(&targetIsDir)) || targetIsDir))) {
michael@0 2012 return false;
michael@0 2013 }
michael@0 2014
michael@0 2015 //
michael@0 2016 // If the file to be loaded is in a subdirectory of the source
michael@0 2017 // (or same-dir if source is not a directory) then it will
michael@0 2018 // inherit its source principal and be scriptable by that source.
michael@0 2019 //
michael@0 2020 bool sourceIsDir;
michael@0 2021 bool allowed = false;
michael@0 2022 nsresult rv = sourceFile->IsDirectory(&sourceIsDir);
michael@0 2023 if (NS_SUCCEEDED(rv) && sourceIsDir) {
michael@0 2024 rv = sourceFile->Contains(targetFile, true, &allowed);
michael@0 2025 } else {
michael@0 2026 nsCOMPtr<nsIFile> sourceParent;
michael@0 2027 rv = sourceFile->GetParent(getter_AddRefs(sourceParent));
michael@0 2028 if (NS_SUCCEEDED(rv) && sourceParent) {
michael@0 2029 rv = sourceParent->Equals(targetFile, &allowed);
michael@0 2030 if (NS_FAILED(rv) || !allowed) {
michael@0 2031 rv = sourceParent->Contains(targetFile, true, &allowed);
michael@0 2032 } else {
michael@0 2033 MOZ_ASSERT(aAllowDirectoryTarget,
michael@0 2034 "sourceFile->Parent == targetFile, but targetFile "
michael@0 2035 "should've been disallowed if it is a directory");
michael@0 2036 }
michael@0 2037 }
michael@0 2038 }
michael@0 2039
michael@0 2040 if (NS_SUCCEEDED(rv) && allowed) {
michael@0 2041 return true;
michael@0 2042 }
michael@0 2043
michael@0 2044 return false;
michael@0 2045 }
michael@0 2046
michael@0 2047 inline bool
michael@0 2048 NS_IsInternalSameURIRedirect(nsIChannel *aOldChannel,
michael@0 2049 nsIChannel *aNewChannel,
michael@0 2050 uint32_t aFlags)
michael@0 2051 {
michael@0 2052 if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
michael@0 2053 return false;
michael@0 2054 }
michael@0 2055
michael@0 2056 nsCOMPtr<nsIURI> oldURI, newURI;
michael@0 2057 aOldChannel->GetURI(getter_AddRefs(oldURI));
michael@0 2058 aNewChannel->GetURI(getter_AddRefs(newURI));
michael@0 2059
michael@0 2060 if (!oldURI || !newURI) {
michael@0 2061 return false;
michael@0 2062 }
michael@0 2063
michael@0 2064 bool res;
michael@0 2065 return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res;
michael@0 2066 }
michael@0 2067
michael@0 2068 inline nsresult
michael@0 2069 NS_LinkRedirectChannels(uint32_t channelId,
michael@0 2070 nsIParentChannel *parentChannel,
michael@0 2071 nsIChannel** _result)
michael@0 2072 {
michael@0 2073 nsresult rv;
michael@0 2074
michael@0 2075 nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
michael@0 2076 do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
michael@0 2077 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2078
michael@0 2079 return registrar->LinkChannels(channelId,
michael@0 2080 parentChannel,
michael@0 2081 _result);
michael@0 2082 }
michael@0 2083
michael@0 2084 /**
michael@0 2085 * Helper function to create a random URL string that's properly formed
michael@0 2086 * but guaranteed to be invalid.
michael@0 2087 */
michael@0 2088 #define NS_FAKE_SCHEME "http://"
michael@0 2089 #define NS_FAKE_TLD ".invalid"
michael@0 2090 inline nsresult
michael@0 2091 NS_MakeRandomInvalidURLString(nsCString& result)
michael@0 2092 {
michael@0 2093 nsresult rv;
michael@0 2094 nsCOMPtr<nsIUUIDGenerator> uuidgen =
michael@0 2095 do_GetService("@mozilla.org/uuid-generator;1", &rv);
michael@0 2096 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2097
michael@0 2098 nsID idee;
michael@0 2099 rv = uuidgen->GenerateUUIDInPlace(&idee);
michael@0 2100 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2101
michael@0 2102 char chars[NSID_LENGTH];
michael@0 2103 idee.ToProvidedString(chars);
michael@0 2104
michael@0 2105 result.AssignLiteral(NS_FAKE_SCHEME);
michael@0 2106 // Strip off the '{' and '}' at the beginning and end of the UUID
michael@0 2107 result.Append(chars + 1, NSID_LENGTH - 3);
michael@0 2108 result.AppendLiteral(NS_FAKE_TLD);
michael@0 2109
michael@0 2110 return NS_OK;
michael@0 2111 }
michael@0 2112 #undef NS_FAKE_SCHEME
michael@0 2113 #undef NS_FAKE_TLD
michael@0 2114
michael@0 2115 /**
michael@0 2116 * Helper function to determine whether urlString is Java-compatible --
michael@0 2117 * whether it can be passed to the Java URL(String) constructor without the
michael@0 2118 * latter throwing a MalformedURLException, or without Java otherwise
michael@0 2119 * mishandling it. This function (in effect) implements a scheme whitelist
michael@0 2120 * for Java.
michael@0 2121 */
michael@0 2122 inline nsresult
michael@0 2123 NS_CheckIsJavaCompatibleURLString(nsCString& urlString, bool *result)
michael@0 2124 {
michael@0 2125 *result = false; // Default to "no"
michael@0 2126
michael@0 2127 nsresult rv = NS_OK;
michael@0 2128 nsCOMPtr<nsIURLParser> urlParser =
michael@0 2129 do_GetService(NS_STDURLPARSER_CONTRACTID, &rv);
michael@0 2130 if (NS_FAILED(rv) || !urlParser)
michael@0 2131 return NS_ERROR_FAILURE;
michael@0 2132
michael@0 2133 bool compatible = true;
michael@0 2134 uint32_t schemePos = 0;
michael@0 2135 int32_t schemeLen = 0;
michael@0 2136 urlParser->ParseURL(urlString.get(), -1, &schemePos, &schemeLen,
michael@0 2137 nullptr, nullptr, nullptr, nullptr);
michael@0 2138 if (schemeLen != -1) {
michael@0 2139 nsCString scheme;
michael@0 2140 scheme.Assign(urlString.get() + schemePos, schemeLen);
michael@0 2141 // By default Java only understands a small number of URL schemes, and of
michael@0 2142 // these only some can legitimately represent a browser page's "origin"
michael@0 2143 // (and be something we can legitimately expect Java to handle ... or not
michael@0 2144 // to mishandle).
michael@0 2145 //
michael@0 2146 // Besides those listed below, the OJI plugin understands the "jar",
michael@0 2147 // "mailto", "netdoc", "javascript" and "rmi" schemes, and Java Plugin2
michael@0 2148 // also understands the "about" scheme. We actually pass "about" URLs
michael@0 2149 // to Java ("about:blank" when processing a javascript: URL (one that
michael@0 2150 // calls Java) from the location bar of a blank page, and (in FF4 and up)
michael@0 2151 // "about:home" when processing a javascript: URL from the home page).
michael@0 2152 // And Java doesn't appear to mishandle them (for example it doesn't allow
michael@0 2153 // connections to "about" URLs). But it doesn't make any sense to do
michael@0 2154 // same-origin checks on "about" URLs, so we don't include them in our
michael@0 2155 // scheme whitelist.
michael@0 2156 //
michael@0 2157 // The OJI plugin doesn't understand "chrome" URLs (only Java Plugin2
michael@0 2158 // does) -- so we mustn't pass them to the OJI plugin. But we do need to
michael@0 2159 // pass "chrome" URLs to Java Plugin2: Java Plugin2 grants additional
michael@0 2160 // privileges to chrome "origins", and some extensions take advantage of
michael@0 2161 // this. For more information see bug 620773.
michael@0 2162 //
michael@0 2163 // As of FF4, we no longer support the OJI plugin.
michael@0 2164 if (PL_strcasecmp(scheme.get(), "http") &&
michael@0 2165 PL_strcasecmp(scheme.get(), "https") &&
michael@0 2166 PL_strcasecmp(scheme.get(), "file") &&
michael@0 2167 PL_strcasecmp(scheme.get(), "ftp") &&
michael@0 2168 PL_strcasecmp(scheme.get(), "gopher") &&
michael@0 2169 PL_strcasecmp(scheme.get(), "chrome"))
michael@0 2170 compatible = false;
michael@0 2171 } else {
michael@0 2172 compatible = false;
michael@0 2173 }
michael@0 2174
michael@0 2175 *result = compatible;
michael@0 2176
michael@0 2177 return NS_OK;
michael@0 2178 }
michael@0 2179
michael@0 2180 /** Given the first (disposition) token from a Content-Disposition header,
michael@0 2181 * tell whether it indicates the content is inline or attachment
michael@0 2182 * @param aDispToken the disposition token from the content-disposition header
michael@0 2183 */
michael@0 2184 inline uint32_t
michael@0 2185 NS_GetContentDispositionFromToken(const nsAString& aDispToken)
michael@0 2186 {
michael@0 2187 // RFC 2183, section 2.8 says that an unknown disposition
michael@0 2188 // value should be treated as "attachment"
michael@0 2189 // If all of these tests eval to false, then we have a content-disposition of
michael@0 2190 // "attachment" or unknown
michael@0 2191 if (aDispToken.IsEmpty() ||
michael@0 2192 aDispToken.LowerCaseEqualsLiteral("inline") ||
michael@0 2193 // Broken sites just send
michael@0 2194 // Content-Disposition: filename="file"
michael@0 2195 // without a disposition token... screen those out.
michael@0 2196 StringHead(aDispToken, 8).LowerCaseEqualsLiteral("filename"))
michael@0 2197 return nsIChannel::DISPOSITION_INLINE;
michael@0 2198
michael@0 2199 return nsIChannel::DISPOSITION_ATTACHMENT;
michael@0 2200 }
michael@0 2201
michael@0 2202 /** Determine the disposition (inline/attachment) of the content based on the
michael@0 2203 * Content-Disposition header
michael@0 2204 * @param aHeader the content-disposition header (full value)
michael@0 2205 * @param aChan the channel the header came from
michael@0 2206 */
michael@0 2207 inline uint32_t
michael@0 2208 NS_GetContentDispositionFromHeader(const nsACString& aHeader, nsIChannel *aChan = nullptr)
michael@0 2209 {
michael@0 2210 nsresult rv;
michael@0 2211 nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
michael@0 2212 if (NS_FAILED(rv))
michael@0 2213 return nsIChannel::DISPOSITION_ATTACHMENT;
michael@0 2214
michael@0 2215 nsAutoCString fallbackCharset;
michael@0 2216 if (aChan) {
michael@0 2217 nsCOMPtr<nsIURI> uri;
michael@0 2218 aChan->GetURI(getter_AddRefs(uri));
michael@0 2219 if (uri)
michael@0 2220 uri->GetOriginCharset(fallbackCharset);
michael@0 2221 }
michael@0 2222
michael@0 2223 nsAutoString dispToken;
michael@0 2224 rv = mimehdrpar->GetParameterHTTP(aHeader, "", fallbackCharset, true, nullptr,
michael@0 2225 dispToken);
michael@0 2226
michael@0 2227 if (NS_FAILED(rv)) {
michael@0 2228 // special case (see bug 272541): empty disposition type handled as "inline"
michael@0 2229 if (rv == NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY)
michael@0 2230 return nsIChannel::DISPOSITION_INLINE;
michael@0 2231 return nsIChannel::DISPOSITION_ATTACHMENT;
michael@0 2232 }
michael@0 2233
michael@0 2234 return NS_GetContentDispositionFromToken(dispToken);
michael@0 2235 }
michael@0 2236
michael@0 2237 /** Extracts the filename out of a content-disposition header
michael@0 2238 * @param aFilename [out] The filename. Can be empty on error.
michael@0 2239 * @param aDisposition Value of a Content-Disposition header
michael@0 2240 * @param aURI Optional. Will be used to get a fallback charset for the
michael@0 2241 * filename, if it is QI'able to nsIURL
michael@0 2242 */
michael@0 2243 inline nsresult
michael@0 2244 NS_GetFilenameFromDisposition(nsAString& aFilename,
michael@0 2245 const nsACString& aDisposition,
michael@0 2246 nsIURI* aURI = nullptr)
michael@0 2247 {
michael@0 2248 aFilename.Truncate();
michael@0 2249
michael@0 2250 nsresult rv;
michael@0 2251 nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
michael@0 2252 do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
michael@0 2253 if (NS_FAILED(rv))
michael@0 2254 return rv;
michael@0 2255
michael@0 2256 nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
michael@0 2257
michael@0 2258 nsAutoCString fallbackCharset;
michael@0 2259 if (url)
michael@0 2260 url->GetOriginCharset(fallbackCharset);
michael@0 2261 // Get the value of 'filename' parameter
michael@0 2262 rv = mimehdrpar->GetParameterHTTP(aDisposition, "filename",
michael@0 2263 fallbackCharset, true, nullptr,
michael@0 2264 aFilename);
michael@0 2265
michael@0 2266 if (NS_FAILED(rv)) {
michael@0 2267 aFilename.Truncate();
michael@0 2268 return rv;
michael@0 2269 }
michael@0 2270
michael@0 2271 if (aFilename.IsEmpty())
michael@0 2272 return NS_ERROR_NOT_AVAILABLE;
michael@0 2273
michael@0 2274 return NS_OK;
michael@0 2275 }
michael@0 2276
michael@0 2277 /**
michael@0 2278 * Make sure Personal Security Manager is initialized
michael@0 2279 */
michael@0 2280 inline void
michael@0 2281 net_EnsurePSMInit()
michael@0 2282 {
michael@0 2283 nsCOMPtr<nsISocketProviderService> spserv =
michael@0 2284 do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID);
michael@0 2285 if (spserv) {
michael@0 2286 nsCOMPtr<nsISocketProvider> provider;
michael@0 2287 spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
michael@0 2288 }
michael@0 2289 }
michael@0 2290
michael@0 2291 /**
michael@0 2292 * Test whether a URI is "about:blank". |uri| must not be null
michael@0 2293 */
michael@0 2294 inline bool
michael@0 2295 NS_IsAboutBlank(nsIURI *uri)
michael@0 2296 {
michael@0 2297 // GetSpec can be expensive for some URIs, so check the scheme first.
michael@0 2298 bool isAbout = false;
michael@0 2299 if (NS_FAILED(uri->SchemeIs("about", &isAbout)) || !isAbout) {
michael@0 2300 return false;
michael@0 2301 }
michael@0 2302
michael@0 2303 nsAutoCString str;
michael@0 2304 uri->GetSpec(str);
michael@0 2305 return str.EqualsLiteral("about:blank");
michael@0 2306 }
michael@0 2307
michael@0 2308
michael@0 2309 inline nsresult
michael@0 2310 NS_GenerateHostPort(const nsCString& host, int32_t port,
michael@0 2311 nsCString& hostLine)
michael@0 2312 {
michael@0 2313 if (strchr(host.get(), ':')) {
michael@0 2314 // host is an IPv6 address literal and must be encapsulated in []'s
michael@0 2315 hostLine.Assign('[');
michael@0 2316 // scope id is not needed for Host header.
michael@0 2317 int scopeIdPos = host.FindChar('%');
michael@0 2318 if (scopeIdPos == -1)
michael@0 2319 hostLine.Append(host);
michael@0 2320 else if (scopeIdPos > 0)
michael@0 2321 hostLine.Append(Substring(host, 0, scopeIdPos));
michael@0 2322 else
michael@0 2323 return NS_ERROR_MALFORMED_URI;
michael@0 2324 hostLine.Append(']');
michael@0 2325 }
michael@0 2326 else
michael@0 2327 hostLine.Assign(host);
michael@0 2328 if (port != -1) {
michael@0 2329 hostLine.Append(':');
michael@0 2330 hostLine.AppendInt(port);
michael@0 2331 }
michael@0 2332 return NS_OK;
michael@0 2333 }
michael@0 2334
michael@0 2335 /**
michael@0 2336 * Sniff the content type for a given request or a given buffer.
michael@0 2337 *
michael@0 2338 * aSnifferType can be either NS_CONTENT_SNIFFER_CATEGORY or
michael@0 2339 * NS_DATA_SNIFFER_CATEGORY. The function returns the sniffed content type
michael@0 2340 * in the aSniffedType argument. This argument will not be modified if the
michael@0 2341 * content type could not be sniffed.
michael@0 2342 */
michael@0 2343 inline void
michael@0 2344 NS_SniffContent(const char* aSnifferType, nsIRequest* aRequest,
michael@0 2345 const uint8_t* aData, uint32_t aLength,
michael@0 2346 nsACString& aSniffedType)
michael@0 2347 {
michael@0 2348 typedef nsCategoryCache<nsIContentSniffer> ContentSnifferCache;
michael@0 2349 extern NS_HIDDEN_(ContentSnifferCache*) gNetSniffers;
michael@0 2350 extern NS_HIDDEN_(ContentSnifferCache*) gDataSniffers;
michael@0 2351 ContentSnifferCache* cache = nullptr;
michael@0 2352 if (!strcmp(aSnifferType, NS_CONTENT_SNIFFER_CATEGORY)) {
michael@0 2353 if (!gNetSniffers) {
michael@0 2354 gNetSniffers = new ContentSnifferCache(NS_CONTENT_SNIFFER_CATEGORY);
michael@0 2355 }
michael@0 2356 cache = gNetSniffers;
michael@0 2357 } else if (!strcmp(aSnifferType, NS_DATA_SNIFFER_CATEGORY)) {
michael@0 2358 if (!gDataSniffers) {
michael@0 2359 gDataSniffers = new ContentSnifferCache(NS_DATA_SNIFFER_CATEGORY);
michael@0 2360 }
michael@0 2361 cache = gDataSniffers;
michael@0 2362 } else {
michael@0 2363 // Invalid content sniffer type was requested
michael@0 2364 MOZ_ASSERT(false);
michael@0 2365 return;
michael@0 2366 }
michael@0 2367
michael@0 2368 nsCOMArray<nsIContentSniffer> sniffers;
michael@0 2369 cache->GetEntries(sniffers);
michael@0 2370 for (int32_t i = 0; i < sniffers.Count(); ++i) {
michael@0 2371 nsresult rv = sniffers[i]->GetMIMETypeFromContent(aRequest, aData, aLength, aSniffedType);
michael@0 2372 if (NS_SUCCEEDED(rv) && !aSniffedType.IsEmpty()) {
michael@0 2373 return;
michael@0 2374 }
michael@0 2375 }
michael@0 2376
michael@0 2377 aSniffedType.Truncate();
michael@0 2378 }
michael@0 2379
michael@0 2380 /**
michael@0 2381 * Whether the channel was created to load a srcdoc document.
michael@0 2382 * Note that view-source:about:srcdoc is classified as a srcdoc document by
michael@0 2383 * this function, which may not be applicable everywhere.
michael@0 2384 */
michael@0 2385 inline bool
michael@0 2386 NS_IsSrcdocChannel(nsIChannel *aChannel)
michael@0 2387 {
michael@0 2388 bool isSrcdoc;
michael@0 2389 nsCOMPtr<nsIInputStreamChannel> isr = do_QueryInterface(aChannel);
michael@0 2390 if (isr) {
michael@0 2391 isr->GetIsSrcdocChannel(&isSrcdoc);
michael@0 2392 return isSrcdoc;
michael@0 2393 }
michael@0 2394 nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(aChannel);
michael@0 2395 if (vsc) {
michael@0 2396 vsc->GetIsSrcdocChannel(&isSrcdoc);
michael@0 2397 return isSrcdoc;
michael@0 2398 }
michael@0 2399 return false;
michael@0 2400 }
michael@0 2401
michael@0 2402 #endif // !nsNetUtil_h__

mercurial