tor-browser

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

nsHttpHandler.cpp (105145B)


      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 "HttpLog.h"
      9 
     10 #include "prsystem.h"
     11 
     12 #include "AltServiceChild.h"
     13 #include "nsCORSListenerProxy.h"
     14 #include "nsError.h"
     15 #include "nsHttp.h"
     16 #include "nsHttpHandler.h"
     17 #include "nsHttpChannel.h"
     18 #include "nsHTTPCompressConv.h"
     19 #include "nsHttpAuthCache.h"
     20 #include "nsStandardURL.h"
     21 #include "LoadContextInfo.h"
     22 #include "nsCategoryManagerUtils.h"
     23 #include "nsDirectoryServiceDefs.h"
     24 #include "nsSocketProviderService.h"
     25 #include "nsISocketProvider.h"
     26 #include "nsPrintfCString.h"
     27 #include "nsCOMPtr.h"
     28 #include "nsNetCID.h"
     29 #include "mozilla/AppShutdown.h"
     30 #include "mozilla/Base64.h"
     31 #include "mozilla/ClearOnShutdown.h"
     32 #include "mozilla/Components.h"
     33 #include "mozilla/Printf.h"
     34 #include "mozilla/RandomNum.h"
     35 #include "mozilla/SHA1.h"
     36 #include "mozilla/ScopeExit.h"
     37 #include "mozilla/Sprintf.h"
     38 #include "mozilla/StaticPrefs_network.h"
     39 #include "mozilla/StaticPrefs_privacy.h"
     40 #include "mozilla/StoragePrincipalHelper.h"
     41 #include "nsAsyncRedirectVerifyHelper.h"
     42 #include "nsSocketTransportService2.h"
     43 #include "ASpdySession.h"
     44 #include "EventTokenBucket.h"
     45 #include "Tickler.h"
     46 #include "nsIXULAppInfo.h"
     47 #include "nsICookieService.h"
     48 #include "nsIObserverService.h"
     49 #include "nsISiteSecurityService.h"
     50 #include "nsIStreamConverterService.h"
     51 #include "nsCRT.h"
     52 #include "nsIParentalControlsService.h"
     53 #include "nsPIDOMWindow.h"
     54 #include "nsIHttpActivityObserver.h"
     55 #include "nsHttpChannelAuthProvider.h"
     56 #include "nsINetworkLinkService.h"
     57 #include "nsNetUtil.h"
     58 #include "nsServiceManagerUtils.h"
     59 #include "nsComponentManagerUtils.h"
     60 #include "nsSocketTransportService2.h"
     61 #include "nsIOService.h"
     62 #include "nsISupportsPrimitives.h"
     63 #include "nsIXULRuntime.h"
     64 #include "nsCharSeparatedTokenizer.h"
     65 #include "nsRFPService.h"
     66 #include "mozilla/net/rust_helper.h"
     67 
     68 #include "mozilla/net/HttpConnectionMgrParent.h"
     69 #include "mozilla/net/NeckoChild.h"
     70 #include "mozilla/net/NeckoParent.h"
     71 #include "mozilla/net/RequestContextService.h"
     72 #include "mozilla/net/SocketProcessParent.h"
     73 #include "mozilla/net/SocketProcessChild.h"
     74 #include "mozilla/intl/LocaleService.h"
     75 #include "mozilla/ipc/URIUtils.h"
     76 #include "mozilla/glean/GleanPings.h"
     77 #include "mozilla/glean/NetwerkProtocolHttpMetrics.h"
     78 #include "mozilla/AntiTrackingRedirectHeuristic.h"
     79 #include "mozilla/DynamicFpiRedirectHeuristic.h"
     80 #include "mozilla/BasePrincipal.h"
     81 #include "mozilla/LazyIdleThread.h"
     82 #include "mozilla/OriginAttributesHashKey.h"
     83 #include "mozilla/StaticPrefs_image.h"
     84 #include "mozilla/SyncRunnable.h"
     85 
     86 #include "mozilla/dom/ContentParent.h"
     87 #include "mozilla/dom/Navigator.h"
     88 #include "mozilla/dom/Promise.h"
     89 #include "mozilla/dom/network/Connection.h"
     90 
     91 #include "nsNSSComponent.h"
     92 #include "TRRServiceChannel.h"
     93 
     94 #include <bitset>
     95 
     96 #if defined(XP_UNIX)
     97 #  include <sys/utsname.h>
     98 #endif
     99 
    100 #if defined(MOZ_WIDGET_GTK)
    101 #  include "mozilla/WidgetUtilsGtk.h"
    102 #endif
    103 
    104 #if defined(XP_WIN)
    105 #  include <windows.h>
    106 #  include "mozilla/WindowsVersion.h"
    107 #endif
    108 
    109 #if defined(XP_MACOSX)
    110 #  include <CoreServices/CoreServices.h>
    111 #endif
    112 
    113 //-----------------------------------------------------------------------------
    114 #include "mozilla/net/HttpChannelChild.h"
    115 
    116 #define UA_PREF_PREFIX "general.useragent."
    117 #ifdef XP_WIN
    118 #  define UA_SPARE_PLATFORM
    119 #endif
    120 
    121 #define HTTP_PREF_PREFIX "network.http."
    122 #define INTL_ACCEPT_LANGUAGES "intl.accept_languages"
    123 #define BROWSER_PREF_PREFIX "browser.cache."
    124 #define H2MANDATORY_SUITE "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256"
    125 #define SAFE_HINT_HEADER_VALUE "safeHint.enabled"
    126 #define SECURITY_PREFIX "security."
    127 #define DOM_SECURITY_PREFIX "dom.security"
    128 
    129 #define ACCEPT_HEADER_STYLE "text/css,*/*;q=0.1"
    130 #define ACCEPT_HEADER_JSON "application/json,*/*;q=0.5"
    131 #define ACCEPT_HEADER_ALL "*/*"
    132 
    133 #define UA_PREF(_pref) UA_PREF_PREFIX _pref
    134 #define HTTP_PREF(_pref) HTTP_PREF_PREFIX _pref
    135 #define BROWSER_PREF(_pref) BROWSER_PREF_PREFIX _pref
    136 
    137 #define NS_HTTP_PROTOCOL_FLAGS \
    138  (URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP | URI_LOADABLE_BY_ANYONE)
    139 
    140 //-----------------------------------------------------------------------------
    141 
    142 using mozilla::dom::Promise;
    143 
    144 namespace mozilla::net {
    145 
    146 LazyLogModule gHttpLog("nsHttp");
    147 LazyLogModule gHttpIOLog("HttpIO");
    148 
    149 #ifdef ANDROID
    150 static nsCString GetDeviceModelId() {
    151  // Assumed to be running on the main thread
    152  // We need the device property in either case
    153  nsAutoCString deviceModelId;
    154  nsCOMPtr<nsIPropertyBag2> infoService;
    155  infoService = mozilla::components::SystemInfo::Service();
    156  MOZ_ASSERT(infoService, "Could not find a system info service");
    157  nsAutoString androidDevice;
    158  nsresult rv = infoService->GetPropertyAsAString(u"device"_ns, androidDevice);
    159  if (NS_SUCCEEDED(rv)) {
    160    deviceModelId = NS_LossyConvertUTF16toASCII(androidDevice);
    161  }
    162  nsAutoCString deviceString;
    163  rv = Preferences::GetCString(UA_PREF("device_string"), deviceString);
    164  if (NS_SUCCEEDED(rv)) {
    165    deviceString.Trim(" ", true, true);
    166    deviceString.ReplaceSubstring("%DEVICEID%"_ns, deviceModelId);
    167    return std::move(deviceString);
    168  }
    169  return std::move(deviceModelId);
    170 }
    171 #endif
    172 
    173 #ifdef XP_UNIX
    174 static bool IsRunningUnderUbuntuSnap() {
    175 #  if defined(MOZ_WIDGET_GTK)
    176  if (!widget::IsRunningUnderSnap()) {
    177    return false;
    178  }
    179 
    180  char version[100];
    181  if (PR_GetSystemInfo(PR_SI_RELEASE_BUILD, version, sizeof(version)) ==
    182      PR_SUCCESS) {
    183    if (strstr(version, "Ubuntu")) {
    184      return true;
    185    }
    186  }
    187 #  endif
    188  return false;
    189 }
    190 #endif
    191 
    192 //-----------------------------------------------------------------------------
    193 // nsHttpHandler <public>
    194 //-----------------------------------------------------------------------------
    195 
    196 StaticRefPtr<nsHttpHandler> gHttpHandler;
    197 
    198 /* static */
    199 already_AddRefed<nsHttpHandler> nsHttpHandler::GetInstance() {
    200  if (!gHttpHandler) {
    201    gHttpHandler = new nsHttpHandler();
    202    DebugOnly<nsresult> rv = gHttpHandler->Init();
    203    MOZ_ASSERT(NS_SUCCEEDED(rv));
    204    // There is code that may be executed during the final cycle collection
    205    // shutdown and still referencing gHttpHandler.
    206    ClearOnShutdown(&gHttpHandler, ShutdownPhase::CCPostLastCycleCollection);
    207  }
    208  RefPtr<nsHttpHandler> httpHandler = gHttpHandler;
    209  return httpHandler.forget();
    210 }
    211 
    212 /// Derive the HTTP Accept header for image requests based on the enabled prefs
    213 /// for non-universal image types. This may be overridden in its entirety by
    214 /// the image.http.accept pref.
    215 static nsCString ImageAcceptHeader() {
    216  nsCString mimeTypes;
    217 
    218 #ifdef MOZ_AV1
    219  mimeTypes.Append("image/avif,");
    220 #endif
    221 
    222  if (mozilla::StaticPrefs::image_jxl_enabled()) {
    223    mimeTypes.Append("image/jxl,");
    224  }
    225 
    226  mimeTypes.Append("image/webp,");
    227 
    228  // Default value as specified by fetch standard
    229  // https://fetch.spec.whatwg.org/commit-snapshots/8dd73dbecfefdbef8f432164fb3a5b9785f7f520/#ref-for-header-list-contains%E2%91%A7
    230  mimeTypes.Append("image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5");
    231 
    232  return mimeTypes;
    233 }
    234 
    235 static nsCString DocumentAcceptHeader() {
    236  // https://fetch.spec.whatwg.org/#document-accept-header-value
    237  // The value specified by the fetch standard is
    238  // `text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`
    239  nsCString mimeTypes("text/html,application/xhtml+xml,application/xml;q=0.9,");
    240 
    241  // we also insert all of the image formats before */* when the pref is set
    242  if (mozilla::StaticPrefs::network_http_accept_include_images()) {
    243 #ifdef MOZ_AV1
    244    mimeTypes.Append("image/avif,");
    245 #endif
    246 
    247    if (mozilla::StaticPrefs::image_jxl_enabled()) {
    248      mimeTypes.Append("image/jxl,");
    249    }
    250 
    251    mimeTypes.Append("image/webp,image/png,image/svg+xml,");
    252  }
    253 
    254  mimeTypes.Append("*/*;q=0.8");
    255 
    256  return mimeTypes;
    257 }
    258 
    259 Atomic<bool, Relaxed> nsHttpHandler::sParentalControlsEnabled(false);
    260 
    261 nsHttpHandler::nsHttpHandler()
    262    : mAuthCache(new nsHttpAuthCache()),
    263      mPrivateAuthCache(new nsHttpAuthCache()),
    264      mIdleTimeout(PR_SecondsToInterval(10)),
    265      mSpdyTimeout(
    266          PR_SecondsToInterval(StaticPrefs::network_http_http2_timeout())),
    267      mResponseTimeout(PR_SecondsToInterval(300)),
    268      mImageAcceptHeader(ImageAcceptHeader()),
    269      mDocumentAcceptHeader(DocumentAcceptHeader()),
    270      mLastUniqueID(NowInSeconds()),
    271      mIdempotencyKeySeed(mozilla::RandomUint64OrDie()),
    272      mPrivateBrowsingIdempotencyKeySeed(mozilla::RandomUint64OrDie()),
    273      mDebugObservations(false),
    274      mEnableAltSvc(false),
    275      mEnableAltSvcOE(false),
    276      mSpdyPingThreshold(PR_SecondsToInterval(
    277          StaticPrefs::network_http_http2_ping_threshold())),
    278      mSpdyPingTimeout(PR_SecondsToInterval(
    279          StaticPrefs::network_http_http2_ping_timeout())) {
    280  LOG(("Creating nsHttpHandler [this=%p].\n", this));
    281 
    282  mUserAgentOverride.SetIsVoid(true);
    283 
    284  MOZ_ASSERT(!gHttpHandler, "HTTP handler already created!");
    285 
    286  nsCOMPtr<nsIXULRuntime> runtime;
    287  runtime = mozilla::components::XULRuntime::Service();
    288  if (runtime) {
    289    runtime->GetProcessID(&mProcessId);
    290    runtime->GetUniqueProcessID(&mUniqueProcessId);
    291  }
    292 }
    293 
    294 nsHttpHandler::~nsHttpHandler() {
    295  LOG(("Deleting nsHttpHandler [this=%p]\n", this));
    296 
    297  // make sure the connection manager is shutdown
    298  if (mConnMgr) {
    299    nsresult rv = mConnMgr->Shutdown();
    300    if (NS_FAILED(rv)) {
    301      LOG(
    302          ("nsHttpHandler [this=%p] "
    303           "failed to shutdown connection manager (%08x)\n",
    304           this, static_cast<uint32_t>(rv)));
    305    }
    306    mConnMgr = nullptr;
    307  }
    308 
    309  // Note: don't call NeckoChild::DestroyNeckoChild() here, as it's too late
    310  // and it'll segfault.  NeckoChild will get cleaned up by process exit.
    311 
    312  nsHttp::DestroyAtomTable();
    313 }
    314 
    315 static const char* gCallbackPrefs[] = {
    316    HTTP_PREF_PREFIX,
    317    UA_PREF_PREFIX,
    318    INTL_ACCEPT_LANGUAGES,
    319    BROWSER_PREF("disk_cache_ssl"),
    320    H2MANDATORY_SUITE,
    321    HTTP_PREF("tcp_keepalive.short_lived_connections"),
    322    HTTP_PREF("tcp_keepalive.long_lived_connections"),
    323    SAFE_HINT_HEADER_VALUE,
    324    SECURITY_PREFIX,
    325    DOM_SECURITY_PREFIX,
    326    "image.http.accept",
    327    "image.jxl.enabled",
    328    nullptr,
    329 };
    330 
    331 nsresult nsHttpHandler::Init() {
    332  nsresult rv;
    333 
    334  LOG(("nsHttpHandler::Init\n"));
    335  MOZ_ASSERT(NS_IsMainThread());
    336 
    337  // We should not create nsHttpHandler during shutdown, but we have some
    338  // xpcshell tests doing this.
    339  if (MOZ_UNLIKELY(AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown) &&
    340                   !PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR"))) {
    341    MOZ_DIAGNOSTIC_CRASH("Try to init HttpHandler after shutdown");
    342    return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
    343  }
    344 
    345  rv = nsHttp::CreateAtomTable();
    346  if (NS_FAILED(rv)) return rv;
    347 
    348  nsCOMPtr<nsIIOService> service;
    349  service = mozilla::components::IO::Service(&rv);
    350  if (NS_FAILED(rv)) {
    351    NS_WARNING("unable to continue without io service");
    352    return rv;
    353  }
    354  mIOService = new nsMainThreadPtrHolder<nsIIOService>(
    355      "nsHttpHandler::mIOService", service);
    356 
    357  gIOService->LaunchSocketProcess();
    358 
    359  if (IsNeckoChild()) NeckoChild::InitNeckoChild();
    360 
    361  InitUserAgentComponents();
    362 
    363  // This preference is only used in parent process.
    364  if (!IsNeckoChild()) {
    365    if (XRE_IsParentProcess()) {
    366      mDictionaryCache = DictionaryCache::GetInstance();
    367 
    368      std::bitset<3> usageOfHTTPSRRPrefs;
    369      usageOfHTTPSRRPrefs[0] = StaticPrefs::network_dns_upgrade_with_https_rr();
    370      usageOfHTTPSRRPrefs[1] =
    371          StaticPrefs::network_dns_use_https_rr_as_altsvc();
    372      usageOfHTTPSRRPrefs[2] = StaticPrefs::network_dns_echconfig_enabled();
    373      glean::networking::https_rr_prefs_usage.Set(
    374          static_cast<uint32_t>(usageOfHTTPSRRPrefs.to_ulong()));
    375      glean::networking::http3_enabled.Set(
    376          StaticPrefs::network_http_http3_enable());
    377    }
    378 
    379    mActivityDistributor = components::HttpActivityDistributor::Service();
    380 
    381    auto initQLogDir = [&]() {
    382      if (!StaticPrefs::network_http_http3_enable_qlog()) {
    383        return EmptyCString();
    384      }
    385 
    386      nsCOMPtr<nsIFile> qlogDir;
    387      nsresult rv =
    388          NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(qlogDir));
    389      if (NS_WARN_IF(NS_FAILED(rv))) {
    390        return EmptyCString();
    391      }
    392 
    393      nsAutoCString dirName("qlog_");
    394      dirName.AppendInt(mProcessId);
    395      rv = qlogDir->AppendNative(dirName);
    396      if (NS_WARN_IF(NS_FAILED(rv))) {
    397        return EmptyCString();
    398      }
    399 
    400      return qlogDir->HumanReadablePath();
    401    };
    402    mHttp3QlogDir = initQLogDir();
    403 
    404    if (const char* origin = PR_GetEnv("MOZ_FORCE_QUIC_ON")) {
    405      nsCCharSeparatedTokenizer tokens(nsDependentCString(origin), ':');
    406      nsAutoCString host;
    407      int32_t port = 443;
    408      if (tokens.hasMoreTokens()) {
    409        host = tokens.nextToken();
    410        if (tokens.hasMoreTokens()) {
    411          nsresult res;
    412          int32_t tmp = tokens.nextToken().ToInteger(&res);
    413          if (NS_SUCCEEDED(res)) {
    414            port = tmp;
    415          }
    416        }
    417        mAltSvcMappingTemptativeMap.InsertOrUpdate(
    418            host, MakeUnique<nsCString>(nsPrintfCString("h3=:%d", port)));
    419      }
    420    }
    421  }
    422 
    423  // monitor some preference changes
    424  Preferences::RegisterPrefixCallbacks(nsHttpHandler::PrefsChanged,
    425                                       gCallbackPrefs, this);
    426  PrefsChanged(nullptr);
    427 
    428  mCompatFirefox.AssignLiteral("Firefox/" MOZILLA_UAVERSION);
    429 
    430  nsCOMPtr<nsIXULAppInfo> appInfo;
    431  appInfo = mozilla::components::XULRuntime::Service();
    432 
    433  mAppName.AssignLiteral(MOZ_APP_UA_NAME);
    434  if (mAppName.Length() == 0 && appInfo) {
    435    // Try to get the UA name from appInfo, falling back to the name
    436    appInfo->GetUAName(mAppName);
    437    if (mAppName.Length() == 0) {
    438      appInfo->GetName(mAppName);
    439    }
    440    appInfo->GetVersion(mAppVersion);
    441    mAppName.StripChars(R"( ()<>@,;:\"/[]?={})");
    442  } else {
    443    mAppVersion.AssignLiteral(MOZ_APP_UA_VERSION);
    444  }
    445 
    446  mMisc.AssignLiteral("rv:" MOZILLA_UAVERSION);
    447 
    448  // Generate the spoofed User Agent for fingerprinting resistance.
    449  nsRFPService::GetSpoofedUserAgent(mSpoofedUserAgent);
    450 
    451  mSessionStartTime = NowInSeconds();
    452  mHandlerActive = true;
    453 
    454  rv = InitConnectionMgr();
    455  if (NS_FAILED(rv)) return rv;
    456 
    457  mAltSvcCache = MakeUnique<AltSvcCache>();
    458 
    459  mRequestContextService = RequestContextService::GetOrCreate();
    460 
    461 #if defined(ANDROID) || defined(XP_IOS)
    462  mProductSub.AssignLiteral(MOZILLA_UAVERSION);
    463 #else
    464  mProductSub.AssignLiteral(LEGACY_UA_GECKO_TRAIL);
    465 #endif
    466 
    467 #if DEBUG
    468  // dump user agent prefs
    469  LOG(("> legacy-app-name = %s\n", mLegacyAppName.get()));
    470  LOG(("> legacy-app-version = %s\n", mLegacyAppVersion.get()));
    471  LOG(("> platform = %s\n", mPlatform.get()));
    472  LOG(("> oscpu = %s\n", mOscpu.get()));
    473  LOG(("> misc = %s\n", mMisc.get()));
    474  LOG(("> product = %s\n", mProduct.get()));
    475  LOG(("> product-sub = %s\n", mProductSub.get()));
    476  LOG(("> app-name = %s\n", mAppName.get()));
    477  LOG(("> app-version = %s\n", mAppVersion.get()));
    478  LOG(("> compat-firefox = %s\n", mCompatFirefox.get()));
    479  LOG(("> user-agent = %s\n", UserAgent(false).get()));
    480 #endif
    481 
    482  // Startup the http category
    483  // Bring alive the objects in the http-protocol-startup category
    484  NS_CreateServicesFromCategory(
    485      NS_HTTP_STARTUP_CATEGORY,
    486      static_cast<nsISupports*>(static_cast<void*>(this)),
    487      NS_HTTP_STARTUP_TOPIC);
    488 
    489  nsCOMPtr<nsIObserverService> obsService =
    490      static_cast<nsIObserverService*>(gIOService);
    491  if (obsService) {
    492    // register the handler object as a weak callback as we don't need to worry
    493    // about shutdown ordering.
    494    obsService->AddObserver(this, "profile-change-net-teardown", true);
    495    obsService->AddObserver(this, "profile-change-net-restore", true);
    496    obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
    497    obsService->AddObserver(this, "net:clear-active-logins", true);
    498    obsService->AddObserver(this, "net:prune-dead-connections", true);
    499    // Sent by the TorButton add-on in the Tor Browser
    500    obsService->AddObserver(this, "net:prune-all-connections", true);
    501    obsService->AddObserver(this, "net:cancel-all-connections", true);
    502    obsService->AddObserver(this, "last-pb-context-exited", true);
    503    obsService->AddObserver(this, "browser:purge-session-history", true);
    504    obsService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
    505    obsService->AddObserver(this, "application-background", true);
    506    obsService->AddObserver(this, "psm:user-certificate-added", true);
    507    obsService->AddObserver(this, "psm:user-certificate-deleted", true);
    508    obsService->AddObserver(this, "intl:app-locales-changed", true);
    509    obsService->AddObserver(this, "browser-delayed-startup-finished", true);
    510    obsService->AddObserver(this, "network:reset-http3-excluded-list", true);
    511    obsService->AddObserver(this, "network:socket-process-crashed", true);
    512    obsService->AddObserver(this, "network:reset_third_party_roots_check",
    513                            true);
    514    obsService->AddObserver(this, "idle-daily", true);
    515 
    516    if (!IsNeckoChild()) {
    517      obsService->AddObserver(this, "net:current-browser-id", true);
    518    }
    519 
    520    // disabled as its a nop right now
    521    // obsService->AddObserver(this, "net:failed-to-process-uri-content", true);
    522  }
    523 
    524  MakeNewRequestTokenBucket();
    525  mWifiTickler = new Tickler();
    526  if (NS_FAILED(mWifiTickler->Init())) {
    527    mWifiTickler = nullptr;
    528  }
    529 
    530  UpdateParentalControlsEnabled(false /* wait for completion */);
    531  return NS_OK;
    532 }
    533 
    534 void nsHttpHandler::UpdateParentalControlsEnabled(bool waitForCompletion) {
    535  // Child process does not have privileges to read parentals control state
    536  if (!XRE_IsParentProcess()) {
    537    return;
    538  }
    539 
    540  auto getParentalControlsTask = []() {
    541    nsCOMPtr<nsIParentalControlsService> pc =
    542        do_CreateInstance("@mozilla.org/parental-controls-service;1");
    543    if (pc) {
    544      bool localEnabled = false;
    545      pc->GetParentalControlsEnabled(&localEnabled);
    546      sParentalControlsEnabled = localEnabled;
    547 
    548      // Cache the state of parental controls via preference
    549      if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
    550        Preferences::SetBool(
    551            StaticPrefs::GetPrefName_network_parental_controls_cached_state(),
    552            localEnabled);
    553      }
    554    }
    555  };
    556 
    557  if (waitForCompletion) {
    558    getParentalControlsTask();
    559  } else {
    560    // To avoid blocking on determining parental controls state, used the cached
    561    // pref until the runnable completes
    562    sParentalControlsEnabled =
    563        mozilla::StaticPrefs::network_parental_controls_cached_state();
    564    (void)NS_DispatchToMainThreadQueue(
    565        NS_NewRunnableFunction("GetParentalControlsEnabled",
    566                               std::move(getParentalControlsTask)),
    567        mozilla::EventQueuePriority::Idle);
    568  }
    569 }
    570 
    571 void nsHttpHandler::GenerateIdempotencyKeyForPost(const uint32_t aPostId,
    572                                                  nsILoadInfo* aLoadInfo,
    573                                                  nsACString& aOutKey) {
    574  MOZ_ASSERT(aLoadInfo);
    575  OriginAttributes attrs = aLoadInfo->GetOriginAttributes();
    576 
    577  // Create a SHA1 string using the origin attributes, session seed and the post
    578  // id.
    579  nsAutoCString sha1Input;
    580  attrs.CreateSuffix(sha1Input);
    581  sha1Input.AppendInt(aPostId);
    582  sha1Input.AppendInt(attrs.IsPrivateBrowsing()
    583                          ? mPrivateBrowsingIdempotencyKeySeed
    584                          : mIdempotencyKeySeed);
    585  SHA1Sum sha1;
    586  SHA1Sum::Hash hash;
    587  sha1.update((sha1Input.get()), sha1Input.Length());
    588  sha1.finish(hash);
    589  uint64_t hashValue = BigEndian::readUint64(&hash);
    590 
    591  aOutKey.Append("\"");
    592  aOutKey.AppendInt(hashValue);
    593  aOutKey.Append("\"");
    594 }
    595 
    596 const nsCString& nsHttpHandler::Http3QlogDir() {
    597  if (StaticPrefs::network_http_http3_enable_qlog()) {
    598    return mHttp3QlogDir;
    599  }
    600 
    601  return EmptyCString();
    602 }
    603 
    604 void nsHttpHandler::MakeNewRequestTokenBucket() {
    605  LOG(("nsHttpHandler::MakeNewRequestTokenBucket this=%p child=%d\n", this,
    606       IsNeckoChild()));
    607  if (!mConnMgr || IsNeckoChild()) {
    608    return;
    609  }
    610  RefPtr<EventTokenBucket> tokenBucket =
    611      new EventTokenBucket(RequestTokenBucketHz(), RequestTokenBucketBurst());
    612  // NOTE The thread or socket may be gone already.
    613  nsresult rv = mConnMgr->UpdateRequestTokenBucket(tokenBucket);
    614  if (NS_FAILED(rv)) {
    615    LOG(("    failed to update request token bucket\n"));
    616  }
    617 }
    618 
    619 nsresult nsHttpHandler::InitConnectionMgr() {
    620  // Init ConnectionManager only on parent!
    621  if (IsNeckoChild()) {
    622    return NS_OK;
    623  }
    624 
    625  if (mConnMgr) {
    626    return NS_OK;
    627  }
    628 
    629  if (nsIOService::UseSocketProcess(true) && XRE_IsParentProcess()) {
    630    mConnMgr = new HttpConnectionMgrParent();
    631    RefPtr<nsHttpHandler> self = this;
    632    auto task = [self]() {
    633      RefPtr<HttpConnectionMgrParent> parent =
    634          self->mConnMgr->AsHttpConnectionMgrParent();
    635      RefPtr<SocketProcessParent> socketParent =
    636          SocketProcessParent::GetSingleton();
    637      (void)socketParent->SendPHttpConnectionMgrConstructor(
    638          parent,
    639          HttpHandlerInitArgs(self->mLegacyAppName, self->mLegacyAppVersion,
    640                              self->mPlatform, self->mOscpu, self->mMisc,
    641                              self->mProduct, self->mProductSub, self->mAppName,
    642                              self->mAppVersion, self->mCompatFirefox,
    643                              self->mCompatDevice, self->mDeviceModelId));
    644    };
    645    gIOService->CallOrWaitForSocketProcess(std::move(task));
    646  } else {
    647    MOZ_ASSERT(XRE_IsSocketProcess() || !nsIOService::UseSocketProcess());
    648    mConnMgr = new nsHttpConnectionMgr();
    649  }
    650 
    651  return mConnMgr->Init(mMaxUrgentExcessiveConns, mMaxConnections,
    652                        mMaxPersistentConnectionsPerServer,
    653                        mMaxPersistentConnectionsPerProxy, mMaxRequestDelay,
    654                        mThrottleEnabled, mThrottleSuspendFor,
    655                        mThrottleResumeFor, mThrottleHoldTime, mThrottleMaxTime,
    656                        mBeConservativeForProxy);
    657 }
    658 
    659 // We're using RequestOverride because this can get called when these are
    660 // set by Fetch from the old request. We need to pass a function pointer to
    661 // let GetDictionaryFor suspend the channel before starting the async
    662 // dictionary load.
    663 nsresult nsHttpHandler::AddAcceptAndDictionaryHeaders(
    664    nsIURI* aURI, ExtContentPolicyType aType, nsHttpRequestHead* aRequest,
    665    bool aSecure, nsHttpChannel* aChan, void (*aSuspend)(nsHttpChannel*),
    666    const std::function<bool(bool, DictionaryCacheEntry*)>& aCallback) {
    667  LOG(("Adding Dictionary headers"));
    668  auto guard = MakeScopeExit([&]() { (aCallback)(false, nullptr); });
    669 
    670  nsresult rv = NS_OK;
    671  // Add the "Accept-Encoding" header and possibly Dictionary headers
    672  if (aSecure) {
    673    // The dictionary info may require us to check the cache.
    674    if (StaticPrefs::network_http_dictionaries_enable()) {
    675      // Note: this is async; the lambda can happen later
    676      // aCallback will now be owned by GetDictionaryFor
    677      guard.release();
    678      mDictionaryCache->GetDictionaryFor(
    679          aURI, aType, aChan, aSuspend,
    680          [self = RefPtr(this), aRequest, aCallback](
    681              bool aNeedsResume, DictionaryCacheEntry* aDict) {
    682            if (!aDict) {
    683              // Accept-Encoding was already set in AddStandardHeaders
    684              (aCallback)(aNeedsResume, nullptr);
    685              return NS_OK;
    686            }
    687 
    688            nsAutoCStringN<64> encodedHash = ":"_ns + aDict->GetHash() + ":"_ns;
    689 
    690            // Need to retain access to the dictionary until the request
    691            // completes. Note that this includes if the dictionary we offered
    692            // gets replaced by another request while we're waiting for a
    693            // response; in that case we need to read in a copy of the
    694            // dictionary into memory before overwriting it and store in dict
    695            // temporarily.
    696            aRequest->SetDictionary(aDict);
    697 
    698            // We want to make sure that the cache entry doesn't disappear out
    699            // from under us if we set the header, so do the callback to
    700            // Prefetch() the entry before adding the headers (so we don't
    701            // have to remove the headers if Prefetch() fails).  It might fail
    702            // if something is asynchronously Dooming the entry but the
    703            // DictionaryCache hasn't been updated to remove the entry yet (or
    704            // any other thing that were to desynchronize the DictionaryCache
    705            // with the actual cache.
    706            if ((aCallback)(aNeedsResume, aDict)) {
    707              LOG_DICTIONARIES(
    708                  ("Setting Available-Dictionary: %s", encodedHash.get()));
    709              nsresult rv = aRequest->SetHeader(
    710                  nsHttp::Available_Dictionary, encodedHash, false,
    711                  nsHttpHeaderArray::eVarietyRequestOverride);
    712              if (NS_FAILED(rv)) {
    713                return rv;
    714              }
    715              if (!aDict->GetId().IsEmpty()) {
    716                nsPrintfCString id("\"%s\"", aDict->GetId().get());
    717                LOG_DICTIONARIES(("Setting Dictionary-Id: %s", id.get()));
    718                rv = aRequest->SetHeader(
    719                    nsHttp::Dictionary_Id, id, false,
    720                    nsHttpHeaderArray::eVarietyRequestOverride);
    721                if (NS_FAILED(rv)) {
    722                  return rv;
    723                }
    724              }
    725              return aRequest->SetHeader(
    726                  nsHttp::Accept_Encoding, self->mDictionaryAcceptEncodings,
    727                  false, nsHttpHeaderArray::eVarietyRequestOverride);
    728            }
    729            return NS_OK;
    730          });
    731    }
    732  }
    733  // guard may call aCallback here
    734  return rv;
    735 }
    736 
    737 nsresult nsHttpHandler::AddStandardRequestHeaders(
    738    nsHttpRequestHead* request, nsIURI* aURI, bool aIsHTTPS,
    739    ExtContentPolicyType aContentPolicyType, bool aShouldResistFingerprinting,
    740    const nsCString& aLanguageOverride) {
    741  nsresult rv;
    742 
    743  // Add the "User-Agent" header
    744  rv = request->SetHeader(nsHttp::User_Agent,
    745                          UserAgent(aShouldResistFingerprinting), false,
    746                          nsHttpHeaderArray::eVarietyRequestDefault);
    747  if (NS_FAILED(rv)) return rv;
    748 
    749  // MIME based content negotiation lives!
    750  // Add the "Accept" header.  Note, this is set as an override because the
    751  // service worker expects to see it.  The other "default" headers are
    752  // hidden from service worker interception.
    753  nsAutoCString accept;
    754  if (aContentPolicyType == ExtContentPolicy::TYPE_DOCUMENT ||
    755      aContentPolicyType == ExtContentPolicy::TYPE_SUBDOCUMENT) {
    756    accept.Assign(mDocumentAcceptHeader);
    757  } else if (aContentPolicyType == ExtContentPolicy::TYPE_IMAGE ||
    758             aContentPolicyType == ExtContentPolicy::TYPE_IMAGESET) {
    759    accept.Assign(mImageAcceptHeader);
    760  } else if (aContentPolicyType == ExtContentPolicy::TYPE_STYLESHEET) {
    761    accept.Assign(ACCEPT_HEADER_STYLE);
    762  } else if (aContentPolicyType == ExtContentPolicy::TYPE_JSON) {
    763    accept.Assign(ACCEPT_HEADER_JSON);
    764  } else {
    765    accept.Assign(ACCEPT_HEADER_ALL);
    766  }
    767 
    768  rv = request->SetHeader(nsHttp::Accept, accept, false,
    769                          nsHttpHeaderArray::eVarietyRequestOverride);
    770  if (NS_FAILED(rv)) return rv;
    771 
    772  if (!aLanguageOverride.IsEmpty()) {
    773    nsAutoCString acceptLanguage;
    774    acceptLanguage.Assign(aLanguageOverride.get());
    775    rv = request->SetHeader(nsHttp::Accept_Language, acceptLanguage, false,
    776                            nsHttpHeaderArray::eVarietyRequestOverride);
    777    if (NS_FAILED(rv)) return rv;
    778  } else {
    779    // Add the "Accept-Language" header.  This header is also exposed to the
    780    // service worker.
    781    if (mAcceptLanguagesIsDirty) {
    782      rv = SetAcceptLanguages();
    783      MOZ_ASSERT(NS_SUCCEEDED(rv));
    784    }
    785 
    786    // Add the "Accept-Language" header
    787    if (!mAcceptLanguages.IsEmpty()) {
    788      rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages, false,
    789                              nsHttpHeaderArray::eVarietyRequestOverride);
    790      if (NS_FAILED(rv)) return rv;
    791    }
    792  }
    793 
    794  // add the "Send Hint" header
    795  if (mSafeHintEnabled || sParentalControlsEnabled) {
    796    rv = request->SetHeader(nsHttp::Prefer, "safe"_ns, false,
    797                            nsHttpHeaderArray::eVarietyRequestDefault);
    798    if (NS_FAILED(rv)) return rv;
    799  }
    800 
    801  if (aIsHTTPS) {
    802    rv = request->SetHeader(nsHttp::Accept_Encoding, mHttpsAcceptEncodings,
    803                            false, nsHttpHeaderArray::eVarietyRequestDefault);
    804  } else {
    805    rv = request->SetHeader(nsHttp::Accept_Encoding, mHttpAcceptEncodings,
    806                            false, nsHttpHeaderArray::eVarietyRequestDefault);
    807  }
    808  return NS_OK;
    809 }
    810 
    811 nsresult nsHttpHandler::AddConnectionHeader(nsHttpRequestHead* request,
    812                                            uint32_t caps) {
    813  // RFC2616 section 19.6.2 states that the "Connection: keep-alive"
    814  // and "Keep-alive" request headers should not be sent by HTTP/1.1
    815  // user-agents.  But this is not a problem in practice, and the
    816  // alternative proxy-connection is worse. see 570283
    817 
    818  constexpr auto close = "close"_ns;
    819  constexpr auto keepAlive = "keep-alive"_ns;
    820 
    821  const nsLiteralCString* connectionType = &close;
    822  if (caps & NS_HTTP_ALLOW_KEEPALIVE) {
    823    connectionType = &keepAlive;
    824  }
    825 
    826  return request->SetHeader(nsHttp::Connection, *connectionType);
    827 }
    828 
    829 bool nsHttpHandler::IsAcceptableEncoding(const char* enc, bool isSecure) {
    830  if (!enc) return false;
    831 
    832  // we used to accept x-foo anytime foo was acceptable, but that's just
    833  // continuing bad behavior.. so limit it to known x-* patterns
    834  bool rv;
    835  if (isSecure) {
    836    // Should be a superset of mAcceptEncodings (unless someone messes with
    837    // prefs)
    838    rv = nsHttp::FindToken(mDictionaryAcceptEncodings.get(), enc,
    839                           HTTP_LWS ",") != nullptr;
    840  } else {
    841    rv = nsHttp::FindToken(mHttpAcceptEncodings.get(), enc, HTTP_LWS ",") !=
    842         nullptr;
    843  }
    844  // gzip and deflate are inherently acceptable in modern HTTP - always
    845  // process them if a stream converter can also be found.
    846  if (!rv &&
    847      (!nsCRT::strcasecmp(enc, "gzip") || !nsCRT::strcasecmp(enc, "deflate") ||
    848       !nsCRT::strcasecmp(enc, "x-gzip") ||
    849       !nsCRT::strcasecmp(enc, "x-deflate"))) {
    850    rv = true;
    851  }
    852  LOG(("nsHttpHandler::IsAceptableEncoding %s https=%d %d\n", enc, isSecure,
    853       rv));
    854  return rv;
    855 }
    856 
    857 nsISiteSecurityService* nsHttpHandler::GetSSService() {
    858  if (!mSSService) {
    859    nsCOMPtr<nsISiteSecurityService> service;
    860    service = mozilla::components::SiteSecurity::Service();
    861    mSSService = new nsMainThreadPtrHolder<nsISiteSecurityService>(
    862        "nsHttpHandler::mSSService", service);
    863  }
    864  return mSSService;
    865 }
    866 
    867 nsICookieService* nsHttpHandler::GetCookieService() {
    868  if (!mCookieService) {
    869    nsCOMPtr<nsICookieService> service =
    870        do_GetService(NS_COOKIESERVICE_CONTRACTID);
    871    mCookieService = new nsMainThreadPtrHolder<nsICookieService>(
    872        "nsHttpHandler::mCookieService", service);
    873  }
    874  return mCookieService;
    875 }
    876 
    877 nsresult nsHttpHandler::GetIOService(nsIIOService** result) {
    878  NS_ENSURE_ARG_POINTER(result);
    879 
    880  *result = do_AddRef(mIOService.get()).take();
    881  return NS_OK;
    882 }
    883 
    884 void nsHttpHandler::NotifyObservers(nsIChannel* chan, const char* event) {
    885  LOG(("nsHttpHandler::NotifyObservers [this=%p chan=%p event=\"%s\"]\n", this,
    886       chan, event));
    887  nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
    888  if (obsService) obsService->NotifyObservers(chan, event, nullptr);
    889 }
    890 
    891 nsresult nsHttpHandler::AsyncOnChannelRedirect(
    892    nsIChannel* oldChan, nsIChannel* newChan, uint32_t flags,
    893    nsIEventTarget* mainThreadEventTarget) {
    894  MOZ_ASSERT(NS_IsMainThread() && (oldChan && newChan));
    895 
    896  nsCOMPtr<nsIURI> oldURI;
    897  oldChan->GetURI(getter_AddRefs(oldURI));
    898  MOZ_ASSERT(oldURI);
    899 
    900  nsCOMPtr<nsIURI> newURI;
    901  newChan->GetURI(getter_AddRefs(newURI));
    902  MOZ_ASSERT(newURI);
    903 
    904  PrepareForAntiTrackingRedirectHeuristic(oldChan, oldURI, newChan, newURI);
    905 
    906  DynamicFpiRedirectHeuristic(oldChan, oldURI, newChan, newURI);
    907 
    908  // TODO E10S This helper has to be initialized on the other process
    909  RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
    910      new nsAsyncRedirectVerifyHelper();
    911 
    912  return redirectCallbackHelper->Init(oldChan, newChan, flags,
    913                                      mainThreadEventTarget);
    914 }
    915 
    916 /* static */
    917 nsresult nsHttpHandler::GenerateHostPort(const nsCString& host, int32_t port,
    918                                         nsACString& hostLine) {
    919  return NS_GenerateHostPort(host, port, hostLine);
    920 }
    921 
    922 // static
    923 uint8_t nsHttpHandler::UrgencyFromCoSFlags(uint32_t cos,
    924                                           int32_t aSupportsPriority) {
    925  uint8_t urgency;
    926  if (cos & nsIClassOfService::UrgentStart) {
    927    // coming from an user interaction => response should be the highest
    928    // priority
    929    urgency = 1;
    930  } else if (cos & nsIClassOfService::Leader) {
    931    // main html document normal priority
    932    urgency = 2;
    933  } else if (cos & nsIClassOfService::Unblocked) {
    934    urgency = 3;
    935  } else if (cos & nsIClassOfService::Follower) {
    936    urgency = 4;
    937  } else if (cos & nsIClassOfService::Speculative) {
    938    urgency = 6;
    939  } else if (cos & nsIClassOfService::Background) {
    940    // background tasks can be deprioritzed to the lowest priority
    941    urgency = 6;
    942  } else if (cos & nsIClassOfService::Tail) {
    943    urgency = mozilla::StaticPrefs::network_http_tailing_urgency();
    944  } else {
    945    // all others get a lower priority than the main html document
    946    urgency = 4;
    947  }
    948 
    949  int8_t adjustment = 0;
    950  if (mozilla::StaticPrefs::network_fetchpriority_adjust_urgency()) {
    951    if (aSupportsPriority <= nsISupportsPriority::PRIORITY_HIGHEST) {
    952      adjustment = -2;
    953    } else if (aSupportsPriority <= nsISupportsPriority::PRIORITY_HIGH) {
    954      adjustment = -1;
    955    } else if (aSupportsPriority >= nsISupportsPriority::PRIORITY_LOWEST) {
    956      adjustment = 2;
    957    } else if (aSupportsPriority >= nsISupportsPriority::PRIORITY_LOW) {
    958      adjustment = 1;
    959    }
    960  }
    961 
    962  auto adjustUrgency = [](uint8_t u, int8_t a) -> uint8_t {
    963    int16_t result = static_cast<int16_t>(u) + a;
    964    if (result <= 0) {
    965      return 0;
    966    }
    967    if (result >= 6) {
    968      return 6;
    969    }
    970    return result;
    971  };
    972 
    973  return adjustUrgency(urgency, adjustment);
    974 }
    975 
    976 //-----------------------------------------------------------------------------
    977 // nsHttpHandler <private>
    978 //-----------------------------------------------------------------------------
    979 
    980 const nsCString& nsHttpHandler::UserAgent(bool aShouldResistFingerprinting) {
    981  if (aShouldResistFingerprinting && !mSpoofedUserAgent.IsEmpty()) {
    982    LOG(("using spoofed userAgent : %s\n", mSpoofedUserAgent.get()));
    983    return mSpoofedUserAgent;
    984  }
    985 
    986  if (!mUserAgentOverride.IsVoid()) {
    987    LOG(("using general.useragent.override : %s\n", mUserAgentOverride.get()));
    988    return mUserAgentOverride;
    989  }
    990 
    991  if (mUserAgentIsDirty) {
    992    BuildUserAgent();
    993    mUserAgentIsDirty = false;
    994  }
    995 
    996  return mUserAgent;
    997 }
    998 
    999 void nsHttpHandler::BuildUserAgent() {
   1000  LOG(("nsHttpHandler::BuildUserAgent\n"));
   1001 
   1002  MOZ_ASSERT(!mLegacyAppName.IsEmpty() && !mLegacyAppVersion.IsEmpty(),
   1003             "HTTP cannot send practical requests without this much");
   1004 
   1005  // preallocate to worst-case size, which should always be better
   1006  // than if we didn't preallocate at all.
   1007  mUserAgent.SetCapacity(mLegacyAppName.Length() + mLegacyAppVersion.Length() +
   1008 #ifndef UA_SPARE_PLATFORM
   1009                         mPlatform.Length() +
   1010 #endif
   1011                         mOscpu.Length() + mMisc.Length() + mProduct.Length() +
   1012                         mProductSub.Length() + mAppName.Length() +
   1013                         mAppVersion.Length() + mCompatFirefox.Length() +
   1014                         mCompatDevice.Length() + mDeviceModelId.Length() + 13);
   1015 
   1016  // Application portion
   1017  mUserAgent.Assign(mLegacyAppName);
   1018  mUserAgent += '/';
   1019  mUserAgent += mLegacyAppVersion;
   1020  mUserAgent += ' ';
   1021 
   1022  // Application comment
   1023  mUserAgent += '(';
   1024 #ifndef UA_SPARE_PLATFORM
   1025  if (!mPlatform.IsEmpty()) {
   1026    mUserAgent += mPlatform;
   1027    mUserAgent.AppendLiteral("; ");
   1028  }
   1029 #endif
   1030  if (!mCompatDevice.IsEmpty()) {
   1031    mUserAgent += mCompatDevice;
   1032    mUserAgent.AppendLiteral("; ");
   1033  } else if (!mOscpu.IsEmpty()) {
   1034    mUserAgent += mOscpu;
   1035    mUserAgent.AppendLiteral("; ");
   1036  }
   1037  if (!mDeviceModelId.IsEmpty()) {
   1038    mUserAgent += mDeviceModelId;
   1039    mUserAgent.AppendLiteral("; ");
   1040  }
   1041  mUserAgent += mMisc;
   1042  mUserAgent += ')';
   1043 
   1044  // Product portion
   1045  mUserAgent += ' ';
   1046  mUserAgent += mProduct;
   1047  mUserAgent += '/';
   1048  mUserAgent += mProductSub;
   1049 
   1050  bool isFirefox = true;
   1051  if (isFirefox || mCompatFirefoxEnabled) {
   1052    // "Firefox/x.y" (compatibility) app token
   1053    mUserAgent += ' ';
   1054    mUserAgent += mCompatFirefox;
   1055  }
   1056  if (!isFirefox) {
   1057    // App portion
   1058    mUserAgent += ' ';
   1059    mUserAgent += mAppName;
   1060    mUserAgent += '/';
   1061    mUserAgent += mAppVersion;
   1062  }
   1063 }
   1064 
   1065 #ifdef XP_WIN
   1066 // Hardcode the reported Windows version to 10.0. This way, Microsoft doesn't
   1067 // get to change Web compat-sensitive values without our veto. The compat-
   1068 // sensitivity keeps going up as 10.0 stays as the current value for longer
   1069 // and longer. If the system-reported version ever changes, we'll be able to
   1070 // take our time to evaluate the Web compat impact instead of having to
   1071 // scramble to react like happened with macOS changing from 10.x to 11.x.
   1072 #  define OSCPU_WINDOWS "Windows NT 10.0"
   1073 #  define OSCPU_WIN64 OSCPU_WINDOWS "; Win64; x64"
   1074 #endif
   1075 
   1076 void nsHttpHandler::InitUserAgentComponents() {
   1077  // Don't build user agent components in socket process, since the system info
   1078  // is not available.
   1079  if (XRE_IsSocketProcess()) {
   1080    mUserAgentIsDirty = true;
   1081    return;
   1082  }
   1083 
   1084  // Gather platform.
   1085  mPlatform.AssignLiteral(
   1086 #if defined(ANDROID)
   1087      "Android"
   1088 #elif defined(XP_WIN)
   1089      "Windows"
   1090 #elif defined(XP_MACOSX)
   1091      "Macintosh"
   1092 #elif defined(XP_IOS)
   1093      "iPhone"
   1094 #elif defined(XP_UNIX)
   1095      // We historically have always had X11 here,
   1096      // and there seems little a webpage can sensibly do
   1097      // based on it being something else, so use X11 for
   1098      // backwards compatibility in all cases.
   1099      "X11"
   1100 #endif
   1101  );
   1102 
   1103 #ifdef XP_UNIX
   1104  if (IsRunningUnderUbuntuSnap()) {
   1105    mPlatform.AppendLiteral("; Ubuntu");
   1106  }
   1107 #endif
   1108 
   1109 #ifdef ANDROID
   1110  nsCOMPtr<nsIPropertyBag2> infoService;
   1111  infoService = mozilla::components::SystemInfo::Service();
   1112  MOZ_ASSERT(infoService, "Could not find a system info service");
   1113  nsresult rv;
   1114 
   1115  // Add the Android version number to the Fennec platform identifier.
   1116  nsAutoString androidVersion;
   1117  rv = infoService->GetPropertyAsAString(u"release_version"_ns, androidVersion);
   1118  MOZ_ASSERT_IF(
   1119      NS_SUCCEEDED(rv),
   1120      // Like version "9"
   1121      (androidVersion.Length() == 1 && std::isdigit(androidVersion[0])) ||
   1122          // Or like version "8.1", "10", or "12.1"
   1123          (androidVersion.Length() >= 2 && std::isdigit(androidVersion[0]) &&
   1124           (androidVersion[1] == u'.' || std::isdigit(androidVersion[1]))));
   1125 
   1126  // Spoof version "Android 10" for Android OS versions < 10 to reduce their
   1127  // fingerprintable user information. For Android OS versions >= 10, report
   1128  // the real OS version because some enterprise websites only want to permit
   1129  // clients with recent OS version (like bug 1876742). Two leading digits
   1130  // in the version string means the version number is >= 10.
   1131  mPlatform += " ";
   1132  if (NS_SUCCEEDED(rv) && androidVersion.Length() >= 2 &&
   1133      std::isdigit(androidVersion[0]) && std::isdigit(androidVersion[1])) {
   1134    mPlatform += NS_LossyConvertUTF16toASCII(androidVersion);
   1135  } else {
   1136    mPlatform.AppendLiteral("10");
   1137  }
   1138 
   1139  // Add the `Mobile` or `TV` token when running on device.
   1140  bool isTV;
   1141  rv = infoService->GetPropertyAsBool(u"tv"_ns, &isTV);
   1142  if (NS_SUCCEEDED(rv) && isTV) {
   1143    mCompatDevice.AssignLiteral("TV");
   1144  } else {
   1145    mCompatDevice.AssignLiteral("Mobile");
   1146  }
   1147 
   1148  if (Preferences::GetBool(UA_PREF("use_device"), false)) {
   1149    mDeviceModelId = mozilla::net::GetDeviceModelId();
   1150  }
   1151 #endif  // ANDROID
   1152 
   1153 #if defined(XP_IOS)
   1154  // Freeze the iOS version to 18.0, use an underscore separator to avoid
   1155  // detection as macOS.
   1156  mCompatDevice.AssignLiteral("CPU iPhone OS 18_0 like Mac OS X");
   1157 #endif
   1158 
   1159  // Gather OS/CPU.
   1160 #if defined(XP_WIN)
   1161 
   1162 #  if defined _M_X64 || defined _M_AMD64
   1163  mOscpu.AssignLiteral(OSCPU_WIN64);
   1164 #  elif defined(_ARM64_)
   1165  // Report ARM64 Windows 11+ as x86_64 and Windows 10 as x86. Windows 11+
   1166  // supports x86_64 emulation, but Windows 10 only supports x86 emulation.
   1167  if (IsWin11OrLater()) {
   1168    mOscpu.AssignLiteral(OSCPU_WIN64);
   1169  } else {
   1170    mOscpu.AssignLiteral(OSCPU_WINDOWS);
   1171  }
   1172 #  else
   1173  BOOL isWow64 = FALSE;
   1174  if (!IsWow64Process(GetCurrentProcess(), &isWow64)) {
   1175    isWow64 = FALSE;
   1176  }
   1177  if (isWow64) {
   1178    mOscpu.AssignLiteral(OSCPU_WIN64);
   1179  } else {
   1180    mOscpu.AssignLiteral(OSCPU_WINDOWS);
   1181  }
   1182 #  endif
   1183 
   1184 #elif defined(XP_MACOSX)
   1185  mOscpu.AssignLiteral("Intel Mac OS X 10.15");
   1186 #elif defined(ANDROID)
   1187  mOscpu.AssignLiteral("Linux armv81");
   1188 #elif defined(XP_IOS)
   1189  mOscpu.AssignLiteral("iPhone");
   1190 #else
   1191  mOscpu.AssignLiteral("Linux x86_64");
   1192 #endif
   1193 
   1194  mUserAgentIsDirty = true;
   1195 }
   1196 
   1197 #ifdef XP_MACOSX
   1198 void nsHttpHandler::InitMSAuthorities() {
   1199  if (!StaticPrefs::network_http_microsoft_entra_sso_enabled()) {
   1200    return;
   1201  }
   1202 
   1203  nsAutoCString authorityList;
   1204 
   1205  if (NS_FAILED(Preferences::GetCString("network.microsoft-sso-authority-list",
   1206                                        authorityList))) {
   1207    return;
   1208  }
   1209  mMSAuthorities.Clear();
   1210 
   1211  // Normalize the MS authority list
   1212  nsCCharSeparatedTokenizer tokenizer(authorityList, ',');
   1213  while (tokenizer.hasMoreTokens()) {
   1214    const nsDependentCSubstring& token = tokenizer.nextToken();
   1215    mMSAuthorities.Insert(token);
   1216  }
   1217 }
   1218 #endif
   1219 
   1220 uint32_t nsHttpHandler::MaxSocketCount() {
   1221  PR_CallOnce(&nsSocketTransportService::gMaxCountInitOnce,
   1222              nsSocketTransportService::DiscoverMaxCount);
   1223  // Don't use the full max count because sockets can be held in
   1224  // the persistent connection pool for a long time and that could
   1225  // starve other users.
   1226 
   1227  uint32_t maxCount = nsSocketTransportService::gMaxCount;
   1228  if (maxCount <= 8) {
   1229    maxCount = 1;
   1230  } else {
   1231    maxCount -= 8;
   1232  }
   1233 
   1234  return maxCount;
   1235 }
   1236 
   1237 // static
   1238 void nsHttpHandler::PrefsChanged(const char* pref, void* self) {
   1239  static_cast<nsHttpHandler*>(self)->PrefsChanged(pref);
   1240 }
   1241 
   1242 void nsHttpHandler::PrefsChanged(const char* pref) {
   1243  nsresult rv = NS_OK;
   1244  int32_t val;
   1245 
   1246  LOG(("nsHttpHandler::PrefsChanged [pref=%s]\n", pref));
   1247 
   1248  if (pref) {
   1249    gIOService->NotifySocketProcessPrefsChanged(pref);
   1250  }
   1251 
   1252 #define PREF_CHANGED(p) ((pref == nullptr) || !strcmp(pref, p))
   1253 #define MULTI_PREF_CHANGED(p) \
   1254  ((pref == nullptr) || !strncmp(pref, p, sizeof(p) - 1))
   1255 
   1256  // If a security pref changed, lets clear our connection pool reuse
   1257  if (MULTI_PREF_CHANGED(SECURITY_PREFIX)) {
   1258    LOG(("nsHttpHandler::PrefsChanged Security Pref Changed %s\n", pref));
   1259    if (mConnMgr) {
   1260      rv = mConnMgr->DoShiftReloadConnectionCleanup();
   1261      if (NS_FAILED(rv)) {
   1262        LOG(
   1263            ("nsHttpHandler::PrefsChanged "
   1264             "DoShiftReloadConnectionCleanup failed (%08x)\n",
   1265             static_cast<uint32_t>(rv)));
   1266      }
   1267      rv = mConnMgr->PruneDeadConnections();
   1268      if (NS_FAILED(rv)) {
   1269        LOG(
   1270            ("nsHttpHandler::PrefsChanged "
   1271             "PruneDeadConnections failed (%08x)\n",
   1272             static_cast<uint32_t>(rv)));
   1273      }
   1274    }
   1275  }
   1276 
   1277  //
   1278  // UA components
   1279  //
   1280 
   1281  bool cVar = false;
   1282 
   1283  if (PREF_CHANGED(UA_PREF("compatMode.firefox"))) {
   1284    rv = Preferences::GetBool(UA_PREF("compatMode.firefox"), &cVar);
   1285    mCompatFirefoxEnabled = (NS_SUCCEEDED(rv) && cVar);
   1286    mUserAgentIsDirty = true;
   1287  }
   1288 
   1289  // general.useragent.override
   1290  if (PREF_CHANGED(UA_PREF("override"))) {
   1291    Preferences::GetCString(UA_PREF("override"), mUserAgentOverride);
   1292    mUserAgentIsDirty = true;
   1293  }
   1294 
   1295 #ifdef ANDROID
   1296  // general.useragent.use_device
   1297  if (PREF_CHANGED(UA_PREF("use_device"))) {
   1298    if (Preferences::GetBool(UA_PREF("use_device"), false)) {
   1299      if (!XRE_IsSocketProcess()) {
   1300        mDeviceModelId = mozilla::net::GetDeviceModelId();
   1301        if (gIOService->SocketProcessReady()) {
   1302          RefPtr<SocketProcessParent> socketParent =
   1303              SocketProcessParent::GetSingleton();
   1304          (void)socketParent->SendUpdateDeviceModelId(mDeviceModelId);
   1305        }
   1306      }
   1307    } else {
   1308      mDeviceModelId.Truncate();
   1309    }
   1310    mUserAgentIsDirty = true;
   1311  }
   1312 #endif
   1313 
   1314  //
   1315  // HTTP options
   1316  //
   1317 
   1318  if (PREF_CHANGED(HTTP_PREF("keep-alive.timeout"))) {
   1319    rv = Preferences::GetInt(HTTP_PREF("keep-alive.timeout"), &val);
   1320    if (NS_SUCCEEDED(rv)) {
   1321      mIdleTimeout = PR_SecondsToInterval(std::clamp(val, 1, 0xffff));
   1322    }
   1323  }
   1324 
   1325  if (PREF_CHANGED(HTTP_PREF("request.max-attempts"))) {
   1326    rv = Preferences::GetInt(HTTP_PREF("request.max-attempts"), &val);
   1327    if (NS_SUCCEEDED(rv)) {
   1328      mMaxRequestAttempts = (uint16_t)std::clamp(val, 1, 0xffff);
   1329    }
   1330  }
   1331 
   1332  if (PREF_CHANGED(HTTP_PREF("request.max-start-delay"))) {
   1333    rv = Preferences::GetInt(HTTP_PREF("request.max-start-delay"), &val);
   1334    if (NS_SUCCEEDED(rv)) {
   1335      mMaxRequestDelay = (uint16_t)std::clamp(val, 0, 0xffff);
   1336      if (mConnMgr) {
   1337        rv = mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_REQUEST_DELAY,
   1338                                   mMaxRequestDelay);
   1339        if (NS_FAILED(rv)) {
   1340          LOG(
   1341              ("nsHttpHandler::PrefsChanged (request.max-start-delay)"
   1342               "UpdateParam failed (%08x)\n",
   1343               static_cast<uint32_t>(rv)));
   1344        }
   1345      }
   1346    }
   1347  }
   1348 
   1349  if (PREF_CHANGED(HTTP_PREF("response.timeout"))) {
   1350    rv = Preferences::GetInt(HTTP_PREF("response.timeout"), &val);
   1351    if (NS_SUCCEEDED(rv)) {
   1352      mResponseTimeout = PR_SecondsToInterval(std::clamp(val, 0, 0xffff));
   1353    }
   1354  }
   1355 
   1356  if (PREF_CHANGED(HTTP_PREF("network-changed.timeout"))) {
   1357    rv = Preferences::GetInt(HTTP_PREF("network-changed.timeout"), &val);
   1358    if (NS_SUCCEEDED(rv)) {
   1359      mNetworkChangedTimeout = std::clamp(val, 1, 600) * 1000;
   1360    }
   1361  }
   1362 
   1363  if (PREF_CHANGED(HTTP_PREF("max-connections"))) {
   1364    rv = Preferences::GetInt(HTTP_PREF("max-connections"), &val);
   1365    if (NS_SUCCEEDED(rv)) {
   1366      mMaxConnections =
   1367          (uint16_t)std::clamp((uint32_t)val, (uint32_t)1, MaxSocketCount());
   1368 
   1369      if (mConnMgr) {
   1370        rv = mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS,
   1371                                   mMaxConnections);
   1372        if (NS_FAILED(rv)) {
   1373          LOG(
   1374              ("nsHttpHandler::PrefsChanged (max-connections)"
   1375               "UpdateParam failed (%08x)\n",
   1376               static_cast<uint32_t>(rv)));
   1377        }
   1378      }
   1379    }
   1380  }
   1381 
   1382  if (PREF_CHANGED(
   1383          HTTP_PREF("max-urgent-start-excessive-connections-per-host"))) {
   1384    rv = Preferences::GetInt(
   1385        HTTP_PREF("max-urgent-start-excessive-connections-per-host"), &val);
   1386    if (NS_SUCCEEDED(rv)) {
   1387      mMaxUrgentExcessiveConns = (uint8_t)std::clamp(val, 1, 0xff);
   1388      if (mConnMgr) {
   1389        rv = mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_URGENT_START_Q,
   1390                                   mMaxUrgentExcessiveConns);
   1391        if (NS_FAILED(rv)) {
   1392          LOG(
   1393              ("nsHttpHandler::PrefsChanged "
   1394               "(max-urgent-start-excessive-connections-per-host)"
   1395               "UpdateParam failed (%08x)\n",
   1396               static_cast<uint32_t>(rv)));
   1397        }
   1398      }
   1399    }
   1400  }
   1401 
   1402  if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-server"))) {
   1403    rv = Preferences::GetInt(HTTP_PREF("max-persistent-connections-per-server"),
   1404                             &val);
   1405    if (NS_SUCCEEDED(rv)) {
   1406      mMaxPersistentConnectionsPerServer = (uint8_t)std::clamp(val, 1, 0xff);
   1407      if (mConnMgr) {
   1408        rv = mConnMgr->UpdateParam(
   1409            nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_HOST,
   1410            mMaxPersistentConnectionsPerServer);
   1411        if (NS_FAILED(rv)) {
   1412          LOG(
   1413              ("nsHttpHandler::PrefsChanged "
   1414               "(max-persistent-connections-per-server)"
   1415               "UpdateParam failed (%08x)\n",
   1416               static_cast<uint32_t>(rv)));
   1417        }
   1418      }
   1419    }
   1420  }
   1421 
   1422  if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-proxy"))) {
   1423    rv = Preferences::GetInt(HTTP_PREF("max-persistent-connections-per-proxy"),
   1424                             &val);
   1425    if (NS_SUCCEEDED(rv)) {
   1426      mMaxPersistentConnectionsPerProxy = (uint8_t)std::clamp(val, 1, 0xff);
   1427      if (mConnMgr) {
   1428        rv = mConnMgr->UpdateParam(
   1429            nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
   1430            mMaxPersistentConnectionsPerProxy);
   1431        if (NS_FAILED(rv)) {
   1432          LOG(
   1433              ("nsHttpHandler::PrefsChanged "
   1434               "(max-persistent-connections-per-proxy)"
   1435               "UpdateParam failed (%08x)\n",
   1436               static_cast<uint32_t>(rv)));
   1437        }
   1438      }
   1439    }
   1440  }
   1441 
   1442  if (PREF_CHANGED(HTTP_PREF("redirection-limit"))) {
   1443    rv = Preferences::GetInt(HTTP_PREF("redirection-limit"), &val);
   1444    if (NS_SUCCEEDED(rv)) mRedirectionLimit = (uint8_t)std::clamp(val, 0, 0xff);
   1445  }
   1446 
   1447  if (PREF_CHANGED(HTTP_PREF("connection-retry-timeout"))) {
   1448    rv = Preferences::GetInt(HTTP_PREF("connection-retry-timeout"), &val);
   1449    if (NS_SUCCEEDED(rv)) mIdleSynTimeout = (uint16_t)std::clamp(val, 0, 3000);
   1450  }
   1451 
   1452  if (PREF_CHANGED(HTTP_PREF("fast-fallback-to-IPv4"))) {
   1453    rv = Preferences::GetBool(HTTP_PREF("fast-fallback-to-IPv4"), &cVar);
   1454    if (NS_SUCCEEDED(rv)) mFastFallbackToIPv4 = cVar;
   1455  }
   1456 
   1457  if (PREF_CHANGED(HTTP_PREF("fallback-connection-timeout"))) {
   1458    rv = Preferences::GetInt(HTTP_PREF("fallback-connection-timeout"), &val);
   1459    if (NS_SUCCEEDED(rv)) {
   1460      mFallbackSynTimeout = (uint16_t)std::clamp(val, 0, 10 * 60);
   1461    }
   1462  }
   1463 
   1464  if (PREF_CHANGED(HTTP_PREF("version"))) {
   1465    nsAutoCString httpVersion;
   1466    Preferences::GetCString(HTTP_PREF("version"), httpVersion);
   1467    if (!httpVersion.IsVoid()) {
   1468      if (httpVersion.EqualsLiteral("1.1")) {
   1469        mHttpVersion = HttpVersion::v1_1;
   1470      } else if (httpVersion.EqualsLiteral("0.9")) {
   1471        mHttpVersion = HttpVersion::v0_9;
   1472      } else {
   1473        mHttpVersion = HttpVersion::v1_0;
   1474      }
   1475    }
   1476  }
   1477 
   1478  if (PREF_CHANGED(HTTP_PREF("proxy.version"))) {
   1479    nsAutoCString httpVersion;
   1480    Preferences::GetCString(HTTP_PREF("proxy.version"), httpVersion);
   1481    if (!httpVersion.IsVoid()) {
   1482      if (httpVersion.EqualsLiteral("1.1")) {
   1483        mProxyHttpVersion = HttpVersion::v1_1;
   1484      } else {
   1485        mProxyHttpVersion = HttpVersion::v1_0;
   1486      }
   1487      // it does not make sense to issue a HTTP/0.9 request to a proxy server
   1488    }
   1489  }
   1490 
   1491  if (PREF_CHANGED(HTTP_PREF("proxy.respect-be-conservative"))) {
   1492    rv =
   1493        Preferences::GetBool(HTTP_PREF("proxy.respect-be-conservative"), &cVar);
   1494    if (NS_SUCCEEDED(rv)) {
   1495      mBeConservativeForProxy = cVar;
   1496      if (mConnMgr) {
   1497        (void)mConnMgr->UpdateParam(
   1498            nsHttpConnectionMgr::PROXY_BE_CONSERVATIVE,
   1499            static_cast<int32_t>(mBeConservativeForProxy));
   1500      }
   1501    }
   1502  }
   1503 
   1504  if (PREF_CHANGED(HTTP_PREF("qos"))) {
   1505    rv = Preferences::GetInt(HTTP_PREF("qos"), &val);
   1506    if (NS_SUCCEEDED(rv)) mQoSBits = (uint8_t)std::clamp(val, 0, 0xff);
   1507  }
   1508 
   1509  if (PREF_CHANGED(HTTP_PREF("accept-encoding"))) {
   1510    nsAutoCString acceptEncodings;
   1511    rv = Preferences::GetCString(HTTP_PREF("accept-encoding"), acceptEncodings);
   1512    if (NS_SUCCEEDED(rv)) {
   1513      rv = SetAcceptEncodings(acceptEncodings.get(), false, false);
   1514      MOZ_ASSERT(NS_SUCCEEDED(rv));
   1515    }
   1516  }
   1517 
   1518  if (PREF_CHANGED(HTTP_PREF("accept-encoding.secure")) ||
   1519      PREF_CHANGED(HTTP_PREF("accept-encoding.dictionary"))) {
   1520    nsAutoCString acceptEncodings;
   1521    rv = Preferences::GetCString(HTTP_PREF("accept-encoding.secure"),
   1522                                 acceptEncodings);
   1523    if (NS_SUCCEEDED(rv)) {
   1524      rv = SetAcceptEncodings(acceptEncodings.get(), true, false);
   1525 
   1526      // Since dictionary encodings are dependent on both accept-encoding.secure
   1527      // and accept-encoding.dictionary, update both if either changes (which is
   1528      // quite rare, so there's no real perf hit)
   1529      nsAutoCString acceptDictionaryEncodings;
   1530      rv = Preferences::GetCString(HTTP_PREF("accept-encoding.dictionary"),
   1531                                   acceptDictionaryEncodings);
   1532      if (NS_SUCCEEDED(rv) && !acceptDictionaryEncodings.IsEmpty()) {
   1533        acceptEncodings.Append(", "_ns);
   1534        acceptEncodings.Append(acceptDictionaryEncodings);
   1535        rv = SetAcceptEncodings(acceptEncodings.get(), true, true);
   1536      }
   1537      MOZ_ASSERT(NS_SUCCEEDED(rv));
   1538    }
   1539  }
   1540 
   1541  if (PREF_CHANGED(HTTP_PREF("default-socket-type"))) {
   1542    nsAutoCString sval;
   1543    rv = Preferences::GetCString(HTTP_PREF("default-socket-type"), sval);
   1544    if (NS_SUCCEEDED(rv)) {
   1545      if (sval.IsEmpty()) {
   1546        mDefaultSocketType.SetIsVoid(true);
   1547      } else {
   1548        // verify that this socket type is actually valid
   1549        nsCOMPtr<nsISocketProviderService> sps =
   1550            nsSocketProviderService::GetOrCreate();
   1551        if (sps) {
   1552          nsCOMPtr<nsISocketProvider> sp;
   1553          rv = sps->GetSocketProvider(sval.get(), getter_AddRefs(sp));
   1554          if (NS_SUCCEEDED(rv)) {
   1555            // OK, this looks like a valid socket provider.
   1556            mDefaultSocketType.Assign(sval);
   1557          }
   1558        }
   1559      }
   1560    }
   1561  }
   1562 
   1563  if (PREF_CHANGED(HTTP_PREF("prompt-temp-redirect"))) {
   1564    rv = Preferences::GetBool(HTTP_PREF("prompt-temp-redirect"), &cVar);
   1565    if (NS_SUCCEEDED(rv)) {
   1566      mPromptTempRedirect = cVar;
   1567    }
   1568  }
   1569 
   1570  if (PREF_CHANGED(HTTP_PREF("assoc-req.enforce"))) {
   1571    cVar = false;
   1572    rv = Preferences::GetBool(HTTP_PREF("assoc-req.enforce"), &cVar);
   1573    if (NS_SUCCEEDED(rv)) mEnforceAssocReq = cVar;
   1574  }
   1575 
   1576  // enable Persistent caching for HTTPS - bug#205921
   1577  if (PREF_CHANGED(BROWSER_PREF("disk_cache_ssl"))) {
   1578    cVar = false;
   1579    rv = Preferences::GetBool(BROWSER_PREF("disk_cache_ssl"), &cVar);
   1580    if (NS_SUCCEEDED(rv)) mEnablePersistentHttpsCaching = cVar;
   1581  }
   1582 
   1583  if (PREF_CHANGED(HTTP_PREF("http2.timeout"))) {
   1584    mSpdyTimeout = PR_SecondsToInterval(
   1585        std::clamp(StaticPrefs::network_http_http2_timeout(), 1, 0xffff));
   1586  }
   1587 
   1588  if (PREF_CHANGED(HTTP_PREF("http2.chunk-size"))) {
   1589    // keep this within http/2 ranges of 1 to 2^24-1
   1590    mSpdySendingChunkSize = (uint32_t)std::clamp(
   1591        StaticPrefs::network_http_http2_chunk_size(), 1, 0xffffff);
   1592  }
   1593 
   1594  // The amount of idle seconds on a http2 connection before initiating a
   1595  // server ping. 0 will disable.
   1596  if (PREF_CHANGED(HTTP_PREF("http2.ping-threshold"))) {
   1597    mSpdyPingThreshold = PR_SecondsToInterval((uint16_t)std::clamp(
   1598        StaticPrefs::network_http_http2_ping_threshold(), 0, 0x7fffffff));
   1599  }
   1600 
   1601  // The amount of seconds to wait for a http2 ping response before
   1602  // closing the session.
   1603  if (PREF_CHANGED(HTTP_PREF("http2.ping-timeout"))) {
   1604    mSpdyPingTimeout = PR_SecondsToInterval((uint16_t)std::clamp(
   1605        StaticPrefs::network_http_http2_ping_timeout(), 0, 0x7fffffff));
   1606  }
   1607 
   1608  if (PREF_CHANGED(HTTP_PREF("altsvc.enabled"))) {
   1609    rv = Preferences::GetBool(HTTP_PREF("altsvc.enabled"), &cVar);
   1610    if (NS_SUCCEEDED(rv)) mEnableAltSvc = cVar;
   1611  }
   1612 
   1613  if (PREF_CHANGED(HTTP_PREF("altsvc.oe"))) {
   1614    rv = Preferences::GetBool(HTTP_PREF("altsvc.oe"), &cVar);
   1615    if (NS_SUCCEEDED(rv)) mEnableAltSvcOE = cVar;
   1616  }
   1617 
   1618  if (PREF_CHANGED(HTTP_PREF("http2.push-allowance"))) {
   1619    mSpdyPushAllowance = static_cast<uint32_t>(
   1620        std::clamp(StaticPrefs::network_http_http2_push_allowance(), 1024,
   1621                   static_cast<int32_t>(ASpdySession::kInitialRwin)));
   1622  }
   1623 
   1624  if (PREF_CHANGED(HTTP_PREF("http2.pull-allowance"))) {
   1625    mSpdyPullAllowance = static_cast<uint32_t>(std::clamp(
   1626        StaticPrefs::network_http_http2_pull_allowance(), 1024, 0x7fffffff));
   1627  }
   1628 
   1629  if (PREF_CHANGED(HTTP_PREF("http2.default-concurrent"))) {
   1630    mDefaultSpdyConcurrent = static_cast<uint32_t>(std::max<int32_t>(
   1631        std::min<int32_t>(StaticPrefs::network_http_http2_default_concurrent(),
   1632                          9999),
   1633        1));
   1634  }
   1635 
   1636  // If http2.send-buffer-size is non-zero, the size to set the TCP
   1637  //  sendbuffer to once the stream has surpassed this number of bytes uploaded
   1638  if (PREF_CHANGED(HTTP_PREF("http2.send-buffer-size"))) {
   1639    mSpdySendBufferSize = (uint32_t)std::clamp(
   1640        StaticPrefs::network_http_http2_send_buffer_size(), 1500, 0x7fffffff);
   1641  }
   1642 
   1643  // The maximum amount of time to wait for socket transport to be
   1644  // established
   1645  if (PREF_CHANGED(HTTP_PREF("connection-timeout"))) {
   1646    rv = Preferences::GetInt(HTTP_PREF("connection-timeout"), &val);
   1647    if (NS_SUCCEEDED(rv)) {
   1648      // the pref is in seconds, but the variable is in milliseconds
   1649      mConnectTimeout = std::clamp(val, 1, 0xffff) * PR_MSEC_PER_SEC;
   1650    }
   1651  }
   1652 
   1653  // The maximum amount of time to wait for a tls handshake to finish.
   1654  if (PREF_CHANGED(HTTP_PREF("tls-handshake-timeout"))) {
   1655    rv = Preferences::GetInt(HTTP_PREF("tls-handshake-timeout"), &val);
   1656    if (NS_SUCCEEDED(rv)) {
   1657      // the pref is in seconds, but the variable is in milliseconds
   1658      mTLSHandshakeTimeout = std::clamp(val, 1, 0xffff) * PR_MSEC_PER_SEC;
   1659    }
   1660  }
   1661 
   1662  // The maximum number of current global half open sockets allowable
   1663  // for starting a new speculative connection.
   1664  if (PREF_CHANGED(HTTP_PREF("speculative-parallel-limit"))) {
   1665    rv = Preferences::GetInt(HTTP_PREF("speculative-parallel-limit"), &val);
   1666    if (NS_SUCCEEDED(rv)) {
   1667      mParallelSpeculativeConnectLimit = (uint32_t)std::clamp(val, 0, 1024);
   1668    }
   1669  }
   1670 
   1671  // Whether or not to block requests for non head js/css items (e.g. media)
   1672  // while those elements load.
   1673  if (PREF_CHANGED(HTTP_PREF("rendering-critical-requests-prioritization"))) {
   1674    rv = Preferences::GetBool(
   1675        HTTP_PREF("rendering-critical-requests-prioritization"), &cVar);
   1676    if (NS_SUCCEEDED(rv)) mCriticalRequestPrioritization = cVar;
   1677  }
   1678 
   1679  // on transition of network.http.diagnostics to true print
   1680  // a bunch of information to the console
   1681  if (pref && PREF_CHANGED(HTTP_PREF("diagnostics"))) {
   1682    rv = Preferences::GetBool(HTTP_PREF("diagnostics"), &cVar);
   1683    if (NS_SUCCEEDED(rv) && cVar) {
   1684      if (mConnMgr) mConnMgr->PrintDiagnostics();
   1685    }
   1686  }
   1687 
   1688  if (PREF_CHANGED(HTTP_PREF("throttle.enable"))) {
   1689    rv = Preferences::GetBool(HTTP_PREF("throttle.enable"), &mThrottleEnabled);
   1690    if (NS_SUCCEEDED(rv) && mConnMgr) {
   1691      (void)mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_ENABLED,
   1692                                  static_cast<int32_t>(mThrottleEnabled));
   1693    }
   1694  }
   1695 
   1696  if (PREF_CHANGED(HTTP_PREF("throttle.suspend-for"))) {
   1697    rv = Preferences::GetInt(HTTP_PREF("throttle.suspend-for"), &val);
   1698    mThrottleSuspendFor = (uint32_t)std::clamp(val, 0, 120000);
   1699    if (NS_SUCCEEDED(rv) && mConnMgr) {
   1700      (void)mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_SUSPEND_FOR,
   1701                                  mThrottleSuspendFor);
   1702    }
   1703  }
   1704 
   1705  if (PREF_CHANGED(HTTP_PREF("throttle.resume-for"))) {
   1706    rv = Preferences::GetInt(HTTP_PREF("throttle.resume-for"), &val);
   1707    mThrottleResumeFor = (uint32_t)std::clamp(val, 0, 120000);
   1708    if (NS_SUCCEEDED(rv) && mConnMgr) {
   1709      (void)mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_RESUME_FOR,
   1710                                  mThrottleResumeFor);
   1711    }
   1712  }
   1713 
   1714  if (PREF_CHANGED(HTTP_PREF("throttle.hold-time-ms"))) {
   1715    rv = Preferences::GetInt(HTTP_PREF("throttle.hold-time-ms"), &val);
   1716    mThrottleHoldTime = (uint32_t)std::clamp(val, 0, 120000);
   1717    if (NS_SUCCEEDED(rv) && mConnMgr) {
   1718      (void)mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_HOLD_TIME,
   1719                                  mThrottleHoldTime);
   1720    }
   1721  }
   1722 
   1723  if (PREF_CHANGED(HTTP_PREF("throttle.max-time-ms"))) {
   1724    rv = Preferences::GetInt(HTTP_PREF("throttle.max-time-ms"), &val);
   1725    mThrottleMaxTime = (uint32_t)std::clamp(val, 0, 120000);
   1726    if (NS_SUCCEEDED(rv) && mConnMgr) {
   1727      (void)mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_MAX_TIME,
   1728                                  mThrottleMaxTime);
   1729    }
   1730  }
   1731 
   1732  if (PREF_CHANGED(HTTP_PREF("send_window_size"))) {
   1733    (void)Preferences::GetInt(HTTP_PREF("send_window_size"), &val);
   1734    mSendWindowSize = val >= 0 ? val : 0;
   1735  }
   1736 
   1737  if (PREF_CHANGED(HTTP_PREF("on_click_priority"))) {
   1738    (void)Preferences::GetBool(HTTP_PREF("on_click_priority"),
   1739                               &mUrgentStartEnabled);
   1740  }
   1741 
   1742  if (PREF_CHANGED(HTTP_PREF("tailing.enabled"))) {
   1743    (void)Preferences::GetBool(HTTP_PREF("tailing.enabled"),
   1744                               &mTailBlockingEnabled);
   1745  }
   1746  if (PREF_CHANGED(HTTP_PREF("tailing.delay-quantum"))) {
   1747    val = StaticPrefs::network_http_tailing_delay_quantum();
   1748    mTailDelayQuantum = (uint32_t)std::clamp(val, 0, 60000);
   1749  }
   1750  if (PREF_CHANGED(HTTP_PREF("tailing.delay-quantum-after-domcontentloaded"))) {
   1751    val = StaticPrefs::
   1752        network_http_tailing_delay_quantum_after_domcontentloaded();
   1753    mTailDelayQuantumAfterDCL = (uint32_t)std::clamp(val, 0, 60000);
   1754  }
   1755  if (PREF_CHANGED(HTTP_PREF("tailing.delay-max"))) {
   1756    val = StaticPrefs::network_http_tailing_delay_max();
   1757    mTailDelayMax = (uint32_t)std::clamp(val, 0, 60000);
   1758  }
   1759  if (PREF_CHANGED(HTTP_PREF("tailing.total-max"))) {
   1760    val = StaticPrefs::network_http_tailing_total_max();
   1761    mTailTotalMax = (uint32_t)std::clamp(val, 0, 60000);
   1762  }
   1763 
   1764  if (PREF_CHANGED(HTTP_PREF("focused_window_transaction_ratio"))) {
   1765    float ratio = 0;
   1766    rv = Preferences::GetFloat(HTTP_PREF("focused_window_transaction_ratio"),
   1767                               &ratio);
   1768    if (NS_SUCCEEDED(rv)) {
   1769      if (ratio > 0 && ratio < 1) {
   1770        mFocusedWindowTransactionRatio = ratio;
   1771      } else {
   1772        NS_WARNING("Wrong value for focused_window_transaction_ratio");
   1773      }
   1774    }
   1775  }
   1776 
   1777  //
   1778  // INTL options
   1779  //
   1780 
   1781  if (PREF_CHANGED(INTL_ACCEPT_LANGUAGES)) {
   1782    // We don't want to set the new accept languages here since
   1783    // this pref is a complex type and it may be racy with flushing
   1784    // string resources.
   1785    mAcceptLanguagesIsDirty = true;
   1786  }
   1787 
   1788  //
   1789  // Tracking options
   1790  //
   1791 
   1792  // Hint option
   1793  if (PREF_CHANGED(SAFE_HINT_HEADER_VALUE)) {
   1794    cVar = false;
   1795    rv = Preferences::GetBool(SAFE_HINT_HEADER_VALUE, &cVar);
   1796    if (NS_SUCCEEDED(rv)) {
   1797      mSafeHintEnabled = cVar;
   1798    }
   1799  }
   1800 
   1801  // toggle to true anytime a token bucket related pref is changed.. that
   1802  // includes telemetry and allow-experiments because of the abtest profile
   1803  bool requestTokenBucketUpdated = false;
   1804 
   1805  // "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256" is the required h2 interop
   1806  // suite.
   1807 
   1808  if (PREF_CHANGED(H2MANDATORY_SUITE)) {
   1809    cVar = false;
   1810    rv = Preferences::GetBool(H2MANDATORY_SUITE, &cVar);
   1811    if (NS_SUCCEEDED(rv)) {
   1812      mH2MandatorySuiteEnabled = cVar;
   1813    }
   1814  }
   1815 
   1816  // network.http.debug-observations
   1817  if (PREF_CHANGED("network.http.debug-observations")) {
   1818    cVar = false;
   1819    rv = Preferences::GetBool("network.http.debug-observations", &cVar);
   1820    if (NS_SUCCEEDED(rv)) {
   1821      mDebugObservations = cVar;
   1822    }
   1823  }
   1824 
   1825  if (PREF_CHANGED(HTTP_PREF("pacing.requests.enabled"))) {
   1826    rv = Preferences::GetBool(HTTP_PREF("pacing.requests.enabled"), &cVar);
   1827    if (NS_SUCCEEDED(rv)) {
   1828      mRequestTokenBucketEnabled = cVar;
   1829      requestTokenBucketUpdated = true;
   1830    }
   1831  }
   1832  if (PREF_CHANGED(HTTP_PREF("pacing.requests.min-parallelism"))) {
   1833    rv =
   1834        Preferences::GetInt(HTTP_PREF("pacing.requests.min-parallelism"), &val);
   1835    if (NS_SUCCEEDED(rv)) {
   1836      mRequestTokenBucketMinParallelism =
   1837          static_cast<uint16_t>(std::clamp(val, 1, 1024));
   1838      requestTokenBucketUpdated = true;
   1839    }
   1840  }
   1841  if (PREF_CHANGED(HTTP_PREF("pacing.requests.hz"))) {
   1842    rv = Preferences::GetInt(HTTP_PREF("pacing.requests.hz"), &val);
   1843    if (NS_SUCCEEDED(rv)) {
   1844      mRequestTokenBucketHz = static_cast<uint32_t>(std::clamp(val, 1, 10000));
   1845      requestTokenBucketUpdated = true;
   1846    }
   1847  }
   1848  if (PREF_CHANGED(HTTP_PREF("pacing.requests.burst"))) {
   1849    rv = Preferences::GetInt(HTTP_PREF("pacing.requests.burst"), &val);
   1850    if (NS_SUCCEEDED(rv)) {
   1851      mRequestTokenBucketBurst = val ? val : 1;
   1852      requestTokenBucketUpdated = true;
   1853    }
   1854  }
   1855  if (requestTokenBucketUpdated) {
   1856    MakeNewRequestTokenBucket();
   1857  }
   1858 
   1859  // Keepalive values for initial and idle connections.
   1860  if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_connections"))) {
   1861    rv = Preferences::GetBool(
   1862        HTTP_PREF("tcp_keepalive.short_lived_connections"), &cVar);
   1863    if (NS_SUCCEEDED(rv) && cVar != mTCPKeepaliveShortLivedEnabled) {
   1864      mTCPKeepaliveShortLivedEnabled = cVar;
   1865    }
   1866  }
   1867 
   1868  if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_time"))) {
   1869    rv = Preferences::GetInt(HTTP_PREF("tcp_keepalive.short_lived_time"), &val);
   1870    if (NS_SUCCEEDED(rv) && val > 0) {
   1871      mTCPKeepaliveShortLivedTimeS = std::clamp(val, 1, 300);  // Max 5 mins.
   1872    }
   1873  }
   1874 
   1875  if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_idle_time"))) {
   1876    rv = Preferences::GetInt(HTTP_PREF("tcp_keepalive.short_lived_idle_time"),
   1877                             &val);
   1878    if (NS_SUCCEEDED(rv) && val > 0) {
   1879      mTCPKeepaliveShortLivedIdleTimeS = std::clamp(val, 1, kMaxTCPKeepIdle);
   1880    }
   1881  }
   1882 
   1883  // Keepalive values for Long-lived Connections.
   1884  if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.long_lived_connections"))) {
   1885    rv = Preferences::GetBool(HTTP_PREF("tcp_keepalive.long_lived_connections"),
   1886                              &cVar);
   1887    if (NS_SUCCEEDED(rv) && cVar != mTCPKeepaliveLongLivedEnabled) {
   1888      mTCPKeepaliveLongLivedEnabled = cVar;
   1889    }
   1890  }
   1891 
   1892  if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.long_lived_idle_time"))) {
   1893    rv = Preferences::GetInt(HTTP_PREF("tcp_keepalive.long_lived_idle_time"),
   1894                             &val);
   1895    if (NS_SUCCEEDED(rv) && val > 0) {
   1896      mTCPKeepaliveLongLivedIdleTimeS = std::clamp(val, 1, kMaxTCPKeepIdle);
   1897    }
   1898  }
   1899 
   1900  if (PREF_CHANGED(HTTP_PREF("enforce-framing.http1")) ||
   1901      PREF_CHANGED(HTTP_PREF("enforce-framing.soft")) ||
   1902      PREF_CHANGED(HTTP_PREF("enforce-framing.strict_chunked_encoding"))) {
   1903    rv = Preferences::GetBool(HTTP_PREF("enforce-framing.http1"), &cVar);
   1904    if (NS_SUCCEEDED(rv) && cVar) {
   1905      mEnforceH1Framing = FRAMECHECK_STRICT;
   1906    } else {
   1907      rv = Preferences::GetBool(
   1908          HTTP_PREF("enforce-framing.strict_chunked_encoding"), &cVar);
   1909      if (NS_SUCCEEDED(rv) && cVar) {
   1910        mEnforceH1Framing = FRAMECHECK_STRICT_CHUNKED;
   1911      } else {
   1912        rv = Preferences::GetBool(HTTP_PREF("enforce-framing.soft"), &cVar);
   1913        if (NS_SUCCEEDED(rv) && cVar) {
   1914          mEnforceH1Framing = FRAMECHECK_BARELY;
   1915        } else {
   1916          mEnforceH1Framing = FRAMECHECK_LAX;
   1917        }
   1918      }
   1919    }
   1920  }
   1921 
   1922  if (PREF_CHANGED(HTTP_PREF("http2.default-hpack-buffer"))) {
   1923    mDefaultHpackBuffer =
   1924        StaticPrefs::network_http_http2_default_hpack_buffer();
   1925  }
   1926 
   1927  if (PREF_CHANGED(HTTP_PREF("http3.default-qpack-table-size"))) {
   1928    rv = Preferences::GetInt(HTTP_PREF("http3.default-qpack-table-size"), &val);
   1929    if (NS_SUCCEEDED(rv)) {
   1930      mQpackTableSize = val;
   1931    }
   1932  }
   1933 
   1934  if (PREF_CHANGED(HTTP_PREF("http3.default-max-stream-blocked"))) {
   1935    rv = Preferences::GetInt(HTTP_PREF("http3.default-max-stream-blocked"),
   1936                             &val);
   1937    if (NS_SUCCEEDED(rv)) {
   1938      mHttp3MaxBlockedStreams = std::clamp(val, 0, 0xffff);
   1939    }
   1940  }
   1941 
   1942  const bool imageAcceptPrefChanged =
   1943      PREF_CHANGED("image.http.accept") || PREF_CHANGED("image.jxl.enabled");
   1944 
   1945  if (imageAcceptPrefChanged) {
   1946    nsAutoCString userSetImageAcceptHeader;
   1947 
   1948    if (Preferences::HasUserValue("image.http.accept")) {
   1949      rv = Preferences::GetCString("image.http.accept",
   1950                                   userSetImageAcceptHeader);
   1951      if (NS_FAILED(rv)) {
   1952        userSetImageAcceptHeader.Truncate();
   1953      }
   1954    }
   1955 
   1956    if (userSetImageAcceptHeader.IsEmpty()) {
   1957      mImageAcceptHeader.Assign(ImageAcceptHeader());
   1958    } else {
   1959      mImageAcceptHeader.Assign(userSetImageAcceptHeader);
   1960    }
   1961  }
   1962 
   1963  if (PREF_CHANGED("network.http.accept") || imageAcceptPrefChanged) {
   1964    nsAutoCString userSetDocumentAcceptHeader;
   1965 
   1966    if (Preferences::HasUserValue("network.http.accept")) {
   1967      rv = Preferences::GetCString("network.http.accept",
   1968                                   userSetDocumentAcceptHeader);
   1969      if (NS_FAILED(rv)) {
   1970        userSetDocumentAcceptHeader.Truncate();
   1971      }
   1972    }
   1973 
   1974    if (userSetDocumentAcceptHeader.IsEmpty()) {
   1975      mDocumentAcceptHeader.Assign(DocumentAcceptHeader());
   1976    } else {
   1977      mDocumentAcceptHeader.Assign(userSetDocumentAcceptHeader);
   1978    }
   1979  }
   1980 
   1981  if (PREF_CHANGED(HTTP_PREF("http3.alt-svc-mapping-for-testing"))) {
   1982    nsAutoCString altSvcMappings;
   1983    rv = Preferences::GetCString(HTTP_PREF("http3.alt-svc-mapping-for-testing"),
   1984                                 altSvcMappings);
   1985    if (NS_SUCCEEDED(rv)) {
   1986      if (altSvcMappings.IsEmpty()) {
   1987        mAltSvcMappingTemptativeMap.Clear();
   1988      } else {
   1989        for (const nsACString& tokenSubstring :
   1990             nsCCharSeparatedTokenizer(altSvcMappings, ',').ToRange()) {
   1991          nsAutoCString token{tokenSubstring};
   1992          int32_t index = token.Find(";");
   1993          if (index != kNotFound) {
   1994            mAltSvcMappingTemptativeMap.InsertOrUpdate(
   1995                Substring(token, 0, index),
   1996                MakeUnique<nsCString>(Substring(token, index + 1)));
   1997          }
   1998        }
   1999      }
   2000    }
   2001  }
   2002 
   2003  if (PREF_CHANGED(HTTP_PREF("http3.enable_qlog"))) {
   2004    // Initialize the directory.
   2005    nsCOMPtr<nsIFile> qlogDir;
   2006    if (Preferences::GetBool(HTTP_PREF("http3.enable_qlog")) &&
   2007        !mHttp3QlogDir.IsEmpty() &&
   2008        NS_SUCCEEDED(
   2009            NS_NewNativeLocalFile(mHttp3QlogDir, getter_AddRefs(qlogDir)))) {
   2010      // Here we do main thread IO, but since this only happens
   2011      // when enabling a developer feature it's not a problem for users.
   2012      rv = qlogDir->Create(nsIFile::DIRECTORY_TYPE, 0755);
   2013      if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
   2014        NS_WARNING("Creating qlog dir failed");
   2015      }
   2016    }
   2017  }
   2018 
   2019 #ifdef XP_MACOSX
   2020  if (XRE_IsParentProcess()) {
   2021    if (PREF_CHANGED(HTTP_PREF("microsoft-entra-sso.enabled"))) {
   2022      rv =
   2023          Preferences::GetBool(HTTP_PREF("microsoft-entra-sso.enabled"), &cVar);
   2024      if (NS_SUCCEEDED(rv) && cVar) {
   2025        InitMSAuthorities();
   2026      }
   2027    }
   2028  }
   2029 #endif
   2030 
   2031  // Enable HTTP response timeout if TCP Keepalives are disabled.
   2032  mResponseTimeoutEnabled =
   2033      !mTCPKeepaliveShortLivedEnabled && !mTCPKeepaliveLongLivedEnabled;
   2034 
   2035 #undef PREF_CHANGED
   2036 #undef MULTI_PREF_CHANGED
   2037 }
   2038 
   2039 /**
   2040 *  Allocates a C string into that contains a ISO 639 language list
   2041 *  notated with HTTP "q" values for output with a HTTP Accept-Language
   2042 *  header. Previous q values will be stripped because the order of
   2043 *  the langs imply the q value. The q values are calculated by dividing
   2044 *  1.0 amongst the number of languages present.
   2045 *
   2046 *  Ex: passing: "en, ja"
   2047 *      returns: "en,ja;q=0.5"
   2048 *
   2049 *      passing: "en, ja, fr_CA"
   2050 *      returns: "en,ja;q=0.7,fr_CA;q=0.3"
   2051 */
   2052 static nsresult PrepareAcceptLanguages(const char* i_AcceptLanguages,
   2053                                       nsACString& o_AcceptLanguages) {
   2054  if (!i_AcceptLanguages) return NS_OK;
   2055 
   2056  const nsAutoCString ns_accept_languages(i_AcceptLanguages);
   2057  return rust_prepare_accept_languages(&ns_accept_languages,
   2058                                       &o_AcceptLanguages);
   2059 }
   2060 
   2061 // Ensure that we've fetched the AcceptLanguages setting
   2062 /* static */
   2063 void nsHttpHandler::PresetAcceptLanguages() {
   2064  if (!gHttpHandler) {
   2065    RefPtr<nsHttpHandler> handler = nsHttpHandler::GetInstance();
   2066    (void)handler.get();
   2067  }
   2068  [[maybe_unused]] nsresult rv = gHttpHandler->SetAcceptLanguages();
   2069 }
   2070 
   2071 nsresult nsHttpHandler::SetAcceptLanguages() {
   2072  if (!NS_IsMainThread()) {
   2073    nsCOMPtr<nsIThread> mainThread;
   2074    nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
   2075    if (NS_FAILED(rv)) {
   2076      return rv;
   2077    }
   2078 
   2079    // Forward to the main thread synchronously.
   2080    SyncRunnable::DispatchToThread(
   2081        mainThread,
   2082        NS_NewRunnableFunction("nsHttpHandler::SetAcceptLanguages", [&rv]() {
   2083          rv = gHttpHandler->SetAcceptLanguages();
   2084        }));
   2085    return rv;
   2086  }
   2087 
   2088  MOZ_ASSERT(NS_IsMainThread());
   2089 
   2090  mAcceptLanguagesIsDirty = false;
   2091 
   2092  nsAutoCString acceptLanguages;
   2093  intl::LocaleService::GetInstance()->GetAcceptLanguages(acceptLanguages);
   2094 
   2095  nsAutoCString buf;
   2096  nsresult rv = PrepareAcceptLanguages(acceptLanguages.get(), buf);
   2097  if (NS_SUCCEEDED(rv)) {
   2098    mAcceptLanguages.Assign(buf);
   2099  }
   2100  return rv;
   2101 }
   2102 
   2103 nsresult nsHttpHandler::SetAcceptEncodings(const char* aAcceptEncodings,
   2104                                           bool isSecure, bool isDictionary) {
   2105  if (isDictionary) {
   2106    mDictionaryAcceptEncodings = aAcceptEncodings;
   2107  } else if (isSecure) {
   2108    mHttpsAcceptEncodings = aAcceptEncodings;
   2109  } else {
   2110    // use legacy list if a secure override is not specified
   2111    mHttpAcceptEncodings = aAcceptEncodings;
   2112    if (mHttpsAcceptEncodings.IsEmpty()) {
   2113      mHttpsAcceptEncodings = aAcceptEncodings;
   2114    }
   2115  }
   2116 
   2117  return NS_OK;
   2118 }
   2119 
   2120 //-----------------------------------------------------------------------------
   2121 // nsHttpHandler::nsISupports
   2122 //-----------------------------------------------------------------------------
   2123 
   2124 NS_IMPL_ISUPPORTS(nsHttpHandler, nsIHttpProtocolHandler,
   2125                  nsIProxiedProtocolHandler, nsIProtocolHandler, nsIObserver,
   2126                  nsISupportsWeakReference, nsISpeculativeConnect)
   2127 
   2128 //-----------------------------------------------------------------------------
   2129 // nsHttpHandler::nsIProtocolHandler
   2130 //-----------------------------------------------------------------------------
   2131 
   2132 NS_IMETHODIMP
   2133 nsHttpHandler::GetScheme(nsACString& aScheme) {
   2134  aScheme.AssignLiteral("http");
   2135  return NS_OK;
   2136 }
   2137 
   2138 NS_IMETHODIMP
   2139 nsHttpHandler::NewChannel(nsIURI* uri, nsILoadInfo* aLoadInfo,
   2140                          nsIChannel** result) {
   2141  LOG(("nsHttpHandler::NewChannel\n"));
   2142 
   2143  NS_ENSURE_ARG_POINTER(uri);
   2144  NS_ENSURE_ARG_POINTER(result);
   2145 
   2146  // Verify that we have been given a valid scheme
   2147  if (!net::SchemeIsHttpOrHttps(uri)) {
   2148    NS_WARNING("Invalid URI scheme");
   2149    return NS_ERROR_UNEXPECTED;
   2150  }
   2151 
   2152  return NewProxiedChannel(uri, nullptr, 0, nullptr, aLoadInfo, result);
   2153 }
   2154 
   2155 NS_IMETHODIMP
   2156 nsHttpHandler::AllowPort(int32_t port, const char* scheme, bool* _retval) {
   2157  // don't override anything.
   2158  *_retval = false;
   2159  return NS_OK;
   2160 }
   2161 
   2162 //-----------------------------------------------------------------------------
   2163 // nsHttpHandler::nsIProxiedProtocolHandler
   2164 //-----------------------------------------------------------------------------
   2165 
   2166 nsresult nsHttpHandler::SetupChannelInternal(
   2167    HttpBaseChannel* aChannel, nsIURI* uri, nsIProxyInfo* givenProxyInfo,
   2168    uint32_t proxyResolveFlags, nsIURI* proxyURI, nsILoadInfo* aLoadInfo,
   2169    nsIChannel** result) {
   2170  RefPtr<HttpBaseChannel> httpChannel = aChannel;
   2171 
   2172  nsCOMPtr<nsProxyInfo> proxyInfo;
   2173  if (givenProxyInfo) {
   2174    proxyInfo = do_QueryInterface(givenProxyInfo);
   2175    NS_ENSURE_ARG(proxyInfo);
   2176  }
   2177 
   2178  uint32_t caps = mCapabilities;
   2179 
   2180  uint64_t channelId = NewChannelId();
   2181  nsresult rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags,
   2182                                  proxyURI, channelId, aLoadInfo);
   2183  if (NS_FAILED(rv)) return rv;
   2184 
   2185  httpChannel.forget(result);
   2186  return NS_OK;
   2187 }
   2188 
   2189 NS_IMETHODIMP
   2190 nsHttpHandler::NewProxiedChannel(nsIURI* uri, nsIProxyInfo* givenProxyInfo,
   2191                                 uint32_t proxyResolveFlags, nsIURI* proxyURI,
   2192                                 nsILoadInfo* aLoadInfo, nsIChannel** result) {
   2193  HttpBaseChannel* httpChannel;
   2194 
   2195  LOG(("nsHttpHandler::NewProxiedChannel [proxyInfo=%p]\n", givenProxyInfo));
   2196 
   2197  if (IsNeckoChild()) {
   2198    httpChannel = new HttpChannelChild();
   2199  } else {
   2200    // HACK: make sure PSM gets initialized on the main thread.
   2201    net_EnsurePSMInit();
   2202    httpChannel = new nsHttpChannel();
   2203  }
   2204 
   2205  return SetupChannelInternal(httpChannel, uri, givenProxyInfo,
   2206                              proxyResolveFlags, proxyURI, aLoadInfo, result);
   2207 }
   2208 
   2209 nsresult nsHttpHandler::CreateTRRServiceChannel(
   2210    nsIURI* uri, nsIProxyInfo* givenProxyInfo, uint32_t proxyResolveFlags,
   2211    nsIURI* proxyURI, nsILoadInfo* aLoadInfo, nsIChannel** result) {
   2212  HttpBaseChannel* httpChannel = new TRRServiceChannel();
   2213 
   2214  LOG(("nsHttpHandler::CreateTRRServiceChannel [proxyInfo=%p]\n",
   2215       givenProxyInfo));
   2216 
   2217  return SetupChannelInternal(httpChannel, uri, givenProxyInfo,
   2218                              proxyResolveFlags, proxyURI, aLoadInfo, result);
   2219 }
   2220 
   2221 //-----------------------------------------------------------------------------
   2222 // nsHttpHandler::nsIHttpProtocolHandler
   2223 //-----------------------------------------------------------------------------
   2224 
   2225 NS_IMETHODIMP
   2226 nsHttpHandler::GetUserAgent(nsACString& value) {
   2227  value = UserAgent(false);
   2228  return NS_OK;
   2229 }
   2230 
   2231 NS_IMETHODIMP
   2232 nsHttpHandler::GetRfpUserAgent(nsACString& value) {
   2233  value = UserAgent(true);
   2234  return NS_OK;
   2235 }
   2236 
   2237 NS_IMETHODIMP
   2238 nsHttpHandler::GetAppName(nsACString& value) {
   2239  value = mLegacyAppName;
   2240  return NS_OK;
   2241 }
   2242 
   2243 NS_IMETHODIMP
   2244 nsHttpHandler::GetAppVersion(nsACString& value) {
   2245  value = mLegacyAppVersion;
   2246  return NS_OK;
   2247 }
   2248 
   2249 NS_IMETHODIMP
   2250 nsHttpHandler::GetPlatform(nsACString& value) {
   2251  value = mPlatform;
   2252  return NS_OK;
   2253 }
   2254 
   2255 NS_IMETHODIMP
   2256 nsHttpHandler::GetOscpu(nsACString& value) {
   2257  value = mOscpu;
   2258  return NS_OK;
   2259 }
   2260 
   2261 NS_IMETHODIMP
   2262 nsHttpHandler::GetMisc(nsACString& value) {
   2263  value = mMisc;
   2264  return NS_OK;
   2265 }
   2266 
   2267 NS_IMETHODIMP
   2268 nsHttpHandler::GetAltSvcCacheKeys(nsTArray<nsCString>& value) {
   2269  return mAltSvcCache->GetAltSvcCacheKeys(value);
   2270 }
   2271 
   2272 NS_IMETHODIMP
   2273 nsHttpHandler::GetAuthCacheKeys(nsTArray<nsCString>& aValues) {
   2274  mAuthCache->CollectKeys(aValues);
   2275  mPrivateAuthCache->CollectKeys(aValues);
   2276  return NS_OK;
   2277 }
   2278 
   2279 //-----------------------------------------------------------------------------
   2280 // nsHttpHandler::nsIObserver
   2281 //-----------------------------------------------------------------------------
   2282 
   2283 NS_IMETHODIMP
   2284 nsHttpHandler::Observe(nsISupports* subject, const char* topic,
   2285                       const char16_t* data) {
   2286  MOZ_ASSERT(NS_IsMainThread());
   2287  LOG(("nsHttpHandler::Observe [topic=\"%s\"]\n", topic));
   2288 
   2289  nsresult rv;
   2290  if (!strcmp(topic, "profile-change-net-teardown") ||
   2291      !strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
   2292    mHandlerActive = false;
   2293 
   2294    // clear cache of all authentication credentials.
   2295    mAuthCache->ClearAll();
   2296    mPrivateAuthCache->ClearAll();
   2297    if (mWifiTickler) mWifiTickler->Cancel();
   2298 
   2299    // Inform nsIOService that network is tearing down.
   2300    gIOService->SetHttpHandlerAlreadyShutingDown();
   2301 
   2302    ShutdownConnectionManager();
   2303 
   2304    // need to reset the session start time since cache validation may
   2305    // depend on this value.
   2306    mSessionStartTime = NowInSeconds();
   2307 
   2308    // Since nsHttpHandler::Observe() is also called in socket process, we don't
   2309    // want to do telemetry twice.
   2310    if (XRE_IsParentProcess()) {
   2311      if (!StaticPrefs::privacy_donottrackheader_enabled()) {
   2312        glean::http::dnt_usage.AccumulateSingleSample(2);
   2313      } else {
   2314        glean::http::dnt_usage.AccumulateSingleSample(1);
   2315      }
   2316    }
   2317 
   2318    mActivityDistributor = nullptr;
   2319  } else if (!strcmp(topic, "profile-change-net-restore")) {
   2320    // initialize connection manager
   2321    rv = InitConnectionMgr();
   2322    MOZ_ASSERT(NS_SUCCEEDED(rv));
   2323    mAltSvcCache = MakeUnique<AltSvcCache>();
   2324  } else if (!strcmp(topic, "net:clear-active-logins")) {
   2325    mAuthCache->ClearAll();
   2326    mPrivateAuthCache->ClearAll();
   2327  } else if (!strcmp(topic, "net:cancel-all-connections")) {
   2328    if (mConnMgr) {
   2329      mConnMgr->AbortAndCloseAllConnections(0, nullptr);
   2330    }
   2331  } else if (!strcmp(topic, "net:prune-dead-connections")) {
   2332    if (mConnMgr) {
   2333      rv = mConnMgr->PruneDeadConnections();
   2334      if (NS_FAILED(rv)) {
   2335        LOG(("    PruneDeadConnections failed (%08x)\n",
   2336             static_cast<uint32_t>(rv)));
   2337      }
   2338    }
   2339  } else if (!strcmp(topic, "net:prune-all-connections")) {
   2340    if (mConnMgr) {
   2341      rv = mConnMgr->DoShiftReloadConnectionCleanup();
   2342      if (NS_FAILED(rv)) {
   2343        LOG(("    DoShiftReloadConnectionCleanup failed (%08x)\n",
   2344             static_cast<uint32_t>(rv)));
   2345      }
   2346      rv = mConnMgr->PruneDeadConnections();
   2347      if (NS_FAILED(rv)) {
   2348        LOG(("    PruneDeadConnections failed (%08x)\n",
   2349             static_cast<uint32_t>(rv)));
   2350      }
   2351    }
   2352 #if 0
   2353    } else if (!strcmp(topic, "net:failed-to-process-uri-content")) {
   2354         // nop right now - we used to cancel h1 pipelines based on this,
   2355         // but those are no longer implemented
   2356         nsCOMPtr<nsIURI> uri = do_QueryInterface(subject);
   2357 #endif
   2358  } else if (!strcmp(topic, "last-pb-context-exited")) {
   2359    mPrivateAuthCache->ClearAll();
   2360    if (mAltSvcCache) {
   2361      mAltSvcCache->ClearAltServiceMappings();
   2362    }
   2363    nsCORSListenerProxy::ClearPrivateBrowsingCache();
   2364  } else if (!strcmp(topic, "browser:purge-session-history")) {
   2365    if (mConnMgr) {
   2366      (void)mConnMgr->ClearConnectionHistory();
   2367    }
   2368    if (mAltSvcCache) {
   2369      mAltSvcCache->ClearAltServiceMappings();
   2370    }
   2371  } else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
   2372    if (mConnMgr) {
   2373      rv = mConnMgr->PruneDeadConnections();
   2374      if (NS_FAILED(rv)) {
   2375        LOG(("    PruneDeadConnections failed (%08x)\n",
   2376             static_cast<uint32_t>(rv)));
   2377      }
   2378      rv = mConnMgr->VerifyTraffic();
   2379      if (NS_FAILED(rv)) {
   2380        LOG(("    VerifyTraffic failed (%08x)\n", static_cast<uint32_t>(rv)));
   2381      }
   2382      // We exclude HTTP/3 for an origin when any error occurs during
   2383      // connection establishment. A common error is caused by UDP being blocked
   2384      // by the network. When the network changes, it’s likely that UDP is no
   2385      // longer blocked, so we should reset the exclusion list to give HTTP/3
   2386      // another chance.
   2387      MutexAutoLock lock(mHttpExclusionLock);
   2388      mExcludedHttp3Origins.Clear();
   2389    }
   2390  } else if (!strcmp(topic, "application-background")) {
   2391    // going to the background on android means we should close
   2392    // down idle connections for power conservation
   2393    if (mConnMgr) {
   2394      rv = mConnMgr->DoShiftReloadConnectionCleanup();
   2395      if (NS_FAILED(rv)) {
   2396        LOG(("    DoShiftReloadConnectionCleanup failed (%08x)\n",
   2397             static_cast<uint32_t>(rv)));
   2398      }
   2399    }
   2400  } else if (!strcmp(topic, "net:current-browser-id")) {
   2401    // The window id will be updated by HttpConnectionMgrParent.
   2402    if (XRE_IsParentProcess()) {
   2403      nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(subject);
   2404      MOZ_RELEASE_ASSERT(wrapper);
   2405 
   2406      uint64_t id = 0;
   2407      wrapper->GetData(&id);
   2408      MOZ_ASSERT(id);
   2409 
   2410      static uint64_t sCurrentBrowserId = 0;
   2411      if (sCurrentBrowserId != id) {
   2412        sCurrentBrowserId = id;
   2413        if (mConnMgr) {
   2414          mConnMgr->UpdateCurrentBrowserId(sCurrentBrowserId);
   2415        }
   2416      }
   2417    }
   2418  } else if (!strcmp(topic, "intl:app-locales-changed")) {
   2419    // If the locale changed, there's a chance the accept language did too
   2420    mAcceptLanguagesIsDirty = true;
   2421  } else if (!strcmp(topic, "network:reset-http3-excluded-list")) {
   2422    MutexAutoLock lock(mHttpExclusionLock);
   2423    mExcludedHttp3Origins.Clear();
   2424  } else if (!strcmp(topic, "network:socket-process-crashed")) {
   2425    ShutdownConnectionManager();
   2426    mConnMgr = nullptr;
   2427    (void)InitConnectionMgr();
   2428  } else if (!strcmp(topic, "idle-daily")) {
   2429    // Submit the local-network-access ping once per day
   2430    if (XRE_IsParentProcess()) {
   2431 #if defined(EARLY_BETA_OR_EARLIER)  // Submit custom telemetry ping.
   2432      glean_pings::LocalNetworkAccess.Submit();
   2433 #endif
   2434    }
   2435  }
   2436  return NS_OK;
   2437 }
   2438 
   2439 // nsISpeculativeConnect
   2440 
   2441 nsresult nsHttpHandler::SpeculativeConnectInternal(
   2442    nsIURI* aURI, nsIPrincipal* aPrincipal,
   2443    Maybe<OriginAttributes>&& aOriginAttributes,
   2444    nsIInterfaceRequestor* aCallbacks, bool anonymous) {
   2445  if (IsNeckoChild()) {
   2446    gNeckoChild->SendSpeculativeConnect(
   2447        aURI, aPrincipal, std::move(aOriginAttributes), anonymous);
   2448    return NS_OK;
   2449  }
   2450 
   2451  if (!mHandlerActive) return NS_OK;
   2452 
   2453  MOZ_ASSERT(NS_IsMainThread());
   2454 
   2455  nsISiteSecurityService* sss = gHttpHandler->GetSSService();
   2456  bool isStsHost = false;
   2457  if (!sss) return NS_OK;
   2458 
   2459  nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(aCallbacks);
   2460  OriginAttributes originAttributes;
   2461  // If the principal is given, we use the originAttributes from this
   2462  // principal. Otherwise, we use the originAttributes from the loadContext.
   2463  if (aOriginAttributes) {
   2464    originAttributes = std::move(aOriginAttributes.ref());
   2465  } else if (aPrincipal) {
   2466    originAttributes = aPrincipal->OriginAttributesRef();
   2467  } else if (loadContext) {
   2468    loadContext->GetOriginAttributes(originAttributes);
   2469  }
   2470 
   2471  nsCOMPtr<nsIURI> clone;
   2472  if (NS_SUCCEEDED(sss->IsSecureURI(aURI, originAttributes, &isStsHost)) &&
   2473      isStsHost) {
   2474    if (NS_SUCCEEDED(NS_GetSecureUpgradedURI(aURI, getter_AddRefs(clone)))) {
   2475      aURI = clone.get();
   2476      // (NOTE: We better make sure |clone| stays alive until the end
   2477      // of the function now, since our aURI arg now points to it!)
   2478    }
   2479  }
   2480 
   2481  if (!aOriginAttributes) {
   2482    // We must update the originAttributes with the network state first party
   2483    // domain **after** we upgrade aURI to https.
   2484    // Otherwise the speculative connection will be keyed by a http URL
   2485    // and end up not being used.
   2486    StoragePrincipalHelper::UpdateOriginAttributesForNetworkState(
   2487        aURI, originAttributes);
   2488  }
   2489 
   2490  nsAutoCString scheme;
   2491  nsresult rv = aURI->GetScheme(scheme);
   2492  if (NS_FAILED(rv)) return rv;
   2493 
   2494  // If this is HTTPS, make sure PSM is initialized as the channel
   2495  // creation path may have been bypassed
   2496  if (scheme.EqualsLiteral("https")) {
   2497    if (!IsNeckoChild()) {
   2498      // make sure PSM gets initialized on the main thread.
   2499      net_EnsurePSMInit();
   2500    }
   2501  }
   2502  // Ensure that this is HTTP or HTTPS, otherwise we don't do preconnect here
   2503  else if (!scheme.EqualsLiteral("http")) {
   2504    return NS_ERROR_UNEXPECTED;
   2505  }
   2506 
   2507  nsAutoCString host;
   2508  rv = aURI->GetAsciiHost(host);
   2509  if (NS_FAILED(rv)) return rv;
   2510 
   2511  int32_t port = -1;
   2512  rv = aURI->GetPort(&port);
   2513  if (NS_FAILED(rv)) return rv;
   2514 
   2515  nsAutoCString username;
   2516  aURI->GetUsername(username);
   2517 
   2518  RefPtr<AltSvcMapping> mapping;
   2519  if (username.IsEmpty()) {
   2520    mapping = gHttpHandler->GetAltServiceMapping(
   2521        scheme, host, port, originAttributes.IsPrivateBrowsing(),
   2522        originAttributes, true, true);
   2523  }
   2524 
   2525  RefPtr<nsHttpConnectionInfo> ci;
   2526  if (mapping) {
   2527    mapping->GetConnectionInfo(getter_AddRefs(ci), nullptr, originAttributes);
   2528  } else {
   2529    ci = new nsHttpConnectionInfo(host, port, ""_ns, username, nullptr,
   2530                                  originAttributes, aURI->SchemeIs("https"));
   2531  }
   2532  ci->SetAnonymous(anonymous);
   2533  if (originAttributes.IsPrivateBrowsing()) {
   2534    ci->SetPrivate(true);
   2535  }
   2536 
   2537  if (mDebugObservations) {
   2538    // this is basically used for test coverage of an otherwise 'hintable'
   2539    // feature
   2540 
   2541    nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
   2542    if (obsService) {
   2543      // This is used to test if the speculative connection has the right
   2544      // connection info.
   2545      nsPrintfCString debugHashKey("%s", ci->HashKey().get());
   2546      obsService->NotifyObservers(nullptr, "speculative-connect-request",
   2547                                  NS_ConvertUTF8toUTF16(debugHashKey).get());
   2548      for (auto* cp :
   2549           dom::ContentParent::AllProcesses(dom::ContentParent::eLive)) {
   2550        PNeckoParent* neckoParent =
   2551            SingleManagedOrNull(cp->ManagedPNeckoParent());
   2552        if (!neckoParent) {
   2553          continue;
   2554        }
   2555        (void)neckoParent->SendSpeculativeConnectRequest();
   2556      }
   2557    }
   2558  }
   2559 
   2560  LOG(("MaybeSpeculativeConnectWithHTTPSRR for ci=%s", ci->HashKey().get()));
   2561  // When ech is enabled, always do speculative connect with HTTPS RR.
   2562  return MaybeSpeculativeConnectWithHTTPSRR(ci, aCallbacks, 0,
   2563                                            EchConfigEnabled());
   2564 }
   2565 
   2566 NS_IMETHODIMP
   2567 nsHttpHandler::SpeculativeConnect(nsIURI* aURI, nsIPrincipal* aPrincipal,
   2568                                  nsIInterfaceRequestor* aCallbacks,
   2569                                  bool aAnonymous) {
   2570  return SpeculativeConnectInternal(aURI, aPrincipal, Nothing(), aCallbacks,
   2571                                    aAnonymous);
   2572 }
   2573 
   2574 NS_IMETHODIMP nsHttpHandler::SpeculativeConnectWithOriginAttributes(
   2575    nsIURI* aURI, JS::Handle<JS::Value> aOriginAttributes,
   2576    nsIInterfaceRequestor* aCallbacks, bool aAnonymous, JSContext* aCx) {
   2577  OriginAttributes attrs;
   2578  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
   2579    return NS_ERROR_INVALID_ARG;
   2580  }
   2581 
   2582  SpeculativeConnectWithOriginAttributesNative(aURI, std::move(attrs),
   2583                                               aCallbacks, aAnonymous);
   2584  return NS_OK;
   2585 }
   2586 
   2587 NS_IMETHODIMP_(void)
   2588 nsHttpHandler::SpeculativeConnectWithOriginAttributesNative(
   2589    nsIURI* aURI, OriginAttributes&& aOriginAttributes,
   2590    nsIInterfaceRequestor* aCallbacks, bool aAnonymous) {
   2591  Maybe<OriginAttributes> originAttributes;
   2592  originAttributes.emplace(aOriginAttributes);
   2593  (void)SpeculativeConnectInternal(aURI, nullptr, std::move(originAttributes),
   2594                                   aCallbacks, aAnonymous);
   2595 }
   2596 
   2597 void nsHttpHandler::TickleWifi(nsIInterfaceRequestor* cb) {
   2598  if (!cb || !mWifiTickler) return;
   2599 
   2600  // If B2G requires a similar mechanism nsINetworkManager, currently only avail
   2601  // on B2G, contains the necessary information on wifi and gateway
   2602 
   2603  nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(cb);
   2604  nsCOMPtr<nsPIDOMWindowOuter> piWindow = do_QueryInterface(domWindow);
   2605  if (!piWindow) return;
   2606 
   2607  RefPtr<dom::Navigator> navigator = piWindow->GetNavigator();
   2608  if (!navigator) return;
   2609 
   2610  RefPtr<dom::network::Connection> networkProperties =
   2611      navigator->GetConnection(IgnoreErrors());
   2612  if (!networkProperties) return;
   2613 
   2614  uint32_t gwAddress = networkProperties->GetDhcpGateway();
   2615  bool isWifi = networkProperties->GetIsWifi();
   2616  if (!gwAddress || !isWifi) return;
   2617 
   2618  mWifiTickler->SetIPV4Address(gwAddress);
   2619  mWifiTickler->Tickle();
   2620 }
   2621 
   2622 //-----------------------------------------------------------------------------
   2623 // nsHttpsHandler implementation
   2624 //-----------------------------------------------------------------------------
   2625 
   2626 NS_IMPL_ISUPPORTS(nsHttpsHandler, nsIHttpProtocolHandler,
   2627                  nsIProxiedProtocolHandler, nsIProtocolHandler,
   2628                  nsISupportsWeakReference, nsISpeculativeConnect)
   2629 
   2630 nsresult nsHttpsHandler::Init() {
   2631  nsCOMPtr<nsIProtocolHandler> httpHandler(
   2632      do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http"));
   2633  MOZ_ASSERT(httpHandler.get() != nullptr);
   2634  return NS_OK;
   2635 }
   2636 
   2637 NS_IMETHODIMP
   2638 nsHttpsHandler::GetScheme(nsACString& aScheme) {
   2639  aScheme.AssignLiteral("https");
   2640  return NS_OK;
   2641 }
   2642 
   2643 NS_IMETHODIMP
   2644 nsHttpsHandler::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo,
   2645                           nsIChannel** _retval) {
   2646  MOZ_ASSERT(gHttpHandler);
   2647  if (!gHttpHandler) return NS_ERROR_UNEXPECTED;
   2648  return gHttpHandler->NewChannel(aURI, aLoadInfo, _retval);
   2649 }
   2650 
   2651 NS_IMETHODIMP
   2652 nsHttpsHandler::AllowPort(int32_t aPort, const char* aScheme, bool* _retval) {
   2653  // don't override anything.
   2654  *_retval = false;
   2655  return NS_OK;
   2656 }
   2657 
   2658 NS_IMETHODIMP
   2659 nsHttpHandler::EnsureHSTSDataReadyNative(
   2660    RefPtr<mozilla::net::HSTSDataCallbackWrapper> aCallback) {
   2661  MOZ_ASSERT(NS_IsMainThread());
   2662 
   2663  nsCOMPtr<nsIURI> uri;
   2664  nsresult rv = NS_NewURI(getter_AddRefs(uri), "http://example.com");
   2665  NS_ENSURE_SUCCESS(rv, rv);
   2666 
   2667  bool shouldUpgrade = false;
   2668  bool willCallback = false;
   2669  OriginAttributes originAttributes;
   2670  auto func = [callback(aCallback)](bool aResult, nsresult aStatus) {
   2671    callback->DoCallback(aResult);
   2672  };
   2673  rv = NS_ShouldSecureUpgrade(uri, nullptr, nullptr, false, originAttributes,
   2674                              shouldUpgrade, std::move(func), willCallback);
   2675  if (NS_FAILED(rv) || !willCallback) {
   2676    aCallback->DoCallback(false);
   2677    return rv;
   2678  }
   2679 
   2680  return rv;
   2681 }
   2682 
   2683 NS_IMETHODIMP
   2684 nsHttpHandler::EnsureHSTSDataReady(JSContext* aCx, Promise** aPromise) {
   2685  if (NS_WARN_IF(!aCx)) {
   2686    return NS_ERROR_FAILURE;
   2687  }
   2688 
   2689  nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
   2690  if (NS_WARN_IF(!globalObject)) {
   2691    return NS_ERROR_FAILURE;
   2692  }
   2693 
   2694  ErrorResult result;
   2695  RefPtr<Promise> promise = Promise::Create(globalObject, result);
   2696  if (NS_WARN_IF(result.Failed())) {
   2697    return result.StealNSResult();
   2698  }
   2699 
   2700  if (IsNeckoChild()) {
   2701    gNeckoChild->SendEnsureHSTSData()->Then(
   2702        GetMainThreadSerialEventTarget(), __func__,
   2703        [promise(promise)](
   2704            NeckoChild::EnsureHSTSDataPromise::ResolveOrRejectValue&& aResult) {
   2705          if (aResult.IsResolve()) {
   2706            promise->MaybeResolve(aResult.ResolveValue());
   2707          } else {
   2708            promise->MaybeReject(NS_ERROR_FAILURE);
   2709          }
   2710        });
   2711    promise.forget(aPromise);
   2712    return NS_OK;
   2713  }
   2714 
   2715  auto callback = [promise(promise)](bool aResult) {
   2716    promise->MaybeResolve(aResult);
   2717  };
   2718 
   2719  RefPtr<HSTSDataCallbackWrapper> wrapper =
   2720      new HSTSDataCallbackWrapper(std::move(callback));
   2721  promise.forget(aPromise);
   2722  return EnsureHSTSDataReadyNative(wrapper);
   2723 }
   2724 
   2725 NS_IMETHODIMP
   2726 nsHttpHandler::ClearCORSPreflightCache() {
   2727  nsCORSListenerProxy::ClearCache();
   2728  return NS_OK;
   2729 }
   2730 
   2731 void nsHttpHandler::ShutdownConnectionManager() {
   2732  // ensure connection manager is shutdown
   2733  if (mConnMgr) {
   2734    nsresult rv = mConnMgr->Shutdown();
   2735    if (NS_FAILED(rv)) {
   2736      LOG(
   2737          ("nsHttpHandler::ShutdownConnectionManager\n"
   2738           "    failed to shutdown connection manager\n"));
   2739    }
   2740  }
   2741 }
   2742 
   2743 uint64_t nsHttpHandler::NewChannelId() {
   2744  // channelId is sometimes passed to JavaScript code (e.g. devtools),
   2745  // values should not exceed safe JavaScript integer range (2^53 – 1).
   2746  // Since the uniqueProcessId starts at 0, this should be safe to use
   2747  // unless we create more than 2^22 processes.
   2748  return ((mUniqueProcessId << 31) & 0xFFFFFFFF80000000LL) | mNextChannelId++;
   2749 }
   2750 
   2751 void nsHttpHandler::NotifyActiveTabLoadOptimization() {
   2752  SetLastActiveTabLoadOptimizationHit(TimeStamp::Now());
   2753 }
   2754 
   2755 TimeStamp nsHttpHandler::GetLastActiveTabLoadOptimizationHit() {
   2756  MutexAutoLock lock(mLastActiveTabLoadOptimizationLock);
   2757 
   2758  return mLastActiveTabLoadOptimizationHit;
   2759 }
   2760 
   2761 void nsHttpHandler::SetLastActiveTabLoadOptimizationHit(TimeStamp const& when) {
   2762  MutexAutoLock lock(mLastActiveTabLoadOptimizationLock);
   2763 
   2764  if (mLastActiveTabLoadOptimizationHit.IsNull() ||
   2765      (!when.IsNull() && mLastActiveTabLoadOptimizationHit < when)) {
   2766    mLastActiveTabLoadOptimizationHit = when;
   2767  }
   2768 }
   2769 
   2770 bool nsHttpHandler::IsBeforeLastActiveTabLoadOptimization(
   2771    TimeStamp const& when) {
   2772  MutexAutoLock lock(mLastActiveTabLoadOptimizationLock);
   2773 
   2774  return !mLastActiveTabLoadOptimizationHit.IsNull() &&
   2775         when <= mLastActiveTabLoadOptimizationHit;
   2776 }
   2777 
   2778 void nsHttpHandler::ExcludeHttp2OrHttp3Internal(
   2779    const nsHttpConnectionInfo* ci) {
   2780  LOG(("nsHttpHandler::ExcludeHttp2OrHttp3Internal ci=%s",
   2781       ci->HashKey().get()));
   2782  // The excluded list needs to be stayed synced between parent process and
   2783  // socket process, so we send this information to the parent process here.
   2784  if (XRE_IsSocketProcess()) {
   2785    MOZ_ASSERT(OnSocketThread());
   2786 
   2787    RefPtr<nsHttpConnectionInfo> cinfo = ci->Clone();
   2788    NS_DispatchToMainThread(NS_NewRunnableFunction(
   2789        "nsHttpHandler::ExcludeHttp2OrHttp3Internal",
   2790        [cinfo{std::move(cinfo)}]() {
   2791          HttpConnectionInfoCloneArgs connInfoArgs;
   2792          nsHttpConnectionInfo::SerializeHttpConnectionInfo(cinfo,
   2793                                                            connInfoArgs);
   2794          (void)SocketProcessChild::GetSingleton()->SendExcludeHttp2OrHttp3(
   2795              connInfoArgs);
   2796        }));
   2797  }
   2798 
   2799  MOZ_ASSERT_IF(nsIOService::UseSocketProcess() && XRE_IsParentProcess(),
   2800                NS_IsMainThread());
   2801  MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(), OnSocketThread());
   2802 
   2803  if (ci->IsHttp3()) {
   2804    if (!mExcludedHttp3Origins.Contains(ci->GetRoutedHost())) {
   2805      MutexAutoLock lock(mHttpExclusionLock);
   2806      mExcludedHttp3Origins.Insert(ci->GetRoutedHost());
   2807    }
   2808    mConnMgr->ExcludeHttp3(ci);
   2809  } else {
   2810    if (!mExcludedHttp2Origins.Contains(ci->GetOrigin())) {
   2811      MutexAutoLock lock(mHttpExclusionLock);
   2812      mExcludedHttp2Origins.Insert(ci->GetOrigin());
   2813    }
   2814    mConnMgr->ExcludeHttp2(ci);
   2815  }
   2816 }
   2817 
   2818 void nsHttpHandler::ExcludeHttp2(const nsHttpConnectionInfo* ci) {
   2819  ExcludeHttp2OrHttp3Internal(ci);
   2820 }
   2821 
   2822 bool nsHttpHandler::IsHttp2Excluded(const nsHttpConnectionInfo* ci) {
   2823  MutexAutoLock lock(mHttpExclusionLock);
   2824  return mExcludedHttp2Origins.Contains(ci->GetOrigin());
   2825 }
   2826 
   2827 void nsHttpHandler::ExcludeHttp3(const nsHttpConnectionInfo* ci) {
   2828  // TODO: exclude HTTP/3 for proxy connection properly.
   2829  if (ci->IsHttp3ProxyConnection()) {
   2830    return;
   2831  }
   2832  MOZ_ASSERT(ci->IsHttp3());
   2833  ExcludeHttp2OrHttp3Internal(ci);
   2834 }
   2835 
   2836 bool nsHttpHandler::IsHttp3Excluded(const nsACString& aRoutedHost) {
   2837  MutexAutoLock lock(mHttpExclusionLock);
   2838  return mExcludedHttp3Origins.Contains(aRoutedHost);
   2839 }
   2840 
   2841 HttpTrafficAnalyzer* nsHttpHandler::GetHttpTrafficAnalyzer() {
   2842  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   2843 
   2844  if (!StaticPrefs::network_traffic_analyzer_enabled()) {
   2845    return nullptr;
   2846  }
   2847 
   2848  return &mHttpTrafficAnalyzer;
   2849 }
   2850 
   2851 bool nsHttpHandler::IsHttp3Enabled() {
   2852  static const uint32_t TLS3_PREF_VALUE = 4;
   2853 
   2854  return StaticPrefs::network_http_http3_enable() &&
   2855         (StaticPrefs::security_tls_version_max() >= TLS3_PREF_VALUE);
   2856 }
   2857 
   2858 bool nsHttpHandler::IsHttp3VersionSupported(const nsACString& version) {
   2859  return (StaticPrefs::network_http_http3_support_version1() &&
   2860          version.EqualsLiteral("h3"));
   2861 }
   2862 
   2863 bool nsHttpHandler::IsHttp3SupportedByServer(
   2864    nsHttpResponseHead* aResponseHead) {
   2865  if ((aResponseHead->Version() != HttpVersion::v2_0) ||
   2866      (aResponseHead->Status() >= 500) || (aResponseHead->Status() == 421)) {
   2867    return false;
   2868  }
   2869 
   2870  nsAutoCString altSvc;
   2871  (void)aResponseHead->GetHeader(nsHttp::Alternate_Service, altSvc);
   2872  if (altSvc.IsEmpty() || !nsHttp::IsReasonableHeaderValue(altSvc)) {
   2873    return false;
   2874  }
   2875 
   2876  return altSvc.Find("h3=") != -1;
   2877 }
   2878 
   2879 nsresult nsHttpHandler::InitiateTransaction(HttpTransactionShell* aTrans,
   2880                                            int32_t aPriority) {
   2881  return mConnMgr->AddTransaction(aTrans, aPriority);
   2882 }
   2883 nsresult nsHttpHandler::InitiateTransactionWithStickyConn(
   2884    HttpTransactionShell* aTrans, int32_t aPriority,
   2885    HttpTransactionShell* aTransWithStickyConn) {
   2886  return mConnMgr->AddTransactionWithStickyConn(aTrans, aPriority,
   2887                                                aTransWithStickyConn);
   2888 }
   2889 
   2890 nsresult nsHttpHandler::RescheduleTransaction(HttpTransactionShell* trans,
   2891                                              int32_t priority) {
   2892  return mConnMgr->RescheduleTransaction(trans, priority);
   2893 }
   2894 
   2895 void nsHttpHandler::UpdateClassOfServiceOnTransaction(
   2896    HttpTransactionShell* trans, const ClassOfService& classOfService) {
   2897  mConnMgr->UpdateClassOfServiceOnTransaction(trans, classOfService);
   2898 }
   2899 
   2900 nsresult nsHttpHandler::CancelTransaction(HttpTransactionShell* trans,
   2901                                          nsresult reason) {
   2902  return mConnMgr->CancelTransaction(trans, reason);
   2903 }
   2904 
   2905 void nsHttpHandler::AddHttpChannel(uint64_t aId, nsISupports* aChannel) {
   2906  MOZ_ASSERT(XRE_IsParentProcess());
   2907  MOZ_ASSERT(NS_IsMainThread());
   2908 
   2909  nsWeakPtr channel(do_GetWeakReference(aChannel));
   2910  mIDToHttpChannelMap.InsertOrUpdate(aId, std::move(channel));
   2911 }
   2912 
   2913 void nsHttpHandler::RemoveHttpChannel(uint64_t aId) {
   2914  MOZ_ASSERT(XRE_IsParentProcess());
   2915  if (!NS_IsMainThread()) {
   2916    nsCOMPtr<nsIRunnable> idleRunnable(NewCancelableRunnableMethod<uint64_t>(
   2917        "nsHttpHandler::RemoveHttpChannel", this,
   2918        &nsHttpHandler::RemoveHttpChannel, aId));
   2919 
   2920    NS_DispatchToMainThreadQueue(do_AddRef(idleRunnable),
   2921                                 EventQueuePriority::Idle);
   2922    return;
   2923  }
   2924 
   2925  auto entry = mIDToHttpChannelMap.Lookup(aId);
   2926  if (entry) {
   2927    entry.Remove();
   2928  }
   2929 }
   2930 
   2931 nsWeakPtr nsHttpHandler::GetWeakHttpChannel(uint64_t aId) {
   2932  MOZ_ASSERT(XRE_IsParentProcess());
   2933  MOZ_ASSERT(NS_IsMainThread());
   2934 
   2935  return mIDToHttpChannelMap.Get(aId);
   2936 }
   2937 
   2938 nsresult nsHttpHandler::CompleteUpgrade(
   2939    HttpTransactionShell* aTrans, nsIHttpUpgradeListener* aUpgradeListener) {
   2940  return mConnMgr->CompleteUpgrade(aTrans, aUpgradeListener);
   2941 }
   2942 
   2943 nsresult nsHttpHandler::DoShiftReloadConnectionCleanupWithConnInfo(
   2944    nsHttpConnectionInfo* aCi) {
   2945  MOZ_ASSERT(aCi);
   2946  return mConnMgr->DoShiftReloadConnectionCleanupWithConnInfo(aCi);
   2947 }
   2948 
   2949 void nsHttpHandler::ClearHostMapping(nsHttpConnectionInfo* aConnInfo) {
   2950  if (XRE_IsSocketProcess()) {
   2951    AltServiceChild::ClearHostMapping(aConnInfo);
   2952    return;
   2953  }
   2954 
   2955  AltServiceCache()->ClearHostMapping(aConnInfo);
   2956 }
   2957 
   2958 void nsHttpHandler::SetHttpHandlerInitArgs(const HttpHandlerInitArgs& aArgs) {
   2959  MOZ_ASSERT(XRE_IsSocketProcess());
   2960  mLegacyAppName = aArgs.mLegacyAppName();
   2961  mLegacyAppVersion = aArgs.mLegacyAppVersion();
   2962  mPlatform = aArgs.mPlatform();
   2963  mOscpu = aArgs.mOscpu();
   2964  mMisc = aArgs.mMisc();
   2965  mProduct = aArgs.mProduct();
   2966  mProductSub = aArgs.mProductSub();
   2967  mAppName = aArgs.mAppName();
   2968  mAppVersion = aArgs.mAppVersion();
   2969  mCompatFirefox = aArgs.mCompatFirefox();
   2970  mCompatDevice = aArgs.mCompatDevice();
   2971  mDeviceModelId = aArgs.mDeviceModelId();
   2972 }
   2973 
   2974 void nsHttpHandler::SetDeviceModelId(const nsACString& aModelId) {
   2975  MOZ_ASSERT(XRE_IsSocketProcess());
   2976  mDeviceModelId = aModelId;
   2977 }
   2978 
   2979 void nsHttpHandler::MaybeAddAltSvcForTesting(
   2980    nsIURI* aUri, const nsACString& aUsername, bool aPrivateBrowsing,
   2981    nsIInterfaceRequestor* aCallbacks,
   2982    const OriginAttributes& aOriginAttributes) {
   2983  if (!IsHttp3Enabled() || mAltSvcMappingTemptativeMap.IsEmpty()) {
   2984    return;
   2985  }
   2986 
   2987  if (!aUri->SchemeIs("https")) {
   2988    // Only set for HTTPS.
   2989    return;
   2990  }
   2991 
   2992  nsAutoCString originHost;
   2993  if (NS_FAILED(aUri->GetAsciiHost(originHost))) {
   2994    return;
   2995  }
   2996 
   2997  nsCString* map = mAltSvcMappingTemptativeMap.Get(originHost);
   2998  if (map) {
   2999    int32_t originPort = 80;
   3000    aUri->GetPort(&originPort);
   3001    LOG(("nsHttpHandler::MaybeAddAltSvcForTesting for %s map: %s",
   3002         originHost.get(), PromiseFlatCString(*map).get()));
   3003    AltSvcMapping::ProcessHeader(*map, nsCString("https"), originHost,
   3004                                 originPort, aUsername, aPrivateBrowsing,
   3005                                 aCallbacks, nullptr, 0, aOriginAttributes,
   3006                                 nullptr, true);
   3007  }
   3008 }
   3009 
   3010 bool nsHttpHandler::EchConfigEnabled(bool aIsHttp3) {
   3011  if (sParentalControlsEnabled) {
   3012    return false;
   3013  }
   3014 
   3015  if (!aIsHttp3) {
   3016    return StaticPrefs::network_dns_echconfig_enabled();
   3017  }
   3018 
   3019  return StaticPrefs::network_dns_http3_echconfig_enabled();
   3020 }
   3021 
   3022 bool nsHttpHandler::FallbackToOriginIfConfigsAreECHAndAllFailed() const {
   3023  return StaticPrefs::
   3024      network_dns_echconfig_fallback_to_origin_when_all_failed();
   3025 }
   3026 
   3027 void nsHttpHandler::ExcludeHTTPSRRHost(const nsACString& aHost) {
   3028  MOZ_ASSERT(NS_IsMainThread());
   3029 
   3030  mExcludedHostsForHTTPSRRUpgrade.Insert(aHost);
   3031 }
   3032 
   3033 bool nsHttpHandler::IsHostExcludedForHTTPSRR(const nsACString& aHost) {
   3034  MOZ_ASSERT(NS_IsMainThread());
   3035 
   3036  return mExcludedHostsForHTTPSRRUpgrade.Contains(aHost);
   3037 }
   3038 
   3039 #ifdef XP_MACOSX
   3040 bool nsHttpHandler::IsHostMSAuthority(const nsACString& aHost) {
   3041  MOZ_ASSERT(NS_IsMainThread());
   3042 
   3043  return mMSAuthorities.Contains(aHost);
   3044 }
   3045 #endif
   3046 
   3047 void nsHttpHandler::Exclude0RttTcp(const nsHttpConnectionInfo* ci) {
   3048  MOZ_ASSERT(OnSocketThread());
   3049 
   3050  if (!StaticPrefs::network_http_early_data_disable_on_error() ||
   3051      (mExcluded0RttTcpOrigins.Count() >=
   3052       StaticPrefs::network_http_early_data_max_error())) {
   3053    return;
   3054  }
   3055 
   3056  mExcluded0RttTcpOrigins.Insert(ci->GetOrigin());
   3057 }
   3058 
   3059 bool nsHttpHandler::Is0RttTcpExcluded(const nsHttpConnectionInfo* ci) {
   3060  MOZ_ASSERT(OnSocketThread());
   3061  if (!StaticPrefs::network_http_early_data_disable_on_error()) {
   3062    return false;
   3063  }
   3064 
   3065  if (mExcluded0RttTcpOrigins.Count() >=
   3066      StaticPrefs::network_http_early_data_max_error()) {
   3067    return true;
   3068  }
   3069 
   3070  return mExcluded0RttTcpOrigins.Contains(ci->GetOrigin());
   3071 }
   3072 
   3073 bool nsHttpHandler::HttpActivityDistributorActivated() {
   3074  if (!mActivityDistributor) {
   3075    return false;
   3076  }
   3077 
   3078  return mActivityDistributor->Activated();
   3079 }
   3080 
   3081 void nsHttpHandler::ObserveHttpActivityWithArgs(
   3082    const HttpActivityArgs& aArgs, uint32_t aActivityType,
   3083    uint32_t aActivitySubtype, PRTime aTimestamp, uint64_t aExtraSizeData,
   3084    const nsACString& aExtraStringData) {
   3085  if (!HttpActivityDistributorActivated()) {
   3086    return;
   3087  }
   3088 
   3089  if (aActivitySubtype == NS_HTTP_ACTIVITY_SUBTYPE_PROXY_RESPONSE_HEADER &&
   3090      !mActivityDistributor->ObserveProxyResponseEnabled()) {
   3091    return;
   3092  }
   3093 
   3094  if (aActivityType == NS_ACTIVITY_TYPE_HTTP_CONNECTION &&
   3095      !mActivityDistributor->ObserveConnectionEnabled()) {
   3096    return;
   3097  }
   3098 
   3099  (void)mActivityDistributor->ObserveActivityWithArgs(
   3100      aArgs, aActivityType, aActivitySubtype, aTimestamp, aExtraSizeData,
   3101      aExtraStringData);
   3102 }
   3103 
   3104 }  // namespace mozilla::net