Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/netwerk/base/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 133 kB image not shown  

Quelle  nsNetUtil.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=4 sw=2 sts=2 et cin: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


// HttpLog.h should generally be included first
#include "DecoderDoctorDiagnostics.h"
#include "HttpLog.h"

#include "nsNetUtil.h"

#include "mozilla/Atomics.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/Components.h"
#include "mozilla/Encoding.h"
#include "mozilla/LoadContext.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/Monitor.h"
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Telemetry.h"
#include "nsAboutProtocolUtils.h"
#include "nsBufferedStreams.h"
#include "nsCategoryCache.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsEscape.h"
#include "nsFileStreams.h"
#include "nsHashKeys.h"
#include "nsHttp.h"
#include "nsMimeTypes.h"
#include "nsIAuthPrompt.h"
#include "nsIAuthPrompt2.h"
#include "nsIAuthPromptAdapterFactory.h"
#include "nsIBufferedStreams.h"
#include "nsBufferedStreams.h"
#include "nsIChannelEventSink.h"
#include "nsIContentSniffer.h"
#include "mozilla/dom/Document.h"
#include "nsIDownloader.h"
#include "nsIFileProtocolHandler.h"
#include "nsIFileStreams.h"
#include "nsIFileURL.h"
#include "nsIIDNService.h"
#include "nsIInputStreamChannel.h"
#include "nsIInputStreamPump.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadContext.h"
#include "nsIMIMEHeaderParam.h"
#include "nsINode.h"
#include "nsIObjectLoadingContent.h"
#include "nsPersistentProperties.h"
#include "nsIPrivateBrowsingChannel.h"
#include "nsIPropertyBag2.h"
#include "nsIProtocolProxyService.h"
#include "mozilla/net/RedirectChannelRegistrar.h"
#include "nsRequestObserverProxy.h"
#include "nsISensitiveInfoHiddenURI.h"
#include "nsISimpleStreamListener.h"
#include "nsISocketProvider.h"
#include "nsIStandardURL.h"
#include "nsIStreamLoader.h"
#include "nsIIncrementalStreamLoader.h"
#include "nsStringStream.h"
#include "nsSyncStreamListener.h"
#include "nsITextToSubURI.h"
#include "nsIURIWithSpecialOrigin.h"
#include "nsIViewSourceChannel.h"
#include "nsInterfaceRequestorAgg.h"
#include "nsINestedURI.h"
#include "mozilla/dom/nsCSPUtils.h"
#include "mozilla/dom/nsHTTPSOnlyUtils.h"
#include "mozilla/dom/nsMixedContentBlocker.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "mozilla/net/HttpBaseChannel.h"
#include "nsIScriptError.h"
#include "nsISiteSecurityService.h"
#include "nsHttpHandler.h"
#include "nsNSSComponent.h"
#include "nsIRedirectHistoryEntry.h"
#include "nsICertStorage.h"
#include "nsICertOverrideService.h"
#include "nsQueryObject.h"
#include "mozIThirdPartyUtil.h"
#include "../mime/nsMIMEHeaderParamImpl.h"
#include "nsStandardURL.h"
#include "DefaultURI.h"
#include "nsChromeProtocolHandler.h"
#include "nsJSProtocolHandler.h"
#include "nsDataHandler.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "nsStreamUtils.h"
#include "nsSocketTransportService2.h"
#include "nsViewSourceHandler.h"
#include "nsJARURI.h"
#ifndef XP_IOS
#  include "nsIconURI.h"
#endif
#include "nsAboutProtocolHandler.h"
#include "nsResProtocolHandler.h"
#include "mozilla/net/ExtensionProtocolHandler.h"
#include "mozilla/net/PageThumbProtocolHandler.h"
#include "mozilla/net/SFVService.h"
#include <limits>
#include "nsIXPConnect.h"
#include "nsParserConstants.h"
#include "nsCRT.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/dom/MediaList.h"
#include "MediaContainerType.h"
#include "DecoderTraits.h"
#include "imgLoader.h"

#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
#  include "nsNewMailnewsURI.h"
#endif

using namespace mozilla;
using namespace mozilla::net;
using mozilla::dom::BlobURLProtocolHandler;
using mozilla::dom::ClientInfo;
using mozilla::dom::PerformanceStorage;
using mozilla::dom::ServiceWorkerDescriptor;

#define MAX_RECURSION_COUNT 50

already_AddRefed<nsIIOService> do_GetIOService(nsresult* error /* = 0 */) {
  nsCOMPtr<nsIIOService> io;
  io = mozilla::components::IO::Service();
  if (error) *error = io ? NS_OK : NS_ERROR_FAILURE;
  return io.forget();
}

nsresult NS_NewLocalFileInputStream(nsIInputStream** result, nsIFile* file,
                                    int32_t ioFlags /* = -1 */,
                                    int32_t perm /* = -1 */,
                                    int32_t behaviorFlags /* = 0 */) {
  nsresult rv;
  nsCOMPtr<nsIFileInputStream> in =
      do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = in->Init(file, ioFlags, perm, behaviorFlags);
    if (NS_SUCCEEDED(rv)) in.forget(result);
  }
  return rv;
}

Result<nsCOMPtr<nsIInputStream>, nsresult> NS_NewLocalFileInputStream(
    nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */,
    int32_t behaviorFlags /* = 0 */) {
  nsCOMPtr<nsIInputStream> stream;
  const nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file,
                                                 ioFlags, perm, behaviorFlags);
  if (NS_SUCCEEDED(rv)) {
    return stream;
  }
  return Err(rv);
}

nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result, nsIFile* file,
                                     int32_t ioFlags /* = -1 */,
                                     int32_t perm /* = -1 */,
                                     int32_t behaviorFlags /* = 0 */) {
  nsresult rv;
  nsCOMPtr<nsIFileOutputStream> out =
      do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = out->Init(file, ioFlags, perm, behaviorFlags);
    if (NS_SUCCEEDED(rv)) out.forget(result);
  }
  return rv;
}

Result<nsCOMPtr<nsIOutputStream>, nsresult> NS_NewLocalFileOutputStream(
    nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */,
    int32_t behaviorFlags /* = 0 */) {
  nsCOMPtr<nsIOutputStream> stream;
  const nsresult rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), file,
                                                  ioFlags, perm, behaviorFlags);
  if (NS_SUCCEEDED(rv)) {
    return stream;
  }
  return Err(rv);
}

nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result,
                                     const mozilla::ipc::FileDescriptor& fd) {
  nsCOMPtr<nsIFileOutputStream> out;
  nsFileOutputStream::Create(NS_GET_IID(nsIFileOutputStream),
                             getter_AddRefs(out));

  nsresult rv =
      static_cast<nsFileOutputStream*>(out.get())->InitWithFileDescriptor(fd);
  if (NS_FAILED(rv)) {
    return rv;
  }

  out.forget(result);
  return NS_OK;
}

nsresult net_EnsureIOService(nsIIOService** ios, nsCOMPtr<nsIIOService>& grip) {
  nsresult rv = NS_OK;
  if (!*ios) {
    grip = do_GetIOService(&rv);
    *ios = grip;
  }
  return rv;
}

nsresult NS_NewFileURI(
    nsIURI** result, nsIFile* spec,
    nsIIOService*
        ioService /* = nullptr */)  // pass in nsIIOService to optimize callers
{
  nsresult rv;
  nsCOMPtr<nsIIOService> grip;
  rv = net_EnsureIOService(&ioService, grip);
  if (ioService) rv = ioService->NewFileURI(spec, result);
  return rv;
}

nsresult NS_GetURIWithNewRef(nsIURI* aInput, const nsACString& aRef,
                             nsIURI** aOutput) {
  MOZ_DIAGNOSTIC_ASSERT(aRef.IsEmpty() || aRef[0] == '#');

  if (NS_WARN_IF(!aInput || !aOutput)) {
    return NS_ERROR_INVALID_ARG;
  }

  bool hasRef;
  nsresult rv = aInput->GetHasRef(&hasRef);

  nsAutoCString ref;
  if (NS_SUCCEEDED(rv)) {
    rv = aInput->GetRef(ref);
  }

  // If the ref is already equal to the new ref, we do not need to do anything.
  // Also, if the GetRef failed (it could return NS_ERROR_NOT_IMPLEMENTED)
  // we can assume SetRef would fail as well, so returning the original
  // URI is OK.
  //
  // Note that aRef contains the hash, but ref doesn't, so need to account for
  // that in the equality check.
  if (NS_FAILED(rv) || (!hasRef && aRef.IsEmpty()) ||
      (!aRef.IsEmpty() && hasRef &&
       Substring(aRef.Data() + 1, aRef.Length() - 1) == ref)) {
    nsCOMPtr<nsIURI> uri = aInput;
    uri.forget(aOutput);
    return NS_OK;
  }

  return NS_MutateURI(aInput).SetRef(aRef).Finalize(aOutput);
}

nsresult NS_GetURIWithoutRef(nsIURI* aInput, nsIURI** aOutput) {
  return NS_GetURIWithNewRef(aInput, ""_ns, aOutput);
}

nsresult NS_NewChannelInternal(
    nsIChannel** outChannel, nsIURI* aUri, nsILoadInfo* aLoadInfo,
    PerformanceStorage* aPerformanceStorage /* = nullptr */,
    nsILoadGroup* aLoadGroup /* = nullptr */,
    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    nsIIOService* aIoService /* = nullptr */) {
  // NS_NewChannelInternal is mostly called for channel redirects. We should
  // allow the creation of a channel even if the original channel did not have a
  // loadinfo attached.
  NS_ENSURE_ARG_POINTER(outChannel);

  nsCOMPtr<nsIIOService> grip;
  nsresult rv = net_EnsureIOService(&aIoService, grip);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIChannel> channel;
  rv = aIoService->NewChannelFromURIWithLoadInfo(aUri, aLoadInfo,
                                                 getter_AddRefs(channel));
  NS_ENSURE_SUCCESS(rv, rv);

  if (aLoadGroup) {
    rv = channel->SetLoadGroup(aLoadGroup);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  if (aCallbacks) {
    rv = channel->SetNotificationCallbacks(aCallbacks);
    NS_ENSURE_SUCCESS(rv, rv);
  }

#ifdef DEBUG
  nsLoadFlags channelLoadFlags = 0;
  channel->GetLoadFlags(&channelLoadFlags);
  // Will be removed when we remove LOAD_REPLACE altogether
  // This check is trying to catch protocol handlers that still
  // try to set the LOAD_REPLACE flag.
  MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
#endif

  if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
    rv = channel->SetLoadFlags(aLoadFlags);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  if (aPerformanceStorage) {
    nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
    loadInfo->SetPerformanceStorage(aPerformanceStorage);
  }

  channel.forget(outChannel);
  return NS_OK;
}

namespace {

void AssertLoadingPrincipalAndClientInfoMatch(
    nsIPrincipal* aLoadingPrincipal, const ClientInfo& aLoadingClientInfo,
    nsContentPolicyType aType) {
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
  // Verify that the provided loading ClientInfo matches the loading
  // principal.  Unfortunately we can't just use nsIPrincipal::Equals() here
  // because of some corner cases:
  //
  //  1. Worker debugger scripts want to use a system loading principal for
  //     worker scripts with a content principal.  We exempt these from this
  //     check.
  //  2. Null principals currently require exact object identity for
  //     nsIPrincipal::Equals() to return true.  This doesn't work here because
  //     ClientInfo::GetPrincipal() uses PrincipalInfoToPrincipal() to allocate
  //     a new object.  To work around this we compare the principal origin
  //     string itself.  If bug 1431771 is fixed then we could switch to
  //     Equals().

  // Allow worker debugger to load with a system principal.
  if (aLoadingPrincipal->IsSystemPrincipal() &&
      (aType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
       aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
       aType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER ||
       aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS ||
       aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE)) {
    return;
  }

  // Perform a fast comparison for most principal checks.
  auto clientPrincipalOrErr(aLoadingClientInfo.GetPrincipal());
  if (clientPrincipalOrErr.isOk()) {
    nsCOMPtr<nsIPrincipal> clientPrincipal = clientPrincipalOrErr.unwrap();
    if (aLoadingPrincipal->Equals(clientPrincipal)) {
      return;
    }
    // Fall back to a slower origin equality test to support null principals.
    nsAutoCString loadingOriginNoSuffix;
    MOZ_ALWAYS_SUCCEEDS(
        aLoadingPrincipal->GetOriginNoSuffix(loadingOriginNoSuffix));

    nsAutoCString clientOriginNoSuffix;
    MOZ_ALWAYS_SUCCEEDS(
        clientPrincipal->GetOriginNoSuffix(clientOriginNoSuffix));

    // The client principal will have the partitionKey set if it's in a third
    // party context, but the loading principal won't. So, we ignore he
    // partitionKey when doing the verification here.
    MOZ_DIAGNOSTIC_ASSERT(loadingOriginNoSuffix == clientOriginNoSuffix);
    MOZ_DIAGNOSTIC_ASSERT(
        aLoadingPrincipal->OriginAttributesRef().EqualsIgnoringPartitionKey(
            clientPrincipal->OriginAttributesRef()));
  }
#endif
}

}  // namespace

nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
                       nsIPrincipal* aLoadingPrincipal,
                       nsSecurityFlags aSecurityFlags,
                       nsContentPolicyType aContentPolicyType,
                       nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
                       PerformanceStorage* aPerformanceStorage /* = nullptr */,
                       nsILoadGroup* aLoadGroup /* = nullptr */,
                       nsIInterfaceRequestor* aCallbacks /* = nullptr */,
                       nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
                       nsIIOService* aIoService /* = nullptr */,
                       uint32_t aSandboxFlags /* = 0 */) {
  return NS_NewChannelInternal(
      outChannel, aUri,
      nullptr,  // aLoadingNode,
      aLoadingPrincipal,
      nullptr,  // aTriggeringPrincipal
      Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
      aContentPolicyType, aCookieJarSettings, aPerformanceStorage, aLoadGroup,
      aCallbacks, aLoadFlags, aIoService, aSandboxFlags);
}

nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
                       nsIPrincipal* aLoadingPrincipal,
                       const ClientInfo& aLoadingClientInfo,
                       const Maybe<ServiceWorkerDescriptor>& aController,
                       nsSecurityFlags aSecurityFlags,
                       nsContentPolicyType aContentPolicyType,
                       nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
                       PerformanceStorage* aPerformanceStorage /* = nullptr */,
                       nsILoadGroup* aLoadGroup /* = nullptr */,
                       nsIInterfaceRequestor* aCallbacks /* = nullptr */,
                       nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
                       nsIIOService* aIoService /* = nullptr */,
                       uint32_t aSandboxFlags /* = 0 */) {
  AssertLoadingPrincipalAndClientInfoMatch(
      aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);

  Maybe<ClientInfo> loadingClientInfo;
  loadingClientInfo.emplace(aLoadingClientInfo);

  return NS_NewChannelInternal(outChannel, aUri,
                               nullptr,  // aLoadingNode,
                               aLoadingPrincipal,
                               nullptr,  // aTriggeringPrincipal
                               loadingClientInfo, aController, aSecurityFlags,
                               aContentPolicyType, aCookieJarSettings,
                               aPerformanceStorage, aLoadGroup, aCallbacks,
                               aLoadFlags, aIoService, aSandboxFlags);
}

nsresult NS_NewChannelInternal(
    nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode,
    nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
    const Maybe<ClientInfo>& aLoadingClientInfo,
    const Maybe<ServiceWorkerDescriptor>& aController,
    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
    nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
    PerformanceStorage* aPerformanceStorage /* = nullptr */,
    nsILoadGroup* aLoadGroup /* = nullptr */,
    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    nsIIOService* aIoService /* = nullptr */,
    uint32_t aSandboxFlags /* = 0 */) {
  NS_ENSURE_ARG_POINTER(outChannel);

  nsCOMPtr<nsIIOService> grip;
  nsresult rv = net_EnsureIOService(&aIoService, grip);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIChannel> channel;
  rv = aIoService->NewChannelFromURIWithClientAndController(
      aUri, aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal,
      aLoadingClientInfo, aController, aSecurityFlags, aContentPolicyType,
      aSandboxFlags, getter_AddRefs(channel));
  if (NS_FAILED(rv)) {
    return rv;
  }

  if (aLoadGroup) {
    rv = channel->SetLoadGroup(aLoadGroup);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  if (aCallbacks) {
    rv = channel->SetNotificationCallbacks(aCallbacks);
    NS_ENSURE_SUCCESS(rv, rv);
  }

#ifdef DEBUG
  nsLoadFlags channelLoadFlags = 0;
  channel->GetLoadFlags(&channelLoadFlags);
  // Will be removed when we remove LOAD_REPLACE altogether
  // This check is trying to catch protocol handlers that still
  // try to set the LOAD_REPLACE flag.
  MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
#endif

  if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
    rv = channel->SetLoadFlags(aLoadFlags);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  if (aPerformanceStorage || aCookieJarSettings) {
    nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();

    if (aPerformanceStorage) {
      loadInfo->SetPerformanceStorage(aPerformanceStorage);
    }

    if (aCookieJarSettings) {
      loadInfo->SetCookieJarSettings(aCookieJarSettings);
    }
  }

  channel.forget(outChannel);
  return NS_OK;
}

nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */
NS_NewChannelWithTriggeringPrincipal(
    nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode,
    nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
    nsContentPolicyType aContentPolicyType,
    PerformanceStorage* aPerformanceStorage /* = nullptr */,
    nsILoadGroup* aLoadGroup /* = nullptr */,
    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    nsIIOService* aIoService /* = nullptr */) {
  MOZ_ASSERT(aLoadingNode);
  NS_ASSERTION(aTriggeringPrincipal,
               "Can not create channel without a triggering Principal!");
  return NS_NewChannelInternal(
      outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
      aTriggeringPrincipal, Maybe<ClientInfo>(),
      Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
      aLoadingNode->OwnerDoc()->CookieJarSettings(), aPerformanceStorage,
      aLoadGroup, aCallbacks, aLoadFlags, aIoService);
}

// See NS_NewChannelInternal for usage and argument description
nsresult NS_NewChannelWithTriggeringPrincipal(
    nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal,
    nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
    nsContentPolicyType aContentPolicyType,
    nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
    PerformanceStorage* aPerformanceStorage /* = nullptr */,
    nsILoadGroup* aLoadGroup /* = nullptr */,
    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    nsIIOService* aIoService /* = nullptr */) {
  NS_ASSERTION(aLoadingPrincipal,
               "Can not create channel without a loading Principal!");
  return NS_NewChannelInternal(
      outChannel, aUri,
      nullptr,  // aLoadingNode
      aLoadingPrincipal, aTriggeringPrincipal, Maybe<ClientInfo>(),
      Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
      aCookieJarSettings, aPerformanceStorage, aLoadGroup, aCallbacks,
      aLoadFlags, aIoService);
}

// See NS_NewChannelInternal for usage and argument description
nsresult NS_NewChannelWithTriggeringPrincipal(
    nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal,
    nsIPrincipal* aTriggeringPrincipal, const ClientInfo& aLoadingClientInfo,
    const Maybe<ServiceWorkerDescriptor>& aController,
    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
    nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
    PerformanceStorage* aPerformanceStorage /* = nullptr */,
    nsILoadGroup* aLoadGroup /* = nullptr */,
    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    nsIIOService* aIoService /* = nullptr */) {
  AssertLoadingPrincipalAndClientInfoMatch(
      aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);

  Maybe<ClientInfo> loadingClientInfo;
  loadingClientInfo.emplace(aLoadingClientInfo);

  return NS_NewChannelInternal(
      outChannel, aUri,
      nullptr,  // aLoadingNode
      aLoadingPrincipal, aTriggeringPrincipal, loadingClientInfo, aController,
      aSecurityFlags, aContentPolicyType, aCookieJarSettings,
      aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService);
}

nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
                       nsINode* aLoadingNode, nsSecurityFlags aSecurityFlags,
                       nsContentPolicyType aContentPolicyType,
                       PerformanceStorage* aPerformanceStorage /* = nullptr */,
                       nsILoadGroup* aLoadGroup /* = nullptr */,
                       nsIInterfaceRequestor* aCallbacks /* = nullptr */,
                       nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
                       nsIIOService* aIoService /* = nullptr */,
                       uint32_t aSandboxFlags /* = 0 */) {
  NS_ASSERTION(aLoadingNode, "Can not create channel without a loading Node!");
  return NS_NewChannelInternal(
      outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
      nullptr,  // aTriggeringPrincipal
      Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
      aContentPolicyType, aLoadingNode->OwnerDoc()->CookieJarSettings(),
      aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService,
      aSandboxFlags);
}

nsresult NS_GetIsDocumentChannel(nsIChannel* aChannel, bool* aIsDocument) {
  // Check if this channel is going to be used to create a document. If it has
  // LOAD_DOCUMENT_URI set it is trivially creating a document. If
  // LOAD_HTML_OBJECT_DATA is set it may or may not be used to create a
  // document, depending on its MIME type.

  if (!aChannel || !aIsDocument) {
    return NS_ERROR_NULL_POINTER;
  }
  *aIsDocument = false;
  nsLoadFlags loadFlags;
  nsresult rv = aChannel->GetLoadFlags(&loadFlags);
  if (NS_FAILED(rv)) {
    return rv;
  }
  if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
    *aIsDocument = true;
    return NS_OK;
  }
  if (!(loadFlags & nsIRequest::LOAD_HTML_OBJECT_DATA)) {
    *aIsDocument = false;
    return NS_OK;
  }
  nsAutoCString mimeType;
  rv = aChannel->GetContentType(mimeType);
  if (NS_FAILED(rv)) {
    return rv;
  }
  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
  if (nsContentUtils::HtmlObjectContentTypeForMIMEType(
          mimeType, loadInfo->GetSandboxFlags()) ==
      nsIObjectLoadingContent::TYPE_DOCUMENT) {
    *aIsDocument = true;
    return NS_OK;
  }
  *aIsDocument = false;
  return NS_OK;
}

nsresult NS_MakeAbsoluteURI(nsACString& result, const nsACString& spec,
                            nsIURI* baseURI) {
  nsresult rv;
  if (!baseURI) {
    NS_WARNING("It doesn't make sense to not supply a base URI");
    result = spec;
    rv = NS_OK;
  } else if (spec.IsEmpty()) {
    rv = baseURI->GetSpec(result);
  } else {
    rv = baseURI->Resolve(spec, result);
  }
  return rv;
}

nsresult NS_MakeAbsoluteURI(char** result, const char* spec, nsIURI* baseURI) {
  nsresult rv;
  nsAutoCString resultBuf;
  rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI);
  if (NS_SUCCEEDED(rv)) {
    *result = ToNewCString(resultBuf, mozilla::fallible);
    if (!*result) rv = NS_ERROR_OUT_OF_MEMORY;
  }
  return rv;
}

nsresult NS_MakeAbsoluteURI(nsAString& result, const nsAString& spec,
                            nsIURI* baseURI) {
  nsresult rv;
  if (!baseURI) {
    NS_WARNING("It doesn't make sense to not supply a base URI");
    result = spec;
    rv = NS_OK;
  } else {
    nsAutoCString resultBuf;
    if (spec.IsEmpty()) {
      rv = baseURI->GetSpec(resultBuf);
    } else {
      rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf);
    }
    if (NS_SUCCEEDED(rv)) CopyUTF8toUTF16(resultBuf, result);
  }
  return rv;
}

int32_t NS_GetDefaultPort(const char* scheme,
                          nsIIOService* ioService /* = nullptr */) {
  nsresult rv;

  // Getting the default port through the protocol handler previously had a lot
  // of XPCOM overhead involved.  We optimize the protocols that matter for Web
  // pages (HTTP and HTTPS) by hardcoding their default ports here.
  //
  // XXX: This might not be necessary for performance anymore.
  if (strncmp(scheme, "http", 4) == 0) {
    if (scheme[4] == 's' && scheme[5] == '\0') {
      return 443;
    }
    if (scheme[4] == '\0') {
      return 80;
    }
  }

  nsCOMPtr<nsIIOService> grip;
  net_EnsureIOService(&ioService, grip);
  if (!ioService) return -1;

  int32_t port;
  rv = ioService->GetDefaultPort(scheme, &port);
  return NS_SUCCEEDED(rv) ? port : -1;
}

int32_t NS_GetRealPort(nsIURI* aURI) {
  int32_t port;
  nsresult rv = aURI->GetPort(&port);
  if (NS_FAILED(rv)) return -1;

  if (port != -1) return port;  // explicitly specified

  // Otherwise, we have to get the default port from the protocol handler

  // Need the scheme first
  nsAutoCString scheme;
  rv = aURI->GetScheme(scheme);
  if (NS_FAILED(rv)) return -1;

  return NS_GetDefaultPort(scheme.get());
}

nsresult NS_NewInputStreamChannelInternal(
    nsIChannel** outChannel, nsIURI* aUri,
    already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType,
    const nsACString& aContentCharset, nsILoadInfo* aLoadInfo) {
  nsresult rv;
  nsCOMPtr<nsIInputStreamChannel> isc =
      do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);
  rv = isc->SetURI(aUri);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIInputStream> stream = std::move(aStream);
  rv = isc->SetContentStream(stream);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIChannel> channel = do_QueryInterface(isc, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  if (!aContentType.IsEmpty()) {
    rv = channel->SetContentType(aContentType);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  if (!aContentCharset.IsEmpty()) {
    rv = channel->SetContentCharset(aContentCharset);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  MOZ_ASSERT(aLoadInfo, "need a loadinfo to create a inputstreamchannel");
  channel->SetLoadInfo(aLoadInfo);

  // If we're sandboxed, make sure to clear any owner the channel
  // might already have.
  if (aLoadInfo && aLoadInfo->GetLoadingSandboxed()) {
    channel->SetOwner(nullptr);
  }

  channel.forget(outChannel);
  return NS_OK;
}

nsresult NS_NewInputStreamChannelInternal(
    nsIChannel** outChannel, nsIURI* aUri,
    already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType,
    const nsACString& aContentCharset, nsINode* aLoadingNode,
    nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType) {
  nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::net::LoadInfo(
      aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
      aContentPolicyType);
  if (!loadInfo) {
    return NS_ERROR_UNEXPECTED;
  }

  nsCOMPtr<nsIInputStream> stream = std::move(aStream);

  return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
                                          aContentType, aContentCharset,
                                          loadInfo);
}

nsresult NS_NewInputStreamChannel(
    nsIChannel** outChannel, nsIURI* aUri,
    already_AddRefed<nsIInputStream> aStream, nsIPrincipal* aLoadingPrincipal,
    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
    const nsACString& aContentType /* = ""_ns */,
    const nsACString& aContentCharset /* = ""_ns */) {
  nsCOMPtr<nsIInputStream> stream = aStream;
  return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
                                          aContentType, aContentCharset,
                                          nullptr,  // aLoadingNode
                                          aLoadingPrincipal,
                                          nullptr,  // aTriggeringPrincipal
                                          aSecurityFlags, aContentPolicyType);
}

nsresult NS_NewInputStreamChannelInternal(nsIChannel** outChannel, nsIURI* aUri,
                                          const nsAString& aData,
                                          const nsACString& aContentType,
                                          nsILoadInfo* aLoadInfo,
                                          bool aIsSrcdocChannel /* = false */) {
  nsresult rv;
  nsCOMPtr<nsIStringInputStream> stream;
  stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  uint32_t len;
  char* utf8Bytes = ToNewUTF8String(aData, &len);
  rv = stream->AdoptData(utf8Bytes, len);

  nsCOMPtr<nsIChannel> channel;
  rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aUri,
                                        stream.forget(), aContentType,
                                        "UTF-8"_ns, aLoadInfo);

  NS_ENSURE_SUCCESS(rv, rv);

  if (aIsSrcdocChannel) {
    nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(channel);
    NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE);
    inStrmChan->SetSrcdocData(aData);
  }
  channel.forget(outChannel);
  return NS_OK;
}

nsresult NS_NewInputStreamChannelInternal(
    nsIChannel** outChannel, nsIURI* aUri, const nsAString& aData,
    const nsACString& aContentType, nsINode* aLoadingNode,
    nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
    bool aIsSrcdocChannel /* = false */) {
  nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::net::LoadInfo(
      aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
      aContentPolicyType);
  return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
                                          loadInfo, aIsSrcdocChannel);
}

nsresult NS_NewInputStreamChannel(nsIChannel** outChannel, nsIURI* aUri,
                                  const nsAString& aData,
                                  const nsACString& aContentType,
                                  nsIPrincipal* aLoadingPrincipal,
                                  nsSecurityFlags aSecurityFlags,
                                  nsContentPolicyType aContentPolicyType,
                                  bool aIsSrcdocChannel /* = false */) {
  return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
                                          nullptr,  // aLoadingNode
                                          aLoadingPrincipal,
                                          nullptr,  // aTriggeringPrincipal
                                          aSecurityFlags, aContentPolicyType,
                                          aIsSrcdocChannel);
}

nsresult NS_NewInputStreamPump(
    nsIInputStreamPump** aResult, already_AddRefed<nsIInputStream> aStream,
    uint32_t aSegsize /* = 0 */, uint32_t aSegcount /* = 0 */,
    bool aCloseWhenDone /* = false */,
    nsISerialEventTarget* aMainThreadTarget /* = nullptr */) {
  nsCOMPtr<nsIInputStream> stream = std::move(aStream);

  nsresult rv;
  nsCOMPtr<nsIInputStreamPump> pump =
      do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = pump->Init(stream, aSegsize, aSegcount, aCloseWhenDone,
                    aMainThreadTarget);
    if (NS_SUCCEEDED(rv)) {
      *aResult = nullptr;
      pump.swap(*aResult);
    }
  }
  return rv;
}

nsresult NS_NewLoadGroup(nsILoadGroup** result, nsIRequestObserver* obs) {
  nsresult rv;
  nsCOMPtr<nsILoadGroup> group =
      do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = group->SetGroupObserver(obs);
    if (NS_SUCCEEDED(rv)) {
      *result = nullptr;
      group.swap(*result);
    }
  }
  return rv;
}

bool NS_IsReasonableHTTPHeaderValue(const nsACString& aValue) {
  return mozilla::net::nsHttp::IsReasonableHeaderValue(aValue);
}

bool NS_IsValidHTTPToken(const nsACString& aToken) {
  return mozilla::net::nsHttp::IsValidToken(aToken);
}

void NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest) {
  mozilla::net::nsHttp::TrimHTTPWhitespace(aSource, aDest);
}

nsresult NS_NewLoadGroup(nsILoadGroup** aResult, nsIPrincipal* aPrincipal) {
  using mozilla::LoadContext;
  nsresult rv;

  nsCOMPtr<nsILoadGroup> group =
      do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  RefPtr<LoadContext> loadContext = new LoadContext(aPrincipal);
  rv = group->SetNotificationCallbacks(loadContext);
  NS_ENSURE_SUCCESS(rv, rv);

  group.forget(aResult);
  return rv;
}

bool NS_LoadGroupMatchesPrincipal(nsILoadGroup* aLoadGroup,
                                  nsIPrincipal* aPrincipal) {
  if (!aPrincipal) {
    return false;
  }

  // If this is a null principal then the load group doesn't really matter.
  // The principal will not be allowed to perform any actions that actually
  // use the load group.  Unconditionally treat null principals as a match.
  if (aPrincipal->GetIsNullPrincipal()) {
    return true;
  }

  if (!aLoadGroup) {
    return false;
  }

  nsCOMPtr<nsILoadContext> loadContext;
  NS_QueryNotificationCallbacks(nullptr, aLoadGroup, NS_GET_IID(nsILoadContext),
                                getter_AddRefs(loadContext));
  NS_ENSURE_TRUE(loadContext, false);

  return true;
}

nsresult NS_NewDownloader(nsIStreamListener** result,
                          nsIDownloadObserver* observer,
                          nsIFile* downloadLocation /* = nullptr */) {
  nsresult rv;
  nsCOMPtr<nsIDownloader> downloader =
      do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = downloader->Init(observer, downloadLocation);
    if (NS_SUCCEEDED(rv)) {
      downloader.forget(result);
    }
  }
  return rv;
}

nsresult NS_NewIncrementalStreamLoader(
    nsIIncrementalStreamLoader** result,
    nsIIncrementalStreamLoaderObserver* observer) {
  nsresult rv;
  nsCOMPtr<nsIIncrementalStreamLoader> loader =
      do_CreateInstance(NS_INCREMENTALSTREAMLOADER_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = loader->Init(observer);
    if (NS_SUCCEEDED(rv)) {
      *result = nullptr;
      loader.swap(*result);
    }
  }
  return rv;
}

nsresult NS_NewStreamLoader(
    nsIStreamLoader** result, nsIStreamLoaderObserver* observer,
    nsIRequestObserver* requestObserver /* = nullptr */) {
  nsresult rv;
  nsCOMPtr<nsIStreamLoader> loader =
      do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = loader->Init(observer, requestObserver);
    if (NS_SUCCEEDED(rv)) {
      *result = nullptr;
      loader.swap(*result);
    }
  }
  return rv;
}

nsresult NS_NewStreamLoaderInternal(
    nsIStreamLoader** outStream, nsIURI* aUri,
    nsIStreamLoaderObserver* aObserver, nsINode* aLoadingNode,
    nsIPrincipal* aLoadingPrincipal, nsSecurityFlags aSecurityFlags,
    nsContentPolicyType aContentPolicyType,
    nsILoadGroup* aLoadGroup /* = nullptr */,
    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
  nsCOMPtr<nsIChannel> channel;
  nsresult rv = NS_NewChannelInternal(
      getter_AddRefs(channel), aUri, aLoadingNode, aLoadingPrincipal,
      nullptr,  // aTriggeringPrincipal
      Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
      aContentPolicyType,
      nullptr,  // nsICookieJarSettings
      nullptr,  // PerformanceStorage
      aLoadGroup, aCallbacks, aLoadFlags);

  NS_ENSURE_SUCCESS(rv, rv);
  rv = NS_NewStreamLoader(outStream, aObserver);
  NS_ENSURE_SUCCESS(rv, rv);
  return channel->AsyncOpen(*outStream);
}

nsresult NS_NewStreamLoader(
    nsIStreamLoader** outStream, nsIURI* aUri,
    nsIStreamLoaderObserver* aObserver, nsINode* aLoadingNode,
    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
    nsILoadGroup* aLoadGroup /* = nullptr */,
    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
  NS_ASSERTION(aLoadingNode,
               "Can not create stream loader without a loading Node!");
  return NS_NewStreamLoaderInternal(
      outStream, aUri, aObserver, aLoadingNode, aLoadingNode->NodePrincipal(),
      aSecurityFlags, aContentPolicyType, aLoadGroup, aCallbacks, aLoadFlags);
}

nsresult NS_NewStreamLoader(
    nsIStreamLoader** outStream, nsIURI* aUri,
    nsIStreamLoaderObserver* aObserver, nsIPrincipal* aLoadingPrincipal,
    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
    nsILoadGroup* aLoadGroup /* = nullptr */,
    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
  return NS_NewStreamLoaderInternal(outStream, aUri, aObserver,
                                    nullptr,  // aLoadingNode
                                    aLoadingPrincipal, aSecurityFlags,
                                    aContentPolicyType, aLoadGroup, aCallbacks,
                                    aLoadFlags);
}

nsresult NS_NewSyncStreamListener(nsIStreamListener** result,
                                  nsIInputStream** stream) {
  nsCOMPtr<nsISyncStreamListener> listener = new nsSyncStreamListener();
  nsresult rv = listener->GetInputStream(stream);
  if (NS_SUCCEEDED(rv)) {
    listener.forget(result);
  }
  return rv;
}

nsresult NS_ImplementChannelOpen(nsIChannel* channel, nsIInputStream** result) {
  nsCOMPtr<nsIStreamListener> listener;
  nsCOMPtr<nsIInputStream> stream;
  nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener),
                                         getter_AddRefs(stream));
  NS_ENSURE_SUCCESS(rv, rv);

  rv = channel->AsyncOpen(listener);
  NS_ENSURE_SUCCESS(rv, rv);

  uint64_t n;
  // block until the initial response is received or an error occurs.
  rv = stream->Available(&n);
  NS_ENSURE_SUCCESS(rv, rv);

  *result = nullptr;
  stream.swap(*result);

  return NS_OK;
}

nsresult NS_NewRequestObserverProxy(nsIRequestObserver** result,
                                    nsIRequestObserver* observer,
                                    nsISupports* context) {
  nsCOMPtr<nsIRequestObserverProxy> proxy = new nsRequestObserverProxy();
  nsresult rv = proxy->Init(observer, context);
  if (NS_SUCCEEDED(rv)) {
    proxy.forget(result);
  }
  return rv;
}

nsresult NS_NewSimpleStreamListener(
    nsIStreamListener** result, nsIOutputStream* sink,
    nsIRequestObserver* observer /* = nullptr */) {
  nsresult rv;
  nsCOMPtr<nsISimpleStreamListener> listener =
      do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = listener->Init(sink, observer);
    if (NS_SUCCEEDED(rv)) {
      listener.forget(result);
    }
  }
  return rv;
}

nsresult NS_CheckPortSafety(int32_t port, const char* scheme,
                            nsIIOService* ioService /* = nullptr */) {
  nsresult rv;
  nsCOMPtr<nsIIOService> grip;
  rv = net_EnsureIOService(&ioService, grip);
  if (ioService) {
    bool allow;
    rv = ioService->AllowPort(port, scheme, &allow);
    if (NS_SUCCEEDED(rv) && !allow) {
      NS_WARNING("port blocked");
      rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED;
    }
  }
  return rv;
}

nsresult NS_CheckPortSafety(nsIURI* uri) {
  int32_t port;
  nsresult rv = uri->GetPort(&port);
  if (NS_FAILED(rv) || port == -1) {  // port undefined or default-valued
    return NS_OK;
  }
  nsAutoCString scheme;
  uri->GetScheme(scheme);
  return NS_CheckPortSafety(port, scheme.get());
}

nsresult NS_NewProxyInfo(const nsACString& type, const nsACString& host,
                         int32_t port, uint32_t flags, nsIProxyInfo** result) {
  nsresult rv;
  nsCOMPtr<nsIProtocolProxyService> pps;
  pps = mozilla::components::ProtocolProxy::Service(&rv);
  if (NS_SUCCEEDED(rv)) {
    rv = pps->NewProxyInfo(type, host, port, ""_ns, ""_ns, flags, UINT32_MAX,
                           nullptr, result);
  }
  return rv;
}

nsresult NS_GetFileProtocolHandler(nsIFileProtocolHandler** result,
                                   nsIIOService* ioService /* = nullptr */) {
  nsresult rv;
  nsCOMPtr<nsIIOService> grip;
  rv = net_EnsureIOService(&ioService, grip);
  if (ioService) {
    nsCOMPtr<nsIProtocolHandler> handler;
    rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler));
    if (NS_SUCCEEDED(rv)) rv = CallQueryInterface(handler, result);
  }
  return rv;
}

nsresult NS_GetFileFromURLSpec(const nsACString& inURL, nsIFile** result,
                               nsIIOService* ioService /* = nullptr */) {
  nsresult rv;
  nsCOMPtr<nsIFileProtocolHandler> fileHandler;
  rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
  if (NS_SUCCEEDED(rv)) rv = fileHandler->GetFileFromURLSpec(inURL, result);
  return rv;
}

nsresult NS_GetURLSpecFromFile(nsIFile* file, nsACString& url,
                               nsIIOService* ioService /* = nullptr */) {
  nsresult rv;
  nsCOMPtr<nsIFileProtocolHandler> fileHandler;
  rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
  if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromFile(file, url);
  return rv;
}

nsresult NS_GetURLSpecFromActualFile(nsIFile* file, nsACString& url,
                                     nsIIOService* ioService /* = nullptr */) {
  nsresult rv;
  nsCOMPtr<nsIFileProtocolHandler> fileHandler;
  rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
  if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromActualFile(file, url);
  return rv;
}

nsresult NS_GetURLSpecFromDir(nsIFile* file, nsACString& url,
                              nsIIOService* ioService /* = nullptr */) {
  nsresult rv;
  nsCOMPtr<nsIFileProtocolHandler> fileHandler;
  rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
  if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromDir(file, url);
  return rv;
}

void NS_GetReferrerFromChannel(nsIChannel* channel, nsIURI** referrer) {
  *referrer = nullptr;

  if (nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(channel)) {
    // We have to check for a property on a property bag because the
    // referrer may be empty for security reasons (for example, when loading
    // an http page with an https referrer).
    nsresult rv;
    nsCOMPtr<nsIURI> uri(
        do_GetProperty(props, u"docshell.internalReferrer"_ns, &rv));
    if (NS_SUCCEEDED(rv)) {
      uri.forget(referrer);
      return;
    }
  }

  // if that didn't work, we can still try to get the referrer from the
  // nsIHttpChannel (if we can QI to it)
  nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel));
  if (!chan) {
    return;
  }

  nsCOMPtr<nsIReferrerInfo> referrerInfo = chan->GetReferrerInfo();
  if (!referrerInfo) {
    return;
  }

  referrerInfo->GetOriginalReferrer(referrer);
}

already_AddRefed<nsINetUtil> do_GetNetUtil(nsresult* error /* = 0 */) {
  nsCOMPtr<nsIIOService> io;
  nsCOMPtr<nsINetUtil> util;

  io = mozilla::components::IO::Service();
  if (io) util = do_QueryInterface(io);

  if (error) *error = !!util ? NS_OK : NS_ERROR_FAILURE;
  return util.forget();
}

nsresult NS_ParseRequestContentType(const nsACString& rawContentType,
                                    nsCString& contentType,
                                    nsCString& contentCharset) {
  // contentCharset is left untouched if not present in rawContentType
  nsresult rv;
  nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
  NS_ENSURE_SUCCESS(rv, rv);
  nsCString charset;
  bool hadCharset;
  rv = util->ParseRequestContentType(rawContentType, charset, &hadCharset,
                                     contentType);
  if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset;
  return rv;
}

nsresult NS_ParseResponseContentType(const nsACString& rawContentType,
                                     nsCString& contentType,
                                     nsCString& contentCharset) {
  // contentCharset is left untouched if not present in rawContentType
  nsresult rv;
  nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
  NS_ENSURE_SUCCESS(rv, rv);
  nsCString charset;
  bool hadCharset;
  rv = util->ParseResponseContentType(rawContentType, charset, &hadCharset,
                                      contentType);
  if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset;
  return rv;
}

nsresult NS_ExtractCharsetFromContentType(const nsACString& rawContentType,
                                          nsCString& contentCharset,
                                          bool* hadCharset,
                                          int32_t* charsetStart,
                                          int32_t* charsetEnd) {
  // contentCharset is left untouched if not present in rawContentType
  nsresult rv;
  nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
  NS_ENSURE_SUCCESS(rv, rv);

  return util->ExtractCharsetFromContentType(
      rawContentType, contentCharset, charsetStart, charsetEnd, hadCharset);
}

nsresult NS_NewAtomicFileOutputStream(nsIOutputStream** result, nsIFile* file,
                                      int32_t ioFlags /* = -1 */,
                                      int32_t perm /* = -1 */,
                                      int32_t behaviorFlags /* = 0 */) {
  nsresult rv;
  nsCOMPtr<nsIFileOutputStream> out =
      do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = out->Init(file, ioFlags, perm, behaviorFlags);
    if (NS_SUCCEEDED(rv)) out.forget(result);
  }
  return rv;
}

nsresult NS_NewSafeLocalFileOutputStream(nsIOutputStream** result,
                                         nsIFile* file,
                                         int32_t ioFlags /* = -1 */,
                                         int32_t perm /* = -1 */,
                                         int32_t behaviorFlags /* = 0 */) {
  nsresult rv;
  nsCOMPtr<nsIFileOutputStream> out =
      do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = out->Init(file, ioFlags, perm, behaviorFlags);
    if (NS_SUCCEEDED(rv)) out.forget(result);
  }
  return rv;
}

nsresult NS_NewLocalFileRandomAccessStream(nsIRandomAccessStream** result,
                                           nsIFile* file,
                                           int32_t ioFlags /* = -1 */,
                                           int32_t perm /* = -1 */,
                                           int32_t behaviorFlags /* = 0 */) {
  nsCOMPtr<nsIFileRandomAccessStream> stream = new nsFileRandomAccessStream();
  nsresult rv = stream->Init(file, ioFlags, perm, behaviorFlags);
  if (NS_SUCCEEDED(rv)) {
    stream.forget(result);
  }
  return rv;
}

mozilla::Result<nsCOMPtr<nsIRandomAccessStream>, nsresult>
NS_NewLocalFileRandomAccessStream(nsIFile* file, int32_t ioFlags /* = -1 */,
                                  int32_t perm /* = -1 */,
                                  int32_t behaviorFlags /* = 0 */) {
  nsCOMPtr<nsIRandomAccessStream> stream;
  const nsresult rv = NS_NewLocalFileRandomAccessStream(
      getter_AddRefs(stream), file, ioFlags, perm, behaviorFlags);
  if (NS_SUCCEEDED(rv)) {
    return stream;
  }
  return Err(rv);
}

nsresult NS_NewBufferedOutputStream(
    nsIOutputStream** aResult, already_AddRefed<nsIOutputStream> aOutputStream,
    uint32_t aBufferSize) {
  nsCOMPtr<nsIOutputStream> outputStream = std::move(aOutputStream);

  nsresult rv;
  nsCOMPtr<nsIBufferedOutputStream> out =
      do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = out->Init(outputStream, aBufferSize);
    if (NS_SUCCEEDED(rv)) {
      out.forget(aResult);
    }
  }
  return rv;
}

[[nodiscard]] nsresult NS_NewBufferedInputStream(
    nsIInputStream** aResult, already_AddRefed<nsIInputStream> aInputStream,
    uint32_t aBufferSize) {
  nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);

  nsCOMPtr<nsIBufferedInputStream> in;
  nsresult rv = nsBufferedInputStream::Create(
      NS_GET_IID(nsIBufferedInputStream), getter_AddRefs(in));
  if (NS_SUCCEEDED(rv)) {
    rv = in->Init(inputStream, aBufferSize);
    if (NS_SUCCEEDED(rv)) {
      *aResult = static_cast<nsBufferedInputStream*>(in.get())
                     ->GetInputStream()
                     .take();
    }
  }
  return rv;
}

Result<nsCOMPtr<nsIInputStream>, nsresult> NS_NewBufferedInputStream(
    already_AddRefed<nsIInputStream> aInputStream, uint32_t aBufferSize) {
  nsCOMPtr<nsIInputStream> stream;
  const nsresult rv = NS_NewBufferedInputStream(
      getter_AddRefs(stream), std::move(aInputStream), aBufferSize);
  if (NS_SUCCEEDED(rv)) {
    return stream;
  }
  return Err(rv);
}

namespace {

#define BUFFER_SIZE 8192

class BufferWriter final : public nsIInputStreamCallback {
 public:
  NS_DECL_THREADSAFE_ISUPPORTS

  BufferWriter(nsIInputStream* aInputStream, void* aBuffer, int64_t aCount)
      : mMonitor("BufferWriter.mMonitor"),
        mInputStream(aInputStream),
        mBuffer(aBuffer),
        mCount(aCount),
        mWrittenData(0),
        mBufferType(aBuffer ? eExternal : eInternal),
        mBufferSize(0) {
    MOZ_ASSERT(aInputStream);
    MOZ_ASSERT(aCount == -1 || aCount > 0);
    MOZ_ASSERT_IF(mBuffer, aCount > 0);
  }

  nsresult Write() {
    NS_ASSERT_OWNINGTHREAD(BufferWriter);

    // Let's make the inputStream buffered if it's not.
    if (!NS_InputStreamIsBuffered(mInputStream)) {
      nsCOMPtr<nsIInputStream> bufferedStream;
      nsresult rv = NS_NewBufferedInputStream(
          getter_AddRefs(bufferedStream), mInputStream.forget(), BUFFER_SIZE);
      NS_ENSURE_SUCCESS(rv, rv);

      mInputStream = bufferedStream;
    }

    mAsyncInputStream = do_QueryInterface(mInputStream);

    if (!mAsyncInputStream) {
      return WriteSync();
    }

    // Let's use mAsyncInputStream only.
    mInputStream = nullptr;

    return WriteAsync();
  }

  uint64_t WrittenData() const {
    NS_ASSERT_OWNINGTHREAD(BufferWriter);
    return mWrittenData;
  }

  void* StealBuffer() {
    NS_ASSERT_OWNINGTHREAD(BufferWriter);
    MOZ_ASSERT(mBufferType == eInternal);

    void* buffer = mBuffer;

    mBuffer = nullptr;
    mBufferSize = 0;

    return buffer;
  }

 private:
  ~BufferWriter() {
    if (mBuffer && mBufferType == eInternal) {
      free(mBuffer);
    }

    if (mTaskQueue) {
      mTaskQueue->BeginShutdown();
    }
  }

  nsresult WriteSync() {
    NS_ASSERT_OWNINGTHREAD(BufferWriter);

    uint64_t length = (uint64_t)mCount;

    if (mCount == -1) {
      nsresult rv = mInputStream->Available(&length);
      NS_ENSURE_SUCCESS(rv, rv);

      if (length == 0) {
        // nothing to read.
        return NS_OK;
      }
    }

    if (mBufferType == eInternal) {
      mBuffer = malloc(length);
      if (NS_WARN_IF(!mBuffer)) {
        return NS_ERROR_OUT_OF_MEMORY;
      }
    }

    uint32_t writtenData;
    nsresult rv = mInputStream->ReadSegments(NS_CopySegmentToBuffer, mBuffer,
                                             length, &writtenData);
    NS_ENSURE_SUCCESS(rv, rv);

    mWrittenData = writtenData;
    return NS_OK;
  }

  nsresult WriteAsync() {
    NS_ASSERT_OWNINGTHREAD(BufferWriter);

    if (mCount > 0 && mBufferType == eInternal) {
      mBuffer = malloc(mCount);
      if (NS_WARN_IF(!mBuffer)) {
        return NS_ERROR_OUT_OF_MEMORY;
      }
    }

    while (true) {
      if (mCount == -1 && !MaybeExpandBufferSize()) {
        return NS_ERROR_OUT_OF_MEMORY;
      }

      uint64_t offset = mWrittenData;
      uint64_t length = mCount == -1 ? BUFFER_SIZE : mCount;

      // Let's try to read data directly.
      uint32_t writtenData;
      nsresult rv = mAsyncInputStream->ReadSegments(
          NS_CopySegmentToBuffer, static_cast<char*>(mBuffer) + offset, length,
          &writtenData);

      // Operation completed. Nothing more to read.
      if (NS_SUCCEEDED(rv) && writtenData == 0) {
        return NS_OK;
      }

      // If we succeeded, let's try to read again.
      if (NS_SUCCEEDED(rv)) {
        mWrittenData += writtenData;
        if (mCount != -1) {
          MOZ_ASSERT(mCount >= writtenData);
          mCount -= writtenData;

          // Is this the end of the reading?
          if (mCount == 0) {
            return NS_OK;
          }
        }

        continue;
      }

      // Async wait...
      if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
        rv = MaybeCreateTaskQueue();
        if (NS_WARN_IF(NS_FAILED(rv))) {
          return rv;
        }

        MonitorAutoLock lock(mMonitor);

        rv = mAsyncInputStream->AsyncWait(this, 0, length, mTaskQueue);
        if (NS_WARN_IF(NS_FAILED(rv))) {
          return rv;
        }

        lock.Wait();
        continue;
      }

      // Otherwise, let's propagate the error.
      return rv;
    }

    MOZ_ASSERT_UNREACHABLE("We should not be here");
    return NS_ERROR_FAILURE;
  }

  nsresult MaybeCreateTaskQueue() {
    NS_ASSERT_OWNINGTHREAD(BufferWriter);

    if (!mTaskQueue) {
      nsCOMPtr<nsIEventTarget> target;
      target = mozilla::components::StreamTransport::Service();
      if (!target) {
        return NS_ERROR_FAILURE;
      }

      mTaskQueue = TaskQueue::Create(target.forget(), "nsNetUtil:BufferWriter");
    }

    return NS_OK;
  }

  NS_IMETHOD
  OnInputStreamReady(nsIAsyncInputStream* aStream) override {
    MOZ_ASSERT(!NS_IsMainThread());

    // We have something to read. Let's unlock the main-thread.
    MonitorAutoLock lock(mMonitor);
    lock.Notify();
    return NS_OK;
  }

  bool MaybeExpandBufferSize() {
    NS_ASSERT_OWNINGTHREAD(BufferWriter);

    MOZ_ASSERT(mCount == -1);

    if (mBufferSize >= mWrittenData + BUFFER_SIZE) {
      // The buffer is big enough.
      return true;
    }

    CheckedUint32 bufferSize =
        std::max<uint32_t>(static_cast<uint32_t>(mWrittenData), BUFFER_SIZE);
    while (bufferSize.isValid() &&
           bufferSize.value() < mWrittenData + BUFFER_SIZE) {
      bufferSize *= 2;
    }

    if (!bufferSize.isValid()) {
      return false;
    }

    void* buffer = realloc(mBuffer, bufferSize.value());
    if (!buffer) {
      return false;
    }

    mBuffer = buffer;
    mBufferSize = bufferSize.value();
    return true;
  }

  // All the members of this class are touched on the owning thread only. The
  // monitor is only used to communicate when there is more data to read.
  Monitor mMonitor MOZ_UNANNOTATED;

  nsCOMPtr<nsIInputStream> mInputStream;
  nsCOMPtr<nsIAsyncInputStream> mAsyncInputStream;

  RefPtr<TaskQueue> mTaskQueue;

  void* mBuffer;
  int64_t mCount;
  uint64_t mWrittenData;

  enum {
    // The buffer is allocated internally and this object must release it
    // in the DTOR if not stolen. The buffer can be reallocated.
    eInternal,

    // The buffer is not owned by this object and it cannot be reallocated.
    eExternal,
  } mBufferType;

  // The following set if needed for the async read.
  uint64_t mBufferSize;
};

NS_IMPL_ISUPPORTS(BufferWriter, nsIInputStreamCallback)

}  // anonymous namespace

nsresult NS_ReadInputStreamToBuffer(nsIInputStream* aInputStream, void** aDest,
                                    int64_t aCount, uint64_t* aWritten) {
  MOZ_ASSERT(aInputStream);
  MOZ_ASSERT(aCount >= -1);

  uint64_t dummyWritten;
  if (!aWritten) {
    aWritten = &dummyWritten;
  }

  if (aCount == 0) {
    *aWritten = 0;
    return NS_OK;
  }

  // This will take care of allocating and reallocating aDest.
  RefPtr<BufferWriter> writer = new BufferWriter(aInputStream, *aDest, aCount);

  nsresult rv = writer->Write();
  NS_ENSURE_SUCCESS(rv, rv);

  *aWritten = writer->WrittenData();

  if (!*aDest) {
    *aDest = writer->StealBuffer();
  }

  return NS_OK;
}

nsresult NS_ReadInputStreamToString(nsIInputStream* aInputStream,
                                    nsACString& aDest, int64_t aCount,
                                    uint64_t* aWritten) {
  uint64_t dummyWritten;
  if (!aWritten) {
    aWritten = &dummyWritten;
  }

  // Nothing to do if aCount is 0.
  if (aCount == 0) {
    aDest.Truncate();
    *aWritten = 0;
    return NS_OK;
  }

  // If we have the size, we can pre-allocate the buffer.
  if (aCount > 0) {
    if (NS_WARN_IF(aCount >= INT32_MAX) ||
        NS_WARN_IF(!aDest.SetLength(aCount, mozilla::fallible))) {
      return NS_ERROR_OUT_OF_MEMORY;
    }

    void* dest = aDest.BeginWriting();
    nsresult rv =
        NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten);
    NS_ENSURE_SUCCESS(rv, rv);

    if ((uint64_t)aCount > *aWritten) {
      aDest.Truncate(*aWritten);
    }

    return NS_OK;
  }

  // If the size is unknown, BufferWriter will allocate the buffer.
  void* dest = nullptr;
  nsresult rv =
      NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten);
  MOZ_ASSERT_IF(NS_FAILED(rv), dest == nullptr);
  NS_ENSURE_SUCCESS(rv, rv);

  if (!dest) {
    MOZ_ASSERT(*aWritten == 0);
    aDest.Truncate();
    return NS_OK;
  }

  aDest.Adopt(reinterpret_cast<char*>(dest), *aWritten);
  return NS_OK;
}

nsresult NS_NewURI(nsIURI** result, const nsACString& spec,
                   NotNull<const Encoding*> encoding,
                   nsIURI* baseURI /* = nullptr */) {
  nsAutoCString charset;
  encoding->Name(charset);
  return NS_NewURI(result, spec, charset.get(), baseURI);
}

nsresult NS_NewURI(nsIURI** result, const nsAString& aSpec,
                   const char* charset /* = nullptr */,
                   nsIURI* baseURI /* = nullptr */) {
  nsAutoCString spec;
  if (!AppendUTF16toUTF8(aSpec, spec, mozilla::fallible)) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  return NS_NewURI(result, spec, charset, baseURI);
}

nsresult NS_NewURI(nsIURI** result, const nsAString& aSpec,
                   NotNull<const Encoding*> encoding,
                   nsIURI* baseURI /* = nullptr */) {
  nsAutoCString spec;
  if (!AppendUTF16toUTF8(aSpec, spec, mozilla::fallible)) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  return NS_NewURI(result, spec, encoding, baseURI);
}

nsresult NS_NewURI(nsIURI** result, const char* spec,
                   nsIURI* baseURI /* = nullptr */) {
  return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI);
}

static nsresult NewStandardURI(const nsACString& aSpec, const char* aCharset,
                               nsIURI* aBaseURI, int32_t aDefaultPort,
                               nsIURI** aURI) {
  return NS_MutateURI(new nsStandardURL::Mutator())
      .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_AUTHORITY,
             aDefaultPort, aSpec, aCharset, aBaseURI, nullptr)
      .Finalize(aURI);
}

nsresult NS_GetSpecWithNSURLEncoding(nsACString& aResult,
                                     const nsACString& aSpec) {
  nsCOMPtr<nsIURI> uri;
  nsresult rv = NS_NewURIWithNSURLEncoding(getter_AddRefs(uri), aSpec);
  NS_ENSURE_SUCCESS(rv, rv);
  return uri->GetAsciiSpec(aResult);
}

nsresult NS_NewURIWithNSURLEncoding(nsIURI** aResult, const nsACString& aSpec) {
  nsCOMPtr<nsIURI> uri;
  nsresult rv = NS_NewURI(getter_AddRefs(uri), aSpec);
  NS_ENSURE_SUCCESS(rv, rv);

  // Escape the ref portion of the URL. NSURL is more strict about which
  // characters in the URL must be % encoded. For example, an unescaped '#'
  // to indicate the beginning of the ref component is accepted by NSURL, but
  // '#' characters in the ref must be escaped. Also adds encoding for other
  // characters not accepted by NSURL in the ref such as '{', '|', '}', and '^'.
  // The ref returned from GetRef() does not include the leading '#'.
  nsAutoCString ref, escapedRef;
  if (NS_SUCCEEDED(uri->GetRef(ref)) && !ref.IsEmpty()) {
    if (!NS_Escape(ref, escapedRef, url_NSURLRef)) {
      return NS_ERROR_INVALID_ARG;
    }
    rv = NS_MutateURI(uri).SetRef(escapedRef).Finalize(uri);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  uri.forget(aResult);
  return NS_OK;
}

extern MOZ_THREAD_LOCAL(uint32_t) gTlsURLRecursionCount;

template <typename T>
class TlsAutoIncrement {
 public:
  explicit TlsAutoIncrement(T& var) : mVar(var) {
    mValue = mVar.get();
    mVar.set(mValue + 1);
  }
  ~TlsAutoIncrement() {
    typename T::Type value = mVar.get();
    MOZ_ASSERT(value == mValue + 1);
    mVar.set(value - 1);
  }

  typename T::Type value() { return mValue; }

 private:
  typename T::Type mValue;
  T& mVar;
};

nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec,
                   const char* aCharset /* = nullptr */,
                   nsIURI* aBaseURI /* = nullptr */) {
  // we don't expect any other processes than: socket, content or parent
  // to be able to create a URL
  MOZ_ASSERT(XRE_IsSocketProcess() || XRE_IsContentProcess() ||
             XRE_IsParentProcess());
  TlsAutoIncrement<decltype(gTlsURLRecursionCount)> inc(gTlsURLRecursionCount);
  if (inc.value() >= MAX_RECURSION_COUNT) {
    return NS_ERROR_MALFORMED_URI;
  }

  nsCOMPtr<nsIIOService> ioService = do_GetIOService();
  if (!ioService) {
    // Individual protocol handlers unfortunately rely on the ioservice, let's
    // return an error here instead of causing unpredictable crashes later.
    return NS_ERROR_NOT_AVAILABLE;
  }

  if (StaticPrefs::network_url_max_length() &&
      aSpec.Length() > StaticPrefs::network_url_max_length()) {
    return NS_ERROR_MALFORMED_URI;
  }

  nsAutoCString scheme;
  nsresult rv = net_ExtractURLScheme(aSpec, scheme);
  if (NS_FAILED(rv)) {
    // then aSpec is relative
    if (!aBaseURI) {
      return NS_ERROR_MALFORMED_URI;
    }

    if (!aSpec.IsEmpty() && aSpec[0] == '#') {
      // Looks like a reference instead of a fully-specified URI.
      // --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
      return NS_GetURIWithNewRef(aBaseURI, aSpec, aURI);
    }

    rv = aBaseURI->GetScheme(scheme);
    if (NS_FAILED(rv)) return rv;
  }

  // If encoding is not UTF-8 and url is not special or url’s scheme is "ws" or
  // "wss" then set encoding to UTF-8.
  if (aCharset && !scheme.IsEmpty() &&
      (scheme.EqualsLiteral("ws") || scheme.EqualsLiteral("wss") ||
       !SchemeIsSpecial(scheme))) {
    aCharset = "UTF-8";
  }

  if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("ws")) {
    return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT,
                          aURI);
  }
  if (scheme.EqualsLiteral("https") || scheme.EqualsLiteral("wss")) {
    return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT,
                          aURI);
  }
  if (scheme.EqualsLiteral("ftp")) {
    return NewStandardURI(aSpec, aCharset, aBaseURI, 21, aURI);
  }

  if (scheme.EqualsLiteral("file")) {
    return NS_MutateURI(new nsStandardURL::Mutator())
        .Apply(&nsIFileURLMutator::MarkFileURL)
        .Apply(&nsIStandardURLMutator::Init,
               nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, aSpec, aCharset,
               aBaseURI, nullptr)
        .Finalize(aURI);
  }

  if (scheme.EqualsLiteral("data")) {
    return nsDataHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
  }

  if (scheme.EqualsLiteral("moz-safe-about") ||
      scheme.EqualsLiteral("page-icon") || scheme.EqualsLiteral("moz") ||
      scheme.EqualsLiteral("cached-favicon")) {
    return NS_MutateURI(new nsSimpleURI::Mutator())
        .SetSpec(aSpec)
        .Finalize(aURI);
  }

  if (scheme.EqualsLiteral("chrome")) {
    return nsChromeProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
                                                 aURI);
  }

  if (scheme.EqualsLiteral("javascript")) {
    return nsJSProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
  }

  if (scheme.EqualsLiteral("blob")) {
    return BlobURLProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
                                                aURI);
  }

  if (scheme.EqualsLiteral("view-source")) {
    return nsViewSourceHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
  }

  if (scheme.EqualsLiteral("resource")) {
    RefPtr<nsResProtocolHandler> handler = nsResProtocolHandler::GetSingleton();
    if (!handler) {
      return NS_ERROR_NOT_AVAILABLE;
    }
    return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
  }

  if (scheme.EqualsLiteral("indexeddb") || scheme.EqualsLiteral("uuid")) {
    return NS_MutateURI(new nsStandardURL::Mutator())
        .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_AUTHORITY,
               0, aSpec, aCharset, aBaseURI, nullptr)
        .Finalize(aURI);
  }

  if (scheme.EqualsLiteral("moz-extension")) {
    RefPtr<mozilla::net::ExtensionProtocolHandler> handler =
        mozilla::net::ExtensionProtocolHandler::GetSingleton();
    if (!handler) {
      return NS_ERROR_NOT_AVAILABLE;
    }
    return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
  }

--> --------------------

--> maximum size reached

--> --------------------

100%


¤ Dauer der Verarbeitung: 0.26 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.