netwerk/base/public/nsNetUtil.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/base/public/nsNetUtil.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2402 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim:set ts=4 sw=4 sts=4 et cin: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef nsNetUtil_h__
    1.11 +#define nsNetUtil_h__
    1.12 +
    1.13 +#include "nsError.h"
    1.14 +#include "nsNetCID.h"
    1.15 +#include "nsStringGlue.h"
    1.16 +#include "nsMemory.h"
    1.17 +#include "nsCOMPtr.h"
    1.18 +#include "prio.h" // for read/write flags, permissions, etc.
    1.19 +#include "nsHashKeys.h"
    1.20 +
    1.21 +#include "plstr.h"
    1.22 +#include "nsIURI.h"
    1.23 +#include "nsIStandardURL.h"
    1.24 +#include "nsIURLParser.h"
    1.25 +#include "nsIUUIDGenerator.h"
    1.26 +#include "nsIInputStream.h"
    1.27 +#include "nsIOutputStream.h"
    1.28 +#include "nsISafeOutputStream.h"
    1.29 +#include "nsIStreamListener.h"
    1.30 +#include "nsIRequestObserverProxy.h"
    1.31 +#include "nsISimpleStreamListener.h"
    1.32 +#include "nsILoadGroup.h"
    1.33 +#include "nsIInterfaceRequestor.h"
    1.34 +#include "nsIInterfaceRequestorUtils.h"
    1.35 +#include "nsIIOService.h"
    1.36 +#include "nsIServiceManager.h"
    1.37 +#include "nsIChannel.h"
    1.38 +#include "nsChannelProperties.h"
    1.39 +#include "nsIInputStreamChannel.h"
    1.40 +#include "nsITransport.h"
    1.41 +#include "nsIStreamTransportService.h"
    1.42 +#include "nsIHttpChannel.h"
    1.43 +#include "nsIDownloader.h"
    1.44 +#include "nsIStreamLoader.h"
    1.45 +#include "nsIUnicharStreamLoader.h"
    1.46 +#include "nsIPipe.h"
    1.47 +#include "nsIProtocolHandler.h"
    1.48 +#include "nsIFileProtocolHandler.h"
    1.49 +#include "nsIStringStream.h"
    1.50 +#include "nsIFile.h"
    1.51 +#include "nsIFileStreams.h"
    1.52 +#include "nsIFileURL.h"
    1.53 +#include "nsIProtocolProxyService.h"
    1.54 +#include "nsIProxyInfo.h"
    1.55 +#include "nsIFileStreams.h"
    1.56 +#include "nsIBufferedStreams.h"
    1.57 +#include "nsIInputStreamPump.h"
    1.58 +#include "nsIAsyncStreamCopier.h"
    1.59 +#include "nsIPersistentProperties2.h"
    1.60 +#include "nsISyncStreamListener.h"
    1.61 +#include "nsInterfaceRequestorAgg.h"
    1.62 +#include "nsINetUtil.h"
    1.63 +#include "nsIURIWithPrincipal.h"
    1.64 +#include "nsIAuthPrompt.h"
    1.65 +#include "nsIAuthPrompt2.h"
    1.66 +#include "nsIAuthPromptAdapterFactory.h"
    1.67 +#include "nsComponentManagerUtils.h"
    1.68 +#include "nsServiceManagerUtils.h"
    1.69 +#include "nsINestedURI.h"
    1.70 +#include "nsIMutable.h"
    1.71 +#include "nsIPropertyBag2.h"
    1.72 +#include "nsIWritablePropertyBag2.h"
    1.73 +#include "nsIIDNService.h"
    1.74 +#include "nsIChannelEventSink.h"
    1.75 +#include "nsIChannelPolicy.h"
    1.76 +#include "nsISocketProviderService.h"
    1.77 +#include "nsISocketProvider.h"
    1.78 +#include "nsIRedirectChannelRegistrar.h"
    1.79 +#include "nsIMIMEHeaderParam.h"
    1.80 +#include "nsILoadContext.h"
    1.81 +#include "mozilla/Services.h"
    1.82 +#include "nsIPrivateBrowsingChannel.h"
    1.83 +#include "mozIApplicationClearPrivateDataParams.h"
    1.84 +#include "nsIOfflineCacheUpdate.h"
    1.85 +#include "nsIContentSniffer.h"
    1.86 +#include "nsCategoryCache.h"
    1.87 +#include "nsStringStream.h"
    1.88 +#include "nsIViewSourceChannel.h"
    1.89 +
    1.90 +#include <limits>
    1.91 +
    1.92 +#ifdef MOZILLA_INTERNAL_API
    1.93 +
    1.94 +#include "nsReadableUtils.h"
    1.95 +
    1.96 +inline already_AddRefed<nsIIOService>
    1.97 +do_GetIOService(nsresult* error = 0)
    1.98 +{
    1.99 +    nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
   1.100 +    if (error)
   1.101 +        *error = io ? NS_OK : NS_ERROR_FAILURE;
   1.102 +    return io.forget();
   1.103 +}
   1.104 +
   1.105 +inline already_AddRefed<nsINetUtil>
   1.106 +do_GetNetUtil(nsresult *error = 0) 
   1.107 +{
   1.108 +    nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
   1.109 +    nsCOMPtr<nsINetUtil> util;
   1.110 +    if (io)
   1.111 +        util = do_QueryInterface(io);
   1.112 +
   1.113 +    if (error)
   1.114 +        *error = !!util ? NS_OK : NS_ERROR_FAILURE;
   1.115 +    return util.forget();
   1.116 +}
   1.117 +#else
   1.118 +// Helper, to simplify getting the I/O service.
   1.119 +inline const nsGetServiceByContractIDWithError
   1.120 +do_GetIOService(nsresult* error = 0)
   1.121 +{
   1.122 +    return nsGetServiceByContractIDWithError(NS_IOSERVICE_CONTRACTID, error);
   1.123 +}
   1.124 +
   1.125 +// An alias to do_GetIOService
   1.126 +inline const nsGetServiceByContractIDWithError
   1.127 +do_GetNetUtil(nsresult* error = 0)
   1.128 +{
   1.129 +    return do_GetIOService(error);
   1.130 +}
   1.131 +#endif
   1.132 +
   1.133 +// private little helper function... don't call this directly!
   1.134 +inline nsresult
   1.135 +net_EnsureIOService(nsIIOService **ios, nsCOMPtr<nsIIOService> &grip)
   1.136 +{
   1.137 +    nsresult rv = NS_OK;
   1.138 +    if (!*ios) {
   1.139 +        grip = do_GetIOService(&rv);
   1.140 +        *ios = grip;
   1.141 +    }
   1.142 +    return rv;
   1.143 +}
   1.144 +
   1.145 +inline nsresult
   1.146 +NS_NewURI(nsIURI **result, 
   1.147 +          const nsACString &spec, 
   1.148 +          const char *charset = nullptr,
   1.149 +          nsIURI *baseURI = nullptr,
   1.150 +          nsIIOService *ioService = nullptr)     // pass in nsIIOService to optimize callers
   1.151 +{
   1.152 +    nsresult rv;
   1.153 +    nsCOMPtr<nsIIOService> grip;
   1.154 +    rv = net_EnsureIOService(&ioService, grip);
   1.155 +    if (ioService)
   1.156 +        rv = ioService->NewURI(spec, charset, baseURI, result);
   1.157 +    return rv; 
   1.158 +}
   1.159 +
   1.160 +inline nsresult
   1.161 +NS_NewURI(nsIURI* *result, 
   1.162 +          const nsAString& spec, 
   1.163 +          const char *charset = nullptr,
   1.164 +          nsIURI* baseURI = nullptr,
   1.165 +          nsIIOService* ioService = nullptr)     // pass in nsIIOService to optimize callers
   1.166 +{
   1.167 +    return NS_NewURI(result, NS_ConvertUTF16toUTF8(spec), charset, baseURI, ioService);
   1.168 +}
   1.169 +
   1.170 +inline nsresult
   1.171 +NS_NewURI(nsIURI* *result, 
   1.172 +          const char *spec,
   1.173 +          nsIURI* baseURI = nullptr,
   1.174 +          nsIIOService* ioService = nullptr)     // pass in nsIIOService to optimize callers
   1.175 +{
   1.176 +    return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI, ioService);
   1.177 +}
   1.178 +
   1.179 +inline nsresult
   1.180 +NS_NewFileURI(nsIURI* *result, 
   1.181 +              nsIFile* spec, 
   1.182 +              nsIIOService* ioService = nullptr)     // pass in nsIIOService to optimize callers
   1.183 +{
   1.184 +    nsresult rv;
   1.185 +    nsCOMPtr<nsIIOService> grip;
   1.186 +    rv = net_EnsureIOService(&ioService, grip);
   1.187 +    if (ioService)
   1.188 +        rv = ioService->NewFileURI(spec, result);
   1.189 +    return rv;
   1.190 +}
   1.191 +
   1.192 +inline nsresult
   1.193 +NS_NewChannel(nsIChannel           **result,
   1.194 +              nsIURI                *uri,
   1.195 +              nsIIOService          *ioService = nullptr,    // pass in nsIIOService to optimize callers
   1.196 +              nsILoadGroup          *loadGroup = nullptr,
   1.197 +              nsIInterfaceRequestor *callbacks = nullptr,
   1.198 +              uint32_t               loadFlags = nsIRequest::LOAD_NORMAL,
   1.199 +              nsIChannelPolicy      *channelPolicy = nullptr)
   1.200 +{
   1.201 +    nsresult rv;
   1.202 +    nsCOMPtr<nsIIOService> grip;
   1.203 +    rv = net_EnsureIOService(&ioService, grip);
   1.204 +    if (ioService) {
   1.205 +        nsCOMPtr<nsIChannel> chan;
   1.206 +        rv = ioService->NewChannelFromURI(uri, getter_AddRefs(chan));
   1.207 +        if (NS_SUCCEEDED(rv)) {
   1.208 +            if (loadGroup) {
   1.209 +                rv = chan->SetLoadGroup(loadGroup);
   1.210 +            }
   1.211 +            if (callbacks) {
   1.212 +                nsresult tmp = chan->SetNotificationCallbacks(callbacks);
   1.213 +                if (NS_FAILED(tmp)) {
   1.214 +                    rv = tmp;
   1.215 +                }
   1.216 +            }
   1.217 +            if (loadFlags != nsIRequest::LOAD_NORMAL) {
   1.218 +                // Retain the LOAD_REPLACE load flag if set.
   1.219 +                nsLoadFlags normalLoadFlags = 0;
   1.220 +                chan->GetLoadFlags(&normalLoadFlags);
   1.221 +                nsresult tmp = chan->SetLoadFlags(loadFlags |
   1.222 +                                                  (normalLoadFlags &
   1.223 +                                                   nsIChannel::LOAD_REPLACE));
   1.224 +                if (NS_FAILED(tmp)) {
   1.225 +                    rv = tmp;
   1.226 +                }
   1.227 +            }
   1.228 +            if (channelPolicy) {
   1.229 +                nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(chan);
   1.230 +                if (props) {
   1.231 +                    props->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
   1.232 +                                                  channelPolicy);
   1.233 +                }
   1.234 +            }
   1.235 +            if (NS_SUCCEEDED(rv))
   1.236 +                chan.forget(result);
   1.237 +        }
   1.238 +    }
   1.239 +    return rv;
   1.240 +}
   1.241 +
   1.242 +// Use this function with CAUTION. It creates a stream that blocks when you
   1.243 +// Read() from it and blocking the UI thread is a bad idea. If you don't want
   1.244 +// to implement a full blown asynchronous consumer (via nsIStreamListener) look
   1.245 +// at nsIStreamLoader instead.
   1.246 +inline nsresult
   1.247 +NS_OpenURI(nsIInputStream       **result,
   1.248 +           nsIURI                *uri,
   1.249 +           nsIIOService          *ioService = nullptr,     // pass in nsIIOService to optimize callers
   1.250 +           nsILoadGroup          *loadGroup = nullptr,
   1.251 +           nsIInterfaceRequestor *callbacks = nullptr,
   1.252 +           uint32_t               loadFlags = nsIRequest::LOAD_NORMAL,
   1.253 +           nsIChannel           **channelOut = nullptr)
   1.254 +{
   1.255 +    nsresult rv;
   1.256 +    nsCOMPtr<nsIChannel> channel;
   1.257 +    rv = NS_NewChannel(getter_AddRefs(channel), uri, ioService,
   1.258 +                       loadGroup, callbacks, loadFlags);
   1.259 +    if (NS_SUCCEEDED(rv)) {
   1.260 +        nsIInputStream *stream;
   1.261 +        rv = channel->Open(&stream);
   1.262 +        if (NS_SUCCEEDED(rv)) {
   1.263 +            *result = stream;
   1.264 +            if (channelOut) {
   1.265 +                *channelOut = nullptr;
   1.266 +                channel.swap(*channelOut);
   1.267 +            }
   1.268 +        }
   1.269 +    }
   1.270 +    return rv;
   1.271 +}
   1.272 +
   1.273 +inline nsresult
   1.274 +NS_OpenURI(nsIStreamListener     *listener, 
   1.275 +           nsISupports           *context, 
   1.276 +           nsIURI                *uri,
   1.277 +           nsIIOService          *ioService = nullptr,     // pass in nsIIOService to optimize callers
   1.278 +           nsILoadGroup          *loadGroup = nullptr,
   1.279 +           nsIInterfaceRequestor *callbacks = nullptr,
   1.280 +           uint32_t               loadFlags = nsIRequest::LOAD_NORMAL)
   1.281 +{
   1.282 +    nsresult rv;
   1.283 +    nsCOMPtr<nsIChannel> channel;
   1.284 +    rv = NS_NewChannel(getter_AddRefs(channel), uri, ioService,
   1.285 +                       loadGroup, callbacks, loadFlags);
   1.286 +    if (NS_SUCCEEDED(rv))
   1.287 +        rv = channel->AsyncOpen(listener, context);
   1.288 +    return rv;
   1.289 +}
   1.290 +
   1.291 +inline nsresult
   1.292 +NS_MakeAbsoluteURI(nsACString       &result,
   1.293 +                   const nsACString &spec, 
   1.294 +                   nsIURI           *baseURI)
   1.295 +{
   1.296 +    nsresult rv;
   1.297 +    if (!baseURI) {
   1.298 +        NS_WARNING("It doesn't make sense to not supply a base URI");
   1.299 +        result = spec;
   1.300 +        rv = NS_OK;
   1.301 +    }
   1.302 +    else if (spec.IsEmpty())
   1.303 +        rv = baseURI->GetSpec(result);
   1.304 +    else
   1.305 +        rv = baseURI->Resolve(spec, result);
   1.306 +    return rv;
   1.307 +}
   1.308 +
   1.309 +inline nsresult
   1.310 +NS_MakeAbsoluteURI(char        **result,
   1.311 +                   const char   *spec, 
   1.312 +                   nsIURI       *baseURI)
   1.313 +{
   1.314 +    nsresult rv;
   1.315 +    nsAutoCString resultBuf;
   1.316 +    rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI);
   1.317 +    if (NS_SUCCEEDED(rv)) {
   1.318 +        *result = ToNewCString(resultBuf);
   1.319 +        if (!*result)
   1.320 +            rv = NS_ERROR_OUT_OF_MEMORY;
   1.321 +    }
   1.322 +    return rv;
   1.323 +}
   1.324 +
   1.325 +inline nsresult
   1.326 +NS_MakeAbsoluteURI(nsAString       &result,
   1.327 +                   const nsAString &spec, 
   1.328 +                   nsIURI          *baseURI)
   1.329 +{
   1.330 +    nsresult rv;
   1.331 +    if (!baseURI) {
   1.332 +        NS_WARNING("It doesn't make sense to not supply a base URI");
   1.333 +        result = spec;
   1.334 +        rv = NS_OK;
   1.335 +    }
   1.336 +    else {
   1.337 +        nsAutoCString resultBuf;
   1.338 +        if (spec.IsEmpty())
   1.339 +            rv = baseURI->GetSpec(resultBuf);
   1.340 +        else
   1.341 +            rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf);
   1.342 +        if (NS_SUCCEEDED(rv))
   1.343 +            CopyUTF8toUTF16(resultBuf, result);
   1.344 +    }
   1.345 +    return rv;
   1.346 +}
   1.347 +
   1.348 +/**
   1.349 + * This function is a helper function to get a scheme's default port.
   1.350 + */
   1.351 +inline int32_t
   1.352 +NS_GetDefaultPort(const char *scheme,
   1.353 +                  nsIIOService* ioService = nullptr)
   1.354 +{
   1.355 +  nsresult rv;
   1.356 +
   1.357 +  nsCOMPtr<nsIIOService> grip;
   1.358 +  net_EnsureIOService(&ioService, grip);
   1.359 +  if (!ioService)
   1.360 +      return -1;
   1.361 + 
   1.362 +  nsCOMPtr<nsIProtocolHandler> handler;
   1.363 +  rv = ioService->GetProtocolHandler(scheme, getter_AddRefs(handler));
   1.364 +  if (NS_FAILED(rv))
   1.365 +    return -1;
   1.366 +  int32_t port;
   1.367 +  rv = handler->GetDefaultPort(&port);
   1.368 +  return NS_SUCCEEDED(rv) ? port : -1;
   1.369 +}
   1.370 +
   1.371 +/**
   1.372 + * This function is a helper function to apply the ToAscii conversion
   1.373 + * to a string
   1.374 + */
   1.375 +inline bool
   1.376 +NS_StringToACE(const nsACString &idn, nsACString &result)
   1.377 +{
   1.378 +  nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
   1.379 +  if (!idnSrv)
   1.380 +    return false;
   1.381 +  nsresult rv = idnSrv->ConvertUTF8toACE(idn, result);
   1.382 +  if (NS_FAILED(rv))
   1.383 +    return false;
   1.384 +  
   1.385 +  return true;
   1.386 +}
   1.387 +
   1.388 +/**
   1.389 + * This function is a helper function to get a protocol's default port if the
   1.390 + * URI does not specify a port explicitly. Returns -1 if this protocol has no
   1.391 + * concept of ports or if there was an error getting the port.
   1.392 + */
   1.393 +inline int32_t
   1.394 +NS_GetRealPort(nsIURI* aURI)
   1.395 +{
   1.396 +    int32_t port;
   1.397 +    nsresult rv = aURI->GetPort(&port);
   1.398 +    if (NS_FAILED(rv))
   1.399 +        return -1;
   1.400 +
   1.401 +    if (port != -1)
   1.402 +        return port; // explicitly specified
   1.403 +
   1.404 +    // Otherwise, we have to get the default port from the protocol handler
   1.405 +
   1.406 +    // Need the scheme first
   1.407 +    nsAutoCString scheme;
   1.408 +    rv = aURI->GetScheme(scheme);
   1.409 +    if (NS_FAILED(rv))
   1.410 +        return -1;
   1.411 +
   1.412 +    return NS_GetDefaultPort(scheme.get());
   1.413 +}
   1.414 +
   1.415 +inline nsresult
   1.416 +NS_NewInputStreamChannel(nsIChannel      **result,
   1.417 +                         nsIURI           *uri,
   1.418 +                         nsIInputStream   *stream,
   1.419 +                         const nsACString &contentType,
   1.420 +                         const nsACString *contentCharset)
   1.421 +{
   1.422 +    nsresult rv;
   1.423 +    nsCOMPtr<nsIInputStreamChannel> isc =
   1.424 +        do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
   1.425 +    if (NS_FAILED(rv))
   1.426 +        return rv;
   1.427 +    rv = isc->SetURI(uri);
   1.428 +    nsresult tmp = isc->SetContentStream(stream);
   1.429 +    if (NS_FAILED(tmp)) {
   1.430 +        rv = tmp;
   1.431 +    }
   1.432 +    if (NS_FAILED(rv))
   1.433 +        return rv;
   1.434 +    nsCOMPtr<nsIChannel> chan = do_QueryInterface(isc, &rv);
   1.435 +    if (NS_FAILED(rv))
   1.436 +        return rv;
   1.437 +    if (!contentType.IsEmpty())
   1.438 +        rv = chan->SetContentType(contentType);
   1.439 +    if (contentCharset && !contentCharset->IsEmpty()) {
   1.440 +        tmp = chan->SetContentCharset(*contentCharset);
   1.441 +        if (NS_FAILED(tmp)) {
   1.442 +            rv = tmp;
   1.443 +        }
   1.444 +    }
   1.445 +    if (NS_SUCCEEDED(rv)) {
   1.446 +        *result = nullptr;
   1.447 +        chan.swap(*result);
   1.448 +    }
   1.449 +    return rv;
   1.450 +}
   1.451 +
   1.452 +inline nsresult
   1.453 +NS_NewInputStreamChannel(nsIChannel      **result,
   1.454 +                         nsIURI           *uri,
   1.455 +                         nsIInputStream   *stream,
   1.456 +                         const nsACString &contentType    = EmptyCString())
   1.457 +{
   1.458 +    return NS_NewInputStreamChannel(result, uri, stream, contentType, nullptr);
   1.459 +}
   1.460 +
   1.461 +inline nsresult
   1.462 +NS_NewInputStreamChannel(nsIChannel      **result,
   1.463 +                         nsIURI           *uri,
   1.464 +                         nsIInputStream   *stream,
   1.465 +                         const nsACString &contentType,
   1.466 +                         const nsACString &contentCharset)
   1.467 +{
   1.468 +    return NS_NewInputStreamChannel(result, uri, stream, contentType,
   1.469 +                                    &contentCharset);
   1.470 +}
   1.471 +
   1.472 +inline nsresult
   1.473 +NS_NewInputStreamChannel(nsIChannel      **result,
   1.474 +                         nsIURI           *uri,
   1.475 +                         const nsAString  &data,
   1.476 +                         const nsACString &contentType,
   1.477 +                         bool              isSrcdocChannel = false)
   1.478 +{
   1.479 +
   1.480 +    nsresult rv;
   1.481 +
   1.482 +    nsCOMPtr<nsIStringInputStream> stream;
   1.483 +    stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
   1.484 +    NS_ENSURE_SUCCESS(rv, rv);
   1.485 +
   1.486 +#ifdef MOZILLA_INTERNAL_API
   1.487 +    uint32_t len;
   1.488 +    char* utf8Bytes = ToNewUTF8String(data, &len);
   1.489 +    rv = stream->AdoptData(utf8Bytes, len);
   1.490 +#else
   1.491 +    char* utf8Bytes = ToNewUTF8String(data);
   1.492 +    rv = stream->AdoptData(utf8Bytes, strlen(utf8Bytes));
   1.493 +#endif
   1.494 +
   1.495 +    nsCOMPtr<nsIChannel> chan;
   1.496 +
   1.497 +    rv = NS_NewInputStreamChannel(getter_AddRefs(chan), uri, stream,
   1.498 +                                  contentType, NS_LITERAL_CSTRING("UTF-8"));
   1.499 +    NS_ENSURE_SUCCESS(rv, rv);
   1.500 +
   1.501 +    if (isSrcdocChannel) {
   1.502 +        nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(chan);
   1.503 +        NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE);
   1.504 +        inStrmChan->SetSrcdocData(data);
   1.505 +    }
   1.506 +
   1.507 +    *result = nullptr;
   1.508 +    chan.swap(*result);
   1.509 +
   1.510 +    return NS_OK;
   1.511 +}
   1.512 +
   1.513 +inline nsresult
   1.514 +NS_NewInputStreamPump(nsIInputStreamPump **result,
   1.515 +                      nsIInputStream      *stream,
   1.516 +                      int64_t              streamPos = int64_t(-1),
   1.517 +                      int64_t              streamLen = int64_t(-1),
   1.518 +                      uint32_t             segsize = 0,
   1.519 +                      uint32_t             segcount = 0,
   1.520 +                      bool                 closeWhenDone = false)
   1.521 +{
   1.522 +    nsresult rv;
   1.523 +    nsCOMPtr<nsIInputStreamPump> pump =
   1.524 +        do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
   1.525 +    if (NS_SUCCEEDED(rv)) {
   1.526 +        rv = pump->Init(stream, streamPos, streamLen,
   1.527 +                        segsize, segcount, closeWhenDone);
   1.528 +        if (NS_SUCCEEDED(rv)) {
   1.529 +            *result = nullptr;
   1.530 +            pump.swap(*result);
   1.531 +        }
   1.532 +    }
   1.533 +    return rv;
   1.534 +}
   1.535 +
   1.536 +// NOTE: you will need to specify whether or not your streams are buffered
   1.537 +// (i.e., do they implement ReadSegments/WriteSegments).  the default
   1.538 +// assumption of TRUE for both streams might not be right for you!
   1.539 +inline nsresult
   1.540 +NS_NewAsyncStreamCopier(nsIAsyncStreamCopier **result,
   1.541 +                        nsIInputStream        *source,
   1.542 +                        nsIOutputStream       *sink,
   1.543 +                        nsIEventTarget        *target,
   1.544 +                        bool                   sourceBuffered = true,
   1.545 +                        bool                   sinkBuffered = true,
   1.546 +                        uint32_t               chunkSize = 0,
   1.547 +                        bool                   closeSource = true,
   1.548 +                        bool                   closeSink = true)
   1.549 +{
   1.550 +    nsresult rv;
   1.551 +    nsCOMPtr<nsIAsyncStreamCopier> copier =
   1.552 +        do_CreateInstance(NS_ASYNCSTREAMCOPIER_CONTRACTID, &rv);
   1.553 +    if (NS_SUCCEEDED(rv)) {
   1.554 +        rv = copier->Init(source, sink, target, sourceBuffered, sinkBuffered,
   1.555 +                          chunkSize, closeSource, closeSink);
   1.556 +        if (NS_SUCCEEDED(rv)) {
   1.557 +            *result = nullptr;
   1.558 +            copier.swap(*result);
   1.559 +        }
   1.560 +    }
   1.561 +    return rv;
   1.562 +}
   1.563 +
   1.564 +inline nsresult
   1.565 +NS_NewLoadGroup(nsILoadGroup      **result,
   1.566 +                nsIRequestObserver *obs)
   1.567 +{
   1.568 +    nsresult rv;
   1.569 +    nsCOMPtr<nsILoadGroup> group =
   1.570 +        do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
   1.571 +    if (NS_SUCCEEDED(rv)) {
   1.572 +        rv = group->SetGroupObserver(obs);
   1.573 +        if (NS_SUCCEEDED(rv)) {
   1.574 +            *result = nullptr;
   1.575 +            group.swap(*result);
   1.576 +        }
   1.577 +    }
   1.578 +    return rv;
   1.579 +}
   1.580 +
   1.581 +inline nsresult
   1.582 +NS_NewDownloader(nsIStreamListener   **result,
   1.583 +                 nsIDownloadObserver  *observer,
   1.584 +                 nsIFile              *downloadLocation = nullptr)
   1.585 +{
   1.586 +    nsresult rv;
   1.587 +    nsCOMPtr<nsIDownloader> downloader =
   1.588 +        do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv);
   1.589 +    if (NS_SUCCEEDED(rv)) {
   1.590 +        rv = downloader->Init(observer, downloadLocation);
   1.591 +        if (NS_SUCCEEDED(rv))
   1.592 +            NS_ADDREF(*result = downloader);
   1.593 +    }
   1.594 +    return rv;
   1.595 +}
   1.596 +
   1.597 +inline nsresult
   1.598 +NS_NewStreamLoader(nsIStreamLoader        **result,
   1.599 +                   nsIStreamLoaderObserver *observer)
   1.600 +{
   1.601 +    nsresult rv;
   1.602 +    nsCOMPtr<nsIStreamLoader> loader =
   1.603 +        do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv);
   1.604 +    if (NS_SUCCEEDED(rv)) {
   1.605 +        rv = loader->Init(observer);
   1.606 +        if (NS_SUCCEEDED(rv)) {
   1.607 +            *result = nullptr;
   1.608 +            loader.swap(*result);
   1.609 +        }
   1.610 +    }
   1.611 +    return rv;
   1.612 +}
   1.613 +
   1.614 +inline nsresult
   1.615 +NS_NewStreamLoader(nsIStreamLoader        **result,
   1.616 +                   nsIURI                  *uri,
   1.617 +                   nsIStreamLoaderObserver *observer,
   1.618 +                   nsISupports             *context   = nullptr,
   1.619 +                   nsILoadGroup            *loadGroup = nullptr,
   1.620 +                   nsIInterfaceRequestor   *callbacks = nullptr,
   1.621 +                   uint32_t                 loadFlags = nsIRequest::LOAD_NORMAL,
   1.622 +                   nsIURI                  *referrer  = nullptr)
   1.623 +{
   1.624 +    nsresult rv;
   1.625 +    nsCOMPtr<nsIChannel> channel;
   1.626 +    rv = NS_NewChannel(getter_AddRefs(channel),
   1.627 +                       uri,
   1.628 +                       nullptr,
   1.629 +                       loadGroup,
   1.630 +                       callbacks,
   1.631 +                       loadFlags);
   1.632 +    if (NS_SUCCEEDED(rv)) {
   1.633 +        nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   1.634 +        if (httpChannel)
   1.635 +            httpChannel->SetReferrer(referrer);
   1.636 +        rv = NS_NewStreamLoader(result, observer);
   1.637 +        if (NS_SUCCEEDED(rv))
   1.638 +          rv = channel->AsyncOpen(*result, context);
   1.639 +    }
   1.640 +    return rv;
   1.641 +}
   1.642 +
   1.643 +inline nsresult
   1.644 +NS_NewUnicharStreamLoader(nsIUnicharStreamLoader        **result,
   1.645 +                          nsIUnicharStreamLoaderObserver *observer)
   1.646 +{
   1.647 +    nsresult rv;
   1.648 +    nsCOMPtr<nsIUnicharStreamLoader> loader =
   1.649 +        do_CreateInstance(NS_UNICHARSTREAMLOADER_CONTRACTID, &rv);
   1.650 +    if (NS_SUCCEEDED(rv)) {
   1.651 +        rv = loader->Init(observer);
   1.652 +        if (NS_SUCCEEDED(rv)) {
   1.653 +            *result = nullptr;
   1.654 +            loader.swap(*result);
   1.655 +        }
   1.656 +    }
   1.657 +    return rv;
   1.658 +}
   1.659 +
   1.660 +inline nsresult
   1.661 +NS_NewSyncStreamListener(nsIStreamListener **result,
   1.662 +                         nsIInputStream    **stream)
   1.663 +{
   1.664 +    nsresult rv;
   1.665 +    nsCOMPtr<nsISyncStreamListener> listener =
   1.666 +        do_CreateInstance(NS_SYNCSTREAMLISTENER_CONTRACTID, &rv);
   1.667 +    if (NS_SUCCEEDED(rv)) {
   1.668 +        rv = listener->GetInputStream(stream);
   1.669 +        if (NS_SUCCEEDED(rv))
   1.670 +            NS_ADDREF(*result = listener);  // cannot use nsCOMPtr::swap
   1.671 +    }
   1.672 +    return rv;
   1.673 +}
   1.674 +
   1.675 +/**
   1.676 + * Implement the nsIChannel::Open(nsIInputStream**) method using the channel's
   1.677 + * AsyncOpen method.
   1.678 + *
   1.679 + * NOTE: Reading from the returned nsIInputStream may spin the current
   1.680 + * thread's event queue, which could result in any event being processed.
   1.681 + */
   1.682 +inline nsresult
   1.683 +NS_ImplementChannelOpen(nsIChannel      *channel,
   1.684 +                        nsIInputStream **result)
   1.685 +{
   1.686 +    nsCOMPtr<nsIStreamListener> listener;
   1.687 +    nsCOMPtr<nsIInputStream> stream;
   1.688 +    nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener),
   1.689 +                                           getter_AddRefs(stream));
   1.690 +    if (NS_SUCCEEDED(rv)) {
   1.691 +        rv = channel->AsyncOpen(listener, nullptr);
   1.692 +        if (NS_SUCCEEDED(rv)) {
   1.693 +            uint64_t n;
   1.694 +            // block until the initial response is received or an error occurs.
   1.695 +            rv = stream->Available(&n);
   1.696 +            if (NS_SUCCEEDED(rv)) {
   1.697 +                *result = nullptr;
   1.698 +                stream.swap(*result);
   1.699 +            }
   1.700 +        }
   1.701 +    }
   1.702 +    return rv;
   1.703 +}
   1.704 +
   1.705 +inline nsresult
   1.706 +NS_NewRequestObserverProxy(nsIRequestObserver **result,
   1.707 +                           nsIRequestObserver  *observer,
   1.708 +                           nsISupports         *context)
   1.709 +{
   1.710 +    nsresult rv;
   1.711 +    nsCOMPtr<nsIRequestObserverProxy> proxy =
   1.712 +        do_CreateInstance(NS_REQUESTOBSERVERPROXY_CONTRACTID, &rv);
   1.713 +    if (NS_SUCCEEDED(rv)) {
   1.714 +        rv = proxy->Init(observer, context);
   1.715 +        if (NS_SUCCEEDED(rv))
   1.716 +            NS_ADDREF(*result = proxy);  // cannot use nsCOMPtr::swap
   1.717 +    }
   1.718 +    return rv;
   1.719 +}
   1.720 +
   1.721 +inline nsresult
   1.722 +NS_NewSimpleStreamListener(nsIStreamListener **result,
   1.723 +                           nsIOutputStream    *sink,
   1.724 +                           nsIRequestObserver *observer = nullptr)
   1.725 +{
   1.726 +    nsresult rv;
   1.727 +    nsCOMPtr<nsISimpleStreamListener> listener = 
   1.728 +        do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv);
   1.729 +    if (NS_SUCCEEDED(rv)) {
   1.730 +        rv = listener->Init(sink, observer);
   1.731 +        if (NS_SUCCEEDED(rv))
   1.732 +            NS_ADDREF(*result = listener);  // cannot use nsCOMPtr::swap
   1.733 +    }
   1.734 +    return rv;
   1.735 +}
   1.736 +
   1.737 +inline nsresult
   1.738 +NS_CheckPortSafety(int32_t       port,
   1.739 +                   const char   *scheme,
   1.740 +                   nsIIOService *ioService = nullptr)
   1.741 +{
   1.742 +    nsresult rv;
   1.743 +    nsCOMPtr<nsIIOService> grip;
   1.744 +    rv = net_EnsureIOService(&ioService, grip);
   1.745 +    if (ioService) {
   1.746 +        bool allow;
   1.747 +        rv = ioService->AllowPort(port, scheme, &allow);
   1.748 +        if (NS_SUCCEEDED(rv) && !allow) {
   1.749 +            NS_WARNING("port blocked");
   1.750 +            rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED;
   1.751 +        }
   1.752 +    }
   1.753 +    return rv;
   1.754 +}
   1.755 +
   1.756 +// Determine if this URI is using a safe port.
   1.757 +inline nsresult
   1.758 +NS_CheckPortSafety(nsIURI *uri) {
   1.759 +    int32_t port;
   1.760 +    nsresult rv = uri->GetPort(&port);
   1.761 +    if (NS_FAILED(rv) || port == -1)  // port undefined or default-valued
   1.762 +        return NS_OK;
   1.763 +    nsAutoCString scheme;
   1.764 +    uri->GetScheme(scheme);
   1.765 +    return NS_CheckPortSafety(port, scheme.get());
   1.766 +}
   1.767 +
   1.768 +inline nsresult
   1.769 +NS_NewProxyInfo(const nsACString &type,
   1.770 +                const nsACString &host,
   1.771 +                int32_t           port,
   1.772 +                uint32_t          flags,
   1.773 +                nsIProxyInfo    **result)
   1.774 +{
   1.775 +    nsresult rv;
   1.776 +    nsCOMPtr<nsIProtocolProxyService> pps =
   1.777 +            do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
   1.778 +    if (NS_SUCCEEDED(rv))
   1.779 +        rv = pps->NewProxyInfo(type, host, port, flags, UINT32_MAX, nullptr,
   1.780 +                               result);
   1.781 +    return rv; 
   1.782 +}
   1.783 +
   1.784 +inline nsresult
   1.785 +NS_GetFileProtocolHandler(nsIFileProtocolHandler **result,
   1.786 +                          nsIIOService            *ioService = nullptr)
   1.787 +{
   1.788 +    nsresult rv;
   1.789 +    nsCOMPtr<nsIIOService> grip;
   1.790 +    rv = net_EnsureIOService(&ioService, grip);
   1.791 +    if (ioService) {
   1.792 +        nsCOMPtr<nsIProtocolHandler> handler;
   1.793 +        rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler));
   1.794 +        if (NS_SUCCEEDED(rv))
   1.795 +            rv = CallQueryInterface(handler, result);
   1.796 +    }
   1.797 +    return rv;
   1.798 +}
   1.799 +
   1.800 +inline nsresult
   1.801 +NS_GetFileFromURLSpec(const nsACString  &inURL,
   1.802 +                      nsIFile          **result,
   1.803 +                      nsIIOService      *ioService = nullptr)
   1.804 +{
   1.805 +    nsresult rv;
   1.806 +    nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   1.807 +    rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   1.808 +    if (NS_SUCCEEDED(rv))
   1.809 +        rv = fileHandler->GetFileFromURLSpec(inURL, result);
   1.810 +    return rv;
   1.811 +}
   1.812 +
   1.813 +inline nsresult
   1.814 +NS_GetURLSpecFromFile(nsIFile      *file,
   1.815 +                      nsACString   &url,
   1.816 +                      nsIIOService *ioService = nullptr)
   1.817 +{
   1.818 +    nsresult rv;
   1.819 +    nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   1.820 +    rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   1.821 +    if (NS_SUCCEEDED(rv))
   1.822 +        rv = fileHandler->GetURLSpecFromFile(file, url);
   1.823 +    return rv;
   1.824 +}
   1.825 +
   1.826 +/**
   1.827 + * Converts the nsIFile to the corresponding URL string.
   1.828 + * Should only be called on files which are not directories,
   1.829 + * is otherwise identical to NS_GetURLSpecFromFile, but is
   1.830 + * usually more efficient.
   1.831 + * Warning: this restriction may not be enforced at runtime!
   1.832 + */
   1.833 +inline nsresult
   1.834 +NS_GetURLSpecFromActualFile(nsIFile      *file,
   1.835 +                            nsACString   &url,
   1.836 +                            nsIIOService *ioService = nullptr)
   1.837 +{
   1.838 +    nsresult rv;
   1.839 +    nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   1.840 +    rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   1.841 +    if (NS_SUCCEEDED(rv))
   1.842 +        rv = fileHandler->GetURLSpecFromActualFile(file, url);
   1.843 +    return rv;
   1.844 +}
   1.845 +
   1.846 +/**
   1.847 + * Converts the nsIFile to the corresponding URL string.
   1.848 + * Should only be called on files which are directories,
   1.849 + * is otherwise identical to NS_GetURLSpecFromFile, but is
   1.850 + * usually more efficient.
   1.851 + * Warning: this restriction may not be enforced at runtime!
   1.852 + */
   1.853 +inline nsresult
   1.854 +NS_GetURLSpecFromDir(nsIFile      *file,
   1.855 +                     nsACString   &url,
   1.856 +                     nsIIOService *ioService = nullptr)
   1.857 +{
   1.858 +    nsresult rv;
   1.859 +    nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   1.860 +    rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   1.861 +    if (NS_SUCCEEDED(rv))
   1.862 +        rv = fileHandler->GetURLSpecFromDir(file, url);
   1.863 +    return rv;
   1.864 +}
   1.865 +
   1.866 +/**
   1.867 + * Obtains the referrer for a given channel.  This first tries to obtain the
   1.868 + * referrer from the property docshell.internalReferrer, and if that doesn't
   1.869 + * work and the channel is an nsIHTTPChannel, we check it's referrer property.
   1.870 + *
   1.871 + * @returns NS_ERROR_NOT_AVAILABLE if no referrer is available.
   1.872 + */
   1.873 +inline nsresult
   1.874 +NS_GetReferrerFromChannel(nsIChannel *channel,
   1.875 +                          nsIURI **referrer)
   1.876 +{
   1.877 +    nsresult rv = NS_ERROR_NOT_AVAILABLE;
   1.878 +    *referrer = nullptr;
   1.879 +
   1.880 +    nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel));
   1.881 +    if (props) {
   1.882 +      // We have to check for a property on a property bag because the
   1.883 +      // referrer may be empty for security reasons (for example, when loading
   1.884 +      // an http page with an https referrer).
   1.885 +      rv = props->GetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
   1.886 +                                         NS_GET_IID(nsIURI),
   1.887 +                                         reinterpret_cast<void **>(referrer));
   1.888 +      if (NS_FAILED(rv))
   1.889 +        *referrer = nullptr;
   1.890 +    }
   1.891 +
   1.892 +    // if that didn't work, we can still try to get the referrer from the
   1.893 +    // nsIHttpChannel (if we can QI to it)
   1.894 +    if (!(*referrer)) {
   1.895 +      nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel));
   1.896 +      if (chan) {
   1.897 +        rv = chan->GetReferrer(referrer);
   1.898 +        if (NS_FAILED(rv))
   1.899 +          *referrer = nullptr;
   1.900 +      }
   1.901 +    }
   1.902 +    return rv;
   1.903 +}
   1.904 +
   1.905 +inline nsresult
   1.906 +NS_ParseContentType(const nsACString &rawContentType,
   1.907 +                    nsCString        &contentType,
   1.908 +                    nsCString        &contentCharset)
   1.909 +{
   1.910 +    // contentCharset is left untouched if not present in rawContentType
   1.911 +    nsresult rv;
   1.912 +    nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
   1.913 +    NS_ENSURE_SUCCESS(rv, rv);
   1.914 +    nsCString charset;
   1.915 +    bool hadCharset;
   1.916 +    rv = util->ParseContentType(rawContentType, charset, &hadCharset,
   1.917 +                                contentType);
   1.918 +    if (NS_SUCCEEDED(rv) && hadCharset)
   1.919 +        contentCharset = charset;
   1.920 +    return rv;
   1.921 +}
   1.922 +
   1.923 +inline nsresult
   1.924 +NS_ExtractCharsetFromContentType(const nsACString &rawContentType,
   1.925 +                                 nsCString        &contentCharset,
   1.926 +                                 bool             *hadCharset,
   1.927 +                                 int32_t          *charsetStart,
   1.928 +                                 int32_t          *charsetEnd)
   1.929 +{
   1.930 +    // contentCharset is left untouched if not present in rawContentType
   1.931 +    nsresult rv;
   1.932 +    nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
   1.933 +    NS_ENSURE_SUCCESS(rv, rv);
   1.934 +
   1.935 +    return util->ExtractCharsetFromContentType(rawContentType,
   1.936 +                                               contentCharset,
   1.937 +                                               charsetStart,
   1.938 +                                               charsetEnd,
   1.939 +                                               hadCharset);
   1.940 +}
   1.941 +
   1.942 +inline nsresult
   1.943 +NS_NewLocalFileInputStream(nsIInputStream **result,
   1.944 +                           nsIFile         *file,
   1.945 +                           int32_t          ioFlags       = -1,
   1.946 +                           int32_t          perm          = -1,
   1.947 +                           int32_t          behaviorFlags = 0)
   1.948 +{
   1.949 +    nsresult rv;
   1.950 +    nsCOMPtr<nsIFileInputStream> in =
   1.951 +        do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
   1.952 +    if (NS_SUCCEEDED(rv)) {
   1.953 +        rv = in->Init(file, ioFlags, perm, behaviorFlags);
   1.954 +        if (NS_SUCCEEDED(rv))
   1.955 +            in.forget(result);
   1.956 +    }
   1.957 +    return rv;
   1.958 +}
   1.959 +
   1.960 +inline nsresult
   1.961 +NS_NewPartialLocalFileInputStream(nsIInputStream **result,
   1.962 +                                  nsIFile         *file,
   1.963 +                                  uint64_t         offset,
   1.964 +                                  uint64_t         length,
   1.965 +                                  int32_t          ioFlags       = -1,
   1.966 +                                  int32_t          perm          = -1,
   1.967 +                                  int32_t          behaviorFlags = 0)
   1.968 +{
   1.969 +    nsresult rv;
   1.970 +    nsCOMPtr<nsIPartialFileInputStream> in =
   1.971 +        do_CreateInstance(NS_PARTIALLOCALFILEINPUTSTREAM_CONTRACTID, &rv);
   1.972 +    if (NS_SUCCEEDED(rv)) {
   1.973 +        rv = in->Init(file, offset, length, ioFlags, perm, behaviorFlags);
   1.974 +        if (NS_SUCCEEDED(rv))
   1.975 +            rv = CallQueryInterface(in, result);
   1.976 +    }
   1.977 +    return rv;
   1.978 +}
   1.979 +
   1.980 +inline nsresult
   1.981 +NS_NewLocalFileOutputStream(nsIOutputStream **result,
   1.982 +                            nsIFile          *file,
   1.983 +                            int32_t           ioFlags       = -1,
   1.984 +                            int32_t           perm          = -1,
   1.985 +                            int32_t           behaviorFlags = 0)
   1.986 +{
   1.987 +    nsresult rv;
   1.988 +    nsCOMPtr<nsIFileOutputStream> out =
   1.989 +        do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
   1.990 +    if (NS_SUCCEEDED(rv)) {
   1.991 +        rv = out->Init(file, ioFlags, perm, behaviorFlags);
   1.992 +        if (NS_SUCCEEDED(rv))
   1.993 +            out.forget(result);
   1.994 +    }
   1.995 +    return rv;
   1.996 +}
   1.997 +
   1.998 +// returns a file output stream which can be QI'ed to nsISafeOutputStream.
   1.999 +inline nsresult
  1.1000 +NS_NewAtomicFileOutputStream(nsIOutputStream **result,
  1.1001 +                                nsIFile          *file,
  1.1002 +                                int32_t           ioFlags       = -1,
  1.1003 +                                int32_t           perm          = -1,
  1.1004 +                                int32_t           behaviorFlags = 0)
  1.1005 +{
  1.1006 +    nsresult rv;
  1.1007 +    nsCOMPtr<nsIFileOutputStream> out =
  1.1008 +        do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
  1.1009 +    if (NS_SUCCEEDED(rv)) {
  1.1010 +        rv = out->Init(file, ioFlags, perm, behaviorFlags);
  1.1011 +        if (NS_SUCCEEDED(rv))
  1.1012 +            out.forget(result);
  1.1013 +    }
  1.1014 +    return rv;
  1.1015 +}
  1.1016 +
  1.1017 +// returns a file output stream which can be QI'ed to nsISafeOutputStream.
  1.1018 +inline nsresult
  1.1019 +NS_NewSafeLocalFileOutputStream(nsIOutputStream **result,
  1.1020 +                                nsIFile          *file,
  1.1021 +                                int32_t           ioFlags       = -1,
  1.1022 +                                int32_t           perm          = -1,
  1.1023 +                                int32_t           behaviorFlags = 0)
  1.1024 +{
  1.1025 +    nsresult rv;
  1.1026 +    nsCOMPtr<nsIFileOutputStream> out =
  1.1027 +        do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
  1.1028 +    if (NS_SUCCEEDED(rv)) {
  1.1029 +        rv = out->Init(file, ioFlags, perm, behaviorFlags);
  1.1030 +        if (NS_SUCCEEDED(rv))
  1.1031 +            out.forget(result);
  1.1032 +    }
  1.1033 +    return rv;
  1.1034 +}
  1.1035 +
  1.1036 +inline nsresult
  1.1037 +NS_NewLocalFileStream(nsIFileStream **result,
  1.1038 +                      nsIFile        *file,
  1.1039 +                      int32_t         ioFlags       = -1,
  1.1040 +                      int32_t         perm          = -1,
  1.1041 +                      int32_t         behaviorFlags = 0)
  1.1042 +{
  1.1043 +    nsresult rv;
  1.1044 +    nsCOMPtr<nsIFileStream> stream =
  1.1045 +        do_CreateInstance(NS_LOCALFILESTREAM_CONTRACTID, &rv);
  1.1046 +    if (NS_SUCCEEDED(rv)) {
  1.1047 +        rv = stream->Init(file, ioFlags, perm, behaviorFlags);
  1.1048 +        if (NS_SUCCEEDED(rv))
  1.1049 +            stream.forget(result);
  1.1050 +    }
  1.1051 +    return rv;
  1.1052 +}
  1.1053 +
  1.1054 +// returns the input end of a pipe.  the output end of the pipe
  1.1055 +// is attached to the original stream.  data from the original
  1.1056 +// stream is read into the pipe on a background thread.
  1.1057 +inline nsresult
  1.1058 +NS_BackgroundInputStream(nsIInputStream **result,
  1.1059 +                         nsIInputStream  *stream,
  1.1060 +                         uint32_t         segmentSize  = 0,
  1.1061 +                         uint32_t         segmentCount = 0)
  1.1062 +{
  1.1063 +    nsresult rv;
  1.1064 +    nsCOMPtr<nsIStreamTransportService> sts =
  1.1065 +        do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
  1.1066 +    if (NS_SUCCEEDED(rv)) {
  1.1067 +        nsCOMPtr<nsITransport> inTransport;
  1.1068 +        rv = sts->CreateInputTransport(stream, int64_t(-1), int64_t(-1),
  1.1069 +                                       true, getter_AddRefs(inTransport));
  1.1070 +        if (NS_SUCCEEDED(rv))
  1.1071 +            rv = inTransport->OpenInputStream(nsITransport::OPEN_BLOCKING,
  1.1072 +                                              segmentSize, segmentCount,
  1.1073 +                                              result);
  1.1074 +    }
  1.1075 +    return rv;
  1.1076 +}
  1.1077 +
  1.1078 +// returns the output end of a pipe.  the input end of the pipe
  1.1079 +// is attached to the original stream.  data written to the pipe
  1.1080 +// is copied to the original stream on a background thread.
  1.1081 +inline nsresult
  1.1082 +NS_BackgroundOutputStream(nsIOutputStream **result,
  1.1083 +                          nsIOutputStream  *stream,
  1.1084 +                          uint32_t          segmentSize  = 0,
  1.1085 +                          uint32_t          segmentCount = 0)
  1.1086 +{
  1.1087 +    nsresult rv;
  1.1088 +    nsCOMPtr<nsIStreamTransportService> sts =
  1.1089 +        do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
  1.1090 +    if (NS_SUCCEEDED(rv)) {
  1.1091 +        nsCOMPtr<nsITransport> inTransport;
  1.1092 +        rv = sts->CreateOutputTransport(stream, int64_t(-1), int64_t(-1),
  1.1093 +                                        true, getter_AddRefs(inTransport));
  1.1094 +        if (NS_SUCCEEDED(rv))
  1.1095 +            rv = inTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING,
  1.1096 +                                               segmentSize, segmentCount,
  1.1097 +                                               result);
  1.1098 +    }
  1.1099 +    return rv;
  1.1100 +}
  1.1101 +
  1.1102 +MOZ_WARN_UNUSED_RESULT inline nsresult
  1.1103 +NS_NewBufferedInputStream(nsIInputStream **result,
  1.1104 +                          nsIInputStream  *str,
  1.1105 +                          uint32_t         bufferSize)
  1.1106 +{
  1.1107 +    nsresult rv;
  1.1108 +    nsCOMPtr<nsIBufferedInputStream> in =
  1.1109 +        do_CreateInstance(NS_BUFFEREDINPUTSTREAM_CONTRACTID, &rv);
  1.1110 +    if (NS_SUCCEEDED(rv)) {
  1.1111 +        rv = in->Init(str, bufferSize);
  1.1112 +        if (NS_SUCCEEDED(rv))
  1.1113 +            NS_ADDREF(*result = in);  // cannot use nsCOMPtr::swap
  1.1114 +    }
  1.1115 +    return rv;
  1.1116 +}
  1.1117 +
  1.1118 +// note: the resulting stream can be QI'ed to nsISafeOutputStream iff the
  1.1119 +// provided stream supports it.
  1.1120 +inline nsresult
  1.1121 +NS_NewBufferedOutputStream(nsIOutputStream **result,
  1.1122 +                           nsIOutputStream  *str,
  1.1123 +                           uint32_t          bufferSize)
  1.1124 +{
  1.1125 +    nsresult rv;
  1.1126 +    nsCOMPtr<nsIBufferedOutputStream> out =
  1.1127 +        do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
  1.1128 +    if (NS_SUCCEEDED(rv)) {
  1.1129 +        rv = out->Init(str, bufferSize);
  1.1130 +        if (NS_SUCCEEDED(rv))
  1.1131 +            NS_ADDREF(*result = out);  // cannot use nsCOMPtr::swap
  1.1132 +    }
  1.1133 +    return rv;
  1.1134 +}
  1.1135 +
  1.1136 +/**
  1.1137 + * Attempts to buffer a given output stream.  If this fails, it returns the
  1.1138 + * passed-in output stream.
  1.1139 + *
  1.1140 + * @param aOutputStream
  1.1141 + *        The output stream we want to buffer.  This cannot be null.
  1.1142 + * @param aBufferSize
  1.1143 + *        The size of the buffer for the buffered output stream.
  1.1144 + * @returns an nsIOutputStream that is buffered with the specified buffer size,
  1.1145 + *          or is aOutputStream if creating the new buffered stream failed.
  1.1146 + */
  1.1147 +inline already_AddRefed<nsIOutputStream>
  1.1148 +NS_BufferOutputStream(nsIOutputStream *aOutputStream,
  1.1149 +                      uint32_t aBufferSize)
  1.1150 +{
  1.1151 +    NS_ASSERTION(aOutputStream, "No output stream given!");
  1.1152 +
  1.1153 +    nsCOMPtr<nsIOutputStream> bos;
  1.1154 +    nsresult rv = NS_NewBufferedOutputStream(getter_AddRefs(bos), aOutputStream,
  1.1155 +                                             aBufferSize);
  1.1156 +    if (NS_SUCCEEDED(rv))
  1.1157 +        return bos.forget();
  1.1158 +
  1.1159 +    bos = aOutputStream;
  1.1160 +    return bos.forget();
  1.1161 +}
  1.1162 +
  1.1163 +// returns an input stream compatible with nsIUploadChannel::SetUploadStream()
  1.1164 +inline nsresult
  1.1165 +NS_NewPostDataStream(nsIInputStream  **result,
  1.1166 +                     bool              isFile,
  1.1167 +                     const nsACString &data)
  1.1168 +{
  1.1169 +    nsresult rv;
  1.1170 +
  1.1171 +    if (isFile) {
  1.1172 +        nsCOMPtr<nsIFile> file;
  1.1173 +        nsCOMPtr<nsIInputStream> fileStream;
  1.1174 +
  1.1175 +        rv = NS_NewNativeLocalFile(data, false, getter_AddRefs(file));
  1.1176 +        if (NS_SUCCEEDED(rv)) {
  1.1177 +            rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file);
  1.1178 +            if (NS_SUCCEEDED(rv)) {
  1.1179 +                // wrap the file stream with a buffered input stream
  1.1180 +                rv = NS_NewBufferedInputStream(result, fileStream, 8192);
  1.1181 +            }
  1.1182 +        }
  1.1183 +        return rv;
  1.1184 +    }
  1.1185 +
  1.1186 +    // otherwise, create a string stream for the data (copies)
  1.1187 +    nsCOMPtr<nsIStringInputStream> stream
  1.1188 +        (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv));
  1.1189 +    if (NS_FAILED(rv))
  1.1190 +        return rv;
  1.1191 +
  1.1192 +    rv = stream->SetData(data.BeginReading(), data.Length());
  1.1193 +    if (NS_FAILED(rv))
  1.1194 +        return rv;
  1.1195 +
  1.1196 +    NS_ADDREF(*result = stream);
  1.1197 +    return NS_OK;
  1.1198 +}
  1.1199 +
  1.1200 +inline nsresult
  1.1201 +NS_ReadInputStreamToBuffer(nsIInputStream *aInputStream, 
  1.1202 +                           void** aDest,
  1.1203 +                           uint32_t aCount)
  1.1204 +{
  1.1205 +    nsresult rv;
  1.1206 +
  1.1207 +    if (!*aDest) {
  1.1208 +        *aDest = malloc(aCount);
  1.1209 +        if (!*aDest)
  1.1210 +            return NS_ERROR_OUT_OF_MEMORY;
  1.1211 +    }
  1.1212 +
  1.1213 +    char * p = reinterpret_cast<char*>(*aDest);
  1.1214 +    uint32_t bytesRead;
  1.1215 +    uint32_t totalRead = 0;
  1.1216 +    while (1) {
  1.1217 +        rv = aInputStream->Read(p + totalRead, aCount - totalRead, &bytesRead);
  1.1218 +        if (!NS_SUCCEEDED(rv)) 
  1.1219 +            return rv;
  1.1220 +        totalRead += bytesRead;
  1.1221 +        if (totalRead == aCount)
  1.1222 +            break;
  1.1223 +        // if Read reads 0 bytes, we've hit EOF 
  1.1224 +        if (bytesRead == 0)
  1.1225 +            return NS_ERROR_UNEXPECTED;
  1.1226 +    }
  1.1227 +    return rv; 
  1.1228 +}
  1.1229 +
  1.1230 +// external code can't see fallible_t
  1.1231 +#ifdef MOZILLA_INTERNAL_API
  1.1232 +
  1.1233 +inline nsresult
  1.1234 +NS_ReadInputStreamToString(nsIInputStream *aInputStream, 
  1.1235 +                           nsACString &aDest,
  1.1236 +                           uint32_t aCount)
  1.1237 +{
  1.1238 +    if (!aDest.SetLength(aCount, mozilla::fallible_t()))
  1.1239 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1240 +    void* dest = aDest.BeginWriting();
  1.1241 +    return NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount);
  1.1242 +}
  1.1243 +
  1.1244 +#endif
  1.1245 +
  1.1246 +inline nsresult
  1.1247 +NS_LoadPersistentPropertiesFromURI(nsIPersistentProperties **result,
  1.1248 +                                   nsIURI                   *uri,
  1.1249 +                                   nsIIOService             *ioService = nullptr)
  1.1250 +{
  1.1251 +    nsCOMPtr<nsIInputStream> in;
  1.1252 +    nsresult rv = NS_OpenURI(getter_AddRefs(in), uri, ioService);
  1.1253 +    if (NS_SUCCEEDED(rv)) {
  1.1254 +        nsCOMPtr<nsIPersistentProperties> properties = 
  1.1255 +            do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID, &rv);
  1.1256 +        if (NS_SUCCEEDED(rv)) {
  1.1257 +            rv = properties->Load(in);
  1.1258 +            if (NS_SUCCEEDED(rv)) {
  1.1259 +                *result = nullptr;
  1.1260 +                properties.swap(*result);
  1.1261 +            }
  1.1262 +        }
  1.1263 +    }
  1.1264 +    return rv;
  1.1265 +}
  1.1266 +
  1.1267 +inline nsresult
  1.1268 +NS_LoadPersistentPropertiesFromURISpec(nsIPersistentProperties **result,
  1.1269 +                                       const nsACString        &spec,
  1.1270 +                                       const char              *charset = nullptr,
  1.1271 +                                       nsIURI                  *baseURI = nullptr,
  1.1272 +                                       nsIIOService            *ioService = nullptr)     
  1.1273 +{
  1.1274 +    nsCOMPtr<nsIURI> uri;
  1.1275 +    nsresult rv = 
  1.1276 +        NS_NewURI(getter_AddRefs(uri), spec, charset, baseURI, ioService);
  1.1277 +
  1.1278 +    if (NS_SUCCEEDED(rv))
  1.1279 +        rv = NS_LoadPersistentPropertiesFromURI(result, uri, ioService);
  1.1280 +
  1.1281 +    return rv;
  1.1282 +}
  1.1283 +
  1.1284 +/**
  1.1285 + * NS_QueryNotificationCallbacks implements the canonical algorithm for
  1.1286 + * querying interfaces from a channel's notification callbacks.  It first
  1.1287 + * searches the channel's notificationCallbacks attribute, and if the interface
  1.1288 + * is not found there, then it inspects the notificationCallbacks attribute of
  1.1289 + * the channel's loadGroup.
  1.1290 + *
  1.1291 + * Note: templatized only because nsIWebSocketChannel is currently not an
  1.1292 + * nsIChannel.
  1.1293 + */
  1.1294 +template <class T> inline void
  1.1295 +NS_QueryNotificationCallbacks(T            *channel,
  1.1296 +                              const nsIID  &iid,
  1.1297 +                              void        **result)
  1.1298 +{
  1.1299 +    NS_PRECONDITION(channel, "null channel");
  1.1300 +    *result = nullptr;
  1.1301 +
  1.1302 +    nsCOMPtr<nsIInterfaceRequestor> cbs;
  1.1303 +    channel->GetNotificationCallbacks(getter_AddRefs(cbs));
  1.1304 +    if (cbs)
  1.1305 +        cbs->GetInterface(iid, result);
  1.1306 +    if (!*result) {
  1.1307 +        // try load group's notification callbacks...
  1.1308 +        nsCOMPtr<nsILoadGroup> loadGroup;
  1.1309 +        channel->GetLoadGroup(getter_AddRefs(loadGroup));
  1.1310 +        if (loadGroup) {
  1.1311 +            loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
  1.1312 +            if (cbs)
  1.1313 +                cbs->GetInterface(iid, result);
  1.1314 +        }
  1.1315 +    }
  1.1316 +}
  1.1317 +
  1.1318 +// template helper:
  1.1319 +// Note: "class C" templatized only because nsIWebSocketChannel is currently not
  1.1320 +// an nsIChannel.
  1.1321 +
  1.1322 +template <class C, class T> inline void
  1.1323 +NS_QueryNotificationCallbacks(C           *channel,
  1.1324 +                              nsCOMPtr<T> &result)
  1.1325 +{
  1.1326 +    NS_QueryNotificationCallbacks(channel, NS_GET_TEMPLATE_IID(T),
  1.1327 +                                  getter_AddRefs(result));
  1.1328 +}
  1.1329 +
  1.1330 +/**
  1.1331 + * Alternate form of NS_QueryNotificationCallbacks designed for use by
  1.1332 + * nsIChannel implementations.
  1.1333 + */
  1.1334 +inline void
  1.1335 +NS_QueryNotificationCallbacks(nsIInterfaceRequestor  *callbacks,
  1.1336 +                              nsILoadGroup           *loadGroup,
  1.1337 +                              const nsIID            &iid,
  1.1338 +                              void                  **result)
  1.1339 +{
  1.1340 +    *result = nullptr;
  1.1341 +
  1.1342 +    if (callbacks)
  1.1343 +        callbacks->GetInterface(iid, result);
  1.1344 +    if (!*result) {
  1.1345 +        // try load group's notification callbacks...
  1.1346 +        if (loadGroup) {
  1.1347 +            nsCOMPtr<nsIInterfaceRequestor> cbs;
  1.1348 +            loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
  1.1349 +            if (cbs)
  1.1350 +                cbs->GetInterface(iid, result);
  1.1351 +        }
  1.1352 +    }
  1.1353 +}
  1.1354 +
  1.1355 +/**
  1.1356 + * Returns true if channel is using Private Browsing, or false if not.
  1.1357 + * Returns false if channel's callbacks don't implement nsILoadContext.
  1.1358 + */
  1.1359 +inline bool
  1.1360 +NS_UsePrivateBrowsing(nsIChannel *channel)
  1.1361 +{
  1.1362 +    bool isPrivate = false;
  1.1363 +    bool isOverriden = false;
  1.1364 +    nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
  1.1365 +    if (pbChannel &&
  1.1366 +        NS_SUCCEEDED(pbChannel->IsPrivateModeOverriden(&isPrivate, &isOverriden)) &&
  1.1367 +        isOverriden) {
  1.1368 +        return isPrivate;
  1.1369 +    }
  1.1370 +    nsCOMPtr<nsILoadContext> loadContext;
  1.1371 +    NS_QueryNotificationCallbacks(channel, loadContext);
  1.1372 +    return loadContext && loadContext->UsePrivateBrowsing();
  1.1373 +}
  1.1374 +
  1.1375 +// Constants duplicated from nsIScriptSecurityManager so we avoid having necko
  1.1376 +// know about script security manager.
  1.1377 +#define NECKO_NO_APP_ID 0
  1.1378 +#define NECKO_UNKNOWN_APP_ID UINT32_MAX
  1.1379 +// special app id reserved for separating the safebrowsing cookie
  1.1380 +#define NECKO_SAFEBROWSING_APP_ID UINT32_MAX - 1
  1.1381 +
  1.1382 +/**
  1.1383 + * Gets AppId and isInBrowserElement from channel's nsILoadContext.
  1.1384 + * Returns false if error or channel's callbacks don't implement nsILoadContext.
  1.1385 + */
  1.1386 +inline bool
  1.1387 +NS_GetAppInfo(nsIChannel *aChannel, uint32_t *aAppID, bool *aIsInBrowserElement)
  1.1388 +{
  1.1389 +    nsCOMPtr<nsILoadContext> loadContext;
  1.1390 +    NS_QueryNotificationCallbacks(aChannel, loadContext);
  1.1391 +    if (!loadContext) {
  1.1392 +        return false;
  1.1393 +    }
  1.1394 +
  1.1395 +    nsresult rv = loadContext->GetAppId(aAppID);
  1.1396 +    NS_ENSURE_SUCCESS(rv, false);
  1.1397 +
  1.1398 +    rv = loadContext->GetIsInBrowserElement(aIsInBrowserElement);
  1.1399 +    NS_ENSURE_SUCCESS(rv, false);
  1.1400 +
  1.1401 +    return true;
  1.1402 +}
  1.1403 +
  1.1404 +/**
  1.1405 + *  Gets appId and browserOnly parameters from the TOPIC_WEB_APP_CLEAR_DATA
  1.1406 + *  nsIObserverService notification.  Used when clearing user data or
  1.1407 + *  uninstalling web apps.
  1.1408 + */
  1.1409 +inline nsresult
  1.1410 +NS_GetAppInfoFromClearDataNotification(nsISupports *aSubject,
  1.1411 +                                       uint32_t *aAppID, bool* aBrowserOnly)
  1.1412 +{
  1.1413 +    nsresult rv;
  1.1414 +
  1.1415 +    nsCOMPtr<mozIApplicationClearPrivateDataParams>
  1.1416 +        clearParams(do_QueryInterface(aSubject));
  1.1417 +    MOZ_ASSERT(clearParams);
  1.1418 +    if (!clearParams) {
  1.1419 +        return NS_ERROR_UNEXPECTED;
  1.1420 +    }
  1.1421 +
  1.1422 +    uint32_t appId;
  1.1423 +    rv = clearParams->GetAppId(&appId);
  1.1424 +    MOZ_ASSERT(NS_SUCCEEDED(rv));
  1.1425 +    MOZ_ASSERT(appId != NECKO_UNKNOWN_APP_ID);
  1.1426 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1427 +    if (appId == NECKO_UNKNOWN_APP_ID) {
  1.1428 +        return NS_ERROR_UNEXPECTED;
  1.1429 +    }
  1.1430 +
  1.1431 +    bool browserOnly = false;
  1.1432 +    rv = clearParams->GetBrowserOnly(&browserOnly);
  1.1433 +    MOZ_ASSERT(NS_SUCCEEDED(rv));
  1.1434 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1435 +
  1.1436 +    *aAppID = appId;
  1.1437 +    *aBrowserOnly = browserOnly;
  1.1438 +    return NS_OK;
  1.1439 +}
  1.1440 +
  1.1441 +/**
  1.1442 + * Determines whether appcache should be checked for a given URI.
  1.1443 + */
  1.1444 +inline bool
  1.1445 +NS_ShouldCheckAppCache(nsIURI *aURI, bool usePrivateBrowsing)
  1.1446 +{
  1.1447 +    if (usePrivateBrowsing) {
  1.1448 +        return false;
  1.1449 +    }
  1.1450 +
  1.1451 +    nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
  1.1452 +        do_GetService("@mozilla.org/offlinecacheupdate-service;1");
  1.1453 +    if (!offlineService) {
  1.1454 +        return false;
  1.1455 +    }
  1.1456 +
  1.1457 +    bool allowed;
  1.1458 +    nsresult rv = offlineService->OfflineAppAllowedForURI(aURI,
  1.1459 +                                                          nullptr,
  1.1460 +                                                          &allowed);
  1.1461 +    return NS_SUCCEEDED(rv) && allowed;
  1.1462 +}
  1.1463 +
  1.1464 +inline bool
  1.1465 +NS_ShouldCheckAppCache(nsIPrincipal * aPrincipal, bool usePrivateBrowsing)
  1.1466 +{
  1.1467 +    if (usePrivateBrowsing) {
  1.1468 +        return false;
  1.1469 +    }
  1.1470 +
  1.1471 +    nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
  1.1472 +        do_GetService("@mozilla.org/offlinecacheupdate-service;1");
  1.1473 +    if (!offlineService) {
  1.1474 +        return false;
  1.1475 +    }
  1.1476 +
  1.1477 +    bool allowed;
  1.1478 +    nsresult rv = offlineService->OfflineAppAllowed(aPrincipal,
  1.1479 +                                                    nullptr,
  1.1480 +                                                    &allowed);
  1.1481 +    return NS_SUCCEEDED(rv) && allowed;
  1.1482 +}
  1.1483 +
  1.1484 +/**
  1.1485 + * Wraps an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2. This
  1.1486 + * method is provided mainly for use by other methods in this file.
  1.1487 + *
  1.1488 + * *aAuthPrompt2 should be set to null before calling this function.
  1.1489 + */
  1.1490 +inline void
  1.1491 +NS_WrapAuthPrompt(nsIAuthPrompt *aAuthPrompt, nsIAuthPrompt2** aAuthPrompt2)
  1.1492 +{
  1.1493 +    nsCOMPtr<nsIAuthPromptAdapterFactory> factory =
  1.1494 +        do_GetService(NS_AUTHPROMPT_ADAPTER_FACTORY_CONTRACTID);
  1.1495 +    if (!factory)
  1.1496 +        return;
  1.1497 +
  1.1498 +    NS_WARNING("Using deprecated nsIAuthPrompt");
  1.1499 +    factory->CreateAdapter(aAuthPrompt, aAuthPrompt2);
  1.1500 +}
  1.1501 +
  1.1502 +/**
  1.1503 + * Gets an auth prompt from an interface requestor. This takes care of wrapping
  1.1504 + * an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2.
  1.1505 + */
  1.1506 +inline void
  1.1507 +NS_QueryAuthPrompt2(nsIInterfaceRequestor  *aCallbacks,
  1.1508 +                    nsIAuthPrompt2        **aAuthPrompt)
  1.1509 +{
  1.1510 +    CallGetInterface(aCallbacks, aAuthPrompt);
  1.1511 +    if (*aAuthPrompt)
  1.1512 +        return;
  1.1513 +
  1.1514 +    // Maybe only nsIAuthPrompt is provided and we have to wrap it.
  1.1515 +    nsCOMPtr<nsIAuthPrompt> prompt(do_GetInterface(aCallbacks));
  1.1516 +    if (!prompt)
  1.1517 +        return;
  1.1518 +
  1.1519 +    NS_WrapAuthPrompt(prompt, aAuthPrompt);
  1.1520 +}
  1.1521 +
  1.1522 +/**
  1.1523 + * Gets an nsIAuthPrompt2 from a channel. Use this instead of
  1.1524 + * NS_QueryNotificationCallbacks for better backwards compatibility.
  1.1525 + */
  1.1526 +inline void
  1.1527 +NS_QueryAuthPrompt2(nsIChannel      *aChannel,
  1.1528 +                    nsIAuthPrompt2 **aAuthPrompt)
  1.1529 +{
  1.1530 +    *aAuthPrompt = nullptr;
  1.1531 +
  1.1532 +    // We want to use any auth prompt we can find on the channel's callbacks,
  1.1533 +    // and if that fails use the loadgroup's prompt (if any)
  1.1534 +    // Therefore, we can't just use NS_QueryNotificationCallbacks, because
  1.1535 +    // that would prefer a loadgroup's nsIAuthPrompt2 over a channel's
  1.1536 +    // nsIAuthPrompt.
  1.1537 +    nsCOMPtr<nsIInterfaceRequestor> callbacks;
  1.1538 +    aChannel->GetNotificationCallbacks(getter_AddRefs(callbacks));
  1.1539 +    if (callbacks) {
  1.1540 +        NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
  1.1541 +        if (*aAuthPrompt)
  1.1542 +            return;
  1.1543 +    }
  1.1544 +
  1.1545 +    nsCOMPtr<nsILoadGroup> group;
  1.1546 +    aChannel->GetLoadGroup(getter_AddRefs(group));
  1.1547 +    if (!group)
  1.1548 +        return;
  1.1549 +
  1.1550 +    group->GetNotificationCallbacks(getter_AddRefs(callbacks));
  1.1551 +    if (!callbacks)
  1.1552 +        return;
  1.1553 +    NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
  1.1554 +}
  1.1555 +
  1.1556 +/* template helper */
  1.1557 +template <class T> inline void
  1.1558 +NS_QueryNotificationCallbacks(nsIInterfaceRequestor *callbacks,
  1.1559 +                              nsILoadGroup          *loadGroup,
  1.1560 +                              nsCOMPtr<T>           &result)
  1.1561 +{
  1.1562 +    NS_QueryNotificationCallbacks(callbacks, loadGroup,
  1.1563 +                                  NS_GET_TEMPLATE_IID(T),
  1.1564 +                                  getter_AddRefs(result));
  1.1565 +}
  1.1566 +
  1.1567 +/* template helper */
  1.1568 +template <class T> inline void
  1.1569 +NS_QueryNotificationCallbacks(const nsCOMPtr<nsIInterfaceRequestor> &aCallbacks,
  1.1570 +                              const nsCOMPtr<nsILoadGroup>          &aLoadGroup,
  1.1571 +                              nsCOMPtr<T>                           &aResult)
  1.1572 +{
  1.1573 +    NS_QueryNotificationCallbacks(aCallbacks.get(), aLoadGroup.get(), aResult);
  1.1574 +}
  1.1575 +
  1.1576 +/* template helper */
  1.1577 +template <class T> inline void
  1.1578 +NS_QueryNotificationCallbacks(const nsCOMPtr<nsIChannel> &aChannel,
  1.1579 +                              nsCOMPtr<T>                &aResult)
  1.1580 +{
  1.1581 +    NS_QueryNotificationCallbacks(aChannel.get(), aResult);
  1.1582 +}
  1.1583 +
  1.1584 +/**
  1.1585 + * This function returns a nsIInterfaceRequestor instance that returns the
  1.1586 + * same result as NS_QueryNotificationCallbacks when queried.  It is useful
  1.1587 + * as the value for nsISocketTransport::securityCallbacks.
  1.1588 + */
  1.1589 +inline nsresult
  1.1590 +NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor  *callbacks,
  1.1591 +                                       nsILoadGroup           *loadGroup,
  1.1592 +                                       nsIEventTarget         *target,
  1.1593 +                                       nsIInterfaceRequestor **result)
  1.1594 +{
  1.1595 +    nsCOMPtr<nsIInterfaceRequestor> cbs;
  1.1596 +    if (loadGroup)
  1.1597 +        loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
  1.1598 +    return NS_NewInterfaceRequestorAggregation(callbacks, cbs, target, result);
  1.1599 +}
  1.1600 +
  1.1601 +inline nsresult
  1.1602 +NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor  *callbacks,
  1.1603 +                                       nsILoadGroup           *loadGroup,
  1.1604 +                                       nsIInterfaceRequestor **result)
  1.1605 +{
  1.1606 +    return NS_NewNotificationCallbacksAggregation(callbacks, loadGroup, nullptr, result);
  1.1607 +}
  1.1608 +
  1.1609 +/**
  1.1610 + * Helper function for testing online/offline state of the browser.
  1.1611 + */
  1.1612 +inline bool
  1.1613 +NS_IsOffline()
  1.1614 +{
  1.1615 +    bool offline = true;
  1.1616 +    nsCOMPtr<nsIIOService> ios = do_GetIOService();
  1.1617 +    if (ios)
  1.1618 +        ios->GetOffline(&offline);
  1.1619 +    return offline;
  1.1620 +}
  1.1621 +
  1.1622 +/**
  1.1623 + * Helper functions for implementing nsINestedURI::innermostURI.
  1.1624 + *
  1.1625 + * Note that NS_DoImplGetInnermostURI is "private" -- call
  1.1626 + * NS_ImplGetInnermostURI instead.
  1.1627 + */
  1.1628 +inline nsresult
  1.1629 +NS_DoImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result)
  1.1630 +{
  1.1631 +    NS_PRECONDITION(nestedURI, "Must have a nested URI!");
  1.1632 +    NS_PRECONDITION(!*result, "Must have null *result");
  1.1633 +    
  1.1634 +    nsCOMPtr<nsIURI> inner;
  1.1635 +    nsresult rv = nestedURI->GetInnerURI(getter_AddRefs(inner));
  1.1636 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1637 +
  1.1638 +    // We may need to loop here until we reach the innermost
  1.1639 +    // URI.
  1.1640 +    nsCOMPtr<nsINestedURI> nestedInner(do_QueryInterface(inner));
  1.1641 +    while (nestedInner) {
  1.1642 +        rv = nestedInner->GetInnerURI(getter_AddRefs(inner));
  1.1643 +        NS_ENSURE_SUCCESS(rv, rv);
  1.1644 +        nestedInner = do_QueryInterface(inner);
  1.1645 +    }
  1.1646 +
  1.1647 +    // Found the innermost one if we reach here.
  1.1648 +    inner.swap(*result);
  1.1649 +
  1.1650 +    return rv;
  1.1651 +}
  1.1652 +
  1.1653 +inline nsresult
  1.1654 +NS_ImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result)
  1.1655 +{
  1.1656 +    // Make it safe to use swap()
  1.1657 +    *result = nullptr;
  1.1658 +
  1.1659 +    return NS_DoImplGetInnermostURI(nestedURI, result);
  1.1660 +}
  1.1661 +
  1.1662 +/**
  1.1663 + * Helper function that ensures that |result| is a URI that's safe to
  1.1664 + * return.  If |uri| is immutable, just returns it, otherwise returns
  1.1665 + * a clone.  |uri| must not be null.
  1.1666 + */
  1.1667 +inline nsresult
  1.1668 +NS_EnsureSafeToReturn(nsIURI* uri, nsIURI** result)
  1.1669 +{
  1.1670 +    NS_PRECONDITION(uri, "Must have a URI");
  1.1671 +    
  1.1672 +    // Assume mutable until told otherwise
  1.1673 +    bool isMutable = true;
  1.1674 +    nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(uri));
  1.1675 +    if (mutableObj) {
  1.1676 +        nsresult rv = mutableObj->GetMutable(&isMutable);
  1.1677 +        isMutable = NS_FAILED(rv) || isMutable;
  1.1678 +    }
  1.1679 +
  1.1680 +    if (!isMutable) {
  1.1681 +        NS_ADDREF(*result = uri);
  1.1682 +        return NS_OK;
  1.1683 +    }
  1.1684 +
  1.1685 +    nsresult rv = uri->Clone(result);
  1.1686 +    if (NS_SUCCEEDED(rv) && !*result) {
  1.1687 +        NS_ERROR("nsIURI.clone contract was violated");
  1.1688 +        return NS_ERROR_UNEXPECTED;
  1.1689 +    }
  1.1690 +
  1.1691 +    return rv;
  1.1692 +}
  1.1693 +
  1.1694 +/**
  1.1695 + * Helper function that tries to set the argument URI to be immutable
  1.1696 + */  
  1.1697 +inline void
  1.1698 +NS_TryToSetImmutable(nsIURI* uri)
  1.1699 +{
  1.1700 +    nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(uri));
  1.1701 +    if (mutableObj) {
  1.1702 +        mutableObj->SetMutable(false);
  1.1703 +    }
  1.1704 +}
  1.1705 +
  1.1706 +/**
  1.1707 + * Helper function for calling ToImmutableURI.  If all else fails, returns
  1.1708 + * the input URI.  The optional second arg indicates whether we had to fall
  1.1709 + * back to the input URI.  Passing in a null URI is ok.
  1.1710 + */
  1.1711 +inline already_AddRefed<nsIURI>
  1.1712 +NS_TryToMakeImmutable(nsIURI* uri,
  1.1713 +                      nsresult* outRv = nullptr)
  1.1714 +{
  1.1715 +    nsresult rv;
  1.1716 +    nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
  1.1717 +
  1.1718 +    nsCOMPtr<nsIURI> result;
  1.1719 +    if (NS_SUCCEEDED(rv)) {
  1.1720 +        NS_ASSERTION(util, "do_GetNetUtil lied");
  1.1721 +        rv = util->ToImmutableURI(uri, getter_AddRefs(result));
  1.1722 +    }
  1.1723 +
  1.1724 +    if (NS_FAILED(rv)) {
  1.1725 +        result = uri;
  1.1726 +    }
  1.1727 +
  1.1728 +    if (outRv) {
  1.1729 +        *outRv = rv;
  1.1730 +    }
  1.1731 +
  1.1732 +    return result.forget();
  1.1733 +}
  1.1734 +
  1.1735 +/**
  1.1736 + * Helper function for testing whether the given URI, or any of its
  1.1737 + * inner URIs, has all the given protocol flags.
  1.1738 + */
  1.1739 +inline nsresult
  1.1740 +NS_URIChainHasFlags(nsIURI   *uri,
  1.1741 +                    uint32_t  flags,
  1.1742 +                    bool     *result)
  1.1743 +{
  1.1744 +    nsresult rv;
  1.1745 +    nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
  1.1746 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1747 +
  1.1748 +    return util->URIChainHasFlags(uri, flags, result);
  1.1749 +}
  1.1750 +
  1.1751 +/**
  1.1752 + * Helper function for getting the innermost URI for a given URI.  The return
  1.1753 + * value could be just the object passed in if it's not a nested URI.
  1.1754 + */
  1.1755 +inline already_AddRefed<nsIURI>
  1.1756 +NS_GetInnermostURI(nsIURI* aURI)
  1.1757 +{
  1.1758 +    NS_PRECONDITION(aURI, "Must have URI");
  1.1759 +
  1.1760 +    nsCOMPtr<nsIURI> uri = aURI;
  1.1761 +    
  1.1762 +    nsCOMPtr<nsINestedURI> nestedURI(do_QueryInterface(uri));
  1.1763 +    if (!nestedURI) {
  1.1764 +        return uri.forget();
  1.1765 +    }
  1.1766 +
  1.1767 +    nsresult rv = nestedURI->GetInnermostURI(getter_AddRefs(uri));
  1.1768 +    if (NS_FAILED(rv)) {
  1.1769 +        return nullptr;
  1.1770 +    }
  1.1771 +
  1.1772 +    return uri.forget();
  1.1773 +}
  1.1774 +
  1.1775 +/**
  1.1776 + * Get the "final" URI for a channel.  This is either the same as GetURI or
  1.1777 + * GetOriginalURI, depending on whether this channel has
  1.1778 + * nsIChanel::LOAD_REPLACE set.  For channels without that flag set, the final
  1.1779 + * URI is the original URI, while for ones with the flag the final URI is the
  1.1780 + * channel URI.
  1.1781 + */
  1.1782 +inline nsresult
  1.1783 +NS_GetFinalChannelURI(nsIChannel* channel, nsIURI** uri)
  1.1784 +{
  1.1785 +    *uri = nullptr;
  1.1786 +    nsLoadFlags loadFlags = 0;
  1.1787 +    nsresult rv = channel->GetLoadFlags(&loadFlags);
  1.1788 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1789 +    
  1.1790 +    if (loadFlags & nsIChannel::LOAD_REPLACE) {
  1.1791 +        return channel->GetURI(uri);
  1.1792 +    }
  1.1793 +    
  1.1794 +    return channel->GetOriginalURI(uri);
  1.1795 +}
  1.1796 +
  1.1797 +// NS_SecurityHashURI must return the same hash value for any two URIs that
  1.1798 +// compare equal according to NS_SecurityCompareURIs.  Unfortunately, in the
  1.1799 +// case of files, it's not clear we can do anything better than returning
  1.1800 +// the schemeHash, so hashing files degenerates to storing them in a list.
  1.1801 +inline uint32_t
  1.1802 +NS_SecurityHashURI(nsIURI* aURI)
  1.1803 +{
  1.1804 +    nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
  1.1805 +
  1.1806 +    nsAutoCString scheme;
  1.1807 +    uint32_t schemeHash = 0;
  1.1808 +    if (NS_SUCCEEDED(baseURI->GetScheme(scheme)))
  1.1809 +        schemeHash = mozilla::HashString(scheme);
  1.1810 +
  1.1811 +    // TODO figure out how to hash file:// URIs
  1.1812 +    if (scheme.EqualsLiteral("file"))
  1.1813 +        return schemeHash; // sad face
  1.1814 +
  1.1815 +    if (scheme.EqualsLiteral("imap") ||
  1.1816 +        scheme.EqualsLiteral("mailbox") ||
  1.1817 +        scheme.EqualsLiteral("news"))
  1.1818 +    {
  1.1819 +        nsAutoCString spec;
  1.1820 +        uint32_t specHash;
  1.1821 +        nsresult res = baseURI->GetSpec(spec);
  1.1822 +        if (NS_SUCCEEDED(res))
  1.1823 +            specHash = mozilla::HashString(spec);
  1.1824 +        else
  1.1825 +            specHash = static_cast<uint32_t>(res);
  1.1826 +        return specHash;
  1.1827 +    }
  1.1828 +
  1.1829 +    nsAutoCString host;
  1.1830 +    uint32_t hostHash = 0;
  1.1831 +    if (NS_SUCCEEDED(baseURI->GetAsciiHost(host)))
  1.1832 +        hostHash = mozilla::HashString(host);
  1.1833 +
  1.1834 +    return mozilla::AddToHash(schemeHash, hostHash, NS_GetRealPort(baseURI));
  1.1835 +}
  1.1836 +
  1.1837 +inline bool
  1.1838 +NS_SecurityCompareURIs(nsIURI* aSourceURI,
  1.1839 +                       nsIURI* aTargetURI,
  1.1840 +                       bool aStrictFileOriginPolicy)
  1.1841 +{
  1.1842 +    // Note that this is not an Equals() test on purpose -- for URIs that don't
  1.1843 +    // support host/port, we want equality to basically be object identity, for
  1.1844 +    // security purposes.  Otherwise, for example, two javascript: URIs that
  1.1845 +    // are otherwise unrelated could end up "same origin", which would be
  1.1846 +    // unfortunate.
  1.1847 +    if (aSourceURI && aSourceURI == aTargetURI)
  1.1848 +    {
  1.1849 +        return true;
  1.1850 +    }
  1.1851 +
  1.1852 +    if (!aTargetURI || !aSourceURI)
  1.1853 +    {
  1.1854 +        return false;
  1.1855 +    }
  1.1856 +
  1.1857 +    // If either URI is a nested URI, get the base URI
  1.1858 +    nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI);
  1.1859 +    nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
  1.1860 +
  1.1861 +    // If either uri is an nsIURIWithPrincipal
  1.1862 +    nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(sourceBaseURI);
  1.1863 +    if (uriPrinc) {
  1.1864 +        uriPrinc->GetPrincipalUri(getter_AddRefs(sourceBaseURI));
  1.1865 +    }
  1.1866 +
  1.1867 +    uriPrinc = do_QueryInterface(targetBaseURI);
  1.1868 +    if (uriPrinc) {
  1.1869 +        uriPrinc->GetPrincipalUri(getter_AddRefs(targetBaseURI));
  1.1870 +    }
  1.1871 +
  1.1872 +    if (!sourceBaseURI || !targetBaseURI)
  1.1873 +        return false;
  1.1874 +
  1.1875 +    // Compare schemes
  1.1876 +    nsAutoCString targetScheme;
  1.1877 +    bool sameScheme = false;
  1.1878 +    if (NS_FAILED( targetBaseURI->GetScheme(targetScheme) ) ||
  1.1879 +        NS_FAILED( sourceBaseURI->SchemeIs(targetScheme.get(), &sameScheme) ) ||
  1.1880 +        !sameScheme)
  1.1881 +    {
  1.1882 +        // Not same-origin if schemes differ
  1.1883 +        return false;
  1.1884 +    }
  1.1885 +
  1.1886 +    // For file scheme, reject unless the files are identical. See
  1.1887 +    // NS_RelaxStrictFileOriginPolicy for enforcing file same-origin checking
  1.1888 +    if (targetScheme.EqualsLiteral("file"))
  1.1889 +    {
  1.1890 +        // in traditional unsafe behavior all files are the same origin
  1.1891 +        if (!aStrictFileOriginPolicy)
  1.1892 +            return true;
  1.1893 +
  1.1894 +        nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(sourceBaseURI));
  1.1895 +        nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(targetBaseURI));
  1.1896 +
  1.1897 +        if (!sourceFileURL || !targetFileURL)
  1.1898 +            return false;
  1.1899 +
  1.1900 +        nsCOMPtr<nsIFile> sourceFile, targetFile;
  1.1901 +
  1.1902 +        sourceFileURL->GetFile(getter_AddRefs(sourceFile));
  1.1903 +        targetFileURL->GetFile(getter_AddRefs(targetFile));
  1.1904 +
  1.1905 +        if (!sourceFile || !targetFile)
  1.1906 +            return false;
  1.1907 +
  1.1908 +        // Otherwise they had better match
  1.1909 +        bool filesAreEqual = false;
  1.1910 +        nsresult rv = sourceFile->Equals(targetFile, &filesAreEqual);
  1.1911 +        return NS_SUCCEEDED(rv) && filesAreEqual;
  1.1912 +    }
  1.1913 +
  1.1914 +    // Special handling for mailnews schemes
  1.1915 +    if (targetScheme.EqualsLiteral("imap") ||
  1.1916 +        targetScheme.EqualsLiteral("mailbox") ||
  1.1917 +        targetScheme.EqualsLiteral("news"))
  1.1918 +    {
  1.1919 +        // Each message is a distinct trust domain; use the
  1.1920 +        // whole spec for comparison
  1.1921 +        nsAutoCString targetSpec;
  1.1922 +        nsAutoCString sourceSpec;
  1.1923 +        return ( NS_SUCCEEDED( targetBaseURI->GetSpec(targetSpec) ) &&
  1.1924 +                 NS_SUCCEEDED( sourceBaseURI->GetSpec(sourceSpec) ) &&
  1.1925 +                 targetSpec.Equals(sourceSpec) );
  1.1926 +    }
  1.1927 +
  1.1928 +    // Compare hosts
  1.1929 +    nsAutoCString targetHost;
  1.1930 +    nsAutoCString sourceHost;
  1.1931 +    if (NS_FAILED( targetBaseURI->GetAsciiHost(targetHost) ) ||
  1.1932 +        NS_FAILED( sourceBaseURI->GetAsciiHost(sourceHost) ))
  1.1933 +    {
  1.1934 +        return false;
  1.1935 +    }
  1.1936 +
  1.1937 +    nsCOMPtr<nsIStandardURL> targetURL(do_QueryInterface(targetBaseURI));
  1.1938 +    nsCOMPtr<nsIStandardURL> sourceURL(do_QueryInterface(sourceBaseURI));
  1.1939 +    if (!targetURL || !sourceURL)
  1.1940 +    {
  1.1941 +        return false;
  1.1942 +    }
  1.1943 +
  1.1944 +#ifdef MOZILLA_INTERNAL_API
  1.1945 +    if (!targetHost.Equals(sourceHost, nsCaseInsensitiveCStringComparator() ))
  1.1946 +#else
  1.1947 +    if (!targetHost.Equals(sourceHost, CaseInsensitiveCompare))
  1.1948 +#endif
  1.1949 +    {
  1.1950 +        return false;
  1.1951 +    }
  1.1952 +
  1.1953 +    return NS_GetRealPort(targetBaseURI) == NS_GetRealPort(sourceBaseURI);
  1.1954 +}
  1.1955 +
  1.1956 +inline bool
  1.1957 +NS_URIIsLocalFile(nsIURI *aURI)
  1.1958 +{
  1.1959 +  nsCOMPtr<nsINetUtil> util = do_GetNetUtil();
  1.1960 +
  1.1961 +  bool isFile;
  1.1962 +  return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
  1.1963 +                                nsIProtocolHandler::URI_IS_LOCAL_FILE,
  1.1964 +                                &isFile)) &&
  1.1965 +         isFile;
  1.1966 +}
  1.1967 +
  1.1968 +// When strict file origin policy is enabled, SecurityCompareURIs will fail for
  1.1969 +// file URIs that do not point to the same local file. This call provides an
  1.1970 +// alternate file-specific origin check that allows target files that are
  1.1971 +// contained in the same directory as the source.
  1.1972 +//
  1.1973 +// https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs
  1.1974 +inline bool
  1.1975 +NS_RelaxStrictFileOriginPolicy(nsIURI *aTargetURI,
  1.1976 +                               nsIURI *aSourceURI,
  1.1977 +                               bool aAllowDirectoryTarget = false)
  1.1978 +{
  1.1979 +  if (!NS_URIIsLocalFile(aTargetURI)) {
  1.1980 +    // This is probably not what the caller intended
  1.1981 +    NS_NOTREACHED("NS_RelaxStrictFileOriginPolicy called with non-file URI");
  1.1982 +    return false;
  1.1983 +  }
  1.1984 +
  1.1985 +  if (!NS_URIIsLocalFile(aSourceURI)) {
  1.1986 +    // If the source is not also a file: uri then forget it
  1.1987 +    // (don't want resource: principals in a file: doc)
  1.1988 +    //
  1.1989 +    // note: we're not de-nesting jar: uris here, we want to
  1.1990 +    // keep archive content bottled up in its own little island
  1.1991 +    return false;
  1.1992 +  }
  1.1993 +
  1.1994 +  //
  1.1995 +  // pull out the internal files
  1.1996 +  //
  1.1997 +  nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(aTargetURI));
  1.1998 +  nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(aSourceURI));
  1.1999 +  nsCOMPtr<nsIFile> targetFile;
  1.2000 +  nsCOMPtr<nsIFile> sourceFile;
  1.2001 +  bool targetIsDir;
  1.2002 +
  1.2003 +  // Make sure targetFile is not a directory (bug 209234)
  1.2004 +  // and that it exists w/out unescaping (bug 395343)
  1.2005 +  if (!sourceFileURL || !targetFileURL ||
  1.2006 +      NS_FAILED(targetFileURL->GetFile(getter_AddRefs(targetFile))) ||
  1.2007 +      NS_FAILED(sourceFileURL->GetFile(getter_AddRefs(sourceFile))) ||
  1.2008 +      !targetFile || !sourceFile ||
  1.2009 +      NS_FAILED(targetFile->Normalize()) ||
  1.2010 +#ifndef MOZ_WIDGET_ANDROID
  1.2011 +      NS_FAILED(sourceFile->Normalize()) ||
  1.2012 +#endif
  1.2013 +      (!aAllowDirectoryTarget &&
  1.2014 +       (NS_FAILED(targetFile->IsDirectory(&targetIsDir)) || targetIsDir))) {
  1.2015 +    return false;
  1.2016 +  }
  1.2017 +
  1.2018 +  //
  1.2019 +  // If the file to be loaded is in a subdirectory of the source
  1.2020 +  // (or same-dir if source is not a directory) then it will
  1.2021 +  // inherit its source principal and be scriptable by that source.
  1.2022 +  //
  1.2023 +  bool sourceIsDir;
  1.2024 +  bool allowed = false;
  1.2025 +  nsresult rv = sourceFile->IsDirectory(&sourceIsDir);
  1.2026 +  if (NS_SUCCEEDED(rv) && sourceIsDir) {
  1.2027 +    rv = sourceFile->Contains(targetFile, true, &allowed);
  1.2028 +  } else {
  1.2029 +    nsCOMPtr<nsIFile> sourceParent;
  1.2030 +    rv = sourceFile->GetParent(getter_AddRefs(sourceParent));
  1.2031 +    if (NS_SUCCEEDED(rv) && sourceParent) {
  1.2032 +      rv = sourceParent->Equals(targetFile, &allowed);
  1.2033 +      if (NS_FAILED(rv) || !allowed) {
  1.2034 +        rv = sourceParent->Contains(targetFile, true, &allowed);
  1.2035 +      } else {
  1.2036 +        MOZ_ASSERT(aAllowDirectoryTarget,
  1.2037 +                   "sourceFile->Parent == targetFile, but targetFile "
  1.2038 +                   "should've been disallowed if it is a directory");
  1.2039 +      }
  1.2040 +    }
  1.2041 +  }
  1.2042 +
  1.2043 +  if (NS_SUCCEEDED(rv) && allowed) {
  1.2044 +    return true;
  1.2045 +  }
  1.2046 +
  1.2047 +  return false;
  1.2048 +}
  1.2049 +
  1.2050 +inline bool
  1.2051 +NS_IsInternalSameURIRedirect(nsIChannel *aOldChannel,
  1.2052 +                             nsIChannel *aNewChannel,
  1.2053 +                             uint32_t aFlags)
  1.2054 +{
  1.2055 +  if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
  1.2056 +    return false;
  1.2057 +  }
  1.2058 +
  1.2059 +  nsCOMPtr<nsIURI> oldURI, newURI;
  1.2060 +  aOldChannel->GetURI(getter_AddRefs(oldURI));
  1.2061 +  aNewChannel->GetURI(getter_AddRefs(newURI));
  1.2062 +
  1.2063 +  if (!oldURI || !newURI) {
  1.2064 +    return false;
  1.2065 +  }
  1.2066 +
  1.2067 +  bool res;
  1.2068 +  return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res;
  1.2069 +}
  1.2070 +
  1.2071 +inline nsresult
  1.2072 +NS_LinkRedirectChannels(uint32_t channelId,
  1.2073 +                        nsIParentChannel *parentChannel,
  1.2074 +                        nsIChannel** _result)
  1.2075 +{
  1.2076 +  nsresult rv;
  1.2077 +
  1.2078 +  nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
  1.2079 +      do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
  1.2080 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2081 +
  1.2082 +  return registrar->LinkChannels(channelId,
  1.2083 +                                 parentChannel,
  1.2084 +                                 _result);
  1.2085 +}
  1.2086 +
  1.2087 +/**
  1.2088 + * Helper function to create a random URL string that's properly formed
  1.2089 + * but guaranteed to be invalid.
  1.2090 + */  
  1.2091 +#define NS_FAKE_SCHEME "http://"
  1.2092 +#define NS_FAKE_TLD ".invalid"
  1.2093 +inline nsresult
  1.2094 +NS_MakeRandomInvalidURLString(nsCString& result)
  1.2095 +{
  1.2096 +  nsresult rv;
  1.2097 +  nsCOMPtr<nsIUUIDGenerator> uuidgen =
  1.2098 +    do_GetService("@mozilla.org/uuid-generator;1", &rv);
  1.2099 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2100 +
  1.2101 +  nsID idee;
  1.2102 +  rv = uuidgen->GenerateUUIDInPlace(&idee);
  1.2103 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2104 +
  1.2105 +  char chars[NSID_LENGTH];
  1.2106 +  idee.ToProvidedString(chars);
  1.2107 +
  1.2108 +  result.AssignLiteral(NS_FAKE_SCHEME);
  1.2109 +  // Strip off the '{' and '}' at the beginning and end of the UUID
  1.2110 +  result.Append(chars + 1, NSID_LENGTH - 3);
  1.2111 +  result.AppendLiteral(NS_FAKE_TLD);
  1.2112 +
  1.2113 +  return NS_OK;
  1.2114 +}
  1.2115 +#undef NS_FAKE_SCHEME
  1.2116 +#undef NS_FAKE_TLD
  1.2117 +
  1.2118 +/**
  1.2119 + * Helper function to determine whether urlString is Java-compatible --
  1.2120 + * whether it can be passed to the Java URL(String) constructor without the
  1.2121 + * latter throwing a MalformedURLException, or without Java otherwise
  1.2122 + * mishandling it.  This function (in effect) implements a scheme whitelist
  1.2123 + * for Java.
  1.2124 + */  
  1.2125 +inline nsresult
  1.2126 +NS_CheckIsJavaCompatibleURLString(nsCString& urlString, bool *result)
  1.2127 +{
  1.2128 +  *result = false; // Default to "no"
  1.2129 +
  1.2130 +  nsresult rv = NS_OK;
  1.2131 +  nsCOMPtr<nsIURLParser> urlParser =
  1.2132 +    do_GetService(NS_STDURLPARSER_CONTRACTID, &rv);
  1.2133 +  if (NS_FAILED(rv) || !urlParser)
  1.2134 +    return NS_ERROR_FAILURE;
  1.2135 +
  1.2136 +  bool compatible = true;
  1.2137 +  uint32_t schemePos = 0;
  1.2138 +  int32_t schemeLen = 0;
  1.2139 +  urlParser->ParseURL(urlString.get(), -1, &schemePos, &schemeLen,
  1.2140 +                      nullptr, nullptr, nullptr, nullptr);
  1.2141 +  if (schemeLen != -1) {
  1.2142 +    nsCString scheme;
  1.2143 +    scheme.Assign(urlString.get() + schemePos, schemeLen);
  1.2144 +    // By default Java only understands a small number of URL schemes, and of
  1.2145 +    // these only some can legitimately represent a browser page's "origin"
  1.2146 +    // (and be something we can legitimately expect Java to handle ... or not
  1.2147 +    // to mishandle).
  1.2148 +    //
  1.2149 +    // Besides those listed below, the OJI plugin understands the "jar",
  1.2150 +    // "mailto", "netdoc", "javascript" and "rmi" schemes, and Java Plugin2
  1.2151 +    // also understands the "about" scheme.  We actually pass "about" URLs
  1.2152 +    // to Java ("about:blank" when processing a javascript: URL (one that
  1.2153 +    // calls Java) from the location bar of a blank page, and (in FF4 and up)
  1.2154 +    // "about:home" when processing a javascript: URL from the home page).
  1.2155 +    // And Java doesn't appear to mishandle them (for example it doesn't allow
  1.2156 +    // connections to "about" URLs).  But it doesn't make any sense to do
  1.2157 +    // same-origin checks on "about" URLs, so we don't include them in our
  1.2158 +    // scheme whitelist.
  1.2159 +    //
  1.2160 +    // The OJI plugin doesn't understand "chrome" URLs (only Java Plugin2
  1.2161 +    // does) -- so we mustn't pass them to the OJI plugin.  But we do need to
  1.2162 +    // pass "chrome" URLs to Java Plugin2:  Java Plugin2 grants additional
  1.2163 +    // privileges to chrome "origins", and some extensions take advantage of
  1.2164 +    // this.  For more information see bug 620773.
  1.2165 +    //
  1.2166 +    // As of FF4, we no longer support the OJI plugin.
  1.2167 +    if (PL_strcasecmp(scheme.get(), "http") &&
  1.2168 +        PL_strcasecmp(scheme.get(), "https") &&
  1.2169 +        PL_strcasecmp(scheme.get(), "file") &&
  1.2170 +        PL_strcasecmp(scheme.get(), "ftp") &&
  1.2171 +        PL_strcasecmp(scheme.get(), "gopher") &&
  1.2172 +        PL_strcasecmp(scheme.get(), "chrome"))
  1.2173 +      compatible = false;
  1.2174 +  } else {
  1.2175 +    compatible = false;
  1.2176 +  }
  1.2177 +
  1.2178 +  *result = compatible;
  1.2179 +
  1.2180 +  return NS_OK;
  1.2181 +}
  1.2182 +
  1.2183 +/** Given the first (disposition) token from a Content-Disposition header,
  1.2184 + * tell whether it indicates the content is inline or attachment
  1.2185 + * @param aDispToken the disposition token from the content-disposition header
  1.2186 + */
  1.2187 +inline uint32_t
  1.2188 +NS_GetContentDispositionFromToken(const nsAString& aDispToken)
  1.2189 +{
  1.2190 +  // RFC 2183, section 2.8 says that an unknown disposition
  1.2191 +  // value should be treated as "attachment"
  1.2192 +  // If all of these tests eval to false, then we have a content-disposition of
  1.2193 +  // "attachment" or unknown
  1.2194 +  if (aDispToken.IsEmpty() ||
  1.2195 +      aDispToken.LowerCaseEqualsLiteral("inline") ||
  1.2196 +      // Broken sites just send
  1.2197 +      // Content-Disposition: filename="file"
  1.2198 +      // without a disposition token... screen those out.
  1.2199 +      StringHead(aDispToken, 8).LowerCaseEqualsLiteral("filename"))
  1.2200 +    return nsIChannel::DISPOSITION_INLINE;
  1.2201 +
  1.2202 +  return nsIChannel::DISPOSITION_ATTACHMENT;
  1.2203 +}
  1.2204 +
  1.2205 +/** Determine the disposition (inline/attachment) of the content based on the
  1.2206 + * Content-Disposition header
  1.2207 + * @param aHeader the content-disposition header (full value)
  1.2208 + * @param aChan the channel the header came from
  1.2209 + */
  1.2210 +inline uint32_t
  1.2211 +NS_GetContentDispositionFromHeader(const nsACString& aHeader, nsIChannel *aChan = nullptr)
  1.2212 +{
  1.2213 +  nsresult rv;
  1.2214 +  nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
  1.2215 +  if (NS_FAILED(rv))
  1.2216 +    return nsIChannel::DISPOSITION_ATTACHMENT;
  1.2217 +
  1.2218 +  nsAutoCString fallbackCharset;
  1.2219 +  if (aChan) {
  1.2220 +    nsCOMPtr<nsIURI> uri;
  1.2221 +    aChan->GetURI(getter_AddRefs(uri));
  1.2222 +    if (uri)
  1.2223 +      uri->GetOriginCharset(fallbackCharset);
  1.2224 +  }
  1.2225 +
  1.2226 +  nsAutoString dispToken;
  1.2227 +  rv = mimehdrpar->GetParameterHTTP(aHeader, "", fallbackCharset, true, nullptr,
  1.2228 +                                    dispToken);
  1.2229 +
  1.2230 +  if (NS_FAILED(rv)) {
  1.2231 +    // special case (see bug 272541): empty disposition type handled as "inline"
  1.2232 +    if (rv == NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY)
  1.2233 +        return nsIChannel::DISPOSITION_INLINE;
  1.2234 +    return nsIChannel::DISPOSITION_ATTACHMENT;
  1.2235 +  }
  1.2236 +
  1.2237 +  return NS_GetContentDispositionFromToken(dispToken);
  1.2238 +}
  1.2239 +
  1.2240 +/** Extracts the filename out of a content-disposition header
  1.2241 + * @param aFilename [out] The filename. Can be empty on error.
  1.2242 + * @param aDisposition Value of a Content-Disposition header
  1.2243 + * @param aURI Optional. Will be used to get a fallback charset for the
  1.2244 + *        filename, if it is QI'able to nsIURL
  1.2245 + */
  1.2246 +inline nsresult
  1.2247 +NS_GetFilenameFromDisposition(nsAString& aFilename,
  1.2248 +                              const nsACString& aDisposition,
  1.2249 +                              nsIURI* aURI = nullptr)
  1.2250 +{
  1.2251 +  aFilename.Truncate();
  1.2252 +
  1.2253 +  nsresult rv;
  1.2254 +  nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
  1.2255 +      do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
  1.2256 +  if (NS_FAILED(rv))
  1.2257 +    return rv;
  1.2258 +
  1.2259 +  nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
  1.2260 +
  1.2261 +  nsAutoCString fallbackCharset;
  1.2262 +  if (url)
  1.2263 +    url->GetOriginCharset(fallbackCharset);
  1.2264 +  // Get the value of 'filename' parameter
  1.2265 +  rv = mimehdrpar->GetParameterHTTP(aDisposition, "filename",
  1.2266 +                                    fallbackCharset, true, nullptr,
  1.2267 +                                    aFilename);
  1.2268 +
  1.2269 +  if (NS_FAILED(rv)) {
  1.2270 +    aFilename.Truncate();
  1.2271 +    return rv;
  1.2272 +  }
  1.2273 +
  1.2274 +  if (aFilename.IsEmpty())
  1.2275 +    return NS_ERROR_NOT_AVAILABLE;
  1.2276 +
  1.2277 +  return NS_OK;
  1.2278 +}
  1.2279 +
  1.2280 +/**
  1.2281 + * Make sure Personal Security Manager is initialized
  1.2282 + */
  1.2283 +inline void
  1.2284 +net_EnsurePSMInit()
  1.2285 +{
  1.2286 +    nsCOMPtr<nsISocketProviderService> spserv =
  1.2287 +            do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID);
  1.2288 +    if (spserv) {
  1.2289 +        nsCOMPtr<nsISocketProvider> provider;
  1.2290 +        spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
  1.2291 +    }
  1.2292 +}
  1.2293 +
  1.2294 +/**
  1.2295 + * Test whether a URI is "about:blank".  |uri| must not be null
  1.2296 + */
  1.2297 +inline bool
  1.2298 +NS_IsAboutBlank(nsIURI *uri)
  1.2299 +{
  1.2300 +    // GetSpec can be expensive for some URIs, so check the scheme first.
  1.2301 +    bool isAbout = false;
  1.2302 +    if (NS_FAILED(uri->SchemeIs("about", &isAbout)) || !isAbout) {
  1.2303 +        return false;
  1.2304 +    }
  1.2305 +
  1.2306 +    nsAutoCString str;
  1.2307 +    uri->GetSpec(str);
  1.2308 +    return str.EqualsLiteral("about:blank");
  1.2309 +}
  1.2310 +
  1.2311 +
  1.2312 +inline nsresult
  1.2313 +NS_GenerateHostPort(const nsCString& host, int32_t port,
  1.2314 +                    nsCString& hostLine)
  1.2315 +{
  1.2316 +    if (strchr(host.get(), ':')) {
  1.2317 +        // host is an IPv6 address literal and must be encapsulated in []'s
  1.2318 +        hostLine.Assign('[');
  1.2319 +        // scope id is not needed for Host header.
  1.2320 +        int scopeIdPos = host.FindChar('%');
  1.2321 +        if (scopeIdPos == -1)
  1.2322 +            hostLine.Append(host);
  1.2323 +        else if (scopeIdPos > 0)
  1.2324 +            hostLine.Append(Substring(host, 0, scopeIdPos));
  1.2325 +        else
  1.2326 +          return NS_ERROR_MALFORMED_URI;
  1.2327 +        hostLine.Append(']');
  1.2328 +    }
  1.2329 +    else
  1.2330 +        hostLine.Assign(host);
  1.2331 +    if (port != -1) {
  1.2332 +        hostLine.Append(':');
  1.2333 +        hostLine.AppendInt(port);
  1.2334 +    }
  1.2335 +    return NS_OK;
  1.2336 +}
  1.2337 +
  1.2338 +/**
  1.2339 + * Sniff the content type for a given request or a given buffer.
  1.2340 + *
  1.2341 + * aSnifferType can be either NS_CONTENT_SNIFFER_CATEGORY or
  1.2342 + * NS_DATA_SNIFFER_CATEGORY.  The function returns the sniffed content type
  1.2343 + * in the aSniffedType argument.  This argument will not be modified if the
  1.2344 + * content type could not be sniffed.
  1.2345 + */
  1.2346 +inline void
  1.2347 +NS_SniffContent(const char* aSnifferType, nsIRequest* aRequest,
  1.2348 +                const uint8_t* aData, uint32_t aLength,
  1.2349 +                nsACString& aSniffedType)
  1.2350 +{
  1.2351 +  typedef nsCategoryCache<nsIContentSniffer> ContentSnifferCache;
  1.2352 +  extern NS_HIDDEN_(ContentSnifferCache*) gNetSniffers;
  1.2353 +  extern NS_HIDDEN_(ContentSnifferCache*) gDataSniffers;
  1.2354 +  ContentSnifferCache* cache = nullptr;
  1.2355 +  if (!strcmp(aSnifferType, NS_CONTENT_SNIFFER_CATEGORY)) {
  1.2356 +    if (!gNetSniffers) {
  1.2357 +      gNetSniffers = new ContentSnifferCache(NS_CONTENT_SNIFFER_CATEGORY);
  1.2358 +    }
  1.2359 +    cache = gNetSniffers;
  1.2360 +  } else if (!strcmp(aSnifferType, NS_DATA_SNIFFER_CATEGORY)) {
  1.2361 +    if (!gDataSniffers) {
  1.2362 +      gDataSniffers = new ContentSnifferCache(NS_DATA_SNIFFER_CATEGORY);
  1.2363 +    }
  1.2364 +    cache = gDataSniffers;
  1.2365 +  } else {
  1.2366 +    // Invalid content sniffer type was requested
  1.2367 +    MOZ_ASSERT(false);
  1.2368 +    return;
  1.2369 +  }
  1.2370 +
  1.2371 +  nsCOMArray<nsIContentSniffer> sniffers;
  1.2372 +  cache->GetEntries(sniffers);
  1.2373 +  for (int32_t i = 0; i < sniffers.Count(); ++i) {
  1.2374 +    nsresult rv = sniffers[i]->GetMIMETypeFromContent(aRequest, aData, aLength, aSniffedType);
  1.2375 +    if (NS_SUCCEEDED(rv) && !aSniffedType.IsEmpty()) {
  1.2376 +      return;
  1.2377 +    }
  1.2378 +  }
  1.2379 +
  1.2380 +  aSniffedType.Truncate();
  1.2381 +}
  1.2382 +
  1.2383 +/**
  1.2384 + * Whether the channel was created to load a srcdoc document.
  1.2385 + * Note that view-source:about:srcdoc is classified as a srcdoc document by 
  1.2386 + * this function, which may not be applicable everywhere.
  1.2387 + */
  1.2388 +inline bool
  1.2389 +NS_IsSrcdocChannel(nsIChannel *aChannel)
  1.2390 +{
  1.2391 +  bool isSrcdoc;
  1.2392 +  nsCOMPtr<nsIInputStreamChannel> isr = do_QueryInterface(aChannel);
  1.2393 +  if (isr) {
  1.2394 +    isr->GetIsSrcdocChannel(&isSrcdoc);
  1.2395 +    return isSrcdoc;
  1.2396 +  }
  1.2397 +  nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(aChannel);
  1.2398 +  if (vsc) {
  1.2399 +    vsc->GetIsSrcdocChannel(&isSrcdoc);
  1.2400 +    return isSrcdoc;
  1.2401 +  }
  1.2402 +  return false;
  1.2403 +}
  1.2404 +
  1.2405 +#endif // !nsNetUtil_h__

mercurial