tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsNetUtil.cpp (146888B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=4 sw=2 sts=2 et cin: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // HttpLog.h should generally be included first
      8 #include "DecoderDoctorDiagnostics.h"
      9 #include "HttpLog.h"
     10 
     11 #include "nsNetUtil.h"
     12 
     13 #include "mozilla/Atomics.h"
     14 #include "mozilla/BasePrincipal.h"
     15 #include "mozilla/Components.h"
     16 #include "mozilla/Encoding.h"
     17 #include "mozilla/LoadContext.h"
     18 #include "mozilla/LoadInfo.h"
     19 #include "mozilla/MathAlgorithms.h"
     20 #include "mozilla/Monitor.h"
     21 #include "mozilla/StaticPrefs_browser.h"
     22 #include "mozilla/StaticPrefs_network.h"
     23 #include "mozilla/StaticPrefs_privacy.h"
     24 #include "mozilla/StaticPrefs_urlclassifier.h"
     25 #include "mozilla/StoragePrincipalHelper.h"
     26 #include "mozilla/TaskQueue.h"
     27 #include "nsAboutProtocolUtils.h"
     28 #include "nsBufferedStreams.h"
     29 #include "nsCategoryCache.h"
     30 #include "nsComponentManagerUtils.h"
     31 #include "nsContentUtils.h"
     32 #include "nsEscape.h"
     33 #include "nsFileStreams.h"
     34 #include "nsHashKeys.h"
     35 #include "nsHttp.h"
     36 #include "nsMimeTypes.h"
     37 #include "nsIAuthPrompt.h"
     38 #include "nsIAuthPrompt2.h"
     39 #include "nsIAuthPromptAdapterFactory.h"
     40 #include "nsIBufferedStreams.h"
     41 #include "nsBufferedStreams.h"
     42 #include "nsIChannelEventSink.h"
     43 #include "nsIClassifiedChannel.h"
     44 #include "nsIContentSniffer.h"
     45 #include "mozilla/dom/Document.h"
     46 #include "nsIDownloader.h"
     47 #include "nsIFileProtocolHandler.h"
     48 #include "nsIFileStreams.h"
     49 #include "nsIFileURL.h"
     50 #include "nsIIDNService.h"
     51 #include "nsIInputStreamChannel.h"
     52 #include "nsIInputStreamPump.h"
     53 #include "nsIInterfaceRequestorUtils.h"
     54 #include "nsILoadContext.h"
     55 #include "nsIMIMEHeaderParam.h"
     56 #include "nsINode.h"
     57 #include "nsIObjectLoadingContent.h"
     58 #include "nsPersistentProperties.h"
     59 #include "nsIPrivateBrowsingChannel.h"
     60 #include "nsIPropertyBag2.h"
     61 #include "nsIProtocolProxyService.h"
     62 #include "mozilla/net/RedirectChannelRegistrar.h"
     63 #include "nsRequestObserverProxy.h"
     64 #include "nsISensitiveInfoHiddenURI.h"
     65 #include "nsISimpleStreamListener.h"
     66 #include "nsISocketProvider.h"
     67 #include "nsIStandardURL.h"
     68 #include "nsIStreamLoader.h"
     69 #include "nsIIncrementalStreamLoader.h"
     70 #include "nsStringStream.h"
     71 #include "nsSyncStreamListener.h"
     72 #include "nsITextToSubURI.h"
     73 #include "nsIURIWithSpecialOrigin.h"
     74 #include "nsIViewSourceChannel.h"
     75 #include "nsInterfaceRequestorAgg.h"
     76 #include "nsINestedURI.h"
     77 #include "mozilla/dom/nsCSPUtils.h"
     78 #include "mozilla/dom/nsHTTPSOnlyUtils.h"
     79 #include "mozilla/dom/nsMixedContentBlocker.h"
     80 #include "mozilla/dom/BlobURLProtocolHandler.h"
     81 #include "mozilla/net/HttpBaseChannel.h"
     82 #include "nsIScriptError.h"
     83 #include "nsISiteSecurityService.h"
     84 #include "nsHttpHandler.h"
     85 #include "nsNSSComponent.h"
     86 #include "nsIRedirectHistoryEntry.h"
     87 #include "nsICertStorage.h"
     88 #include "nsICertOverrideService.h"
     89 #include "nsQueryObject.h"
     90 #include "mozIThirdPartyUtil.h"
     91 #include "../mime/nsMIMEHeaderParamImpl.h"
     92 #include "nsStandardURL.h"
     93 #include "DefaultURI.h"
     94 #include "nsChromeProtocolHandler.h"
     95 #include "nsJSProtocolHandler.h"
     96 #include "nsDataHandler.h"
     97 #include "mozilla/dom/BlobURLProtocolHandler.h"
     98 #include "nsStreamUtils.h"
     99 #include "nsSocketTransportService2.h"
    100 #include "nsViewSourceHandler.h"
    101 #include "nsJARURI.h"
    102 #ifndef XP_IOS
    103 #  include "nsIconURI.h"
    104 #endif
    105 #include "nsAboutProtocolHandler.h"
    106 #include "nsResProtocolHandler.h"
    107 #include "mozilla/net/CookieJarSettings.h"
    108 #include "mozilla/net/MozSrcProtocolHandler.h"
    109 #include "mozilla/net/ExtensionProtocolHandler.h"
    110 #include "mozilla/net/MozNewTabWallpaperProtocolHandler.h"
    111 #include "mozilla/net/PageThumbProtocolHandler.h"
    112 #include "mozilla/net/SFVService.h"
    113 #include "nsICookieService.h"
    114 #include "nsIXPConnect.h"
    115 #include "nsParserConstants.h"
    116 #include "nsCRT.h"
    117 #include "nsServiceManagerUtils.h"
    118 #include "mozilla/dom/MediaList.h"
    119 #include "MediaContainerType.h"
    120 #include "DecoderTraits.h"
    121 #include "imgLoader.h"
    122 
    123 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
    124 #  include "nsNewMailnewsURI.h"
    125 #endif
    126 
    127 using namespace mozilla;
    128 using namespace mozilla::net;
    129 using mozilla::dom::BlobURLProtocolHandler;
    130 using mozilla::dom::ClientInfo;
    131 using mozilla::dom::PerformanceStorage;
    132 using mozilla::dom::ServiceWorkerDescriptor;
    133 
    134 #define MAX_RECURSION_COUNT 50
    135 
    136 enum class ClassifierMode {
    137  Disabled = 0,
    138  AntiTracking = 1,
    139  SafeBrowsing = 2,
    140  Enabled = 3,
    141 };
    142 
    143 already_AddRefed<nsIIOService> do_GetIOService(nsresult* error /* = 0 */) {
    144  nsCOMPtr<nsIIOService> io;
    145  io = mozilla::components::IO::Service();
    146  if (error) *error = io ? NS_OK : NS_ERROR_FAILURE;
    147  return io.forget();
    148 }
    149 
    150 nsresult NS_NewLocalFileInputStream(nsIInputStream** result, nsIFile* file,
    151                                    int32_t ioFlags /* = -1 */,
    152                                    int32_t perm /* = -1 */,
    153                                    int32_t behaviorFlags /* = 0 */) {
    154  nsresult rv;
    155  nsCOMPtr<nsIFileInputStream> in =
    156      do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
    157  if (NS_SUCCEEDED(rv)) {
    158    rv = in->Init(file, ioFlags, perm, behaviorFlags);
    159    if (NS_SUCCEEDED(rv)) in.forget(result);
    160  }
    161  return rv;
    162 }
    163 
    164 Result<nsCOMPtr<nsIInputStream>, nsresult> NS_NewLocalFileInputStream(
    165    nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */,
    166    int32_t behaviorFlags /* = 0 */) {
    167  nsCOMPtr<nsIInputStream> stream;
    168  const nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file,
    169                                                 ioFlags, perm, behaviorFlags);
    170  if (NS_SUCCEEDED(rv)) {
    171    return stream;
    172  }
    173  return Err(rv);
    174 }
    175 
    176 nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result, nsIFile* file,
    177                                     int32_t ioFlags /* = -1 */,
    178                                     int32_t perm /* = -1 */,
    179                                     int32_t behaviorFlags /* = 0 */) {
    180  nsresult rv;
    181  nsCOMPtr<nsIFileOutputStream> out =
    182      do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
    183  if (NS_SUCCEEDED(rv)) {
    184    rv = out->Init(file, ioFlags, perm, behaviorFlags);
    185    if (NS_SUCCEEDED(rv)) out.forget(result);
    186  }
    187  return rv;
    188 }
    189 
    190 Result<nsCOMPtr<nsIOutputStream>, nsresult> NS_NewLocalFileOutputStream(
    191    nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */,
    192    int32_t behaviorFlags /* = 0 */) {
    193  nsCOMPtr<nsIOutputStream> stream;
    194  const nsresult rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), file,
    195                                                  ioFlags, perm, behaviorFlags);
    196  if (NS_SUCCEEDED(rv)) {
    197    return stream;
    198  }
    199  return Err(rv);
    200 }
    201 
    202 nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result,
    203                                     const mozilla::ipc::FileDescriptor& fd) {
    204  nsCOMPtr<nsIFileOutputStream> out;
    205  nsFileOutputStream::Create(NS_GET_IID(nsIFileOutputStream),
    206                             getter_AddRefs(out));
    207 
    208  nsresult rv =
    209      static_cast<nsFileOutputStream*>(out.get())->InitWithFileDescriptor(fd);
    210  if (NS_FAILED(rv)) {
    211    return rv;
    212  }
    213 
    214  out.forget(result);
    215  return NS_OK;
    216 }
    217 
    218 nsresult net_EnsureIOService(nsIIOService** ios, nsCOMPtr<nsIIOService>& grip) {
    219  nsresult rv = NS_OK;
    220  if (!*ios) {
    221    grip = do_GetIOService(&rv);
    222    *ios = grip;
    223  }
    224  return rv;
    225 }
    226 
    227 nsresult NS_NewFileURI(
    228    nsIURI** result, nsIFile* spec,
    229    nsIIOService*
    230        ioService /* = nullptr */)  // pass in nsIIOService to optimize callers
    231 {
    232  nsresult rv;
    233  nsCOMPtr<nsIIOService> grip;
    234  rv = net_EnsureIOService(&ioService, grip);
    235  if (ioService) rv = ioService->NewFileURI(spec, result);
    236  return rv;
    237 }
    238 
    239 nsresult NS_GetURIWithNewRef(nsIURI* aInput, const nsACString& aRef,
    240                             nsIURI** aOutput) {
    241  MOZ_DIAGNOSTIC_ASSERT(aRef.IsEmpty() || aRef[0] == '#');
    242 
    243  if (NS_WARN_IF(!aInput || !aOutput)) {
    244    return NS_ERROR_INVALID_ARG;
    245  }
    246 
    247  bool hasRef;
    248  nsresult rv = aInput->GetHasRef(&hasRef);
    249 
    250  nsAutoCString ref;
    251  if (NS_SUCCEEDED(rv)) {
    252    rv = aInput->GetRef(ref);
    253  }
    254 
    255  // If the ref is already equal to the new ref, we do not need to do anything.
    256  // Also, if the GetRef failed (it could return NS_ERROR_NOT_IMPLEMENTED)
    257  // we can assume SetRef would fail as well, so returning the original
    258  // URI is OK.
    259  //
    260  // Note that aRef contains the hash, but ref doesn't, so need to account for
    261  // that in the equality check.
    262  if (NS_FAILED(rv) || (!hasRef && aRef.IsEmpty()) ||
    263      (!aRef.IsEmpty() && hasRef &&
    264       Substring(aRef.Data() + 1, aRef.Length() - 1) == ref)) {
    265    nsCOMPtr<nsIURI> uri = aInput;
    266    uri.forget(aOutput);
    267    return NS_OK;
    268  }
    269 
    270  return NS_MutateURI(aInput).SetRef(aRef).Finalize(aOutput);
    271 }
    272 
    273 nsresult NS_GetURIWithoutRef(nsIURI* aInput, nsIURI** aOutput) {
    274  return NS_GetURIWithNewRef(aInput, ""_ns, aOutput);
    275 }
    276 
    277 nsresult NS_NewChannelInternal(
    278    nsIChannel** outChannel, nsIURI* aUri, nsILoadInfo* aLoadInfo,
    279    PerformanceStorage* aPerformanceStorage /* = nullptr */,
    280    nsILoadGroup* aLoadGroup /* = nullptr */,
    281    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    282    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    283    nsIIOService* aIoService /* = nullptr */) {
    284  // NS_NewChannelInternal is mostly called for channel redirects. We should
    285  // allow the creation of a channel even if the original channel did not have a
    286  // loadinfo attached.
    287  NS_ENSURE_ARG_POINTER(outChannel);
    288 
    289  nsCOMPtr<nsIIOService> grip;
    290  nsresult rv = net_EnsureIOService(&aIoService, grip);
    291  NS_ENSURE_SUCCESS(rv, rv);
    292 
    293  nsCOMPtr<nsIChannel> channel;
    294  rv = aIoService->NewChannelFromURIWithLoadInfo(aUri, aLoadInfo,
    295                                                 getter_AddRefs(channel));
    296  NS_ENSURE_SUCCESS(rv, rv);
    297 
    298  if (aLoadGroup) {
    299    rv = channel->SetLoadGroup(aLoadGroup);
    300    NS_ENSURE_SUCCESS(rv, rv);
    301  }
    302 
    303  if (aCallbacks) {
    304    rv = channel->SetNotificationCallbacks(aCallbacks);
    305    NS_ENSURE_SUCCESS(rv, rv);
    306  }
    307 
    308 #ifdef DEBUG
    309  nsLoadFlags channelLoadFlags = 0;
    310  channel->GetLoadFlags(&channelLoadFlags);
    311  // Will be removed when we remove LOAD_REPLACE altogether
    312  // This check is trying to catch protocol handlers that still
    313  // try to set the LOAD_REPLACE flag.
    314  MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
    315 #endif
    316 
    317  if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
    318    rv = channel->SetLoadFlags(aLoadFlags);
    319    NS_ENSURE_SUCCESS(rv, rv);
    320  }
    321 
    322  if (aPerformanceStorage) {
    323    nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
    324    loadInfo->SetPerformanceStorage(aPerformanceStorage);
    325  }
    326 
    327  channel.forget(outChannel);
    328  return NS_OK;
    329 }
    330 
    331 namespace {
    332 
    333 void AssertLoadingPrincipalAndClientInfoMatch(
    334    nsIPrincipal* aLoadingPrincipal, const ClientInfo& aLoadingClientInfo,
    335    nsContentPolicyType aType) {
    336 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    337  // Verify that the provided loading ClientInfo matches the loading
    338  // principal.  Unfortunately we can't just use nsIPrincipal::Equals() here
    339  // because of some corner cases:
    340  //
    341  //  1. Worker debugger scripts want to use a system loading principal for
    342  //     worker scripts with a content principal.  We exempt these from this
    343  //     check.
    344  //  2. Null principals currently require exact object identity for
    345  //     nsIPrincipal::Equals() to return true.  This doesn't work here because
    346  //     ClientInfo::GetPrincipal() uses PrincipalInfoToPrincipal() to allocate
    347  //     a new object.  To work around this we compare the principal origin
    348  //     string itself.  If bug 1431771 is fixed then we could switch to
    349  //     Equals().
    350 
    351  // Allow worker debugger to load with a system principal.
    352  if (aLoadingPrincipal->IsSystemPrincipal() &&
    353      (aType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
    354       aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
    355       aType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER ||
    356       aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS ||
    357       aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE)) {
    358    return;
    359  }
    360 
    361  // Perform a fast comparison for most principal checks.
    362  auto clientPrincipalOrErr(aLoadingClientInfo.GetPrincipal());
    363  if (clientPrincipalOrErr.isOk()) {
    364    nsCOMPtr<nsIPrincipal> clientPrincipal = clientPrincipalOrErr.unwrap();
    365    if (aLoadingPrincipal->Equals(clientPrincipal)) {
    366      return;
    367    }
    368    // Fall back to a slower origin equality test to support null principals.
    369    nsAutoCString loadingOriginNoSuffix;
    370    MOZ_ALWAYS_SUCCEEDS(
    371        aLoadingPrincipal->GetOriginNoSuffix(loadingOriginNoSuffix));
    372 
    373    nsAutoCString clientOriginNoSuffix;
    374    MOZ_ALWAYS_SUCCEEDS(
    375        clientPrincipal->GetOriginNoSuffix(clientOriginNoSuffix));
    376 
    377    // The client principal will have the partitionKey set if it's in a third
    378    // party context, but the loading principal won't. So, we ignore he
    379    // partitionKey when doing the verification here.
    380    MOZ_DIAGNOSTIC_ASSERT(loadingOriginNoSuffix == clientOriginNoSuffix);
    381    MOZ_DIAGNOSTIC_ASSERT(
    382        aLoadingPrincipal->OriginAttributesRef().EqualsIgnoringPartitionKey(
    383            clientPrincipal->OriginAttributesRef()));
    384  }
    385 #endif
    386 }
    387 
    388 }  // namespace
    389 
    390 nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
    391                       nsIPrincipal* aLoadingPrincipal,
    392                       nsSecurityFlags aSecurityFlags,
    393                       nsContentPolicyType aContentPolicyType,
    394                       nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
    395                       PerformanceStorage* aPerformanceStorage /* = nullptr */,
    396                       nsILoadGroup* aLoadGroup /* = nullptr */,
    397                       nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    398                       nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    399                       nsIIOService* aIoService /* = nullptr */,
    400                       uint32_t aSandboxFlags /* = 0 */) {
    401  return NS_NewChannelInternal(
    402      outChannel, aUri,
    403      nullptr,  // aLoadingNode,
    404      aLoadingPrincipal,
    405      nullptr,  // aTriggeringPrincipal
    406      Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
    407      aContentPolicyType, aCookieJarSettings, aPerformanceStorage, aLoadGroup,
    408      aCallbacks, aLoadFlags, aIoService, aSandboxFlags);
    409 }
    410 
    411 nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
    412                       nsIPrincipal* aLoadingPrincipal,
    413                       const ClientInfo& aLoadingClientInfo,
    414                       const Maybe<ServiceWorkerDescriptor>& aController,
    415                       nsSecurityFlags aSecurityFlags,
    416                       nsContentPolicyType aContentPolicyType,
    417                       nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
    418                       PerformanceStorage* aPerformanceStorage /* = nullptr */,
    419                       nsILoadGroup* aLoadGroup /* = nullptr */,
    420                       nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    421                       nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    422                       nsIIOService* aIoService /* = nullptr */,
    423                       uint32_t aSandboxFlags /* = 0 */) {
    424  AssertLoadingPrincipalAndClientInfoMatch(
    425      aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);
    426 
    427  Maybe<ClientInfo> loadingClientInfo;
    428  loadingClientInfo.emplace(aLoadingClientInfo);
    429 
    430  return NS_NewChannelInternal(outChannel, aUri,
    431                               nullptr,  // aLoadingNode,
    432                               aLoadingPrincipal,
    433                               nullptr,  // aTriggeringPrincipal
    434                               loadingClientInfo, aController, aSecurityFlags,
    435                               aContentPolicyType, aCookieJarSettings,
    436                               aPerformanceStorage, aLoadGroup, aCallbacks,
    437                               aLoadFlags, aIoService, aSandboxFlags);
    438 }
    439 
    440 nsresult NS_NewChannelInternal(
    441    nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode,
    442    nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
    443    const Maybe<ClientInfo>& aLoadingClientInfo,
    444    const Maybe<ServiceWorkerDescriptor>& aController,
    445    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
    446    nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
    447    PerformanceStorage* aPerformanceStorage /* = nullptr */,
    448    nsILoadGroup* aLoadGroup /* = nullptr */,
    449    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    450    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    451    nsIIOService* aIoService /* = nullptr */,
    452    uint32_t aSandboxFlags /* = 0 */) {
    453  NS_ENSURE_ARG_POINTER(outChannel);
    454 
    455  nsCOMPtr<nsIIOService> grip;
    456  nsresult rv = net_EnsureIOService(&aIoService, grip);
    457  NS_ENSURE_SUCCESS(rv, rv);
    458 
    459  nsCOMPtr<nsIChannel> channel;
    460  rv = aIoService->NewChannelFromURIWithClientAndController(
    461      aUri, aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal,
    462      aLoadingClientInfo, aController, aSecurityFlags, aContentPolicyType,
    463      aSandboxFlags, getter_AddRefs(channel));
    464  if (NS_FAILED(rv)) {
    465    return rv;
    466  }
    467 
    468  if (aLoadGroup) {
    469    rv = channel->SetLoadGroup(aLoadGroup);
    470    NS_ENSURE_SUCCESS(rv, rv);
    471  }
    472 
    473  if (aCallbacks) {
    474    rv = channel->SetNotificationCallbacks(aCallbacks);
    475    NS_ENSURE_SUCCESS(rv, rv);
    476  }
    477 
    478 #ifdef DEBUG
    479  nsLoadFlags channelLoadFlags = 0;
    480  channel->GetLoadFlags(&channelLoadFlags);
    481  // Will be removed when we remove LOAD_REPLACE altogether
    482  // This check is trying to catch protocol handlers that still
    483  // try to set the LOAD_REPLACE flag.
    484  MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
    485 #endif
    486 
    487  if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
    488    rv = channel->SetLoadFlags(aLoadFlags);
    489    NS_ENSURE_SUCCESS(rv, rv);
    490  }
    491 
    492  if (aPerformanceStorage || aCookieJarSettings) {
    493    nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
    494 
    495    if (aPerformanceStorage) {
    496      loadInfo->SetPerformanceStorage(aPerformanceStorage);
    497    }
    498 
    499    if (aCookieJarSettings) {
    500      loadInfo->SetCookieJarSettings(aCookieJarSettings);
    501    }
    502  }
    503 
    504  if (aLoadingNode) {
    505    nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
    506    ClassificationFlags flags =
    507        aLoadingNode->OwnerDoc()->GetScriptTrackingFlags();
    508 
    509    loadInfo->SetTriggeringFirstPartyClassificationFlags(flags.firstPartyFlags);
    510    loadInfo->SetTriggeringThirdPartyClassificationFlags(flags.thirdPartyFlags);
    511  }
    512 
    513  channel.forget(outChannel);
    514  return NS_OK;
    515 }
    516 
    517 nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */
    518 NS_NewChannelWithTriggeringPrincipal(
    519    nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode,
    520    nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
    521    nsContentPolicyType aContentPolicyType,
    522    PerformanceStorage* aPerformanceStorage /* = nullptr */,
    523    nsILoadGroup* aLoadGroup /* = nullptr */,
    524    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    525    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    526    nsIIOService* aIoService /* = nullptr */) {
    527  MOZ_ASSERT(aLoadingNode);
    528  NS_ASSERTION(aTriggeringPrincipal,
    529               "Can not create channel without a triggering Principal!");
    530 
    531  nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
    532 
    533  // Special treatment for resources injected by add-ons if not document,
    534  // iframe, workers.
    535  if (!nsContentUtils::IsNonSubresourceInternalPolicyType(aContentPolicyType) &&
    536      aTriggeringPrincipal &&
    537      StaticPrefs::privacy_antitracking_isolateContentScriptResources() &&
    538      nsContentUtils::IsExpandedPrincipal(aTriggeringPrincipal)) {
    539    bool shouldResistFingerprinting =
    540        nsContentUtils::ShouldResistFingerprinting_dangerous(
    541            aLoadingNode->NodePrincipal(),
    542            "CookieJarSettings can't exist yet, we're creating it",
    543            RFPTarget::IsAlwaysEnabledForPrecompute);
    544    cookieJarSettings = CookieJarSettings::Create(
    545        nsICookieService::BEHAVIOR_REJECT,
    546        StoragePrincipalHelper::PartitionKeyForExpandedPrincipal(
    547            aTriggeringPrincipal),
    548        OriginAttributes::IsFirstPartyEnabled(), false,
    549        shouldResistFingerprinting);
    550  } else {
    551    // Let's inherit the cookie behavior and permission from the parent
    552    // document.
    553    cookieJarSettings = aLoadingNode->OwnerDoc()->CookieJarSettings();
    554  }
    555 
    556  return NS_NewChannelInternal(
    557      outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
    558      aTriggeringPrincipal, Maybe<ClientInfo>(),
    559      Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
    560      cookieJarSettings, aPerformanceStorage, aLoadGroup, aCallbacks,
    561      aLoadFlags, aIoService);
    562 }
    563 
    564 // See NS_NewChannelInternal for usage and argument description
    565 nsresult NS_NewChannelWithTriggeringPrincipal(
    566    nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal,
    567    nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
    568    nsContentPolicyType aContentPolicyType,
    569    nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
    570    PerformanceStorage* aPerformanceStorage /* = nullptr */,
    571    nsILoadGroup* aLoadGroup /* = nullptr */,
    572    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    573    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    574    nsIIOService* aIoService /* = nullptr */) {
    575  NS_ASSERTION(aLoadingPrincipal,
    576               "Can not create channel without a loading Principal!");
    577  return NS_NewChannelInternal(
    578      outChannel, aUri,
    579      nullptr,  // aLoadingNode
    580      aLoadingPrincipal, aTriggeringPrincipal, Maybe<ClientInfo>(),
    581      Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
    582      aCookieJarSettings, aPerformanceStorage, aLoadGroup, aCallbacks,
    583      aLoadFlags, aIoService);
    584 }
    585 
    586 // See NS_NewChannelInternal for usage and argument description
    587 nsresult NS_NewChannelWithTriggeringPrincipal(
    588    nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal,
    589    nsIPrincipal* aTriggeringPrincipal, const ClientInfo& aLoadingClientInfo,
    590    const Maybe<ServiceWorkerDescriptor>& aController,
    591    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
    592    nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
    593    PerformanceStorage* aPerformanceStorage /* = nullptr */,
    594    nsILoadGroup* aLoadGroup /* = nullptr */,
    595    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    596    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    597    nsIIOService* aIoService /* = nullptr */) {
    598  AssertLoadingPrincipalAndClientInfoMatch(
    599      aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);
    600 
    601  Maybe<ClientInfo> loadingClientInfo;
    602  loadingClientInfo.emplace(aLoadingClientInfo);
    603 
    604  return NS_NewChannelInternal(
    605      outChannel, aUri,
    606      nullptr,  // aLoadingNode
    607      aLoadingPrincipal, aTriggeringPrincipal, loadingClientInfo, aController,
    608      aSecurityFlags, aContentPolicyType, aCookieJarSettings,
    609      aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService);
    610 }
    611 
    612 nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
    613                       nsINode* aLoadingNode, nsSecurityFlags aSecurityFlags,
    614                       nsContentPolicyType aContentPolicyType,
    615                       PerformanceStorage* aPerformanceStorage /* = nullptr */,
    616                       nsILoadGroup* aLoadGroup /* = nullptr */,
    617                       nsIInterfaceRequestor* aCallbacks /* = nullptr */,
    618                       nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
    619                       nsIIOService* aIoService /* = nullptr */,
    620                       uint32_t aSandboxFlags /* = 0 */) {
    621  NS_ASSERTION(aLoadingNode, "Can not create channel without a loading Node!");
    622  return NS_NewChannelInternal(
    623      outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
    624      nullptr,  // aTriggeringPrincipal
    625      Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
    626      aContentPolicyType, aLoadingNode->OwnerDoc()->CookieJarSettings(),
    627      aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService,
    628      aSandboxFlags);
    629 }
    630 
    631 nsresult NS_GetIsDocumentChannel(nsIChannel* aChannel, bool* aIsDocument) {
    632  // Check if this channel is going to be used to create a document. If it has
    633  // LOAD_DOCUMENT_URI set it is trivially creating a document. If
    634  // LOAD_HTML_OBJECT_DATA is set it may or may not be used to create a
    635  // document, depending on its MIME type.
    636 
    637  if (!aChannel || !aIsDocument) {
    638    return NS_ERROR_NULL_POINTER;
    639  }
    640  *aIsDocument = false;
    641  nsLoadFlags loadFlags;
    642  nsresult rv = aChannel->GetLoadFlags(&loadFlags);
    643  if (NS_FAILED(rv)) {
    644    return rv;
    645  }
    646  if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
    647    *aIsDocument = true;
    648    return NS_OK;
    649  }
    650  if (!(loadFlags & nsIRequest::LOAD_HTML_OBJECT_DATA)) {
    651    *aIsDocument = false;
    652    return NS_OK;
    653  }
    654  nsAutoCString mimeType;
    655  rv = aChannel->GetContentType(mimeType);
    656  if (NS_FAILED(rv)) {
    657    return rv;
    658  }
    659  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
    660  if (nsContentUtils::HtmlObjectContentTypeForMIMEType(
    661          mimeType, loadInfo->GetSandboxFlags()) ==
    662      nsIObjectLoadingContent::TYPE_DOCUMENT) {
    663    *aIsDocument = true;
    664    return NS_OK;
    665  }
    666  *aIsDocument = false;
    667  return NS_OK;
    668 }
    669 
    670 nsresult NS_MakeAbsoluteURI(nsACString& result, const nsACString& spec,
    671                            nsIURI* baseURI) {
    672  nsresult rv;
    673  if (!baseURI) {
    674    NS_WARNING("It doesn't make sense to not supply a base URI");
    675    result = spec;
    676    rv = NS_OK;
    677  } else if (spec.IsEmpty()) {
    678    rv = baseURI->GetSpec(result);
    679  } else {
    680    rv = baseURI->Resolve(spec, result);
    681  }
    682  return rv;
    683 }
    684 
    685 nsresult NS_MakeAbsoluteURI(char** result, const char* spec, nsIURI* baseURI) {
    686  nsresult rv;
    687  nsAutoCString resultBuf;
    688  rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI);
    689  if (NS_SUCCEEDED(rv)) {
    690    *result = ToNewCString(resultBuf, mozilla::fallible);
    691    if (!*result) rv = NS_ERROR_OUT_OF_MEMORY;
    692  }
    693  return rv;
    694 }
    695 
    696 nsresult NS_MakeAbsoluteURI(nsAString& result, const nsAString& spec,
    697                            nsIURI* baseURI) {
    698  nsresult rv;
    699  if (!baseURI) {
    700    NS_WARNING("It doesn't make sense to not supply a base URI");
    701    result = spec;
    702    rv = NS_OK;
    703  } else {
    704    nsAutoCString resultBuf;
    705    if (spec.IsEmpty()) {
    706      rv = baseURI->GetSpec(resultBuf);
    707    } else {
    708      rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf);
    709    }
    710    if (NS_SUCCEEDED(rv)) CopyUTF8toUTF16(resultBuf, result);
    711  }
    712  return rv;
    713 }
    714 
    715 int32_t NS_GetDefaultPort(const char* scheme,
    716                          nsIIOService* ioService /* = nullptr */) {
    717  nsresult rv;
    718 
    719  // Getting the default port through the protocol handler previously had a lot
    720  // of XPCOM overhead involved.  We optimize the protocols that matter for Web
    721  // pages (HTTP and HTTPS) by hardcoding their default ports here.
    722  //
    723  // XXX: This might not be necessary for performance anymore.
    724  if (strncmp(scheme, "http", 4) == 0) {
    725    if (scheme[4] == 's' && scheme[5] == '\0') {
    726      return 443;
    727    }
    728    if (scheme[4] == '\0') {
    729      return 80;
    730    }
    731  }
    732 
    733  nsCOMPtr<nsIIOService> grip;
    734  net_EnsureIOService(&ioService, grip);
    735  if (!ioService) return -1;
    736 
    737  int32_t port;
    738  rv = ioService->GetDefaultPort(scheme, &port);
    739  return NS_SUCCEEDED(rv) ? port : -1;
    740 }
    741 
    742 int32_t NS_GetRealPort(nsIURI* aURI) {
    743  int32_t port;
    744  nsresult rv = aURI->GetPort(&port);
    745  if (NS_FAILED(rv)) return -1;
    746 
    747  if (port != -1) return port;  // explicitly specified
    748 
    749  // Otherwise, we have to get the default port from the protocol handler
    750 
    751  // Need the scheme first
    752  nsAutoCString scheme;
    753  rv = aURI->GetScheme(scheme);
    754  if (NS_FAILED(rv)) return -1;
    755 
    756  return NS_GetDefaultPort(scheme.get());
    757 }
    758 
    759 nsresult NS_NewInputStreamChannelInternal(
    760    nsIChannel** outChannel, nsIURI* aUri,
    761    already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType,
    762    const nsACString& aContentCharset, nsILoadInfo* aLoadInfo) {
    763  nsresult rv;
    764  nsCOMPtr<nsIInputStreamChannel> isc =
    765      do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
    766  NS_ENSURE_SUCCESS(rv, rv);
    767  rv = isc->SetURI(aUri);
    768  NS_ENSURE_SUCCESS(rv, rv);
    769 
    770  nsCOMPtr<nsIInputStream> stream = std::move(aStream);
    771  rv = isc->SetContentStream(stream);
    772  NS_ENSURE_SUCCESS(rv, rv);
    773 
    774  nsCOMPtr<nsIChannel> channel = do_QueryInterface(isc, &rv);
    775  NS_ENSURE_SUCCESS(rv, rv);
    776 
    777  if (!aContentType.IsEmpty()) {
    778    rv = channel->SetContentType(aContentType);
    779    NS_ENSURE_SUCCESS(rv, rv);
    780  }
    781 
    782  if (!aContentCharset.IsEmpty()) {
    783    rv = channel->SetContentCharset(aContentCharset);
    784    NS_ENSURE_SUCCESS(rv, rv);
    785  }
    786 
    787  MOZ_ASSERT(aLoadInfo, "need a loadinfo to create a inputstreamchannel");
    788  channel->SetLoadInfo(aLoadInfo);
    789 
    790  // If we're sandboxed, make sure to clear any owner the channel
    791  // might already have.
    792  if (aLoadInfo && aLoadInfo->GetLoadingSandboxed()) {
    793    channel->SetOwner(nullptr);
    794  }
    795 
    796  channel.forget(outChannel);
    797  return NS_OK;
    798 }
    799 
    800 nsresult NS_NewInputStreamChannelInternal(
    801    nsIChannel** outChannel, nsIURI* aUri,
    802    already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType,
    803    const nsACString& aContentCharset, nsINode* aLoadingNode,
    804    nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
    805    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType) {
    806  nsCOMPtr<nsILoadInfo> loadInfo = MOZ_TRY(
    807      LoadInfo::Create(aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode,
    808                       aSecurityFlags, aContentPolicyType));
    809  if (!loadInfo) {
    810    return NS_ERROR_UNEXPECTED;
    811  }
    812 
    813  nsCOMPtr<nsIInputStream> stream = std::move(aStream);
    814 
    815  return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
    816                                          aContentType, aContentCharset,
    817                                          loadInfo);
    818 }
    819 
    820 nsresult NS_NewInputStreamChannel(
    821    nsIChannel** outChannel, nsIURI* aUri,
    822    already_AddRefed<nsIInputStream> aStream, nsIPrincipal* aLoadingPrincipal,
    823    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
    824    const nsACString& aContentType /* = ""_ns */,
    825    const nsACString& aContentCharset /* = ""_ns */) {
    826  nsCOMPtr<nsIInputStream> stream = aStream;
    827  return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
    828                                          aContentType, aContentCharset,
    829                                          nullptr,  // aLoadingNode
    830                                          aLoadingPrincipal,
    831                                          nullptr,  // aTriggeringPrincipal
    832                                          aSecurityFlags, aContentPolicyType);
    833 }
    834 
    835 nsresult NS_NewInputStreamChannelInternal(nsIChannel** outChannel, nsIURI* aUri,
    836                                          const nsAString& aData,
    837                                          const nsACString& aContentType,
    838                                          nsILoadInfo* aLoadInfo,
    839                                          bool aIsSrcdocChannel /* = false */) {
    840  nsresult rv;
    841  nsCOMPtr<nsIStringInputStream> stream;
    842  stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
    843  NS_ENSURE_SUCCESS(rv, rv);
    844 
    845  uint32_t len;
    846  char* utf8Bytes = ToNewUTF8String(aData, &len);
    847  rv = stream->AdoptData(utf8Bytes, len);
    848 
    849  nsCOMPtr<nsIChannel> channel;
    850  rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aUri,
    851                                        stream.forget(), aContentType,
    852                                        "UTF-8"_ns, aLoadInfo);
    853 
    854  NS_ENSURE_SUCCESS(rv, rv);
    855 
    856  if (aIsSrcdocChannel) {
    857    nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(channel);
    858    NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE);
    859    inStrmChan->SetSrcdocData(aData);
    860  }
    861  channel.forget(outChannel);
    862  return NS_OK;
    863 }
    864 
    865 nsresult NS_NewInputStreamChannelInternal(
    866    nsIChannel** outChannel, nsIURI* aUri, const nsAString& aData,
    867    const nsACString& aContentType, nsINode* aLoadingNode,
    868    nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
    869    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
    870    bool aIsSrcdocChannel /* = false */) {
    871  nsCOMPtr<nsILoadInfo> loadInfo = MOZ_TRY(
    872      net::LoadInfo::Create(aLoadingPrincipal, aTriggeringPrincipal,
    873                            aLoadingNode, aSecurityFlags, aContentPolicyType));
    874  return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
    875                                          loadInfo, aIsSrcdocChannel);
    876 }
    877 
    878 nsresult NS_NewInputStreamChannel(nsIChannel** outChannel, nsIURI* aUri,
    879                                  const nsAString& aData,
    880                                  const nsACString& aContentType,
    881                                  nsIPrincipal* aLoadingPrincipal,
    882                                  nsSecurityFlags aSecurityFlags,
    883                                  nsContentPolicyType aContentPolicyType,
    884                                  bool aIsSrcdocChannel /* = false */) {
    885  return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
    886                                          nullptr,  // aLoadingNode
    887                                          aLoadingPrincipal,
    888                                          nullptr,  // aTriggeringPrincipal
    889                                          aSecurityFlags, aContentPolicyType,
    890                                          aIsSrcdocChannel);
    891 }
    892 
    893 nsresult NS_NewInputStreamPump(
    894    nsIInputStreamPump** aResult, already_AddRefed<nsIInputStream> aStream,
    895    uint32_t aSegsize /* = 0 */, uint32_t aSegcount /* = 0 */,
    896    bool aCloseWhenDone /* = false */,
    897    nsISerialEventTarget* aMainThreadTarget /* = nullptr */) {
    898  nsCOMPtr<nsIInputStream> stream = std::move(aStream);
    899 
    900  nsresult rv;
    901  nsCOMPtr<nsIInputStreamPump> pump =
    902      do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
    903  if (NS_SUCCEEDED(rv)) {
    904    rv = pump->Init(stream, aSegsize, aSegcount, aCloseWhenDone,
    905                    aMainThreadTarget);
    906    if (NS_SUCCEEDED(rv)) {
    907      *aResult = nullptr;
    908      pump.swap(*aResult);
    909    }
    910  }
    911  return rv;
    912 }
    913 
    914 nsresult NS_NewLoadGroup(nsILoadGroup** result, nsIRequestObserver* obs) {
    915  nsresult rv;
    916  nsCOMPtr<nsILoadGroup> group =
    917      do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
    918  if (NS_SUCCEEDED(rv)) {
    919    rv = group->SetGroupObserver(obs);
    920    if (NS_SUCCEEDED(rv)) {
    921      *result = nullptr;
    922      group.swap(*result);
    923    }
    924  }
    925  return rv;
    926 }
    927 
    928 bool NS_IsReasonableHTTPHeaderValue(const nsACString& aValue) {
    929  return mozilla::net::nsHttp::IsReasonableHeaderValue(aValue);
    930 }
    931 
    932 bool NS_IsValidHTTPToken(const nsACString& aToken) {
    933  return mozilla::net::nsHttp::IsValidToken(aToken);
    934 }
    935 
    936 void NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest) {
    937  mozilla::net::nsHttp::TrimHTTPWhitespace(aSource, aDest);
    938 }
    939 
    940 nsresult NS_NewLoadGroup(nsILoadGroup** aResult, nsIPrincipal* aPrincipal) {
    941  using mozilla::LoadContext;
    942  nsresult rv;
    943 
    944  nsCOMPtr<nsILoadGroup> group =
    945      do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
    946  NS_ENSURE_SUCCESS(rv, rv);
    947 
    948  RefPtr<LoadContext> loadContext = new LoadContext(aPrincipal);
    949  rv = group->SetNotificationCallbacks(loadContext);
    950  NS_ENSURE_SUCCESS(rv, rv);
    951 
    952  group.forget(aResult);
    953  return rv;
    954 }
    955 
    956 bool NS_LoadGroupMatchesPrincipal(nsILoadGroup* aLoadGroup,
    957                                  nsIPrincipal* aPrincipal) {
    958  if (!aPrincipal) {
    959    return false;
    960  }
    961 
    962  // If this is a null principal then the load group doesn't really matter.
    963  // The principal will not be allowed to perform any actions that actually
    964  // use the load group.  Unconditionally treat null principals as a match.
    965  if (aPrincipal->GetIsNullPrincipal()) {
    966    return true;
    967  }
    968 
    969  if (!aLoadGroup) {
    970    return false;
    971  }
    972 
    973  nsCOMPtr<nsILoadContext> loadContext;
    974  NS_QueryNotificationCallbacks(nullptr, aLoadGroup, NS_GET_IID(nsILoadContext),
    975                                getter_AddRefs(loadContext));
    976  NS_ENSURE_TRUE(loadContext, false);
    977 
    978  return true;
    979 }
    980 
    981 nsresult NS_NewDownloader(nsIStreamListener** result,
    982                          nsIDownloadObserver* observer,
    983                          nsIFile* downloadLocation /* = nullptr */) {
    984  nsresult rv;
    985  nsCOMPtr<nsIDownloader> downloader =
    986      do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv);
    987  if (NS_SUCCEEDED(rv)) {
    988    rv = downloader->Init(observer, downloadLocation);
    989    if (NS_SUCCEEDED(rv)) {
    990      downloader.forget(result);
    991    }
    992  }
    993  return rv;
    994 }
    995 
    996 nsresult NS_NewIncrementalStreamLoader(
    997    nsIIncrementalStreamLoader** result,
    998    nsIIncrementalStreamLoaderObserver* observer) {
    999  nsresult rv;
   1000  nsCOMPtr<nsIIncrementalStreamLoader> loader =
   1001      do_CreateInstance(NS_INCREMENTALSTREAMLOADER_CONTRACTID, &rv);
   1002  if (NS_SUCCEEDED(rv)) {
   1003    rv = loader->Init(observer);
   1004    if (NS_SUCCEEDED(rv)) {
   1005      *result = nullptr;
   1006      loader.swap(*result);
   1007    }
   1008  }
   1009  return rv;
   1010 }
   1011 
   1012 nsresult NS_NewStreamLoader(
   1013    nsIStreamLoader** result, nsIStreamLoaderObserver* observer,
   1014    nsIRequestObserver* requestObserver /* = nullptr */) {
   1015  nsresult rv;
   1016  nsCOMPtr<nsIStreamLoader> loader =
   1017      do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv);
   1018  if (NS_SUCCEEDED(rv)) {
   1019    rv = loader->Init(observer, requestObserver);
   1020    if (NS_SUCCEEDED(rv)) {
   1021      *result = nullptr;
   1022      loader.swap(*result);
   1023    }
   1024  }
   1025  return rv;
   1026 }
   1027 
   1028 nsresult NS_NewStreamLoaderInternal(
   1029    nsIStreamLoader** outStream, nsIURI* aUri,
   1030    nsIStreamLoaderObserver* aObserver, nsINode* aLoadingNode,
   1031    nsIPrincipal* aLoadingPrincipal, nsSecurityFlags aSecurityFlags,
   1032    nsContentPolicyType aContentPolicyType,
   1033    nsILoadGroup* aLoadGroup /* = nullptr */,
   1034    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
   1035    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
   1036  nsCOMPtr<nsIChannel> channel;
   1037  nsresult rv = NS_NewChannelInternal(
   1038      getter_AddRefs(channel), aUri, aLoadingNode, aLoadingPrincipal,
   1039      nullptr,  // aTriggeringPrincipal
   1040      Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
   1041      aContentPolicyType,
   1042      nullptr,  // nsICookieJarSettings
   1043      nullptr,  // PerformanceStorage
   1044      aLoadGroup, aCallbacks, aLoadFlags);
   1045 
   1046  NS_ENSURE_SUCCESS(rv, rv);
   1047  rv = NS_NewStreamLoader(outStream, aObserver);
   1048  NS_ENSURE_SUCCESS(rv, rv);
   1049  return channel->AsyncOpen(*outStream);
   1050 }
   1051 
   1052 nsresult NS_NewStreamLoader(
   1053    nsIStreamLoader** outStream, nsIURI* aUri,
   1054    nsIStreamLoaderObserver* aObserver, nsINode* aLoadingNode,
   1055    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
   1056    nsILoadGroup* aLoadGroup /* = nullptr */,
   1057    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
   1058    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
   1059  NS_ASSERTION(aLoadingNode,
   1060               "Can not create stream loader without a loading Node!");
   1061  return NS_NewStreamLoaderInternal(
   1062      outStream, aUri, aObserver, aLoadingNode, aLoadingNode->NodePrincipal(),
   1063      aSecurityFlags, aContentPolicyType, aLoadGroup, aCallbacks, aLoadFlags);
   1064 }
   1065 
   1066 nsresult NS_NewStreamLoader(
   1067    nsIStreamLoader** outStream, nsIURI* aUri,
   1068    nsIStreamLoaderObserver* aObserver, nsIPrincipal* aLoadingPrincipal,
   1069    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
   1070    nsILoadGroup* aLoadGroup /* = nullptr */,
   1071    nsIInterfaceRequestor* aCallbacks /* = nullptr */,
   1072    nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
   1073  return NS_NewStreamLoaderInternal(outStream, aUri, aObserver,
   1074                                    nullptr,  // aLoadingNode
   1075                                    aLoadingPrincipal, aSecurityFlags,
   1076                                    aContentPolicyType, aLoadGroup, aCallbacks,
   1077                                    aLoadFlags);
   1078 }
   1079 
   1080 nsresult NS_NewSyncStreamListener(nsIStreamListener** result,
   1081                                  nsIInputStream** stream) {
   1082  nsCOMPtr<nsISyncStreamListener> listener = new nsSyncStreamListener();
   1083  nsresult rv = listener->GetInputStream(stream);
   1084  if (NS_SUCCEEDED(rv)) {
   1085    listener.forget(result);
   1086  }
   1087  return rv;
   1088 }
   1089 
   1090 nsresult NS_ImplementChannelOpen(nsIChannel* channel, nsIInputStream** result) {
   1091  nsCOMPtr<nsIStreamListener> listener;
   1092  nsCOMPtr<nsIInputStream> stream;
   1093  nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener),
   1094                                         getter_AddRefs(stream));
   1095  NS_ENSURE_SUCCESS(rv, rv);
   1096 
   1097  rv = channel->AsyncOpen(listener);
   1098  NS_ENSURE_SUCCESS(rv, rv);
   1099 
   1100  uint64_t n;
   1101  // block until the initial response is received or an error occurs.
   1102  rv = stream->Available(&n);
   1103  NS_ENSURE_SUCCESS(rv, rv);
   1104 
   1105  *result = nullptr;
   1106  stream.swap(*result);
   1107 
   1108  return NS_OK;
   1109 }
   1110 
   1111 nsresult NS_NewRequestObserverProxy(nsIRequestObserver** result,
   1112                                    nsIRequestObserver* observer,
   1113                                    nsISupports* context) {
   1114  nsCOMPtr<nsIRequestObserverProxy> proxy = new nsRequestObserverProxy();
   1115  nsresult rv = proxy->Init(observer, context);
   1116  if (NS_SUCCEEDED(rv)) {
   1117    proxy.forget(result);
   1118  }
   1119  return rv;
   1120 }
   1121 
   1122 nsresult NS_NewSimpleStreamListener(
   1123    nsIStreamListener** result, nsIOutputStream* sink,
   1124    nsIRequestObserver* observer /* = nullptr */) {
   1125  nsresult rv;
   1126  nsCOMPtr<nsISimpleStreamListener> listener =
   1127      do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv);
   1128  if (NS_SUCCEEDED(rv)) {
   1129    rv = listener->Init(sink, observer);
   1130    if (NS_SUCCEEDED(rv)) {
   1131      listener.forget(result);
   1132    }
   1133  }
   1134  return rv;
   1135 }
   1136 
   1137 nsresult NS_CheckPortSafety(int32_t port, const char* scheme,
   1138                            nsIIOService* ioService /* = nullptr */) {
   1139  nsresult rv;
   1140  nsCOMPtr<nsIIOService> grip;
   1141  rv = net_EnsureIOService(&ioService, grip);
   1142  if (ioService) {
   1143    bool allow;
   1144    rv = ioService->AllowPort(port, scheme, &allow);
   1145    if (NS_SUCCEEDED(rv) && !allow) {
   1146      NS_WARNING("port blocked");
   1147      rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED;
   1148    }
   1149  }
   1150  return rv;
   1151 }
   1152 
   1153 nsresult NS_CheckPortSafety(nsIURI* uri) {
   1154  int32_t port;
   1155  nsresult rv = uri->GetPort(&port);
   1156  if (NS_FAILED(rv) || port == -1) {  // port undefined or default-valued
   1157    return NS_OK;
   1158  }
   1159  nsAutoCString scheme;
   1160  uri->GetScheme(scheme);
   1161  return NS_CheckPortSafety(port, scheme.get());
   1162 }
   1163 
   1164 nsresult NS_GetFileProtocolHandler(nsIFileProtocolHandler** result,
   1165                                   nsIIOService* ioService /* = nullptr */) {
   1166  nsresult rv;
   1167  nsCOMPtr<nsIIOService> grip;
   1168  rv = net_EnsureIOService(&ioService, grip);
   1169  if (ioService) {
   1170    nsCOMPtr<nsIProtocolHandler> handler;
   1171    rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler));
   1172    if (NS_SUCCEEDED(rv)) rv = CallQueryInterface(handler, result);
   1173  }
   1174  return rv;
   1175 }
   1176 
   1177 nsresult NS_GetFileFromURLSpec(const nsACString& inURL, nsIFile** result,
   1178                               nsIIOService* ioService /* = nullptr */) {
   1179  nsresult rv;
   1180  nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   1181  rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   1182  if (NS_SUCCEEDED(rv)) rv = fileHandler->GetFileFromURLSpec(inURL, result);
   1183  return rv;
   1184 }
   1185 
   1186 nsresult NS_GetURLSpecFromFile(nsIFile* file, nsACString& url,
   1187                               nsIIOService* ioService /* = nullptr */) {
   1188  nsresult rv;
   1189  nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   1190  rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   1191  if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromFile(file, url);
   1192  return rv;
   1193 }
   1194 
   1195 nsresult NS_GetURLSpecFromActualFile(nsIFile* file, nsACString& url,
   1196                                     nsIIOService* ioService /* = nullptr */) {
   1197  nsresult rv;
   1198  nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   1199  rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   1200  if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromActualFile(file, url);
   1201  return rv;
   1202 }
   1203 
   1204 nsresult NS_GetURLSpecFromDir(nsIFile* file, nsACString& url,
   1205                              nsIIOService* ioService /* = nullptr */) {
   1206  nsresult rv;
   1207  nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   1208  rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   1209  if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromDir(file, url);
   1210  return rv;
   1211 }
   1212 
   1213 void NS_GetReferrerFromChannel(nsIChannel* channel, nsIURI** referrer) {
   1214  *referrer = nullptr;
   1215 
   1216  if (nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(channel)) {
   1217    // We have to check for a property on a property bag because the
   1218    // referrer may be empty for security reasons (for example, when loading
   1219    // an http page with an https referrer).
   1220    nsresult rv;
   1221    nsCOMPtr<nsIURI> uri(
   1222        do_GetProperty(props, u"docshell.internalReferrer"_ns, &rv));
   1223    if (NS_SUCCEEDED(rv)) {
   1224      uri.forget(referrer);
   1225      return;
   1226    }
   1227  }
   1228 
   1229  // if that didn't work, we can still try to get the referrer from the
   1230  // nsIHttpChannel (if we can QI to it)
   1231  nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel));
   1232  if (!chan) {
   1233    return;
   1234  }
   1235 
   1236  nsCOMPtr<nsIReferrerInfo> referrerInfo = chan->GetReferrerInfo();
   1237  if (!referrerInfo) {
   1238    return;
   1239  }
   1240 
   1241  referrerInfo->GetOriginalReferrer(referrer);
   1242 }
   1243 
   1244 already_AddRefed<nsINetUtil> do_GetNetUtil(nsresult* error /* = 0 */) {
   1245  nsCOMPtr<nsIIOService> io;
   1246  nsCOMPtr<nsINetUtil> util;
   1247 
   1248  io = mozilla::components::IO::Service();
   1249  if (io) util = do_QueryInterface(io);
   1250 
   1251  if (error) *error = !!util ? NS_OK : NS_ERROR_FAILURE;
   1252  return util.forget();
   1253 }
   1254 
   1255 nsresult NS_ParseRequestContentType(const nsACString& rawContentType,
   1256                                    nsCString& contentType,
   1257                                    nsCString& contentCharset) {
   1258  // contentCharset is left untouched if not present in rawContentType
   1259  nsresult rv;
   1260  nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
   1261  NS_ENSURE_SUCCESS(rv, rv);
   1262  nsCString charset;
   1263  bool hadCharset;
   1264  rv = util->ParseRequestContentType(rawContentType, charset, &hadCharset,
   1265                                     contentType);
   1266  if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset;
   1267  return rv;
   1268 }
   1269 
   1270 nsresult NS_ParseResponseContentType(const nsACString& rawContentType,
   1271                                     nsCString& contentType,
   1272                                     nsCString& contentCharset) {
   1273  // contentCharset is left untouched if not present in rawContentType
   1274  nsresult rv;
   1275  nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
   1276  NS_ENSURE_SUCCESS(rv, rv);
   1277  nsCString charset;
   1278  bool hadCharset;
   1279  rv = util->ParseResponseContentType(rawContentType, charset, &hadCharset,
   1280                                      contentType);
   1281  if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset;
   1282  return rv;
   1283 }
   1284 
   1285 nsresult NS_ExtractCharsetFromContentType(const nsACString& rawContentType,
   1286                                          nsCString& contentCharset,
   1287                                          bool* hadCharset,
   1288                                          int32_t* charsetStart,
   1289                                          int32_t* charsetEnd) {
   1290  // contentCharset is left untouched if not present in rawContentType
   1291  nsresult rv;
   1292  nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
   1293  NS_ENSURE_SUCCESS(rv, rv);
   1294 
   1295  return util->ExtractCharsetFromContentType(
   1296      rawContentType, contentCharset, charsetStart, charsetEnd, hadCharset);
   1297 }
   1298 
   1299 nsresult NS_NewAtomicFileOutputStream(nsIOutputStream** result, nsIFile* file,
   1300                                      int32_t ioFlags /* = -1 */,
   1301                                      int32_t perm /* = -1 */,
   1302                                      int32_t behaviorFlags /* = 0 */) {
   1303  nsresult rv;
   1304  nsCOMPtr<nsIFileOutputStream> out =
   1305      do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
   1306  if (NS_SUCCEEDED(rv)) {
   1307    rv = out->Init(file, ioFlags, perm, behaviorFlags);
   1308    if (NS_SUCCEEDED(rv)) out.forget(result);
   1309  }
   1310  return rv;
   1311 }
   1312 
   1313 nsresult NS_NewSafeLocalFileOutputStream(nsIOutputStream** result,
   1314                                         nsIFile* file,
   1315                                         int32_t ioFlags /* = -1 */,
   1316                                         int32_t perm /* = -1 */,
   1317                                         int32_t behaviorFlags /* = 0 */) {
   1318  nsresult rv;
   1319  nsCOMPtr<nsIFileOutputStream> out =
   1320      do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
   1321  if (NS_SUCCEEDED(rv)) {
   1322    rv = out->Init(file, ioFlags, perm, behaviorFlags);
   1323    if (NS_SUCCEEDED(rv)) out.forget(result);
   1324  }
   1325  return rv;
   1326 }
   1327 
   1328 nsresult NS_NewLocalFileRandomAccessStream(nsIRandomAccessStream** result,
   1329                                           nsIFile* file,
   1330                                           int32_t ioFlags /* = -1 */,
   1331                                           int32_t perm /* = -1 */,
   1332                                           int32_t behaviorFlags /* = 0 */) {
   1333  nsCOMPtr<nsIFileRandomAccessStream> stream = new nsFileRandomAccessStream();
   1334  nsresult rv = stream->Init(file, ioFlags, perm, behaviorFlags);
   1335  if (NS_SUCCEEDED(rv)) {
   1336    stream.forget(result);
   1337  }
   1338  return rv;
   1339 }
   1340 
   1341 mozilla::Result<nsCOMPtr<nsIRandomAccessStream>, nsresult>
   1342 NS_NewLocalFileRandomAccessStream(nsIFile* file, int32_t ioFlags /* = -1 */,
   1343                                  int32_t perm /* = -1 */,
   1344                                  int32_t behaviorFlags /* = 0 */) {
   1345  nsCOMPtr<nsIRandomAccessStream> stream;
   1346  const nsresult rv = NS_NewLocalFileRandomAccessStream(
   1347      getter_AddRefs(stream), file, ioFlags, perm, behaviorFlags);
   1348  if (NS_SUCCEEDED(rv)) {
   1349    return stream;
   1350  }
   1351  return Err(rv);
   1352 }
   1353 
   1354 nsresult NS_NewBufferedOutputStream(
   1355    nsIOutputStream** aResult, already_AddRefed<nsIOutputStream> aOutputStream,
   1356    uint32_t aBufferSize) {
   1357  nsCOMPtr<nsIOutputStream> outputStream = std::move(aOutputStream);
   1358 
   1359  nsresult rv;
   1360  nsCOMPtr<nsIBufferedOutputStream> out =
   1361      do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
   1362  if (NS_SUCCEEDED(rv)) {
   1363    rv = out->Init(outputStream, aBufferSize);
   1364    if (NS_SUCCEEDED(rv)) {
   1365      out.forget(aResult);
   1366    }
   1367  }
   1368  return rv;
   1369 }
   1370 
   1371 [[nodiscard]] nsresult NS_NewBufferedInputStream(
   1372    nsIInputStream** aResult, already_AddRefed<nsIInputStream> aInputStream,
   1373    uint32_t aBufferSize) {
   1374  nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
   1375 
   1376  nsCOMPtr<nsIBufferedInputStream> in;
   1377  nsresult rv = nsBufferedInputStream::Create(
   1378      NS_GET_IID(nsIBufferedInputStream), getter_AddRefs(in));
   1379  if (NS_SUCCEEDED(rv)) {
   1380    rv = in->Init(inputStream, aBufferSize);
   1381    if (NS_SUCCEEDED(rv)) {
   1382      *aResult = static_cast<nsBufferedInputStream*>(in.get())
   1383                     ->GetInputStream()
   1384                     .take();
   1385    }
   1386  }
   1387  return rv;
   1388 }
   1389 
   1390 Result<nsCOMPtr<nsIInputStream>, nsresult> NS_NewBufferedInputStream(
   1391    already_AddRefed<nsIInputStream> aInputStream, uint32_t aBufferSize) {
   1392  nsCOMPtr<nsIInputStream> stream;
   1393  const nsresult rv = NS_NewBufferedInputStream(
   1394      getter_AddRefs(stream), std::move(aInputStream), aBufferSize);
   1395  if (NS_SUCCEEDED(rv)) {
   1396    return stream;
   1397  }
   1398  return Err(rv);
   1399 }
   1400 
   1401 namespace {
   1402 
   1403 // Returns the buffer size from the pref, floored to the nearest power of two.
   1404 static uint32_t GetBufferSize() {
   1405  uint32_t prefValue = StaticPrefs::network_buffer_default_size();
   1406  return uint32_t(1) << FloorLog2(prefValue);
   1407 }
   1408 
   1409 class BufferWriter final : public nsIInputStreamCallback {
   1410 public:
   1411  NS_DECL_THREADSAFE_ISUPPORTS
   1412 
   1413  BufferWriter(nsIInputStream* aInputStream, void* aBuffer, int64_t aCount)
   1414      : mMonitor("BufferWriter.mMonitor"),
   1415        mInputStream(aInputStream),
   1416        mBuffer(aBuffer),
   1417        mCount(aCount),
   1418        mWrittenData(0),
   1419        mBufferType(aBuffer ? eExternal : eInternal),
   1420        mBufferSize(0) {
   1421    MOZ_ASSERT(aInputStream);
   1422    MOZ_ASSERT(aCount == -1 || aCount > 0);
   1423    MOZ_ASSERT_IF(mBuffer, aCount > 0);
   1424  }
   1425 
   1426  nsresult Write() {
   1427    NS_ASSERT_OWNINGTHREAD(BufferWriter);
   1428 
   1429    // Let's make the inputStream buffered if it's not.
   1430    if (!NS_InputStreamIsBuffered(mInputStream)) {
   1431      nsCOMPtr<nsIInputStream> bufferedStream;
   1432      nsresult rv =
   1433          NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
   1434                                    mInputStream.forget(), GetBufferSize());
   1435      NS_ENSURE_SUCCESS(rv, rv);
   1436 
   1437      mInputStream = bufferedStream;
   1438    }
   1439 
   1440    mAsyncInputStream = do_QueryInterface(mInputStream);
   1441 
   1442    if (!mAsyncInputStream) {
   1443      return WriteSync();
   1444    }
   1445 
   1446    // Let's use mAsyncInputStream only.
   1447    mInputStream = nullptr;
   1448 
   1449    return WriteAsync();
   1450  }
   1451 
   1452  uint64_t WrittenData() const {
   1453    NS_ASSERT_OWNINGTHREAD(BufferWriter);
   1454    return mWrittenData;
   1455  }
   1456 
   1457  void* StealBuffer() {
   1458    NS_ASSERT_OWNINGTHREAD(BufferWriter);
   1459    MOZ_ASSERT(mBufferType == eInternal);
   1460 
   1461    void* buffer = mBuffer;
   1462 
   1463    mBuffer = nullptr;
   1464    mBufferSize = 0;
   1465 
   1466    return buffer;
   1467  }
   1468 
   1469 private:
   1470  ~BufferWriter() {
   1471    if (mBuffer && mBufferType == eInternal) {
   1472      free(mBuffer);
   1473    }
   1474 
   1475    if (mTaskQueue) {
   1476      mTaskQueue->BeginShutdown();
   1477    }
   1478  }
   1479 
   1480  nsresult WriteSync() {
   1481    NS_ASSERT_OWNINGTHREAD(BufferWriter);
   1482 
   1483    uint64_t length = (uint64_t)mCount;
   1484 
   1485    if (mCount == -1) {
   1486      nsresult rv = mInputStream->Available(&length);
   1487      NS_ENSURE_SUCCESS(rv, rv);
   1488 
   1489      if (length == 0) {
   1490        // nothing to read.
   1491        return NS_OK;
   1492      }
   1493    }
   1494 
   1495    if (mBufferType == eInternal) {
   1496      mBuffer = malloc(length);
   1497      if (NS_WARN_IF(!mBuffer)) {
   1498        return NS_ERROR_OUT_OF_MEMORY;
   1499      }
   1500    }
   1501 
   1502    uint32_t writtenData;
   1503    nsresult rv = mInputStream->ReadSegments(NS_CopySegmentToBuffer, mBuffer,
   1504                                             length, &writtenData);
   1505    NS_ENSURE_SUCCESS(rv, rv);
   1506 
   1507    mWrittenData = writtenData;
   1508    return NS_OK;
   1509  }
   1510 
   1511  nsresult WriteAsync() {
   1512    NS_ASSERT_OWNINGTHREAD(BufferWriter);
   1513 
   1514    if (mCount > 0 && mBufferType == eInternal) {
   1515      mBuffer = malloc(mCount);
   1516      if (NS_WARN_IF(!mBuffer)) {
   1517        return NS_ERROR_OUT_OF_MEMORY;
   1518      }
   1519    }
   1520 
   1521    while (true) {
   1522      if (mCount == -1 && !MaybeExpandBufferSize()) {
   1523        return NS_ERROR_OUT_OF_MEMORY;
   1524      }
   1525 
   1526      uint64_t offset = mWrittenData;
   1527      uint64_t length = mCount == -1 ? GetBufferSize() : mCount;
   1528 
   1529      // Let's try to read data directly.
   1530      uint32_t writtenData;
   1531      nsresult rv = mAsyncInputStream->ReadSegments(
   1532          NS_CopySegmentToBuffer, static_cast<char*>(mBuffer) + offset, length,
   1533          &writtenData);
   1534 
   1535      // Operation completed. Nothing more to read.
   1536      if (NS_SUCCEEDED(rv) && writtenData == 0) {
   1537        return NS_OK;
   1538      }
   1539 
   1540      // If we succeeded, let's try to read again.
   1541      if (NS_SUCCEEDED(rv)) {
   1542        mWrittenData += writtenData;
   1543        if (mCount != -1) {
   1544          MOZ_ASSERT(mCount >= writtenData);
   1545          mCount -= writtenData;
   1546 
   1547          // Is this the end of the reading?
   1548          if (mCount == 0) {
   1549            return NS_OK;
   1550          }
   1551        }
   1552 
   1553        continue;
   1554      }
   1555 
   1556      // Async wait...
   1557      if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
   1558        rv = MaybeCreateTaskQueue();
   1559        if (NS_WARN_IF(NS_FAILED(rv))) {
   1560          return rv;
   1561        }
   1562 
   1563        MonitorAutoLock lock(mMonitor);
   1564 
   1565        rv = mAsyncInputStream->AsyncWait(this, 0, length, mTaskQueue);
   1566        if (NS_WARN_IF(NS_FAILED(rv))) {
   1567          return rv;
   1568        }
   1569 
   1570        lock.Wait();
   1571        continue;
   1572      }
   1573 
   1574      // Otherwise, let's propagate the error.
   1575      return rv;
   1576    }
   1577 
   1578    MOZ_ASSERT_UNREACHABLE("We should not be here");
   1579    return NS_ERROR_FAILURE;
   1580  }
   1581 
   1582  nsresult MaybeCreateTaskQueue() {
   1583    NS_ASSERT_OWNINGTHREAD(BufferWriter);
   1584 
   1585    if (!mTaskQueue) {
   1586      nsCOMPtr<nsIEventTarget> target;
   1587      target = mozilla::components::StreamTransport::Service();
   1588      if (!target) {
   1589        return NS_ERROR_FAILURE;
   1590      }
   1591 
   1592      mTaskQueue = TaskQueue::Create(target.forget(), "nsNetUtil:BufferWriter");
   1593    }
   1594 
   1595    return NS_OK;
   1596  }
   1597 
   1598  NS_IMETHOD
   1599  OnInputStreamReady(nsIAsyncInputStream* aStream) override {
   1600    MOZ_ASSERT(!NS_IsMainThread());
   1601 
   1602    // We have something to read. Let's unlock the main-thread.
   1603    MonitorAutoLock lock(mMonitor);
   1604    lock.Notify();
   1605    return NS_OK;
   1606  }
   1607 
   1608  bool MaybeExpandBufferSize() {
   1609    NS_ASSERT_OWNINGTHREAD(BufferWriter);
   1610 
   1611    MOZ_ASSERT(mCount == -1);
   1612 
   1613    uint32_t bufSize = GetBufferSize();
   1614    if (mBufferSize >= mWrittenData + bufSize) {
   1615      // The buffer is big enough.
   1616      return true;
   1617    }
   1618 
   1619    CheckedUint32 bufferSize =
   1620        std::max<uint32_t>(static_cast<uint32_t>(mWrittenData), bufSize);
   1621    while (bufferSize.isValid() &&
   1622           bufferSize.value() < mWrittenData + bufSize) {
   1623      bufferSize *= 2;
   1624    }
   1625 
   1626    if (!bufferSize.isValid()) {
   1627      return false;
   1628    }
   1629 
   1630    void* buffer = realloc(mBuffer, bufferSize.value());
   1631    if (!buffer) {
   1632      return false;
   1633    }
   1634 
   1635    mBuffer = buffer;
   1636    mBufferSize = bufferSize.value();
   1637    return true;
   1638  }
   1639 
   1640  // All the members of this class are touched on the owning thread only. The
   1641  // monitor is only used to communicate when there is more data to read.
   1642  Monitor mMonitor MOZ_UNANNOTATED;
   1643 
   1644  nsCOMPtr<nsIInputStream> mInputStream;
   1645  nsCOMPtr<nsIAsyncInputStream> mAsyncInputStream;
   1646 
   1647  RefPtr<TaskQueue> mTaskQueue;
   1648 
   1649  void* mBuffer;
   1650  int64_t mCount;
   1651  uint64_t mWrittenData;
   1652 
   1653  enum {
   1654    // The buffer is allocated internally and this object must release it
   1655    // in the DTOR if not stolen. The buffer can be reallocated.
   1656    eInternal,
   1657 
   1658    // The buffer is not owned by this object and it cannot be reallocated.
   1659    eExternal,
   1660  } mBufferType;
   1661 
   1662  // The following set if needed for the async read.
   1663  uint64_t mBufferSize;
   1664 };
   1665 
   1666 NS_IMPL_ISUPPORTS(BufferWriter, nsIInputStreamCallback)
   1667 
   1668 }  // anonymous namespace
   1669 
   1670 nsresult NS_ReadInputStreamToBuffer(nsIInputStream* aInputStream, void** aDest,
   1671                                    int64_t aCount, uint64_t* aWritten) {
   1672  MOZ_ASSERT(aInputStream);
   1673  MOZ_ASSERT(aCount >= -1);
   1674 
   1675  uint64_t dummyWritten;
   1676  if (!aWritten) {
   1677    aWritten = &dummyWritten;
   1678  }
   1679 
   1680  if (aCount == 0) {
   1681    *aWritten = 0;
   1682    return NS_OK;
   1683  }
   1684 
   1685  // This will take care of allocating and reallocating aDest.
   1686  RefPtr<BufferWriter> writer = new BufferWriter(aInputStream, *aDest, aCount);
   1687 
   1688  nsresult rv = writer->Write();
   1689  NS_ENSURE_SUCCESS(rv, rv);
   1690 
   1691  *aWritten = writer->WrittenData();
   1692 
   1693  if (!*aDest) {
   1694    *aDest = writer->StealBuffer();
   1695  }
   1696 
   1697  return NS_OK;
   1698 }
   1699 
   1700 nsresult NS_ReadInputStreamToString(nsIInputStream* aInputStream,
   1701                                    nsACString& aDest, int64_t aCount,
   1702                                    uint64_t* aWritten) {
   1703  uint64_t dummyWritten;
   1704  if (!aWritten) {
   1705    aWritten = &dummyWritten;
   1706  }
   1707 
   1708  // Nothing to do if aCount is 0.
   1709  if (aCount == 0) {
   1710    aDest.Truncate();
   1711    *aWritten = 0;
   1712    return NS_OK;
   1713  }
   1714 
   1715  // If we have the size, we can pre-allocate the buffer.
   1716  if (aCount > 0) {
   1717    if (NS_WARN_IF(aCount >= INT32_MAX) ||
   1718        NS_WARN_IF(!aDest.SetLength(aCount, mozilla::fallible))) {
   1719      return NS_ERROR_OUT_OF_MEMORY;
   1720    }
   1721 
   1722    void* dest = aDest.BeginWriting();
   1723    nsresult rv =
   1724        NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten);
   1725    NS_ENSURE_SUCCESS(rv, rv);
   1726 
   1727    if ((uint64_t)aCount > *aWritten) {
   1728      aDest.Truncate(*aWritten);
   1729    }
   1730 
   1731    return NS_OK;
   1732  }
   1733 
   1734  // If the size is unknown, BufferWriter will allocate the buffer.
   1735  void* dest = nullptr;
   1736  nsresult rv =
   1737      NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten);
   1738  MOZ_ASSERT_IF(NS_FAILED(rv), dest == nullptr);
   1739  NS_ENSURE_SUCCESS(rv, rv);
   1740 
   1741  if (!dest) {
   1742    MOZ_ASSERT(*aWritten == 0);
   1743    aDest.Truncate();
   1744    return NS_OK;
   1745  }
   1746 
   1747  aDest.Adopt(reinterpret_cast<char*>(dest), *aWritten);
   1748  return NS_OK;
   1749 }
   1750 
   1751 nsresult NS_NewURI(nsIURI** result, const nsACString& spec,
   1752                   NotNull<const Encoding*> encoding,
   1753                   nsIURI* baseURI /* = nullptr */) {
   1754  nsAutoCString charset;
   1755  encoding->Name(charset);
   1756  return NS_NewURI(result, spec, charset.get(), baseURI);
   1757 }
   1758 
   1759 nsresult NS_NewURI(nsIURI** result, const nsAString& aSpec,
   1760                   const char* charset /* = nullptr */,
   1761                   nsIURI* baseURI /* = nullptr */) {
   1762  nsAutoCString spec;
   1763  if (!AppendUTF16toUTF8(aSpec, spec, mozilla::fallible)) {
   1764    return NS_ERROR_OUT_OF_MEMORY;
   1765  }
   1766  return NS_NewURI(result, spec, charset, baseURI);
   1767 }
   1768 
   1769 nsresult NS_NewURI(nsIURI** result, const nsAString& aSpec,
   1770                   NotNull<const Encoding*> encoding,
   1771                   nsIURI* baseURI /* = nullptr */) {
   1772  nsAutoCString spec;
   1773  if (!AppendUTF16toUTF8(aSpec, spec, mozilla::fallible)) {
   1774    return NS_ERROR_OUT_OF_MEMORY;
   1775  }
   1776  return NS_NewURI(result, spec, encoding, baseURI);
   1777 }
   1778 
   1779 nsresult NS_NewURI(nsIURI** result, const char* spec,
   1780                   nsIURI* baseURI /* = nullptr */) {
   1781  return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI);
   1782 }
   1783 
   1784 static nsresult NewStandardURI(const nsACString& aSpec, const char* aCharset,
   1785                               nsIURI* aBaseURI, int32_t aDefaultPort,
   1786                               nsIURI** aURI) {
   1787  return NS_MutateURI(new nsStandardURL::Mutator())
   1788      .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_AUTHORITY,
   1789             aDefaultPort, aSpec, aCharset, aBaseURI, nullptr)
   1790      .Finalize(aURI);
   1791 }
   1792 
   1793 nsresult NS_GetSpecWithNSURLEncoding(nsACString& aResult,
   1794                                     const nsACString& aSpec) {
   1795  nsCOMPtr<nsIURI> uri;
   1796  nsresult rv = NS_NewURIWithNSURLEncoding(getter_AddRefs(uri), aSpec);
   1797  NS_ENSURE_SUCCESS(rv, rv);
   1798  return uri->GetAsciiSpec(aResult);
   1799 }
   1800 
   1801 nsresult NS_NewURIWithNSURLEncoding(nsIURI** aResult, const nsACString& aSpec) {
   1802  nsCOMPtr<nsIURI> uri;
   1803  nsresult rv = NS_NewURI(getter_AddRefs(uri), aSpec);
   1804  NS_ENSURE_SUCCESS(rv, rv);
   1805 
   1806  // Escape the ref portion of the URL. NSURL is more strict about which
   1807  // characters in the URL must be % encoded. For example, an unescaped '#'
   1808  // to indicate the beginning of the ref component is accepted by NSURL, but
   1809  // '#' characters in the ref must be escaped. Also adds encoding for other
   1810  // characters not accepted by NSURL in the ref such as '{', '|', '}', and '^'.
   1811  // The ref returned from GetRef() does not include the leading '#'.
   1812  nsAutoCString ref, escapedRef;
   1813  if (NS_SUCCEEDED(uri->GetRef(ref)) && !ref.IsEmpty()) {
   1814    if (!NS_Escape(ref, escapedRef, url_NSURLRef)) {
   1815      return NS_ERROR_INVALID_ARG;
   1816    }
   1817    rv = NS_MutateURI(uri).SetRef(escapedRef).Finalize(uri);
   1818    NS_ENSURE_SUCCESS(rv, rv);
   1819  }
   1820 
   1821  uri.forget(aResult);
   1822  return NS_OK;
   1823 }
   1824 
   1825 extern MOZ_THREAD_LOCAL(uint32_t) gTlsURLRecursionCount;
   1826 
   1827 template <typename T>
   1828 class TlsAutoIncrement {
   1829 public:
   1830  explicit TlsAutoIncrement(T& var) : mVar(var) {
   1831    mValue = mVar.get();
   1832    mVar.set(mValue + 1);
   1833  }
   1834  ~TlsAutoIncrement() {
   1835    typename T::Type value = mVar.get();
   1836    MOZ_ASSERT(value == mValue + 1);
   1837    mVar.set(value - 1);
   1838  }
   1839 
   1840  typename T::Type value() { return mValue; }
   1841 
   1842 private:
   1843  typename T::Type mValue;
   1844  T& mVar;
   1845 };
   1846 
   1847 nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec,
   1848                   const char* aCharset /* = nullptr */,
   1849                   nsIURI* aBaseURI /* = nullptr */) {
   1850  // we don't expect any other processes than: socket, content or parent
   1851  // to be able to create a URL
   1852  MOZ_ASSERT(XRE_IsSocketProcess() || XRE_IsContentProcess() ||
   1853             XRE_IsParentProcess());
   1854  TlsAutoIncrement<decltype(gTlsURLRecursionCount)> inc(gTlsURLRecursionCount);
   1855  if (inc.value() >= MAX_RECURSION_COUNT) {
   1856    return NS_ERROR_MALFORMED_URI;
   1857  }
   1858 
   1859  nsCOMPtr<nsIIOService> ioService = do_GetIOService();
   1860  if (!ioService) {
   1861    // Individual protocol handlers unfortunately rely on the ioservice, let's
   1862    // return an error here instead of causing unpredictable crashes later.
   1863    return NS_ERROR_NOT_AVAILABLE;
   1864  }
   1865 
   1866  if (StaticPrefs::network_url_max_length() &&
   1867      aSpec.Length() > StaticPrefs::network_url_max_length()) {
   1868    return NS_ERROR_MALFORMED_URI;
   1869  }
   1870 
   1871  nsAutoCString scheme;
   1872  nsresult rv = net_ExtractURLScheme(aSpec, scheme);
   1873  if (NS_FAILED(rv)) {
   1874    // then aSpec is relative
   1875    if (!aBaseURI) {
   1876      return NS_ERROR_MALFORMED_URI;
   1877    }
   1878 
   1879    if (!aSpec.IsEmpty() && aSpec[0] == '#') {
   1880      // Looks like a reference instead of a fully-specified URI.
   1881      // --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
   1882      return NS_GetURIWithNewRef(aBaseURI, aSpec, aURI);
   1883    }
   1884 
   1885    rv = aBaseURI->GetScheme(scheme);
   1886    if (NS_FAILED(rv)) return rv;
   1887  }
   1888 
   1889  // If encoding is not UTF-8 and url is not special or url’s scheme is "ws" or
   1890  // "wss" then set encoding to UTF-8.
   1891  if (aCharset && !scheme.IsEmpty() &&
   1892      (scheme.EqualsLiteral("ws") || scheme.EqualsLiteral("wss") ||
   1893       !SchemeIsSpecial(scheme))) {
   1894    aCharset = "UTF-8";
   1895  }
   1896 
   1897  if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("ws")) {
   1898    return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT,
   1899                          aURI);
   1900  }
   1901  if (scheme.EqualsLiteral("https") || scheme.EqualsLiteral("wss")) {
   1902    return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT,
   1903                          aURI);
   1904  }
   1905  if (scheme.EqualsLiteral("ftp")) {
   1906    return NewStandardURI(aSpec, aCharset, aBaseURI, 21, aURI);
   1907  }
   1908 
   1909  if (scheme.EqualsLiteral("file")) {
   1910    return NS_MutateURI(new nsStandardURL::Mutator())
   1911        .Apply(&nsIFileURLMutator::MarkFileURL)
   1912        .Apply(&nsIStandardURLMutator::Init,
   1913               nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, aSpec, aCharset,
   1914               aBaseURI, nullptr)
   1915        .Finalize(aURI);
   1916  }
   1917 
   1918  if (scheme.EqualsLiteral("data")) {
   1919    return nsDataHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
   1920  }
   1921 
   1922  if (scheme.EqualsLiteral("moz-safe-about") ||
   1923      scheme.EqualsLiteral("page-icon") || scheme.EqualsLiteral("moz") ||
   1924      scheme.EqualsLiteral("cached-favicon")) {
   1925    return NS_MutateURI(new nsSimpleURI::Mutator())
   1926        .SetSpec(aSpec)
   1927        .Finalize(aURI);
   1928  }
   1929 
   1930  if (scheme.EqualsLiteral("chrome")) {
   1931    return nsChromeProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
   1932                                                 aURI);
   1933  }
   1934 
   1935  if (scheme.EqualsLiteral("javascript")) {
   1936    return nsJSProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
   1937  }
   1938 
   1939  if (scheme.EqualsLiteral("blob")) {
   1940    return BlobURLProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
   1941                                                aURI);
   1942  }
   1943 
   1944  if (scheme.EqualsLiteral("view-source")) {
   1945    return nsViewSourceHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
   1946  }
   1947 
   1948  if (scheme.EqualsLiteral("resource")) {
   1949    RefPtr<nsResProtocolHandler> handler = nsResProtocolHandler::GetSingleton();
   1950    if (!handler) {
   1951      return NS_ERROR_NOT_AVAILABLE;
   1952    }
   1953    return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
   1954  }
   1955 
   1956  if (scheme.EqualsLiteral("moz-src")) {
   1957    RefPtr<MozSrcProtocolHandler> handler =
   1958        MozSrcProtocolHandler::GetSingleton();
   1959    if (!handler) {
   1960      return NS_ERROR_NOT_AVAILABLE;
   1961    }
   1962    return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
   1963  }
   1964 
   1965  if (scheme.EqualsLiteral("indexeddb") || scheme.EqualsLiteral("uuid")) {
   1966    return NS_MutateURI(new nsStandardURL::Mutator())
   1967        .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_AUTHORITY,
   1968               0, aSpec, aCharset, aBaseURI, nullptr)
   1969        .Finalize(aURI);
   1970  }
   1971 
   1972  if (scheme.EqualsLiteral("moz-extension")) {
   1973    RefPtr<mozilla::net::ExtensionProtocolHandler> handler =
   1974        mozilla::net::ExtensionProtocolHandler::GetSingleton();
   1975    if (!handler) {
   1976      return NS_ERROR_NOT_AVAILABLE;
   1977    }
   1978    return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
   1979  }
   1980 
   1981  if (scheme.EqualsLiteral("moz-page-thumb")) {
   1982    // The moz-page-thumb service runs JS to resolve a URI to a
   1983    // storage location, so this should only ever run on the main
   1984    // thread.
   1985    if (!NS_IsMainThread()) {
   1986      return NS_ERROR_NOT_AVAILABLE;
   1987    }
   1988 
   1989    RefPtr<mozilla::net::PageThumbProtocolHandler> handler =
   1990        mozilla::net::PageThumbProtocolHandler::GetSingleton();
   1991    if (!handler) {
   1992      return NS_ERROR_NOT_AVAILABLE;
   1993    }
   1994    return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
   1995  }
   1996 
   1997  if (scheme.EqualsLiteral("moz-newtab-wallpaper")) {
   1998    RefPtr<mozilla::net::MozNewTabWallpaperProtocolHandler> handler =
   1999        mozilla::net::MozNewTabWallpaperProtocolHandler::GetSingleton();
   2000    if (!handler) {
   2001      return NS_ERROR_NOT_AVAILABLE;
   2002    }
   2003    return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
   2004  }
   2005 
   2006  if (scheme.EqualsLiteral("about")) {
   2007    return nsAboutProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
   2008                                                aURI);
   2009  }
   2010 
   2011  if (scheme.EqualsLiteral("jar")) {
   2012    return NS_MutateURI(new nsJARURI::Mutator())
   2013        .Apply(&nsIJARURIMutator::SetSpecBaseCharset, aSpec, aBaseURI, aCharset)
   2014        .Finalize(aURI);
   2015  }
   2016 
   2017 #ifndef XP_IOS
   2018  if (scheme.EqualsLiteral("moz-icon")) {
   2019    return NS_MutateURI(new nsMozIconURI::Mutator())
   2020        .SetSpec(aSpec)
   2021        .Finalize(aURI);
   2022  }
   2023 #endif
   2024 
   2025 #ifdef MOZ_WIDGET_GTK
   2026  if (scheme.EqualsLiteral("smb") || scheme.EqualsLiteral("sftp")) {
   2027    return NS_MutateURI(new nsStandardURL::Mutator())
   2028        .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_STANDARD,
   2029               -1, aSpec, aCharset, aBaseURI, nullptr)
   2030        .Finalize(aURI);
   2031  }
   2032 #endif
   2033 
   2034  if (scheme.EqualsLiteral("android")) {
   2035    return NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
   2036        .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_STANDARD,
   2037               -1, aSpec, aCharset, aBaseURI, nullptr)
   2038        .Finalize(aURI);
   2039  }
   2040 
   2041  // web-extensions can add custom protocol implementations with standard URLs
   2042  // that have notion of hostname, authority and relative URLs. Below we
   2043  // manually check agains set of known protocols schemes until more general
   2044  // solution is in place (See Bug 1569733)
   2045  if (!StaticPrefs::network_url_useDefaultURI()) {
   2046    if (scheme.EqualsLiteral("ssh")) {
   2047      return NewStandardURI(aSpec, aCharset, aBaseURI, 22, aURI);
   2048    }
   2049 
   2050    if (scheme.EqualsLiteral("dweb") || scheme.EqualsLiteral("dat") ||
   2051        scheme.EqualsLiteral("ipfs") || scheme.EqualsLiteral("ipns") ||
   2052        scheme.EqualsLiteral("ssb") || scheme.EqualsLiteral("wtp")) {
   2053      return NewStandardURI(aSpec, aCharset, aBaseURI, -1, aURI);
   2054    }
   2055  }
   2056 
   2057 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
   2058  rv = NS_NewMailnewsURI(aURI, aSpec, aCharset, aBaseURI);
   2059  if (rv != NS_ERROR_UNKNOWN_PROTOCOL) {
   2060    return rv;
   2061  }
   2062 #endif
   2063 
   2064  auto mustUseSimpleURI = [](const nsCString& scheme) -> bool {
   2065    if (!StaticPrefs::network_url_simple_uri_unknown_schemes_enabled()) {
   2066      return false;
   2067    }
   2068 
   2069    bool res = false;
   2070    RefPtr<nsIIOService> ios = do_GetIOService();
   2071    MOZ_ALWAYS_SUCCEEDS(ios->IsSimpleURIUnknownScheme(scheme, &res));
   2072    return res;
   2073  };
   2074 
   2075  if (aBaseURI) {
   2076    nsAutoCString newSpec;
   2077    rv = aBaseURI->Resolve(aSpec, newSpec);
   2078    NS_ENSURE_SUCCESS(rv, rv);
   2079 
   2080    nsAutoCString newScheme;
   2081    rv = net_ExtractURLScheme(newSpec, newScheme);
   2082    if (NS_SUCCEEDED(rv)) {
   2083      // The scheme shouldn't really change at this point.
   2084      MOZ_DIAGNOSTIC_ASSERT(newScheme == scheme);
   2085    }
   2086 
   2087    if (StaticPrefs::network_url_useDefaultURI()) {
   2088      if (mustUseSimpleURI(scheme)) {
   2089        return NS_MutateURI(new nsSimpleURI::Mutator())
   2090            .SetSpec(newSpec)
   2091            .Finalize(aURI);
   2092      }
   2093 
   2094      return NS_MutateURI(new DefaultURI::Mutator())
   2095          .SetSpec(newSpec)
   2096          .Finalize(aURI);
   2097    }
   2098 
   2099    return NS_MutateURI(new nsSimpleURI::Mutator())
   2100        .SetSpec(newSpec)
   2101        .Finalize(aURI);
   2102  }
   2103 
   2104  if (StaticPrefs::network_url_useDefaultURI()) {
   2105    if (mustUseSimpleURI(scheme)) {
   2106      return NS_MutateURI(new nsSimpleURI::Mutator())
   2107          .SetSpec(aSpec)
   2108          .Finalize(aURI);
   2109    }
   2110    return NS_MutateURI(new DefaultURI::Mutator())
   2111        .SetSpec(aSpec)
   2112        .Finalize(aURI);
   2113  }
   2114 
   2115  // Falls back to external protocol handler.
   2116  return NS_MutateURI(new nsSimpleURI::Mutator()).SetSpec(aSpec).Finalize(aURI);
   2117 }
   2118 
   2119 nsresult NS_GetSanitizedURIStringFromURI(nsIURI* aUri,
   2120                                         nsACString& aSanitizedSpec) {
   2121  aSanitizedSpec.Truncate();
   2122 
   2123  nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = do_QueryInterface(aUri);
   2124  nsAutoCString cSpec;
   2125  nsresult rv;
   2126  if (safeUri) {
   2127    rv = safeUri->GetSensitiveInfoHiddenSpec(cSpec);
   2128  } else {
   2129    rv = aUri->GetSpec(cSpec);
   2130  }
   2131 
   2132  if (NS_SUCCEEDED(rv)) {
   2133    aSanitizedSpec.Assign(cSpec);
   2134  }
   2135  return rv;
   2136 }
   2137 
   2138 nsresult NS_LoadPersistentPropertiesFromURISpec(
   2139    nsIPersistentProperties** outResult, const nsACString& aSpec) {
   2140  nsCOMPtr<nsIURI> uri;
   2141  nsresult rv = NS_NewURI(getter_AddRefs(uri), aSpec);
   2142  NS_ENSURE_SUCCESS(rv, rv);
   2143 
   2144  nsCOMPtr<nsIChannel> channel;
   2145  rv = NS_NewChannel(getter_AddRefs(channel), uri,
   2146                     nsContentUtils::GetSystemPrincipal(),
   2147                     nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
   2148                     nsIContentPolicy::TYPE_OTHER);
   2149  NS_ENSURE_SUCCESS(rv, rv);
   2150  nsCOMPtr<nsIInputStream> in;
   2151  rv = channel->Open(getter_AddRefs(in));
   2152  NS_ENSURE_SUCCESS(rv, rv);
   2153 
   2154  nsCOMPtr<nsIPersistentProperties> properties = new nsPersistentProperties();
   2155  rv = properties->Load(in);
   2156  NS_ENSURE_SUCCESS(rv, rv);
   2157 
   2158  properties.swap(*outResult);
   2159  return NS_OK;
   2160 }
   2161 
   2162 bool NS_UsePrivateBrowsing(nsIChannel* channel) {
   2163  OriginAttributes attrs;
   2164  bool result = StoragePrincipalHelper::GetOriginAttributes(
   2165      channel, attrs, StoragePrincipalHelper::eRegularPrincipal);
   2166  NS_ENSURE_TRUE(result, result);
   2167  return attrs.IsPrivateBrowsing();
   2168 }
   2169 
   2170 bool NS_HasBeenCrossOrigin(nsIChannel* aChannel, bool aReport) {
   2171  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   2172  // TYPE_DOCUMENT loads have a null LoadingPrincipal and can not be cross
   2173  // origin.
   2174  if (!loadInfo->GetLoadingPrincipal()) {
   2175    return false;
   2176  }
   2177 
   2178  // Always treat tainted channels as cross-origin.
   2179  if (loadInfo->GetTainting() != LoadTainting::Basic) {
   2180    return true;
   2181  }
   2182 
   2183  nsCOMPtr<nsIPrincipal> loadingPrincipal = loadInfo->GetLoadingPrincipal();
   2184  uint32_t mode = loadInfo->GetSecurityMode();
   2185  bool dataInherits =
   2186      mode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT ||
   2187      mode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT ||
   2188      mode == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
   2189 
   2190  bool aboutBlankInherits = dataInherits && loadInfo->GetAboutBlankInherits();
   2191 
   2192  uint64_t innerWindowID = loadInfo->GetInnerWindowID();
   2193 
   2194  for (nsIRedirectHistoryEntry* redirectHistoryEntry :
   2195       loadInfo->RedirectChain()) {
   2196    nsCOMPtr<nsIPrincipal> principal;
   2197    redirectHistoryEntry->GetPrincipal(getter_AddRefs(principal));
   2198    if (!principal) {
   2199      return true;
   2200    }
   2201 
   2202    nsCOMPtr<nsIURI> uri;
   2203    auto* basePrin = BasePrincipal::Cast(principal);
   2204    basePrin->GetURI(getter_AddRefs(uri));
   2205    if (!uri) {
   2206      return true;
   2207    }
   2208 
   2209    if (aboutBlankInherits && NS_IsAboutBlank(uri)) {
   2210      continue;
   2211    }
   2212 
   2213    nsresult res;
   2214    if (aReport) {
   2215      res = loadingPrincipal->CheckMayLoadWithReporting(uri, dataInherits,
   2216                                                        innerWindowID);
   2217    } else {
   2218      res = loadingPrincipal->CheckMayLoad(uri, dataInherits);
   2219    }
   2220    if (NS_FAILED(res)) {
   2221      return true;
   2222    }
   2223  }
   2224 
   2225  nsCOMPtr<nsIURI> uri;
   2226  NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   2227  if (!uri) {
   2228    return true;
   2229  }
   2230 
   2231  if (aboutBlankInherits && NS_IsAboutBlank(uri)) {
   2232    return false;
   2233  }
   2234 
   2235  nsresult res;
   2236  if (aReport) {
   2237    res = loadingPrincipal->CheckMayLoadWithReporting(uri, dataInherits,
   2238                                                      innerWindowID);
   2239  } else {
   2240    res = loadingPrincipal->CheckMayLoad(uri, dataInherits);
   2241  }
   2242 
   2243  return NS_FAILED(res);
   2244 }
   2245 
   2246 bool NS_IsSafeMethodNav(nsIChannel* aChannel) {
   2247  RefPtr<HttpBaseChannel> baseChan = do_QueryObject(aChannel);
   2248  if (!baseChan) {
   2249    return false;
   2250  }
   2251  nsHttpRequestHead* requestHead = baseChan->GetRequestHead();
   2252  if (!requestHead) {
   2253    return false;
   2254  }
   2255  return requestHead->IsSafeMethod();
   2256 }
   2257 
   2258 void NS_WrapAuthPrompt(nsIAuthPrompt* aAuthPrompt,
   2259                       nsIAuthPrompt2** aAuthPrompt2) {
   2260  nsCOMPtr<nsIAuthPromptAdapterFactory> factory;
   2261  factory = mozilla::components::AuthPromptAdapter::Service();
   2262  if (!factory) return;
   2263 
   2264  NS_WARNING("Using deprecated nsIAuthPrompt");
   2265  factory->CreateAdapter(aAuthPrompt, aAuthPrompt2);
   2266 }
   2267 
   2268 void NS_QueryAuthPrompt2(nsIInterfaceRequestor* aCallbacks,
   2269                         nsIAuthPrompt2** aAuthPrompt) {
   2270  CallGetInterface(aCallbacks, aAuthPrompt);
   2271  if (*aAuthPrompt) return;
   2272 
   2273  // Maybe only nsIAuthPrompt is provided and we have to wrap it.
   2274  nsCOMPtr<nsIAuthPrompt> prompt(do_GetInterface(aCallbacks));
   2275  if (!prompt) return;
   2276 
   2277  NS_WrapAuthPrompt(prompt, aAuthPrompt);
   2278 }
   2279 
   2280 void NS_QueryAuthPrompt2(nsIChannel* aChannel, nsIAuthPrompt2** aAuthPrompt) {
   2281  *aAuthPrompt = nullptr;
   2282 
   2283  // We want to use any auth prompt we can find on the channel's callbacks,
   2284  // and if that fails use the loadgroup's prompt (if any)
   2285  // Therefore, we can't just use NS_QueryNotificationCallbacks, because
   2286  // that would prefer a loadgroup's nsIAuthPrompt2 over a channel's
   2287  // nsIAuthPrompt.
   2288  nsCOMPtr<nsIInterfaceRequestor> callbacks;
   2289  aChannel->GetNotificationCallbacks(getter_AddRefs(callbacks));
   2290  if (callbacks) {
   2291    NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
   2292    if (*aAuthPrompt) return;
   2293  }
   2294 
   2295  nsCOMPtr<nsILoadGroup> group;
   2296  aChannel->GetLoadGroup(getter_AddRefs(group));
   2297  if (!group) return;
   2298 
   2299  group->GetNotificationCallbacks(getter_AddRefs(callbacks));
   2300  if (!callbacks) return;
   2301  NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
   2302 }
   2303 
   2304 nsresult NS_NewNotificationCallbacksAggregation(
   2305    nsIInterfaceRequestor* callbacks, nsILoadGroup* loadGroup,
   2306    nsIEventTarget* target, nsIInterfaceRequestor** result) {
   2307  nsCOMPtr<nsIInterfaceRequestor> cbs;
   2308  if (loadGroup) loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
   2309  return NS_NewInterfaceRequestorAggregation(callbacks, cbs, target, result);
   2310 }
   2311 
   2312 nsresult NS_NewNotificationCallbacksAggregation(
   2313    nsIInterfaceRequestor* callbacks, nsILoadGroup* loadGroup,
   2314    nsIInterfaceRequestor** result) {
   2315  return NS_NewNotificationCallbacksAggregation(callbacks, loadGroup, nullptr,
   2316                                                result);
   2317 }
   2318 
   2319 nsresult NS_DoImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result) {
   2320  MOZ_ASSERT(nestedURI, "Must have a nested URI!");
   2321  MOZ_ASSERT(!*result, "Must have null *result");
   2322 
   2323  nsCOMPtr<nsIURI> inner;
   2324  nsresult rv = nestedURI->GetInnerURI(getter_AddRefs(inner));
   2325  NS_ENSURE_SUCCESS(rv, rv);
   2326 
   2327  // We may need to loop here until we reach the innermost
   2328  // URI.
   2329  nsCOMPtr<nsINestedURI> nestedInner(do_QueryInterface(inner));
   2330  while (nestedInner) {
   2331    rv = nestedInner->GetInnerURI(getter_AddRefs(inner));
   2332    NS_ENSURE_SUCCESS(rv, rv);
   2333    nestedInner = do_QueryInterface(inner);
   2334  }
   2335 
   2336  // Found the innermost one if we reach here.
   2337  inner.swap(*result);
   2338 
   2339  return rv;
   2340 }
   2341 
   2342 nsresult NS_ImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result) {
   2343  // Make it safe to use swap()
   2344  *result = nullptr;
   2345 
   2346  return NS_DoImplGetInnermostURI(nestedURI, result);
   2347 }
   2348 
   2349 already_AddRefed<nsIURI> NS_GetInnermostURI(nsIURI* aURI) {
   2350  MOZ_ASSERT(aURI, "Must have URI");
   2351 
   2352  nsCOMPtr<nsIURI> uri = aURI;
   2353 
   2354  nsCOMPtr<nsINestedURI> nestedURI(do_QueryInterface(uri));
   2355  if (!nestedURI) {
   2356    return uri.forget();
   2357  }
   2358 
   2359  nsresult rv = nestedURI->GetInnermostURI(getter_AddRefs(uri));
   2360  if (NS_FAILED(rv)) {
   2361    return nullptr;
   2362  }
   2363 
   2364  return uri.forget();
   2365 }
   2366 
   2367 nsresult NS_GetFinalChannelURI(nsIChannel* channel, nsIURI** uri) {
   2368  *uri = nullptr;
   2369 
   2370  nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
   2371  nsCOMPtr<nsIURI> resultPrincipalURI;
   2372  loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
   2373  if (resultPrincipalURI) {
   2374    resultPrincipalURI.forget(uri);
   2375    return NS_OK;
   2376  }
   2377  return channel->GetOriginalURI(uri);
   2378 }
   2379 
   2380 nsresult NS_URIChainHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
   2381  nsresult rv;
   2382  nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
   2383  NS_ENSURE_SUCCESS(rv, rv);
   2384 
   2385  return util->URIChainHasFlags(uri, flags, result);
   2386 }
   2387 
   2388 uint32_t NS_SecurityHashURI(nsIURI* aURI) {
   2389  nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
   2390 
   2391  nsAutoCString scheme;
   2392  uint32_t schemeHash = 0;
   2393  if (NS_SUCCEEDED(baseURI->GetScheme(scheme))) {
   2394    schemeHash = mozilla::HashString(scheme);
   2395  }
   2396 
   2397  // TODO figure out how to hash file:// URIs
   2398  if (scheme.EqualsLiteral("file")) return schemeHash;  // sad face
   2399 
   2400 #if IS_ORIGIN_IS_FULL_SPEC_DEFINED
   2401  bool hasFlag;
   2402  if (NS_FAILED(NS_URIChainHasFlags(
   2403          baseURI, nsIProtocolHandler::ORIGIN_IS_FULL_SPEC, &hasFlag)) ||
   2404      hasFlag) {
   2405    nsAutoCString spec;
   2406    uint32_t specHash;
   2407    nsresult res = baseURI->GetSpec(spec);
   2408    if (NS_SUCCEEDED(res))
   2409      specHash = mozilla::HashString(spec);
   2410    else
   2411      specHash = static_cast<uint32_t>(res);
   2412    return specHash;
   2413  }
   2414 #endif
   2415 
   2416  nsAutoCString host;
   2417  uint32_t hostHash = 0;
   2418  if (NS_SUCCEEDED(baseURI->GetAsciiHost(host))) {
   2419    hostHash = mozilla::HashString(host);
   2420  }
   2421 
   2422  return mozilla::AddToHash(schemeHash, hostHash, NS_GetRealPort(baseURI));
   2423 }
   2424 
   2425 bool NS_SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI,
   2426                            bool aStrictFileOriginPolicy) {
   2427  nsresult rv;
   2428 
   2429  // Note that this is not an Equals() test on purpose -- for URIs that don't
   2430  // support host/port, we want equality to basically be object identity, for
   2431  // security purposes.  Otherwise, for example, two javascript: URIs that
   2432  // are otherwise unrelated could end up "same origin", which would be
   2433  // unfortunate.
   2434  if (aSourceURI && aSourceURI == aTargetURI) {
   2435    return true;
   2436  }
   2437 
   2438  if (!aTargetURI || !aSourceURI) {
   2439    return false;
   2440  }
   2441 
   2442  // If either URI is a nested URI, get the base URI
   2443  nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI);
   2444  nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
   2445 
   2446 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
   2447  // Check if either URI has a special origin.
   2448  nsCOMPtr<nsIURI> origin;
   2449  nsCOMPtr<nsIURIWithSpecialOrigin> uriWithSpecialOrigin =
   2450      do_QueryInterface(sourceBaseURI);
   2451  if (uriWithSpecialOrigin) {
   2452    rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin));
   2453    if (NS_WARN_IF(NS_FAILED(rv))) {
   2454      return false;
   2455    }
   2456    MOZ_ASSERT(origin);
   2457    sourceBaseURI = origin;
   2458  }
   2459  uriWithSpecialOrigin = do_QueryInterface(targetBaseURI);
   2460  if (uriWithSpecialOrigin) {
   2461    rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin));
   2462    if (NS_WARN_IF(NS_FAILED(rv))) {
   2463      return false;
   2464    }
   2465    MOZ_ASSERT(origin);
   2466    targetBaseURI = origin;
   2467  }
   2468 #endif
   2469 
   2470  nsCOMPtr<nsIPrincipal> sourceBlobPrincipal;
   2471  if (BlobURLProtocolHandler::GetBlobURLPrincipal(
   2472          sourceBaseURI, getter_AddRefs(sourceBlobPrincipal))) {
   2473    nsCOMPtr<nsIURI> sourceBlobOwnerURI;
   2474    auto* basePrin = BasePrincipal::Cast(sourceBlobPrincipal);
   2475    rv = basePrin->GetURI(getter_AddRefs(sourceBlobOwnerURI));
   2476    if (NS_SUCCEEDED(rv)) {
   2477      sourceBaseURI = sourceBlobOwnerURI;
   2478    }
   2479  }
   2480 
   2481  nsCOMPtr<nsIPrincipal> targetBlobPrincipal;
   2482  if (BlobURLProtocolHandler::GetBlobURLPrincipal(
   2483          targetBaseURI, getter_AddRefs(targetBlobPrincipal))) {
   2484    nsCOMPtr<nsIURI> targetBlobOwnerURI;
   2485    auto* basePrin = BasePrincipal::Cast(targetBlobPrincipal);
   2486    rv = basePrin->GetURI(getter_AddRefs(targetBlobOwnerURI));
   2487    if (NS_SUCCEEDED(rv)) {
   2488      targetBaseURI = targetBlobOwnerURI;
   2489    }
   2490  }
   2491 
   2492  if (!sourceBaseURI || !targetBaseURI) return false;
   2493 
   2494  // Compare schemes
   2495  nsAutoCString targetScheme;
   2496  bool sameScheme = false;
   2497  if (NS_FAILED(targetBaseURI->GetScheme(targetScheme)) ||
   2498      NS_FAILED(sourceBaseURI->SchemeIs(targetScheme.get(), &sameScheme)) ||
   2499      !sameScheme) {
   2500    // Not same-origin if schemes differ
   2501    return false;
   2502  }
   2503 
   2504  // For file scheme, reject unless the files are identical.
   2505  if (targetScheme.EqualsLiteral("file")) {
   2506    // in traditional unsafe behavior all files are the same origin
   2507    if (!aStrictFileOriginPolicy) return true;
   2508 
   2509    nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(sourceBaseURI));
   2510    nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(targetBaseURI));
   2511 
   2512    if (!sourceFileURL || !targetFileURL) return false;
   2513 
   2514    nsCOMPtr<nsIFile> sourceFile, targetFile;
   2515 
   2516    sourceFileURL->GetFile(getter_AddRefs(sourceFile));
   2517    targetFileURL->GetFile(getter_AddRefs(targetFile));
   2518 
   2519    if (!sourceFile || !targetFile) return false;
   2520 
   2521    // Otherwise they had better match
   2522    bool filesAreEqual = false;
   2523    rv = sourceFile->Equals(targetFile, &filesAreEqual);
   2524    return NS_SUCCEEDED(rv) && filesAreEqual;
   2525  }
   2526 
   2527 #if IS_ORIGIN_IS_FULL_SPEC_DEFINED
   2528  bool hasFlag;
   2529  if (NS_FAILED(NS_URIChainHasFlags(
   2530          targetBaseURI, nsIProtocolHandler::ORIGIN_IS_FULL_SPEC, &hasFlag)) ||
   2531      hasFlag) {
   2532    // URIs with this flag have the whole spec as a distinct trust
   2533    // domain; use the whole spec for comparison
   2534    nsAutoCString targetSpec;
   2535    nsAutoCString sourceSpec;
   2536    return (NS_SUCCEEDED(targetBaseURI->GetSpec(targetSpec)) &&
   2537            NS_SUCCEEDED(sourceBaseURI->GetSpec(sourceSpec)) &&
   2538            targetSpec.Equals(sourceSpec));
   2539  }
   2540 #endif
   2541 
   2542  // Compare hosts
   2543  nsAutoCString targetHost;
   2544  nsAutoCString sourceHost;
   2545  if (NS_FAILED(targetBaseURI->GetAsciiHost(targetHost)) ||
   2546      NS_FAILED(sourceBaseURI->GetAsciiHost(sourceHost))) {
   2547    return false;
   2548  }
   2549 
   2550  nsCOMPtr<nsIStandardURL> targetURL(do_QueryInterface(targetBaseURI));
   2551  nsCOMPtr<nsIStandardURL> sourceURL(do_QueryInterface(sourceBaseURI));
   2552  if (!targetURL || !sourceURL) {
   2553    return false;
   2554  }
   2555 
   2556  if (!targetHost.Equals(sourceHost, nsCaseInsensitiveCStringComparator)) {
   2557    return false;
   2558  }
   2559 
   2560  return NS_GetRealPort(targetBaseURI) == NS_GetRealPort(sourceBaseURI);
   2561 }
   2562 
   2563 bool NS_URIIsLocalFile(nsIURI* aURI) {
   2564  nsCOMPtr<nsINetUtil> util = do_GetNetUtil();
   2565 
   2566  bool isFile;
   2567  return util &&
   2568         NS_SUCCEEDED(util->ProtocolHasFlags(
   2569             aURI, nsIProtocolHandler::URI_IS_LOCAL_FILE, &isFile)) &&
   2570         isFile;
   2571 }
   2572 
   2573 bool NS_IsInternalSameURIRedirect(nsIChannel* aOldChannel,
   2574                                  nsIChannel* aNewChannel, uint32_t aFlags) {
   2575  if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
   2576    return false;
   2577  }
   2578 
   2579  nsCOMPtr<nsIURI> oldURI, newURI;
   2580  aOldChannel->GetURI(getter_AddRefs(oldURI));
   2581  aNewChannel->GetURI(getter_AddRefs(newURI));
   2582 
   2583  if (!oldURI || !newURI) {
   2584    return false;
   2585  }
   2586 
   2587  bool res;
   2588  return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res;
   2589 }
   2590 
   2591 bool NS_IsHSTSUpgradeRedirect(nsIChannel* aOldChannel, nsIChannel* aNewChannel,
   2592                              uint32_t aFlags) {
   2593  if (!(aFlags & nsIChannelEventSink::REDIRECT_STS_UPGRADE)) {
   2594    return false;
   2595  }
   2596 
   2597  nsCOMPtr<nsIURI> oldURI, newURI;
   2598  aOldChannel->GetURI(getter_AddRefs(oldURI));
   2599  aNewChannel->GetURI(getter_AddRefs(newURI));
   2600 
   2601  if (!oldURI || !newURI) {
   2602    return false;
   2603  }
   2604 
   2605  if (!oldURI->SchemeIs("http")) {
   2606    return false;
   2607  }
   2608 
   2609  nsCOMPtr<nsIURI> upgradedURI;
   2610  nsresult rv = NS_GetSecureUpgradedURI(oldURI, getter_AddRefs(upgradedURI));
   2611  if (NS_FAILED(rv)) {
   2612    return false;
   2613  }
   2614 
   2615  bool res;
   2616  return NS_SUCCEEDED(upgradedURI->Equals(newURI, &res)) && res;
   2617 }
   2618 
   2619 bool NS_ShouldRemoveAuthHeaderOnRedirect(nsIChannel* aOldChannel,
   2620                                         nsIChannel* aNewChannel,
   2621                                         uint32_t aFlags) {
   2622  // we need to strip Authentication headers for external cross-origin redirects
   2623  // Howerver, we should NOT strip auth headers for
   2624  // - internal redirects/HSTS upgrades
   2625  // - same origin redirects
   2626  // Ref: https://fetch.spec.whatwg.org/#http-redirect-fetch
   2627  if ((aFlags & (nsIChannelEventSink::REDIRECT_STS_UPGRADE |
   2628                 nsIChannelEventSink::REDIRECT_INTERNAL))) {
   2629    // this is an internal redirect do not strip auth header
   2630    return false;
   2631  }
   2632  nsCOMPtr<nsIURI> oldUri;
   2633  MOZ_ALWAYS_SUCCEEDS(
   2634      NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldUri)));
   2635 
   2636  nsCOMPtr<nsIURI> newUri;
   2637  MOZ_ALWAYS_SUCCEEDS(
   2638      NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newUri)));
   2639 
   2640  nsresult rv = nsContentUtils::GetSecurityManager()->CheckSameOriginURI(
   2641      newUri, oldUri, false, false);
   2642 
   2643  return NS_FAILED(rv);
   2644 }
   2645 
   2646 nsresult NS_LinkRedirectChannels(uint64_t channelId,
   2647                                 nsIParentChannel* parentChannel,
   2648                                 nsIChannel** _result) {
   2649  nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
   2650      RedirectChannelRegistrar::GetOrCreate();
   2651  MOZ_ASSERT(registrar);
   2652 
   2653  return registrar->LinkChannels(channelId, parentChannel, _result);
   2654 }
   2655 
   2656 nsILoadInfo::CrossOriginEmbedderPolicy
   2657 NS_GetCrossOriginEmbedderPolicyFromHeader(
   2658    const nsACString& aHeader, bool aIsOriginTrialCoepCredentiallessEnabled) {
   2659  nsCOMPtr<nsISFVService> sfv = GetSFVService();
   2660 
   2661  nsCOMPtr<nsISFVItem> item;
   2662  nsresult rv = sfv->ParseItem(aHeader, getter_AddRefs(item));
   2663  if (NS_FAILED(rv)) {
   2664    return nsILoadInfo::EMBEDDER_POLICY_NULL;
   2665  }
   2666 
   2667  nsCOMPtr<nsISFVBareItem> value;
   2668  rv = item->GetValue(getter_AddRefs(value));
   2669  if (NS_FAILED(rv)) {
   2670    return nsILoadInfo::EMBEDDER_POLICY_NULL;
   2671  }
   2672 
   2673  nsCOMPtr<nsISFVToken> token = do_QueryInterface(value);
   2674  if (!token) {
   2675    return nsILoadInfo::EMBEDDER_POLICY_NULL;
   2676  }
   2677 
   2678  nsAutoCString embedderPolicy;
   2679  rv = token->GetValue(embedderPolicy);
   2680  if (NS_FAILED(rv)) {
   2681    return nsILoadInfo::EMBEDDER_POLICY_NULL;
   2682  }
   2683 
   2684  if (embedderPolicy.EqualsLiteral("require-corp")) {
   2685    return nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP;
   2686  } else if (embedderPolicy.EqualsLiteral("credentialless") &&
   2687             IsCoepCredentiallessEnabled(
   2688                 aIsOriginTrialCoepCredentiallessEnabled)) {
   2689    return nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS;
   2690  }
   2691 
   2692  return nsILoadInfo::EMBEDDER_POLICY_NULL;
   2693 }
   2694 
   2695 bool NS_GetForceLoadAtTopFromHeader(const nsACString& aHeader) {
   2696  nsCOMPtr<nsISFVService> sfv = mozilla::net::GetSFVService();
   2697 
   2698  nsCOMPtr<nsISFVDictionary> dict;
   2699  if (NS_FAILED(sfv->ParseDictionary(aHeader, getter_AddRefs(dict)))) {
   2700    return false;
   2701  }
   2702  nsCOMPtr<nsISFVItemOrInnerList> iil;
   2703  if (NS_FAILED(dict->Get("force-load-at-top"_ns, getter_AddRefs(iil)))) {
   2704    return false;
   2705  }
   2706 
   2707  nsCOMPtr<nsISFVItem> item(do_QueryInterface(iil));
   2708  if (!item) {
   2709    return false;
   2710  }
   2711 
   2712  nsCOMPtr<nsISFVBareItem> bareItem;
   2713  if (NS_FAILED(item->GetValue(getter_AddRefs(bareItem)))) {
   2714    return false;
   2715  }
   2716 
   2717  int32_t type;
   2718  if (NS_FAILED(bareItem->GetType(&type))) {
   2719    return false;
   2720  }
   2721 
   2722  nsCOMPtr<nsISFVBool> boolItem(do_QueryInterface(bareItem));
   2723  if (!boolItem) {
   2724    return false;
   2725  }
   2726 
   2727  bool b;
   2728  if (NS_FAILED(boolItem->GetValue(&b))) {
   2729    return false;
   2730  }
   2731 
   2732  return b;
   2733 }
   2734 
   2735 /** Given the first (disposition) token from a Content-Disposition header,
   2736 * tell whether it indicates the content is inline or attachment
   2737 * @param aDispToken the disposition token from the content-disposition header
   2738 */
   2739 uint32_t NS_GetContentDispositionFromToken(const nsAString& aDispToken) {
   2740  // RFC 2183, section 2.8 says that an unknown disposition
   2741  // value should be treated as "attachment"
   2742  // If all of these tests eval to false, then we have a content-disposition of
   2743  // "attachment" or unknown
   2744  if (aDispToken.IsEmpty() || aDispToken.LowerCaseEqualsLiteral("inline") ||
   2745      // Broken sites just send
   2746      // Content-Disposition: filename="file"
   2747      // without a disposition token... screen those out.
   2748      StringHead(aDispToken, 8).LowerCaseEqualsLiteral("filename")) {
   2749    return nsIChannel::DISPOSITION_INLINE;
   2750  }
   2751 
   2752  return nsIChannel::DISPOSITION_ATTACHMENT;
   2753 }
   2754 
   2755 uint32_t NS_GetContentDispositionFromHeader(const nsACString& aHeader,
   2756                                            nsIChannel* aChan /* = nullptr */) {
   2757  nsresult rv;
   2758  nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar;
   2759  mimehdrpar = mozilla::components::MimeHeaderParam::Service(&rv);
   2760  if (NS_FAILED(rv)) return nsIChannel::DISPOSITION_ATTACHMENT;
   2761 
   2762  nsAutoString dispToken;
   2763  rv = mimehdrpar->GetParameterHTTP(aHeader, "", ""_ns, true, nullptr,
   2764                                    dispToken);
   2765 
   2766  if (NS_FAILED(rv)) {
   2767    // special case (see bug 272541): empty disposition type handled as "inline"
   2768    if (rv == NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY) {
   2769      return nsIChannel::DISPOSITION_INLINE;
   2770    }
   2771    return nsIChannel::DISPOSITION_ATTACHMENT;
   2772  }
   2773 
   2774  return NS_GetContentDispositionFromToken(dispToken);
   2775 }
   2776 
   2777 nsresult NS_GetFilenameFromDisposition(nsAString& aFilename,
   2778                                       const nsACString& aDisposition) {
   2779  aFilename.Truncate();
   2780 
   2781  nsresult rv;
   2782  nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar;
   2783  mimehdrpar = mozilla::components::MimeHeaderParam::Service(&rv);
   2784  if (NS_FAILED(rv)) return rv;
   2785 
   2786  // Get the value of 'filename' parameter
   2787  rv = mimehdrpar->GetParameterHTTP(aDisposition, "filename", ""_ns, true,
   2788                                    nullptr, aFilename);
   2789 
   2790  if (NS_FAILED(rv)) {
   2791    aFilename.Truncate();
   2792    return rv;
   2793  }
   2794 
   2795  if (aFilename.IsEmpty()) return NS_ERROR_NOT_AVAILABLE;
   2796 
   2797  // Filename may still be percent-encoded. Fix:
   2798  if (aFilename.FindChar('%') != -1) {
   2799    nsCOMPtr<nsITextToSubURI> textToSubURI;
   2800    textToSubURI = mozilla::components::TextToSubURI::Service(&rv);
   2801    if (NS_SUCCEEDED(rv)) {
   2802      nsAutoString unescaped;
   2803      textToSubURI->UnEscapeURIForUI(NS_ConvertUTF16toUTF8(aFilename),
   2804                                     /* dontEscape = */ true, unescaped);
   2805      aFilename.Assign(unescaped);
   2806    }
   2807  }
   2808 
   2809  return NS_OK;
   2810 }
   2811 
   2812 void net_EnsurePSMInit() {
   2813  if (XRE_IsSocketProcess()) {
   2814    EnsureNSSInitializedChromeOrContent();
   2815    return;
   2816  }
   2817 
   2818  MOZ_ASSERT(XRE_IsParentProcess());
   2819  MOZ_ASSERT(NS_IsMainThread());
   2820 
   2821  DebugOnly<bool> rv = EnsureNSSInitializedChromeOrContent();
   2822  MOZ_ASSERT(rv);
   2823 }
   2824 
   2825 bool NS_IsAboutBlank(nsIURI* uri) {
   2826  // GetSpec can be expensive for some URIs, so check the scheme first.
   2827  if (!uri->SchemeIs("about")) {
   2828    return false;
   2829  }
   2830 
   2831  nsAutoCString spec;
   2832  if (NS_FAILED(uri->GetSpec(spec))) {
   2833    return false;
   2834  }
   2835 
   2836  return spec.EqualsLiteral("about:blank");
   2837 }
   2838 
   2839 bool NS_IsAboutBlankAllowQueryAndFragment(nsIURI* uri) {
   2840  // GetSpec can be expensive for some URIs, so check the scheme first.
   2841  if (!uri->SchemeIs("about")) {
   2842    return false;
   2843  }
   2844 
   2845  nsAutoCString name;
   2846  if (NS_FAILED(NS_GetAboutModuleName(uri, name))) {
   2847    return false;
   2848  }
   2849 
   2850  return name.EqualsLiteral("blank");
   2851 }
   2852 
   2853 bool NS_IsAboutSrcdoc(nsIURI* uri) {
   2854  // GetSpec can be expensive for some URIs, so check the scheme first.
   2855  if (!uri->SchemeIs("about")) {
   2856    return false;
   2857  }
   2858 
   2859  nsAutoCString spec;
   2860  if (NS_FAILED(uri->GetSpec(spec))) {
   2861    return false;
   2862  }
   2863 
   2864  return spec.EqualsLiteral("about:srcdoc");
   2865 }
   2866 
   2867 // https://fetch.spec.whatwg.org/#fetch-scheme
   2868 bool NS_IsFetchScheme(nsIURI* uri) {
   2869  for (const auto& scheme : {
   2870           "http",
   2871           "https",
   2872           "about",
   2873           "blob",
   2874           "data",
   2875           "file",
   2876       }) {
   2877    if (uri->SchemeIs(scheme)) {
   2878      return true;
   2879    }
   2880  }
   2881 
   2882  return false;
   2883 }
   2884 
   2885 nsresult NS_GenerateHostPort(const nsCString& host, int32_t port,
   2886                             nsACString& hostLine) {
   2887  if (strchr(host.get(), ':')) {
   2888    // host is an IPv6 address literal and must be encapsulated in []'s
   2889    hostLine.Assign('[');
   2890    // scope id is not needed for Host header.
   2891    int scopeIdPos = host.FindChar('%');
   2892    if (scopeIdPos == -1) {
   2893      hostLine.Append(host);
   2894    } else if (scopeIdPos > 0) {
   2895      hostLine.Append(Substring(host, 0, scopeIdPos));
   2896    } else {
   2897      return NS_ERROR_MALFORMED_URI;
   2898    }
   2899    hostLine.Append(']');
   2900  } else {
   2901    hostLine.Assign(host);
   2902  }
   2903  if (port != -1) {
   2904    hostLine.Append(':');
   2905    hostLine.AppendInt(port);
   2906  }
   2907  return NS_OK;
   2908 }
   2909 
   2910 void NS_SniffContent(const char* aSnifferType, nsIRequest* aRequest,
   2911                     const uint8_t* aData, uint32_t aLength,
   2912                     nsACString& aSniffedType) {
   2913  using ContentSnifferCache = nsCategoryCache<nsIContentSniffer>;
   2914  extern ContentSnifferCache* gNetSniffers;
   2915  extern ContentSnifferCache* gDataSniffers;
   2916  extern ContentSnifferCache* gORBSniffers;
   2917  extern ContentSnifferCache* gNetAndORBSniffers;
   2918  ContentSnifferCache* cache = nullptr;
   2919  if (!strcmp(aSnifferType, NS_CONTENT_SNIFFER_CATEGORY)) {
   2920    if (!gNetSniffers) {
   2921      gNetSniffers = new ContentSnifferCache(NS_CONTENT_SNIFFER_CATEGORY);
   2922    }
   2923    cache = gNetSniffers;
   2924  } else if (!strcmp(aSnifferType, NS_DATA_SNIFFER_CATEGORY)) {
   2925    if (!gDataSniffers) {
   2926      gDataSniffers = new ContentSnifferCache(NS_DATA_SNIFFER_CATEGORY);
   2927    }
   2928    cache = gDataSniffers;
   2929  } else if (!strcmp(aSnifferType, NS_ORB_SNIFFER_CATEGORY)) {
   2930    if (!gORBSniffers) {
   2931      gORBSniffers = new ContentSnifferCache(NS_ORB_SNIFFER_CATEGORY);
   2932    }
   2933    cache = gORBSniffers;
   2934  } else if (!strcmp(aSnifferType, NS_CONTENT_AND_ORB_SNIFFER_CATEGORY)) {
   2935    if (!gNetAndORBSniffers) {
   2936      gNetAndORBSniffers =
   2937          new ContentSnifferCache(NS_CONTENT_AND_ORB_SNIFFER_CATEGORY);
   2938    }
   2939    cache = gNetAndORBSniffers;
   2940  } else {
   2941    // Invalid content sniffer type was requested
   2942    MOZ_ASSERT(false);
   2943    return;
   2944  }
   2945 
   2946  // In case XCTO nosniff was present, we could just skip sniffing here
   2947  nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
   2948  if (channel) {
   2949    nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
   2950    if (loadInfo->GetSkipContentSniffing()) {
   2951      /* Bug 1571742
   2952       * We cannot skip snffing if the current MIME-Type might be a JSON.
   2953       * The JSON-Viewer relies on its own sniffer to determine, if it can
   2954       * render the page, so we need to make an exception if the Server provides
   2955       * a application/ mime, as it might be json.
   2956       */
   2957      nsAutoCString currentContentType;
   2958      channel->GetContentType(currentContentType);
   2959      if (!StringBeginsWith(currentContentType, "application/"_ns)) {
   2960        return;
   2961      }
   2962    }
   2963  }
   2964  nsCOMArray<nsIContentSniffer> sniffers;
   2965  cache->GetEntries(sniffers);
   2966  for (int32_t i = 0; i < sniffers.Count(); ++i) {
   2967    nsresult rv = sniffers[i]->GetMIMETypeFromContent(aRequest, aData, aLength,
   2968                                                      aSniffedType);
   2969    if (NS_SUCCEEDED(rv) && !aSniffedType.IsEmpty()) {
   2970      return;
   2971    }
   2972  }
   2973 
   2974  aSniffedType.Truncate();
   2975 }
   2976 
   2977 bool NS_IsSrcdocChannel(nsIChannel* aChannel) {
   2978  bool isSrcdoc;
   2979  nsCOMPtr<nsIInputStreamChannel> isr = do_QueryInterface(aChannel);
   2980  if (isr) {
   2981    isr->GetIsSrcdocChannel(&isSrcdoc);
   2982    return isSrcdoc;
   2983  }
   2984  nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(aChannel);
   2985  if (vsc) {
   2986    nsresult rv = vsc->GetIsSrcdocChannel(&isSrcdoc);
   2987    if (NS_SUCCEEDED(rv)) {
   2988      return isSrcdoc;
   2989    }
   2990  }
   2991  return false;
   2992 }
   2993 
   2994 // helper function for NS_ShouldSecureUpgrade for checking HSTS
   2995 bool handleResultFunc(bool aAllowSTS, bool aIsStsHost) {
   2996  if (aIsStsHost) {
   2997    LOG(("nsHttpChannel::Connect() STS permissions found\n"));
   2998    if (aAllowSTS) {
   2999      return true;
   3000    }
   3001  }
   3002  return false;
   3003 };
   3004 // That function is a helper function of NS_ShouldSecureUpgrade to check if
   3005 // CSP upgrade-insecure-requests, Mixed content auto upgrading or HTTPs-Only/-
   3006 // First should upgrade the given request.
   3007 static bool ShouldSecureUpgradeNoHSTS(nsIURI* aURI, nsILoadInfo* aLoadInfo) {
   3008  // 2. CSP upgrade-insecure-requests
   3009  if (aLoadInfo->GetUpgradeInsecureRequests()) {
   3010    // let's log a message to the console that we are upgrading a request
   3011    nsAutoCString scheme;
   3012    aURI->GetScheme(scheme);
   3013    // append the additional 's' for security to the scheme :-)
   3014    scheme.AppendLiteral("s");
   3015    NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
   3016    NS_ConvertUTF8toUTF16 reportScheme(scheme);
   3017    AutoTArray<nsString, 2> params = {reportSpec, reportScheme};
   3018    uint64_t innerWindowId = aLoadInfo->GetInnerWindowID();
   3019    CSP_LogLocalizedStr("upgradeInsecureRequest", params,
   3020                        ""_ns,   // aSourceFile
   3021                        u""_ns,  // aScriptSample
   3022                        0,       // aLineNumber
   3023                        1,       // aColumnNumber
   3024                        nsIScriptError::warningFlag,
   3025                        "upgradeInsecureRequest"_ns, innerWindowId,
   3026                        aLoadInfo->GetOriginAttributes().IsPrivateBrowsing());
   3027    aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::CSP_UIR);
   3028    return true;
   3029  }
   3030  // 3. Mixed content auto upgrading
   3031  if (aLoadInfo->GetBrowserUpgradeInsecureRequests()) {
   3032    // let's log a message to the console that we are upgrading a request
   3033    nsAutoCString scheme;
   3034    aURI->GetScheme(scheme);
   3035    // append the additional 's' for security to the scheme :-)
   3036    scheme.AppendLiteral("s");
   3037    NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
   3038    NS_ConvertUTF8toUTF16 reportScheme(scheme);
   3039    AutoTArray<nsString, 2> params = {reportSpec, reportScheme};
   3040 
   3041    nsAutoString localizedMsg;
   3042    nsContentUtils::FormatLocalizedString(nsContentUtils::eSECURITY_PROPERTIES,
   3043                                          "MixedContentAutoUpgrade", params,
   3044                                          localizedMsg);
   3045 
   3046    // Prepending ixed Content to the outgoing console message
   3047    nsString message;
   3048    message.AppendLiteral(u"Mixed Content: ");
   3049    message.Append(localizedMsg);
   3050 
   3051    uint64_t innerWindowId = aLoadInfo->GetInnerWindowID();
   3052    nsContentUtils::ReportToConsoleByWindowID(
   3053        message, nsIScriptError::warningFlag, "Mixed Content Message"_ns,
   3054        innerWindowId, SourceLocation(aURI));
   3055 
   3056    // Set this flag so we know we'll upgrade because of
   3057    // 'security.mixed_content.upgrade_display_content'.
   3058    aLoadInfo->SetBrowserDidUpgradeInsecureRequests(true);
   3059    return true;
   3060  }
   3061 
   3062  // 4. Https-Only
   3063  if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, aLoadInfo)) {
   3064    aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::HTTPS_ONLY_UPGRADE);
   3065    return true;
   3066  }
   3067  // 4.a Https-First
   3068  if (nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(aURI, aLoadInfo)) {
   3069    if (aLoadInfo->GetSchemelessInput() ==
   3070        nsILoadInfo::SchemelessInputTypeSchemeless) {
   3071      aLoadInfo->SetHttpsUpgradeTelemetry(
   3072          nsILoadInfo::HTTPS_FIRST_SCHEMELESS_UPGRADE);
   3073    } else {
   3074      aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::HTTPS_FIRST_UPGRADE);
   3075    }
   3076    return true;
   3077  }
   3078  return false;
   3079 }
   3080 
   3081 // Check if channel should be upgraded. check in the following order:
   3082 // 1. HSTS
   3083 // 2. CSP upgrade-insecure-requests
   3084 // 3. Mixed content auto upgrading
   3085 // 4. Https-Only / first
   3086 // (5. Https RR - will be checked in nsHttpChannel)
   3087 nsresult NS_ShouldSecureUpgrade(
   3088    nsIURI* aURI, nsILoadInfo* aLoadInfo, nsIPrincipal* aChannelResultPrincipal,
   3089    bool aAllowSTS, const OriginAttributes& aOriginAttributes,
   3090    bool& aShouldUpgrade, std::function<void(bool, nsresult)>&& aResultCallback,
   3091    bool& aWillCallback) {
   3092  MOZ_ASSERT(XRE_IsParentProcess());
   3093  if (!XRE_IsParentProcess()) {
   3094    return NS_ERROR_NOT_AVAILABLE;
   3095  }
   3096 
   3097  aWillCallback = false;
   3098  aShouldUpgrade = false;
   3099 
   3100  // Even if we're in private browsing mode, we still enforce existing STS
   3101  // data (it is read-only).
   3102  // if the connection is not using SSL and either the exact host matches or
   3103  // a superdomain wants to force HTTPS, do it.
   3104  bool isHttps = aURI->SchemeIs("https");
   3105 
   3106  // If request is https, then there is nothing to do here.
   3107  if (isHttps) {
   3108    aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::ALREADY_HTTPS);
   3109    aShouldUpgrade = false;
   3110    return NS_OK;
   3111  }
   3112  // If it is a mixed content trustworthy loopback, then we shouldn't upgrade
   3113  // it.
   3114  if (nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(aURI) ||
   3115      nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(aURI)) {
   3116    aShouldUpgrade = false;
   3117    return NS_OK;
   3118  }
   3119  // If no loadInfo exist there is nothing to upgrade here.
   3120  if (!aLoadInfo) {
   3121    aShouldUpgrade = false;
   3122    return NS_OK;
   3123  }
   3124  // The loadInfo indicates no HTTPS upgrade.
   3125  bool skipHTTPSUpgrade = false;
   3126  (void)aLoadInfo->GetSkipHTTPSUpgrade(&skipHTTPSUpgrade);
   3127  if (skipHTTPSUpgrade) {
   3128    aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::SKIP_HTTPS_UPGRADE);
   3129    aShouldUpgrade = false;
   3130    return NS_OK;
   3131  }
   3132  MOZ_ASSERT(!aURI->SchemeIs("https"));
   3133 
   3134  // enforce Strict-Transport-Security
   3135  nsISiteSecurityService* sss = gHttpHandler->GetSSService();
   3136  NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
   3137 
   3138  bool isStsHost = false;
   3139  // Calling |IsSecureURI| before the storage is ready to read will
   3140  // block the main thread. Once the storage is ready, we can call it
   3141  // from main thread.
   3142  static Atomic<bool, Relaxed> storageReady(false);
   3143  if (!storageReady && gSocketTransportService && aResultCallback) {
   3144    nsCOMPtr<nsILoadInfo> loadInfo = aLoadInfo;
   3145    nsCOMPtr<nsIURI> uri = aURI;
   3146    auto callbackWrapper = [resultCallback{std::move(aResultCallback)}, uri,
   3147                            loadInfo](bool aShouldUpgrade, nsresult aStatus) {
   3148      MOZ_ASSERT(NS_IsMainThread());
   3149 
   3150      // 1. HSTS upgrade
   3151      if (aShouldUpgrade || NS_FAILED(aStatus)) {
   3152        resultCallback(aShouldUpgrade, aStatus);
   3153        return;
   3154      }
   3155      // Check if we need to upgrade because of other reasons.
   3156      // 2. CSP upgrade-insecure-requests
   3157      // 3. Mixed content auto upgrading
   3158      // 4. Https-Only / first
   3159      bool shouldUpgrade = ShouldSecureUpgradeNoHSTS(uri, loadInfo);
   3160      resultCallback(shouldUpgrade, aStatus);
   3161    };
   3162    nsCOMPtr<nsISiteSecurityService> service = sss;
   3163    nsresult rv = gSocketTransportService->Dispatch(
   3164        NS_NewRunnableFunction(
   3165            "net::NS_ShouldSecureUpgrade",
   3166            [service{std::move(service)}, uri{std::move(uri)},
   3167             originAttributes(aOriginAttributes),
   3168             handleResultFunc{std::move(handleResultFunc)},
   3169             callbackWrapper{std::move(callbackWrapper)},
   3170             allowSTS{std::move(aAllowSTS)}]() mutable {
   3171              bool isStsHost = false;
   3172              nsresult rv =
   3173                  service->IsSecureURI(uri, originAttributes, &isStsHost);
   3174 
   3175              // Successfully get the result from |IsSecureURI| implies that
   3176              // the storage is ready to read.
   3177              storageReady = NS_SUCCEEDED(rv);
   3178              bool shouldUpgrade = handleResultFunc(allowSTS, isStsHost);
   3179              // Check if request should be upgraded.
   3180              NS_DispatchToMainThread(NS_NewRunnableFunction(
   3181                  "net::NS_ShouldSecureUpgrade::ResultCallback",
   3182                  [rv, shouldUpgrade,
   3183                   callbackWrapper{std::move(callbackWrapper)}]() {
   3184                    callbackWrapper(shouldUpgrade, rv);
   3185                  }));
   3186            }),
   3187        NS_DISPATCH_NORMAL);
   3188    aWillCallback = NS_SUCCEEDED(rv);
   3189    return rv;
   3190  }
   3191 
   3192  nsresult rv = sss->IsSecureURI(aURI, aOriginAttributes, &isStsHost);
   3193 
   3194  // if the SSS check fails, it's likely because this load is on a
   3195  // malformed URI or something else in the setup is wrong, so any error
   3196  // should be reported.
   3197  NS_ENSURE_SUCCESS(rv, rv);
   3198 
   3199  aShouldUpgrade = handleResultFunc(aAllowSTS, isStsHost);
   3200  // we can't pass the loadinfo to handleResultFunc since it's not threadsafe
   3201  // hence we set the http telemetry information on the loadinfo here.
   3202  if (aShouldUpgrade) {
   3203    aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::HSTS);
   3204  }
   3205  if (!aShouldUpgrade) {
   3206    // Check for CSP upgrade-insecure-requests, Mixed content auto upgrading
   3207    // and Https-Only / -First.
   3208    aShouldUpgrade = ShouldSecureUpgradeNoHSTS(aURI, aLoadInfo);
   3209  }
   3210  return rv;
   3211 }
   3212 
   3213 nsresult NS_GetSecureUpgradedURI(nsIURI* aURI, nsIURI** aUpgradedURI) {
   3214  NS_MutateURI mutator(aURI);
   3215  mutator.SetScheme("https"_ns);  // Change the scheme to HTTPS:
   3216 
   3217  // Change the default port to 443:
   3218  nsCOMPtr<nsIStandardURL> stdURL = do_QueryInterface(aURI);
   3219  if (stdURL) {
   3220    mutator.Apply(&nsIStandardURLMutator::SetDefaultPort, 443, nullptr);
   3221  } else {
   3222    // If we don't have a nsStandardURL, fall back to using GetPort/SetPort.
   3223    // XXXdholbert Is this function even called with a non-nsStandardURL arg,
   3224    // in practice?
   3225    NS_WARNING("Calling NS_GetSecureUpgradedURI for non nsStandardURL");
   3226    int32_t oldPort = -1;
   3227    nsresult rv = aURI->GetPort(&oldPort);
   3228    if (NS_FAILED(rv)) return rv;
   3229 
   3230    // Keep any nonstandard ports so only the scheme is changed.
   3231    // For example:
   3232    //  http://foo.com:80 -> https://foo.com:443
   3233    //  http://foo.com:81 -> https://foo.com:81
   3234 
   3235    if (oldPort == 80 || oldPort == -1) {
   3236      mutator.SetPort(-1);
   3237    } else {
   3238      mutator.SetPort(oldPort);
   3239    }
   3240  }
   3241 
   3242  return mutator.Finalize(aUpgradedURI);
   3243 }
   3244 
   3245 nsresult NS_CompareLoadInfoAndLoadContext(nsIChannel* aChannel) {
   3246  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   3247 
   3248  nsCOMPtr<nsILoadContext> loadContext;
   3249  NS_QueryNotificationCallbacks(aChannel, loadContext);
   3250  if (!loadContext) {
   3251    return NS_OK;
   3252  }
   3253 
   3254  // We try to skip about:newtab.
   3255  // about:newtab will use SystemPrincipal to download thumbnails through
   3256  // https:// and blob URLs.
   3257  bool isAboutPage = false;
   3258  nsINode* node = loadInfo->LoadingNode();
   3259  if (node) {
   3260    nsIURI* uri = node->OwnerDoc()->GetDocumentURI();
   3261    isAboutPage = uri->SchemeIs("about");
   3262  }
   3263 
   3264  if (isAboutPage) {
   3265    return NS_OK;
   3266  }
   3267 
   3268  // We skip the favicon loading here. The favicon loading might be
   3269  // triggered by the XUL image. For that case, the loadContext will have
   3270  // default originAttributes since the XUL image uses SystemPrincipal, but
   3271  // the loadInfo will use originAttributes from the content. Thus, the
   3272  // originAttributes between loadInfo and loadContext will be different.
   3273  // That's why we have to skip the comparison for the favicon loading.
   3274  if (loadInfo->GetLoadingPrincipal() &&
   3275      loadInfo->GetLoadingPrincipal()->IsSystemPrincipal() &&
   3276      loadInfo->InternalContentPolicyType() ==
   3277          nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) {
   3278    return NS_OK;
   3279  }
   3280 
   3281  OriginAttributes originAttrsLoadInfo = loadInfo->GetOriginAttributes();
   3282  OriginAttributes originAttrsLoadContext;
   3283  loadContext->GetOriginAttributes(originAttrsLoadContext);
   3284 
   3285  LOG(
   3286      ("NS_CompareLoadInfoAndLoadContext - loadInfo: %d, %d; "
   3287       "loadContext: %d, %d. [channel=%p]",
   3288       originAttrsLoadInfo.mUserContextId,
   3289       originAttrsLoadInfo.mPrivateBrowsingId,
   3290       originAttrsLoadContext.mUserContextId,
   3291       originAttrsLoadContext.mPrivateBrowsingId, aChannel));
   3292 
   3293  MOZ_ASSERT(originAttrsLoadInfo.mUserContextId ==
   3294                 originAttrsLoadContext.mUserContextId,
   3295             "The value of mUserContextId in the loadContext and in the "
   3296             "loadInfo are not the same!");
   3297 
   3298  MOZ_ASSERT(originAttrsLoadInfo.mPrivateBrowsingId ==
   3299                 originAttrsLoadContext.mPrivateBrowsingId,
   3300             "The value of mPrivateBrowsingId in the loadContext and in the "
   3301             "loadInfo are not the same!");
   3302 
   3303  return NS_OK;
   3304 }
   3305 
   3306 nsresult NS_SetRequestBlockingReason(nsIChannel* channel, uint32_t reason) {
   3307  NS_ENSURE_ARG(channel);
   3308 
   3309  nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
   3310  return NS_SetRequestBlockingReason(loadInfo, reason);
   3311 }
   3312 
   3313 nsresult NS_SetRequestBlockingReason(nsILoadInfo* loadInfo, uint32_t reason) {
   3314  NS_ENSURE_ARG(loadInfo);
   3315 
   3316  return loadInfo->SetRequestBlockingReason(reason);
   3317 }
   3318 
   3319 nsresult NS_SetRequestBlockingReasonIfNull(nsILoadInfo* loadInfo,
   3320                                           uint32_t reason) {
   3321  NS_ENSURE_ARG(loadInfo);
   3322 
   3323  uint32_t existingReason;
   3324  if (NS_SUCCEEDED(loadInfo->GetRequestBlockingReason(&existingReason)) &&
   3325      existingReason != nsILoadInfo::BLOCKING_REASON_NONE) {
   3326    return NS_OK;
   3327  }
   3328 
   3329  return loadInfo->SetRequestBlockingReason(reason);
   3330 }
   3331 
   3332 bool NS_IsOffline() {
   3333  bool offline = true;
   3334  bool connectivity = true;
   3335  nsCOMPtr<nsIIOService> ios = do_GetIOService();
   3336  if (ios) {
   3337    ios->GetOffline(&offline);
   3338    ios->GetConnectivity(&connectivity);
   3339  }
   3340  return offline || !connectivity;
   3341 }
   3342 
   3343 /**
   3344 * This function returns true if this channel should be classified by
   3345 * the URL Classifier, false otherwise. There are two types of classification:
   3346 *   1. SafeBrowsing
   3347 *   2. Enhanced Tracking Protection (ETP)
   3348 *
   3349 * The idea of the algorithm to determine if a channel should be
   3350 * classified is based on:
   3351 * 1. Channels created by non-privileged code should be classified for
   3352 *    ETP. For SafeBrowsing, it depends on the pref
   3353 *    "browser.safebrowsing.only_top_level" to decide if it should be
   3354 *    classified.
   3355 * 2. Top-level document’s channels, if loaded by privileged code
   3356 *    (system principal), should be classified for both types.
   3357 * 3. Any other channel, created by privileged code, is considered safe.
   3358 *
   3359 * A bad/hacked/corrupted safebrowsing database, plus a mistakenly
   3360 * classified critical channel (this may result from a bug in the exemption
   3361 * rules or incorrect information being passed into) can cause serious
   3362 * problems. For example, if the updater channel is classified and blocked
   3363 * by the Safe Browsing, Firefox can't update itself, and there is no way to
   3364 * recover from that.
   3365 *
   3366 * So two safeguards are added to ensure critical channels are never
   3367 * automatically classified either because there is a bug in the algorithm
   3368 * or the data in loadinfo is wrong.
   3369 * 1. beConservative, this is set by ServiceRequest and we treat
   3370 *    channel created for ServiceRequest as critical channels.
   3371 * 2. nsIChannel::LOAD_BYPASS_URL_CLASSIFIER, channel's opener can use this
   3372 *    flag to enforce bypassing the URL classifier check.
   3373 */
   3374 bool NS_ShouldClassifyChannel(nsIChannel* aChannel, ClassifyType aType) {
   3375  auto pref =
   3376      static_cast<ClassifierMode>(StaticPrefs::urlclassifier_enabled_mode());
   3377  if (pref == ClassifierMode::Disabled) {
   3378    return false;
   3379  }
   3380  if (aType == ClassifyType::SafeBrowsing &&
   3381      pref == ClassifierMode::AntiTracking) {
   3382    return false;
   3383  }
   3384  if (aType == ClassifyType::ETP && pref == ClassifierMode::SafeBrowsing) {
   3385    return false;
   3386  }
   3387 
   3388  nsLoadFlags loadFlags;
   3389  (void)aChannel->GetLoadFlags(&loadFlags);
   3390  //  If our load flags dictate that we must let this channel through without
   3391  //  URL classification, obey that here without performing more checks.
   3392  if (loadFlags & nsIChannel::LOAD_BYPASS_URL_CLASSIFIER) {
   3393    return false;
   3394  }
   3395 
   3396  nsCOMPtr<nsIHttpChannelInternal> httpChannel(do_QueryInterface(aChannel));
   3397  if (httpChannel) {
   3398    bool beConservative;
   3399    nsresult rv = httpChannel->GetBeConservative(&beConservative);
   3400 
   3401    // beConservative flag, set by ServiceRequest to ensure channels that
   3402    // fetch update use conservative TLS setting, are used here to identify
   3403    // channels are critical to bypass classification. for channels don't
   3404    // support beConservative, continue to apply the exemption rules.
   3405    if (NS_SUCCEEDED(rv) && beConservative) {
   3406      return false;
   3407    }
   3408  }
   3409 
   3410  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   3411  ExtContentPolicyType type = loadInfo->GetExternalContentPolicyType();
   3412 
   3413  // Skip classifying channel for safe browsing unless it is a top-level.
   3414  if (aType == ClassifyType::SafeBrowsing &&
   3415      (StaticPrefs::browser_safebrowsing_only_top_level() &&
   3416       ExtContentPolicy::TYPE_DOCUMENT != type)) {
   3417    return false;
   3418  }
   3419 
   3420  // Skip classifying channel triggered by system unless it is a top-level
   3421  // load.
   3422  return !(loadInfo->TriggeringPrincipal()->IsSystemPrincipal() &&
   3423           ExtContentPolicy::TYPE_DOCUMENT != type);
   3424 }
   3425 
   3426 namespace mozilla {
   3427 namespace net {
   3428 
   3429 bool InScriptableRange(int64_t val) {
   3430  return (val <= kJS_MAX_SAFE_INTEGER) && (val >= kJS_MIN_SAFE_INTEGER);
   3431 }
   3432 
   3433 bool InScriptableRange(uint64_t val) { return val <= kJS_MAX_SAFE_UINTEGER; }
   3434 
   3435 nsresult GetParameterHTTP(const nsACString& aHeaderVal, const char* aParamName,
   3436                          nsAString& aResult) {
   3437  return nsMIMEHeaderParamImpl::GetParameterHTTP(aHeaderVal, aParamName,
   3438                                                 aResult);
   3439 }
   3440 
   3441 bool ChannelIsPost(nsIChannel* aChannel) {
   3442  if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) {
   3443    nsAutoCString method;
   3444    (void)httpChannel->GetRequestMethod(method);
   3445    return method.EqualsLiteral("POST");
   3446  }
   3447  return false;
   3448 }
   3449 
   3450 bool SchemeIsHttpOrHttps(nsIURI* aURI) {
   3451  MOZ_ASSERT(aURI);
   3452  return aURI->SchemeIs("http") || aURI->SchemeIs("https");
   3453 }
   3454 
   3455 bool SchemeIsSpecial(const nsACString& aScheme) {
   3456  // See https://url.spec.whatwg.org/#special-scheme
   3457  return aScheme.EqualsIgnoreCase("ftp") || aScheme.EqualsIgnoreCase("file") ||
   3458         aScheme.EqualsIgnoreCase("http") ||
   3459         aScheme.EqualsIgnoreCase("https") || aScheme.EqualsIgnoreCase("ws") ||
   3460         aScheme.EqualsIgnoreCase("wss");
   3461 }
   3462 
   3463 bool IsSchemeChangePermitted(nsIURI* aOldURI, const nsACString& newScheme) {
   3464  // See step 2.1 in https://url.spec.whatwg.org/#special-scheme
   3465  // Note: The spec text uses "buffer" instead of newScheme, and "url"
   3466  MOZ_ASSERT(aOldURI);
   3467 
   3468  nsAutoCString tmp;
   3469  nsresult rv = aOldURI->GetScheme(tmp);
   3470  // If url's scheme is a special scheme and buffer is not a
   3471  // special scheme, then return.
   3472  // If url's scheme is not a special scheme and buffer is a
   3473  // special scheme, then return.
   3474  if (NS_FAILED(rv) || SchemeIsSpecial(tmp) != SchemeIsSpecial(newScheme)) {
   3475    return false;
   3476  }
   3477 
   3478  // If url's scheme is "file" and its host is an empty host, then return.
   3479  if (aOldURI->SchemeIs("file")) {
   3480    rv = aOldURI->GetHost(tmp);
   3481    if (NS_FAILED(rv) || tmp.IsEmpty()) {
   3482      return false;
   3483    }
   3484  }
   3485 
   3486  // URL Spec: If url includes credentials or has a non-null port, and
   3487  // buffer is "file", then return.
   3488  if (newScheme.EqualsIgnoreCase("file")) {
   3489    bool hasUserPass;
   3490    if (NS_FAILED(aOldURI->GetHasUserPass(&hasUserPass)) || hasUserPass) {
   3491      return false;
   3492    }
   3493    int32_t port;
   3494    rv = aOldURI->GetPort(&port);
   3495    if (NS_FAILED(rv) || port != -1) {
   3496      return false;
   3497    }
   3498  }
   3499 
   3500  return true;
   3501 }
   3502 
   3503 already_AddRefed<nsIURI> TryChangeProtocol(nsIURI* aURI,
   3504                                           const nsACString& aProtocol) {
   3505  MOZ_ASSERT(aURI);
   3506 
   3507  nsACString::const_iterator start;
   3508  aProtocol.BeginReading(start);
   3509 
   3510  nsACString::const_iterator end;
   3511  aProtocol.EndReading(end);
   3512 
   3513  nsACString::const_iterator iter(start);
   3514  FindCharInReadable(':', iter, end);
   3515 
   3516  // Changing the protocol of a URL, changes the "nature" of the URI
   3517  // implementation. In order to do this properly, we have to serialize the
   3518  // existing URL and reparse it in a new object.
   3519  nsCOMPtr<nsIURI> clone;
   3520  nsresult rv =
   3521      NS_MutateURI(aURI).SetScheme(Substring(start, iter)).Finalize(clone);
   3522  if (NS_WARN_IF(NS_FAILED(rv))) {
   3523    return nullptr;
   3524  }
   3525 
   3526  nsAutoCString newScheme;
   3527  rv = clone->GetScheme(newScheme);
   3528  if (NS_FAILED(rv) || !net::IsSchemeChangePermitted(aURI, newScheme)) {
   3529    nsAutoCString url;
   3530    (void)clone->GetSpec(url);
   3531    AutoTArray<nsString, 2> params;
   3532    params.AppendElement(NS_ConvertUTF8toUTF16(url));
   3533    params.AppendElement(NS_ConvertUTF8toUTF16(newScheme));
   3534    nsContentUtils::ReportToConsole(
   3535        nsIScriptError::warningFlag, "Strict Url Protocol Setter"_ns, nullptr,
   3536        nsContentUtils::eNECKO_PROPERTIES, "StrictUrlProtocolSetter", params);
   3537    return nullptr;
   3538  }
   3539 
   3540  nsAutoCString href;
   3541  rv = clone->GetSpec(href);
   3542  if (NS_WARN_IF(NS_FAILED(rv))) {
   3543    return nullptr;
   3544  }
   3545 
   3546  RefPtr<nsIURI> uri;
   3547  rv = NS_NewURI(getter_AddRefs(uri), href);
   3548  if (NS_WARN_IF(NS_FAILED(rv))) {
   3549    return nullptr;
   3550  }
   3551  return uri.forget();
   3552 }
   3553 
   3554 // Decode a parameter value using the encoding defined in RFC 5987 (in place)
   3555 //
   3556 //   charset  "'" [ language ] "'" value-chars
   3557 //
   3558 // returns true when decoding happened successfully (otherwise leaves
   3559 // passed value alone)
   3560 static bool Decode5987Format(nsAString& aEncoded) {
   3561  nsresult rv;
   3562  nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar;
   3563  mimehdrpar = mozilla::components::MimeHeaderParam::Service(&rv);
   3564  if (NS_FAILED(rv)) return false;
   3565 
   3566  nsAutoCString asciiValue;
   3567 
   3568  const char16_t* encstart = aEncoded.BeginReading();
   3569  const char16_t* encend = aEncoded.EndReading();
   3570 
   3571  // create a plain ASCII string, aborting if we can't do that
   3572  // converted form is always shorter than input
   3573  while (encstart != encend) {
   3574    if (*encstart > 0 && *encstart < 128) {
   3575      asciiValue.Append((char)*encstart);
   3576    } else {
   3577      return false;
   3578    }
   3579    encstart++;
   3580  }
   3581 
   3582  nsAutoString decoded;
   3583  nsAutoCString language;
   3584 
   3585  rv = mimehdrpar->DecodeRFC5987Param(asciiValue, language, decoded);
   3586  if (NS_FAILED(rv)) return false;
   3587 
   3588  aEncoded = decoded;
   3589  return true;
   3590 }
   3591 
   3592 LinkHeader::LinkHeader() { mCrossOrigin.SetIsVoid(true); }
   3593 
   3594 void LinkHeader::Reset() {
   3595  mHref.Truncate();
   3596  mRel.Truncate();
   3597  mTitle.Truncate();
   3598  mNonce.Truncate();
   3599  mIntegrity.Truncate();
   3600  mSrcset.Truncate();
   3601  mSizes.Truncate();
   3602  mType.Truncate();
   3603  mMedia.Truncate();
   3604  mAnchor.Truncate();
   3605  mCrossOrigin.Truncate();
   3606  mReferrerPolicy.Truncate();
   3607  mAs.Truncate();
   3608  mCrossOrigin.SetIsVoid(true);
   3609  mFetchPriority.Truncate();
   3610 }
   3611 
   3612 nsresult LinkHeader::NewResolveHref(nsIURI** aOutURI, nsIURI* aBaseURI) const {
   3613  if (mAnchor.IsEmpty()) {
   3614    // use the base uri
   3615    return NS_NewURI(aOutURI, mHref, nullptr, aBaseURI);
   3616  }
   3617 
   3618  // compute the anchored URI
   3619  nsCOMPtr<nsIURI> anchoredURI;
   3620  nsresult rv =
   3621      NS_NewURI(getter_AddRefs(anchoredURI), mAnchor, nullptr, aBaseURI);
   3622  NS_ENSURE_SUCCESS(rv, rv);
   3623 
   3624  return NS_NewURI(aOutURI, mHref, nullptr, anchoredURI);
   3625 }
   3626 
   3627 bool LinkHeader::operator==(const LinkHeader& rhs) const {
   3628  return mHref == rhs.mHref && mRel == rhs.mRel && mTitle == rhs.mTitle &&
   3629         mNonce == rhs.mNonce && mIntegrity == rhs.mIntegrity &&
   3630         mSrcset == rhs.mSrcset && mSizes == rhs.mSizes && mType == rhs.mType &&
   3631         mMedia == rhs.mMedia && mAnchor == rhs.mAnchor &&
   3632         mCrossOrigin == rhs.mCrossOrigin &&
   3633         mReferrerPolicy == rhs.mReferrerPolicy && mAs == rhs.mAs &&
   3634         mFetchPriority == rhs.mFetchPriority;
   3635 }
   3636 
   3637 constexpr auto kTitleStar = "title*"_ns;
   3638 
   3639 nsTArray<LinkHeader> ParseLinkHeader(const nsAString& aLinkData) {
   3640  nsTArray<LinkHeader> linkHeaders;
   3641 
   3642  // keep track where we are within the header field
   3643  bool seenParameters = false;
   3644 
   3645  // parse link content and add to array
   3646  LinkHeader header;
   3647  nsAutoString titleStar;
   3648 
   3649  // copy to work buffer
   3650  nsAutoString stringList(aLinkData);
   3651 
   3652  // put an extra null at the end
   3653  stringList.Append(kNullCh);
   3654 
   3655  char16_t* start = stringList.BeginWriting();
   3656 
   3657  while (*start != kNullCh) {
   3658    // parse link content and call process style link
   3659 
   3660    // skip leading space
   3661    while ((*start != kNullCh) && nsCRT::IsAsciiSpace(*start)) {
   3662      ++start;
   3663    }
   3664 
   3665    char16_t* end = start;
   3666    char16_t* last = end - 1;
   3667 
   3668    bool wasQuotedString = false;
   3669 
   3670    // look for semicolon or comma
   3671    while (*end != kNullCh && *end != kSemicolon && *end != kComma) {
   3672      char16_t ch = *end;
   3673 
   3674      if (ch == kQuote || ch == kLessThan) {
   3675        // quoted string
   3676 
   3677        char16_t quote = ch;
   3678        if (quote == kLessThan) {
   3679          quote = kGreaterThan;
   3680        }
   3681 
   3682        wasQuotedString = (ch == kQuote);
   3683 
   3684        char16_t* closeQuote = (end + 1);
   3685 
   3686        // seek closing quote
   3687        while (*closeQuote != kNullCh && quote != *closeQuote) {
   3688          // in quoted-string, "\" is an escape character
   3689          if (wasQuotedString && *closeQuote == kBackSlash &&
   3690              *(closeQuote + 1) != kNullCh) {
   3691            ++closeQuote;
   3692          }
   3693 
   3694          ++closeQuote;
   3695        }
   3696 
   3697        if (quote == *closeQuote) {
   3698          // found closer
   3699 
   3700          // skip to close quote
   3701          end = closeQuote;
   3702 
   3703          last = end - 1;
   3704 
   3705          ch = *(end + 1);
   3706 
   3707          if (ch != kNullCh && ch != kSemicolon && ch != kComma) {
   3708            // end string here
   3709            *(++end) = kNullCh;
   3710 
   3711            ch = *(end + 1);
   3712 
   3713            // keep going until semi or comma
   3714            while (ch != kNullCh && ch != kSemicolon && ch != kComma) {
   3715              ++end;
   3716 
   3717              ch = *(end + 1);
   3718            }
   3719          }
   3720        }
   3721      }
   3722 
   3723      ++end;
   3724      ++last;
   3725    }
   3726 
   3727    char16_t endCh = *end;
   3728 
   3729    // end string here
   3730    *end = kNullCh;
   3731 
   3732    if (start < end) {
   3733      if ((*start == kLessThan) && (*last == kGreaterThan)) {
   3734        *last = kNullCh;
   3735 
   3736        // first instance of <...> wins
   3737        // also, do not allow hrefs after the first param was seen
   3738        if (header.mHref.IsEmpty() && !seenParameters) {
   3739          header.mHref = (start + 1);
   3740          header.mHref.StripWhitespace();
   3741        }
   3742      } else {
   3743        char16_t* equals = start;
   3744        seenParameters = true;
   3745 
   3746        while ((*equals != kNullCh) && (*equals != kEqual)) {
   3747          equals++;
   3748        }
   3749 
   3750        const bool hadEquals = *equals != kNullCh;
   3751        *equals = kNullCh;
   3752        nsAutoString attr(start);
   3753        attr.StripWhitespace();
   3754 
   3755        char16_t* value = hadEquals ? ++equals : equals;
   3756        while (nsCRT::IsAsciiSpace(*value)) {
   3757          value++;
   3758        }
   3759 
   3760        if ((*value == kQuote) && (*value == *last)) {
   3761          *last = kNullCh;
   3762          value++;
   3763        }
   3764 
   3765        if (wasQuotedString) {
   3766          // unescape in-place
   3767          char16_t* unescaped = value;
   3768          char16_t* src = value;
   3769 
   3770          while (*src != kNullCh) {
   3771            if (*src == kBackSlash && *(src + 1) != kNullCh) {
   3772              src++;
   3773            }
   3774            *unescaped++ = *src++;
   3775          }
   3776 
   3777          *unescaped = kNullCh;
   3778        }
   3779 
   3780        if (attr.LowerCaseEqualsASCII(kTitleStar.get())) {
   3781          if (titleStar.IsEmpty() && !wasQuotedString) {
   3782            // RFC 5987 encoding; uses token format only, so skip if we get
   3783            // here with a quoted-string
   3784            nsAutoString tmp;
   3785            tmp = value;
   3786            if (Decode5987Format(tmp)) {
   3787              titleStar = tmp;
   3788              titleStar.CompressWhitespace();
   3789            } else {
   3790              // header value did not parse, throw it away
   3791              titleStar.Truncate();
   3792            }
   3793          }
   3794        } else {
   3795          header.MaybeUpdateAttribute(attr, value);
   3796        }
   3797      }
   3798    }
   3799 
   3800    if (endCh == kComma) {
   3801      // hit a comma, process what we've got so far
   3802 
   3803      header.mHref.Trim(" \t\n\r\f");  // trim HTML5 whitespace
   3804      if (!header.mHref.IsEmpty() && !header.mRel.IsEmpty()) {
   3805        if (!titleStar.IsEmpty()) {
   3806          // prefer RFC 5987 variant over non-I18zed version
   3807          header.mTitle = titleStar;
   3808        }
   3809        linkHeaders.AppendElement(header);
   3810      }
   3811 
   3812      titleStar.Truncate();
   3813      header.Reset();
   3814 
   3815      seenParameters = false;
   3816    }
   3817 
   3818    start = ++end;
   3819  }
   3820 
   3821  header.mHref.Trim(" \t\n\r\f");  // trim HTML5 whitespace
   3822  if (!header.mHref.IsEmpty() && !header.mRel.IsEmpty()) {
   3823    if (!titleStar.IsEmpty()) {
   3824      // prefer RFC 5987 variant over non-I18zed version
   3825      header.mTitle = titleStar;
   3826    }
   3827    linkHeaders.AppendElement(header);
   3828  }
   3829 
   3830  return linkHeaders;
   3831 }
   3832 
   3833 void LinkHeader::MaybeUpdateAttribute(const nsAString& aAttribute,
   3834                                      const char16_t* aValue) {
   3835  MOZ_ASSERT(!aAttribute.LowerCaseEqualsASCII(kTitleStar.get()));
   3836 
   3837  if (aAttribute.LowerCaseEqualsLiteral("rel")) {
   3838    if (mRel.IsEmpty()) {
   3839      mRel = aValue;
   3840      mRel.CompressWhitespace();
   3841    }
   3842  } else if (aAttribute.LowerCaseEqualsLiteral("title")) {
   3843    if (mTitle.IsEmpty()) {
   3844      mTitle = aValue;
   3845      mTitle.CompressWhitespace();
   3846    }
   3847  } else if (aAttribute.LowerCaseEqualsLiteral("type")) {
   3848    if (mType.IsEmpty()) {
   3849      mType = aValue;
   3850      mType.StripWhitespace();
   3851    }
   3852  } else if (aAttribute.LowerCaseEqualsLiteral("media")) {
   3853    if (mMedia.IsEmpty()) {
   3854      mMedia = aValue;
   3855 
   3856      // The HTML5 spec is formulated in terms of the CSS3 spec,
   3857      // which specifies that media queries are case insensitive.
   3858      nsContentUtils::ASCIIToLower(mMedia);
   3859    }
   3860  } else if (aAttribute.LowerCaseEqualsLiteral("anchor")) {
   3861    if (mAnchor.IsEmpty()) {
   3862      mAnchor = aValue;
   3863      mAnchor.StripWhitespace();
   3864    }
   3865  } else if (aAttribute.LowerCaseEqualsLiteral("crossorigin")) {
   3866    if (mCrossOrigin.IsVoid()) {
   3867      mCrossOrigin.SetIsVoid(false);
   3868      mCrossOrigin = aValue;
   3869      mCrossOrigin.StripWhitespace();
   3870    }
   3871  } else if (aAttribute.LowerCaseEqualsLiteral("as")) {
   3872    if (mAs.IsEmpty()) {
   3873      mAs = aValue;
   3874      mAs.CompressWhitespace();
   3875    }
   3876  } else if (aAttribute.LowerCaseEqualsLiteral("referrerpolicy")) {
   3877    // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#referrer-policy-attribute
   3878    // Specs says referrer policy attribute is an enumerated attribute,
   3879    // case insensitive and includes the empty string
   3880    // We will parse the aValue with AttributeReferrerPolicyFromString
   3881    // later, which will handle parsing it as an enumerated attribute.
   3882    if (mReferrerPolicy.IsEmpty()) {
   3883      mReferrerPolicy = aValue;
   3884    }
   3885 
   3886  } else if (aAttribute.LowerCaseEqualsLiteral("nonce")) {
   3887    if (mNonce.IsEmpty()) {
   3888      mNonce = aValue;
   3889    }
   3890  } else if (aAttribute.LowerCaseEqualsLiteral("integrity")) {
   3891    if (mIntegrity.IsEmpty()) {
   3892      mIntegrity = aValue;
   3893    }
   3894  } else if (aAttribute.LowerCaseEqualsLiteral("imagesrcset")) {
   3895    if (mSrcset.IsEmpty()) {
   3896      mSrcset = aValue;
   3897    }
   3898  } else if (aAttribute.LowerCaseEqualsLiteral("imagesizes")) {
   3899    if (mSizes.IsEmpty()) {
   3900      mSizes = aValue;
   3901    }
   3902  } else if (aAttribute.LowerCaseEqualsLiteral("fetchpriority")) {
   3903    if (mFetchPriority.IsEmpty()) {
   3904      LOG(("Update fetchPriority to \"%s\"",
   3905           NS_ConvertUTF16toUTF8(aValue).get()));
   3906      mFetchPriority = aValue;
   3907    }
   3908  }
   3909 }
   3910 
   3911 // We will use official mime-types from:
   3912 // https://www.iana.org/assignments/media-types/media-types.xhtml#font
   3913 // We do not support old deprecated mime-types for preload feature.
   3914 // (We currectly do not support font/collection)
   3915 static uint32_t StyleLinkElementFontMimeTypesNum = 5;
   3916 static const char* StyleLinkElementFontMimeTypes[] = {
   3917    "font/otf", "font/sfnt", "font/ttf", "font/woff", "font/woff2"};
   3918 
   3919 bool IsFontMimeType(const nsAString& aType) {
   3920  if (aType.IsEmpty()) {
   3921    return true;
   3922  }
   3923  for (uint32_t i = 0; i < StyleLinkElementFontMimeTypesNum; i++) {
   3924    if (aType.EqualsASCII(StyleLinkElementFontMimeTypes[i])) {
   3925      return true;
   3926    }
   3927  }
   3928  return false;
   3929 }
   3930 
   3931 static constexpr nsAttrValue::EnumTableEntry kAsAttributeTable[] = {
   3932    {"", DESTINATION_INVALID},      {"audio", DESTINATION_AUDIO},
   3933    {"font", DESTINATION_FONT},     {"image", DESTINATION_IMAGE},
   3934    {"script", DESTINATION_SCRIPT}, {"style", DESTINATION_STYLE},
   3935    {"track", DESTINATION_TRACK},   {"video", DESTINATION_VIDEO},
   3936    {"fetch", DESTINATION_FETCH},   {"json", DESTINATION_JSON},
   3937 };
   3938 
   3939 void ParseAsValue(const nsAString& aValue, nsAttrValue& aResult) {
   3940  DebugOnly<bool> success =
   3941      aResult.ParseEnumValue(aValue, kAsAttributeTable, false,
   3942                             // default value is a empty string
   3943                             // if aValue is not a value we
   3944                             // understand
   3945                             &kAsAttributeTable[0]);
   3946  MOZ_ASSERT(success);
   3947 }
   3948 
   3949 nsContentPolicyType AsValueToContentPolicy(const nsAttrValue& aValue) {
   3950  switch (aValue.GetEnumValue()) {
   3951    case DESTINATION_INVALID:
   3952      return nsIContentPolicy::TYPE_INVALID;
   3953    case DESTINATION_AUDIO:
   3954      return nsIContentPolicy::TYPE_INTERNAL_AUDIO;
   3955    case DESTINATION_TRACK:
   3956      return nsIContentPolicy::TYPE_INTERNAL_TRACK;
   3957    case DESTINATION_VIDEO:
   3958      return nsIContentPolicy::TYPE_INTERNAL_VIDEO;
   3959    case DESTINATION_FONT:
   3960      return nsIContentPolicy::TYPE_FONT;
   3961    case DESTINATION_IMAGE:
   3962      return nsIContentPolicy::TYPE_IMAGE;
   3963    case DESTINATION_SCRIPT:
   3964      return nsIContentPolicy::TYPE_SCRIPT;
   3965    case DESTINATION_STYLE:
   3966      return nsIContentPolicy::TYPE_STYLESHEET;
   3967    case DESTINATION_FETCH:
   3968      return nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD;
   3969    case DESTINATION_JSON:
   3970      return nsIContentPolicy::TYPE_JSON;
   3971  }
   3972  return nsIContentPolicy::TYPE_INVALID;
   3973 }
   3974 
   3975 // TODO: implement this using nsAttrValue's destination enums when support for
   3976 // the new destinations is added; see this diff for a possible start:
   3977 // https://phabricator.services.mozilla.com/D172368?vs=705114&id=708720
   3978 bool IsScriptLikeOrInvalid(const nsAString& aAs) {
   3979  return !(
   3980      aAs.LowerCaseEqualsASCII("fetch") || aAs.LowerCaseEqualsASCII("audio") ||
   3981      aAs.LowerCaseEqualsASCII("document") ||
   3982      aAs.LowerCaseEqualsASCII("embed") || aAs.LowerCaseEqualsASCII("font") ||
   3983      aAs.LowerCaseEqualsASCII("frame") || aAs.LowerCaseEqualsASCII("iframe") ||
   3984      aAs.LowerCaseEqualsASCII("image") ||
   3985      aAs.LowerCaseEqualsASCII("manifest") ||
   3986      aAs.LowerCaseEqualsASCII("object") ||
   3987      aAs.LowerCaseEqualsASCII("report") || aAs.LowerCaseEqualsASCII("style") ||
   3988      aAs.LowerCaseEqualsASCII("track") || aAs.LowerCaseEqualsASCII("video") ||
   3989      aAs.LowerCaseEqualsASCII("webidentity") ||
   3990      aAs.LowerCaseEqualsASCII("xslt") || aAs.LowerCaseEqualsASCII("json"));
   3991 }
   3992 
   3993 bool CheckPreloadAttrs(const nsAttrValue& aAs, const nsAString& aType,
   3994                       const nsAString& aMedia,
   3995                       mozilla::dom::Document* aDocument) {
   3996  nsContentPolicyType policyType = AsValueToContentPolicy(aAs);
   3997  if (policyType == nsIContentPolicy::TYPE_INVALID) {
   3998    return false;
   3999  }
   4000 
   4001  // Check if media attribute is valid.
   4002  if (!aMedia.IsEmpty()) {
   4003    RefPtr<mozilla::dom::MediaList> mediaList =
   4004        mozilla::dom::MediaList::Create(NS_ConvertUTF16toUTF8(aMedia));
   4005    if (!mediaList->Matches(*aDocument)) {
   4006      return false;
   4007    }
   4008  }
   4009 
   4010  if (aType.IsEmpty()) {
   4011    return true;
   4012  }
   4013 
   4014  if (policyType == nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD) {
   4015    return true;
   4016  }
   4017 
   4018  nsAutoString type(aType);
   4019  ToLowerCase(type);
   4020  if (policyType == nsIContentPolicy::TYPE_MEDIA) {
   4021    if (aAs.GetEnumValue() == DESTINATION_TRACK) {
   4022      return type.EqualsASCII("text/vtt");
   4023    }
   4024    Maybe<MediaContainerType> mimeType = MakeMediaContainerType(aType);
   4025    if (!mimeType) {
   4026      return false;
   4027    }
   4028    DecoderDoctorDiagnostics diagnostics;
   4029    CanPlayStatus status =
   4030        DecoderTraits::CanHandleContainerType(*mimeType, &diagnostics);
   4031    // Preload if this return CANPLAY_YES and CANPLAY_MAYBE.
   4032    return status != CANPLAY_NO;
   4033  }
   4034  if (policyType == nsIContentPolicy::TYPE_FONT) {
   4035    return IsFontMimeType(type);
   4036  }
   4037  if (policyType == nsIContentPolicy::TYPE_IMAGE) {
   4038    return imgLoader::SupportImageWithMimeType(
   4039        NS_ConvertUTF16toUTF8(type), AcceptedMimeTypes::IMAGES_AND_DOCUMENTS);
   4040  }
   4041  if (policyType == nsIContentPolicy::TYPE_SCRIPT) {
   4042    return nsContentUtils::IsJavascriptMIMEType(type);
   4043  }
   4044  if (policyType == nsIContentPolicy::TYPE_STYLESHEET) {
   4045    return type.EqualsASCII("text/css");
   4046  }
   4047  if (policyType == nsIContentPolicy::TYPE_JSON) {
   4048    return nsContentUtils::IsJsonMimeType(type);
   4049  }
   4050  return false;
   4051 }
   4052 
   4053 void WarnIgnoredPreload(const mozilla::dom::Document& aDoc, nsIURI& aURI) {
   4054  AutoTArray<nsString, 1> params;
   4055  {
   4056    nsCString uri = nsContentUtils::TruncatedURLForDisplay(&aURI);
   4057    AppendUTF8toUTF16(uri, *params.AppendElement());
   4058  }
   4059  nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns, &aDoc,
   4060                                  nsContentUtils::eDOM_PROPERTIES,
   4061                                  "PreloadIgnoredInvalidAttr", params);
   4062 }
   4063 
   4064 bool NS_ParseUseAsDictionary(const nsACString& aValue, nsACString& aMatch,
   4065                             nsACString& aMatchId,
   4066                             nsTArray<nsCString>& aMatchDestItems,
   4067                             nsACString& aType) {
   4068  // Note: match= is required
   4069  // Use-As-Dictionary = %s"match" /
   4070  //                     %il"match-dest" /
   4071  //                     %s"id" /
   4072  //                     %t"type" ; case-sensitive
   4073 
   4074  nsCOMPtr<nsISFVService> sfv = GetSFVService();
   4075 
   4076  nsCOMPtr<nsISFVDictionary> parsedHeader;
   4077  nsresult rv;
   4078  if (NS_FAILED(
   4079          rv = sfv->ParseDictionary(aValue, getter_AddRefs(parsedHeader)))) {
   4080    return false;
   4081  }
   4082 
   4083  nsCOMPtr<nsISFVItemOrInnerList> match;
   4084  rv = parsedHeader->Get("match"_ns, getter_AddRefs(match));
   4085  if (NS_FAILED(rv)) {
   4086    return false;  // match is required, fail if not found
   4087  }
   4088  if (nsCOMPtr<nsISFVItem> listItem = do_QueryInterface(match)) {
   4089    nsCOMPtr<nsISFVBareItem> value;
   4090    rv = listItem->GetValue(getter_AddRefs(value));
   4091    if (NS_FAILED(rv)) {
   4092      return false;
   4093    }
   4094    if (nsCOMPtr<nsISFVString> stringVal = do_QueryInterface(value)) {
   4095      if (NS_FAILED(stringVal->GetValue(aMatch))) {
   4096        return false;
   4097      }
   4098      if (aMatch.IsEmpty()) {
   4099        return false;  // match is required, fail if not found
   4100      }
   4101    } else {
   4102      return false;
   4103    }
   4104  } else {
   4105    return false;
   4106  }
   4107 
   4108  nsCOMPtr<nsISFVItemOrInnerList> matchdest;
   4109  rv = parsedHeader->Get("match-dest"_ns, getter_AddRefs(matchdest));
   4110  if (NS_SUCCEEDED(rv)) {
   4111    if (nsCOMPtr<nsISFVInnerList> innerList = do_QueryInterface(matchdest)) {
   4112      // Extract the first entry of each inner list, which should contain the
   4113      // endpoint's URL string
   4114      nsTArray<RefPtr<nsISFVItem>> items;
   4115      if (NS_FAILED(innerList->GetItems(items))) {
   4116        return false;
   4117      }
   4118      // Don't check items.IsEmpty() because an empty list is valid
   4119 
   4120      for (auto& item : items) {
   4121        nsCOMPtr<nsISFVBareItem> value;
   4122        if (NS_FAILED(item->GetValue(getter_AddRefs(value)))) {
   4123          return false;
   4124        }
   4125        if (nsCOMPtr<nsISFVString> stringVal = do_QueryInterface(value)) {
   4126          nsAutoCString string;
   4127          if (NS_FAILED(stringVal->GetValue(string))) {
   4128            return false;
   4129          }
   4130          aMatchDestItems.AppendElement(string);
   4131        } else {
   4132          return false;  // match-dest is an inner list of strings
   4133        }
   4134      }
   4135    }
   4136  }
   4137 
   4138  nsCOMPtr<nsISFVItemOrInnerList> matchid;
   4139  rv = parsedHeader->Get("id"_ns, getter_AddRefs(matchid));
   4140  if (NS_SUCCEEDED(rv)) {
   4141    if (nsCOMPtr<nsISFVItem> listItem = do_QueryInterface(matchid)) {
   4142      nsCOMPtr<nsISFVBareItem> value;
   4143      rv = listItem->GetValue(getter_AddRefs(value));
   4144      if (NS_FAILED(rv)) {
   4145        return false;
   4146      }
   4147      if (nsCOMPtr<nsISFVString> stringVal = do_QueryInterface(value)) {
   4148        if (NS_FAILED(stringVal->GetValue(aMatchId))) {
   4149          return false;
   4150        }
   4151      } else {
   4152        return false;
   4153      }
   4154    } else {
   4155      return false;
   4156    }
   4157  }
   4158 
   4159  nsCOMPtr<nsISFVItemOrInnerList> type;
   4160  rv = parsedHeader->Get("type"_ns, getter_AddRefs(type));
   4161  if (NS_SUCCEEDED(rv)) {
   4162    if (nsCOMPtr<nsISFVItem> listItem = do_QueryInterface(type)) {
   4163      nsCOMPtr<nsISFVBareItem> value;
   4164      rv = listItem->GetValue(getter_AddRefs(value));
   4165      if (NS_FAILED(rv)) {
   4166        return false;
   4167      }
   4168      if (nsCOMPtr<nsISFVToken> tokenVal = do_QueryInterface(value)) {
   4169        if (NS_FAILED(tokenVal->GetValue(aType))) {
   4170          return false;
   4171        }
   4172        if (!aType.Equals("raw"_ns)) {
   4173          return false;
   4174        }
   4175      } else {
   4176        return false;
   4177      }
   4178    } else {
   4179      return false;
   4180    }
   4181  }
   4182 
   4183  return true;
   4184 }
   4185 
   4186 nsresult HasRootDomain(const nsACString& aInput, const nsACString& aHost,
   4187                       bool* aResult) {
   4188  if (NS_WARN_IF(!aResult)) {
   4189    return NS_ERROR_FAILURE;
   4190  }
   4191 
   4192  *aResult = false;
   4193 
   4194  // If the strings are the same, we obviously have a match.
   4195  if (aInput == aHost) {
   4196    *aResult = true;
   4197    return NS_OK;
   4198  }
   4199 
   4200  // If aHost is not found, we know we do not have it as a root domain.
   4201  int32_t index = nsAutoCString(aInput).Find(aHost);
   4202  if (index == kNotFound) {
   4203    return NS_OK;
   4204  }
   4205 
   4206  // Otherwise, we have aHost as our root domain iff the index of aHost is
   4207  // aHost.length subtracted from our length and (since we do not have an
   4208  // exact match) the character before the index is a dot or slash.
   4209  *aResult = index > 0 && (uint32_t)index == aInput.Length() - aHost.Length() &&
   4210             (aInput[index - 1] == '.' || aInput[index - 1] == '/');
   4211  return NS_OK;
   4212 }
   4213 
   4214 void CheckForBrokenChromeURL(nsILoadInfo* aLoadInfo, nsIURI* aURI) {
   4215  if (!aURI) {
   4216    return;
   4217  }
   4218  nsAutoCString scheme;
   4219  aURI->GetScheme(scheme);
   4220  if (!scheme.EqualsLiteral("chrome") && !scheme.EqualsLiteral("resource")) {
   4221    return;
   4222  }
   4223  nsAutoCString host;
   4224  aURI->GetHost(host);
   4225  // Ignore test hits.
   4226  if (host.EqualsLiteral("mochitests") || host.EqualsLiteral("reftest")) {
   4227    return;
   4228  }
   4229 
   4230  nsAutoCString filePath;
   4231  aURI->GetFilePath(filePath);
   4232  // Fluent likes checking for files everywhere and expects failure.
   4233  if (StringEndsWith(filePath, ".ftl"_ns)) {
   4234    return;
   4235  }
   4236 
   4237  // Ignore fetches/xhrs, as they are frequently used in a way where
   4238  // non-existence is OK (ie with fallbacks). This risks false negatives (ie
   4239  // files that *should* be there but aren't) - which we accept for now.
   4240  ExtContentPolicy policy = aLoadInfo
   4241                                ? aLoadInfo->GetExternalContentPolicyType()
   4242                                : ExtContentPolicy::TYPE_OTHER;
   4243  if (policy == ExtContentPolicy::TYPE_FETCH ||
   4244      policy == ExtContentPolicy::TYPE_XMLHTTPREQUEST) {
   4245    return;
   4246  }
   4247 
   4248  nsCString spec;
   4249  aURI->GetSpec(spec);
   4250 
   4251 #ifdef ANDROID
   4252  // Various toolkit files use this and are shipped on android, but
   4253  // info-pages.css and aboutLicense.css are not - bug 1808987
   4254  if (StringEndsWith(spec, "info-pages.css"_ns) ||
   4255      StringEndsWith(spec, "aboutLicense.css"_ns) ||
   4256      // Error page CSS is also missing: bug 1810039
   4257      StringEndsWith(spec, "aboutNetError.css"_ns) ||
   4258      StringEndsWith(spec, "aboutHttpsOnlyError.css"_ns) ||
   4259      StringEndsWith(spec, "error-pages.css"_ns) ||
   4260      // popup.css is used in a single mochitest: bug 1810577
   4261      StringEndsWith(spec, "/popup.css"_ns) ||
   4262      // Used by an extension installation test - bug 1809650
   4263      StringBeginsWith(spec, "resource://android/assets/web_extensions/"_ns)) {
   4264    return;
   4265  }
   4266 #endif
   4267 
   4268  // DTD files from gre may not exist when requested by tests.
   4269  if (StringBeginsWith(spec, "resource://gre/res/dtd/"_ns)) {
   4270    return;
   4271  }
   4272 
   4273  // The background task machinery allows the caller to specify a JSM on the
   4274  // command line, which is then looked up in both app-specific and toolkit-wide
   4275  // locations.
   4276  if (spec.Find("backgroundtasks") != kNotFound) {
   4277    return;
   4278  }
   4279 
   4280  if (xpc::IsInAutomation()) {
   4281 #ifdef DEBUG
   4282    if (NS_IsMainThread()) {
   4283      nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect();
   4284      (void)xpc->DebugDumpJSStack(false, false, false);
   4285    }
   4286 #endif
   4287    MOZ_CRASH_UNSAFE_PRINTF("Missing chrome or resource URLs: %s", spec.get());
   4288  } else {
   4289    printf_stderr("Missing chrome or resource URL: %s\n", spec.get());
   4290  }
   4291 }
   4292 
   4293 bool IsCoepCredentiallessEnabled(bool aIsOriginTrialCoepCredentiallessEnabled) {
   4294  return StaticPrefs::
   4295             browser_tabs_remote_coep_credentialless_DoNotUseDirectly() ||
   4296         aIsOriginTrialCoepCredentiallessEnabled;
   4297 }
   4298 
   4299 nsresult AddExtraHeaders(nsIHttpChannel* aHttpChannel,
   4300                         const nsACString& aExtraHeaders,
   4301                         bool aMerge /* = true */) {
   4302  nsresult rv;
   4303  nsAutoCString oneHeader;
   4304  nsAutoCString headerName;
   4305  nsAutoCString headerValue;
   4306  int32_t crlf = 0;
   4307  int32_t colon = 0;
   4308  const char* kWhitespace = "\b\t\r\n ";
   4309  nsAutoCString extraHeaders(aExtraHeaders);
   4310  while (true) {
   4311    crlf = extraHeaders.Find("\r\n");
   4312    if (crlf == -1) break;
   4313    extraHeaders.Mid(oneHeader, 0, crlf);
   4314    extraHeaders.Cut(0, crlf + 2);
   4315    colon = oneHeader.Find(":");
   4316    if (colon == -1) break;  // Should have a colon.
   4317    oneHeader.Left(headerName, colon);
   4318    colon++;
   4319    oneHeader.Mid(headerValue, colon, oneHeader.Length() - colon);
   4320    headerName.Trim(kWhitespace);
   4321    headerValue.Trim(kWhitespace);
   4322    // Add the header (merging if required).
   4323    rv = aHttpChannel->SetRequestHeader(headerName, headerValue, aMerge);
   4324    NS_ENSURE_SUCCESS(rv, rv);
   4325  }
   4326  return NS_OK;
   4327 }
   4328 
   4329 bool IsLocalHostAccess(
   4330    const nsILoadInfo::IPAddressSpace aParentIPAddressSpace,
   4331    const nsILoadInfo::IPAddressSpace aTargetIPAddressSpace) {
   4332  // Determine if the request is moving to a more private address space
   4333  // i.e. Public -> LocalHost
   4334  // Private -> LocalHost
   4335 
   4336  return ((aTargetIPAddressSpace == nsILoadInfo::IPAddressSpace::Local) &&
   4337          (aParentIPAddressSpace == nsILoadInfo::IPAddressSpace::Public ||
   4338           aParentIPAddressSpace == nsILoadInfo::IPAddressSpace::Private));
   4339 }
   4340 
   4341 bool IsPrivateNetworkAccess(
   4342    const nsILoadInfo::IPAddressSpace aParentIPAddressSpace,
   4343    const nsILoadInfo::IPAddressSpace aTargetIPAddressSpace) {
   4344  // Determine if the request is moving from public to private address space
   4345 
   4346  return ((aTargetIPAddressSpace == nsILoadInfo::IPAddressSpace::Private) &&
   4347          (aParentIPAddressSpace == nsILoadInfo::IPAddressSpace::Public));
   4348 }
   4349 
   4350 bool IsLocalOrPrivateNetworkAccess(
   4351    const nsILoadInfo::IPAddressSpace aParentIPAddressSpace,
   4352    const nsILoadInfo::IPAddressSpace aTargetIPAddressSpace) {
   4353  // Determine if the request is moving to a more private address space
   4354  // i.e. Public -> Private or Local
   4355  // Private -> Local
   4356  // Refer
   4357  // https://wicg.github.io/private-network-access/#private-network-request-heading
   4358  // for private network access
   4359  // XXX (sunil) add link to LNA spec once it is published
   4360 
   4361  return IsPrivateNetworkAccess(aParentIPAddressSpace, aTargetIPAddressSpace) ||
   4362         IsLocalHostAccess(aParentIPAddressSpace, aTargetIPAddressSpace);
   4363 }
   4364 
   4365 Result<ActivateStorageAccess, nsresult> ParseActivateStorageAccess(
   4366    const nsACString& aActivateStorageAcess) {
   4367  nsCOMPtr<nsISFVService> sfv = GetSFVService();
   4368 
   4369  // Parse storage acces values
   4370  //  * Activate-Storage-Access: load
   4371  //  * Activate-Storage-Access: retry; allowed-origin="https://foo.bar"
   4372  //  * Activate-Storage-Access: retry; allowed-origin=*
   4373  // into ActivateStorageAccess struct. See ActivateStorageAccessVariant for
   4374  // documentation on fields
   4375  nsCOMPtr<nsISFVItem> parsedHeader;
   4376  MOZ_TRY(sfv->ParseItem(aActivateStorageAcess, getter_AddRefs(parsedHeader)));
   4377 
   4378  nsCOMPtr<nsISFVBareItem> value;
   4379  MOZ_TRY(parsedHeader->GetValue(getter_AddRefs(value)));
   4380 
   4381  nsCOMPtr<nsISFVToken> token = do_QueryInterface(value);
   4382  if (!token) {
   4383    return Err(NS_ERROR_FAILURE);
   4384  }
   4385  nsAutoCString tokenValue;
   4386  token->GetValue(tokenValue);
   4387 
   4388  if (tokenValue.EqualsLiteral("load")) {
   4389    return ActivateStorageAccess{
   4390        ActivateStorageAccessVariant::Load,
   4391    };
   4392  }
   4393  if (!tokenValue.EqualsLiteral("retry")) {
   4394    return Err(NS_ERROR_FAILURE);
   4395  }
   4396  nsCOMPtr<nsISFVParams> params;
   4397  MOZ_TRY(parsedHeader->GetParams(getter_AddRefs(params)));
   4398 
   4399  nsCOMPtr<nsISFVBareItem> item;
   4400  MOZ_TRY(params->Get("allowed-origin"_ns, getter_AddRefs(item)));
   4401 
   4402  // Evaluate whether the token value is a wildcard symbol.
   4403  nsCOMPtr<nsISFVToken> itemToken = do_QueryInterface(item);
   4404  if (itemToken) {
   4405    itemToken->GetValue(tokenValue);
   4406    if (!tokenValue.EqualsLiteral("*")) {
   4407      return Err(NS_ERROR_FAILURE);
   4408    }
   4409    return ActivateStorageAccess{
   4410        ActivateStorageAccessVariant::RetryAny,
   4411    };
   4412  }
   4413 
   4414  // Evaluate whether the token value is an origin.
   4415  nsCOMPtr<nsISFVString> itemString = do_QueryInterface(item);
   4416  if (!itemString) {
   4417    return Err(NS_ERROR_FAILURE);
   4418  }
   4419  ActivateStorageAccess result{ActivateStorageAccessVariant::RetryOrigin};
   4420  itemString->GetValue(result.origin);
   4421  return result;
   4422 }
   4423 
   4424 }  // namespace net
   4425 }  // namespace mozilla