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