/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=4 sw=2 sts=2 et cin: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// HttpLog.h should generally be included first #include"HttpLog.h"
#ifdef ANDROID static nsCString GetDeviceModelId() { // Assumed to be running on the main thread // We need the device property in either case
nsAutoCString deviceModelId;
nsCOMPtr<nsIPropertyBag2> infoService;
infoService = mozilla::components::SystemInfo::Service();
MOZ_ASSERT(infoService, "Could not find a system info service");
nsAutoString androidDevice;
nsresult rv = infoService->GetPropertyAsAString(u"device"_ns, androidDevice); if (NS_SUCCEEDED(rv)) {
deviceModelId = NS_LossyConvertUTF16toASCII(androidDevice);
}
nsAutoCString deviceString;
rv = Preferences::GetCString(UA_PREF("device_string"), deviceString); if (NS_SUCCEEDED(rv)) {
deviceString.Trim(" ", true, true);
deviceString.ReplaceSubstring("%DEVICEID%"_ns, deviceModelId); return std::move(deviceString);
} return std::move(deviceModelId);
} #endif
/* static */
already_AddRefed<nsHttpHandler> nsHttpHandler::GetInstance() { if (!gHttpHandler) {
gHttpHandler = new nsHttpHandler();
DebugOnly<nsresult> rv = gHttpHandler->Init();
MOZ_ASSERT(NS_SUCCEEDED(rv)); // There is code that may be executed during the final cycle collection // shutdown and still referencing gHttpHandler.
ClearOnShutdown(&gHttpHandler, ShutdownPhase::CCPostLastCycleCollection);
}
RefPtr<nsHttpHandler> httpHandler = gHttpHandler; return httpHandler.forget();
}
/// Derive the HTTP Accept header for image requests based on the enabled prefs /// for non-universal image types. This may be overridden in its entirety by /// the image.http.accept pref. static nsCString ImageAcceptHeader() {
nsCString mimeTypes;
if (mozilla::StaticPrefs::image_avif_enabled()) {
mimeTypes.Append("image/avif,");
}
if (mozilla::StaticPrefs::image_jxl_enabled()) {
mimeTypes.Append("image/jxl,");
}
static nsCString DocumentAcceptHeader() { // https://fetch.spec.whatwg.org/#document-accept-header-value // The value specified by the fetch standard is // `text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`
nsCString mimeTypes("text/html,application/xhtml+xml,application/xml;q=0.9,");
// we also insert all of the image formats before */* when the pref is set if (mozilla::StaticPrefs::network_http_accept_include_images()) { if (mozilla::StaticPrefs::image_avif_enabled()) {
mimeTypes.Append("image/avif,");
}
if (mozilla::StaticPrefs::image_jxl_enabled()) {
mimeTypes.Append("image/jxl,");
}
// We should not create nsHttpHandler during shutdown, but we have some // xpcshell tests doing this. if (MOZ_UNLIKELY(AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown) &&
!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR"))) {
MOZ_DIAGNOSTIC_CRASH("Try to init HttpHandler after shutdown"); return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
}
rv = nsHttp::CreateAtomTable(); if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIIOService> service;
service = mozilla::components::IO::Service(&rv); if (NS_FAILED(rv)) {
NS_WARNING("unable to continue without io service"); return rv;
}
mIOService = new nsMainThreadPtrHolder<nsIIOService>( "nsHttpHandler::mIOService", service);
gIOService->LaunchSocketProcess();
if (IsNeckoChild()) NeckoChild::InitNeckoChild();
InitUserAgentComponents();
// This preference is only used in parent process. if (!IsNeckoChild()) {
mActiveTabPriority =
Preferences::GetBool(HTTP_PREF("active_tab_priority"), true); if (XRE_IsParentProcess()) {
std::bitset<3> usageOfHTTPSRRPrefs;
usageOfHTTPSRRPrefs[0] = StaticPrefs::network_dns_upgrade_with_https_rr();
usageOfHTTPSRRPrefs[1] =
StaticPrefs::network_dns_use_https_rr_as_altsvc();
usageOfHTTPSRRPrefs[2] = StaticPrefs::network_dns_echconfig_enabled();
glean::networking::https_rr_prefs_usage.Set( static_cast<uint32_t>(usageOfHTTPSRRPrefs.to_ulong()));
glean::networking::http3_enabled.Set(
StaticPrefs::network_http_http3_enable());
}
mAppName.AssignLiteral(MOZ_APP_UA_NAME); if (mAppName.Length() == 0 && appInfo) { // Try to get the UA name from appInfo, falling back to the name
appInfo->GetUAName(mAppName); if (mAppName.Length() == 0) {
appInfo->GetName(mAppName);
}
appInfo->GetVersion(mAppVersion);
mAppName.StripChars(R"( ()<>@,;:\"/[]?={})");
} else {
mAppVersion.AssignLiteral(MOZ_APP_UA_VERSION);
}
mMisc.AssignLiteral("rv:" MOZILLA_UAVERSION);
// Generate the spoofed User Agent for fingerprinting resistance.
nsRFPService::GetSpoofedUserAgent(mSpoofedUserAgent);
// Startup the http category // Bring alive the objects in the http-protocol-startup category
NS_CreateServicesFromCategory(
NS_HTTP_STARTUP_CATEGORY, static_cast<nsISupports*>(static_cast<void*>(this)),
NS_HTTP_STARTUP_TOPIC);
nsCOMPtr<nsIObserverService> obsService = static_cast<nsIObserverService*>(gIOService); if (obsService) { // register the handler object as a weak callback as we don't need to worry // about shutdown ordering.
obsService->AddObserver(this, "profile-change-net-teardown", true);
obsService->AddObserver(this, "profile-change-net-restore", true);
obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
obsService->AddObserver(this, "net:clear-active-logins", true);
obsService->AddObserver(this, "net:prune-dead-connections", true); // Sent by the TorButton add-on in the Tor Browser
obsService->AddObserver(this, "net:prune-all-connections", true);
obsService->AddObserver(this, "net:cancel-all-connections", true);
obsService->AddObserver(this, "last-pb-context-exited", true);
obsService->AddObserver(this, "browser:purge-session-history", true);
obsService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
obsService->AddObserver(this, "application-background", true);
obsService->AddObserver(this, "psm:user-certificate-added", true);
obsService->AddObserver(this, "psm:user-certificate-deleted", true);
obsService->AddObserver(this, "intl:app-locales-changed", true);
obsService->AddObserver(this, "browser-delayed-startup-finished", true);
obsService->AddObserver(this, "network:reset-http3-excluded-list", true);
obsService->AddObserver(this, "network:socket-process-crashed", true);
obsService->AddObserver(this, "network:reset_third_party_roots_check", true);
if (!IsNeckoChild()) {
obsService->AddObserver(this, "net:current-browser-id", true);
}
// disabled as its a nop right now // obsService->AddObserver(this, "net:failed-to-process-uri-content", true);
}
MakeNewRequestTokenBucket();
mWifiTickler = new Tickler(); if (NS_FAILED(mWifiTickler->Init())) {
mWifiTickler = nullptr;
}
UpdateParentalControlsEnabled(false/* wait for completion */); return NS_OK;
}
void nsHttpHandler::UpdateParentalControlsEnabled(bool waitForCompletion) { // Child process does not have privileges to read parentals control state if (!XRE_IsParentProcess()) { return;
}
auto getParentalControlsTask = []() {
nsCOMPtr<nsIParentalControlsService> pc =
do_CreateInstance("@mozilla.org/parental-controls-service;1"); if (pc) { bool localEnabled = false;
pc->GetParentalControlsEnabled(&localEnabled);
sParentalControlsEnabled = localEnabled;
// Cache the state of parental controls via preference if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
Preferences::SetBool(
StaticPrefs::GetPrefName_network_parental_controls_cached_state(),
localEnabled);
}
}
};
if (waitForCompletion) {
getParentalControlsTask();
} else { // To avoid blocking on determining parental controls state, used the cached // pref until the runnable completes
sParentalControlsEnabled =
mozilla::StaticPrefs::network_parental_controls_cached_state();
Unused << NS_DispatchToMainThreadQueue(
NS_NewRunnableFunction("GetParentalControlsEnabled",
std::move(getParentalControlsTask)),
mozilla::EventQueuePriority::Idle);
}
}
// Add the "User-Agent" header
rv = request->SetHeader(nsHttp::User_Agent,
UserAgent(aShouldResistFingerprinting), false,
nsHttpHeaderArray::eVarietyRequestDefault); if (NS_FAILED(rv)) return rv;
// MIME based content negotiation lives! // Add the "Accept" header. Note, this is set as an override because the // service worker expects to see it. The other "default" headers are // hidden from service worker interception.
nsAutoCString accept; if (aContentPolicyType == ExtContentPolicy::TYPE_DOCUMENT ||
aContentPolicyType == ExtContentPolicy::TYPE_SUBDOCUMENT) {
accept.Assign(mDocumentAcceptHeader);
} elseif (aContentPolicyType == ExtContentPolicy::TYPE_IMAGE ||
aContentPolicyType == ExtContentPolicy::TYPE_IMAGESET) {
accept.Assign(mImageAcceptHeader);
} elseif (aContentPolicyType == ExtContentPolicy::TYPE_STYLESHEET) {
accept.Assign(ACCEPT_HEADER_STYLE);
} else {
accept.Assign(ACCEPT_HEADER_ALL);
}
rv = request->SetHeader(nsHttp::Accept, accept, false,
nsHttpHeaderArray::eVarietyRequestOverride); if (NS_FAILED(rv)) return rv;
// Add the "Accept-Language" header. This header is also exposed to the // service worker. if (mAcceptLanguagesIsDirty) {
rv = SetAcceptLanguages();
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
// Add the "Accept-Language" header if (!mAcceptLanguages.IsEmpty()) {
rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages, false,
nsHttpHeaderArray::eVarietyRequestOverride); if (NS_FAILED(rv)) return rv;
}
// Add the "Accept-Encoding" header if (isSecure) {
rv = request->SetHeader(nsHttp::Accept_Encoding, mHttpsAcceptEncodings, false, nsHttpHeaderArray::eVarietyRequestDefault);
} else {
rv = request->SetHeader(nsHttp::Accept_Encoding, mHttpAcceptEncodings, false, nsHttpHeaderArray::eVarietyRequestDefault);
} if (NS_FAILED(rv)) return rv;
// add the "Send Hint" header if (mSafeHintEnabled || sParentalControlsEnabled) {
rv = request->SetHeader(nsHttp::Prefer, "safe"_ns, false,
nsHttpHeaderArray::eVarietyRequestDefault); if (NS_FAILED(rv)) return rv;
} return NS_OK;
}
nsresult nsHttpHandler::AddConnectionHeader(nsHttpRequestHead* request,
uint32_t caps) { // RFC2616 section 19.6.2 states that the "Connection: keep-alive" // and "Keep-alive" request headers should not be sent by HTTP/1.1 // user-agents. But this is not a problem in practice, and the // alternative proxy-connection is worse. see 570283
constexpr auto close = "close"_ns;
constexpr auto keepAlive = "keep-alive"_ns;
bool nsHttpHandler::IsAcceptableEncoding(constchar* enc, bool isSecure) { if (!enc) returnfalse;
// we used to accept x-foo anytime foo was acceptable, but that's just // continuing bad behavior.. so limit it to known x-* patterns bool rv; if (isSecure) {
rv = nsHttp::FindToken(mHttpsAcceptEncodings.get(), enc, HTTP_LWS ",") !=
nullptr;
} else {
rv = nsHttp::FindToken(mHttpAcceptEncodings.get(), enc, HTTP_LWS ",") !=
nullptr;
} // gzip and deflate are inherently acceptable in modern HTTP - always // process them if a stream converter can also be found. if (!rv &&
(!nsCRT::strcasecmp(enc, "gzip") || !nsCRT::strcasecmp(enc, "deflate") ||
!nsCRT::strcasecmp(enc, "x-gzip") ||
!nsCRT::strcasecmp(enc, "x-deflate"))) {
rv = true;
}
LOG(("nsHttpHandler::IsAceptableEncoding %s https=%d %d\n", enc, isSecure,
rv)); return rv;
}
nsISiteSecurityService* nsHttpHandler::GetSSService() { if (!mSSService) {
nsCOMPtr<nsISiteSecurityService> service;
service = mozilla::components::SiteSecurity::Service();
mSSService = new nsMainThreadPtrHolder<nsISiteSecurityService>( "nsHttpHandler::mSSService", service);
} return mSSService;
}
nsICookieService* nsHttpHandler::GetCookieService() { if (!mCookieService) {
nsCOMPtr<nsICookieService> service =
do_GetService(NS_COOKIESERVICE_CONTRACTID);
mCookieService = new nsMainThreadPtrHolder<nsICookieService>( "nsHttpHandler::mCookieService", service);
} return mCookieService;
}
// TODO E10S This helper has to be initialized on the other process
RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper = new nsAsyncRedirectVerifyHelper();
#ifdef XP_WIN // Hardcode the reported Windows version to 10.0. This way, Microsoft doesn't // get to change Web compat-sensitive values without our veto. The compat- // sensitivity keeps going up as 10.0 stays as the current value for longer // and longer. If the system-reported version ever changes, we'll be able to // take our time to evaluate the Web compat impact instead of having to // scramble to react like happened with macOS changing from 10.x to 11.x. # define OSCPU_WINDOWS "Windows NT 10.0" # define OSCPU_WIN64 OSCPU_WINDOWS "; Win64; x64" #endif
void nsHttpHandler::InitUserAgentComponents() { // Don't build user agent components in socket process, since the system info // is not available. if (XRE_IsSocketProcess()) {
mUserAgentIsDirty = true; return;
}
// Gather platform.
mPlatform.AssignLiteral( #ifdefined(ANDROID) "Android" #elifdefined(XP_WIN) "Windows" #elifdefined(XP_MACOSX) "Macintosh" #elifdefined(XP_IOS) "iPhone" #elifdefined(XP_UNIX) // We historically have always had X11 here, // and there seems little a webpage can sensibly do // based on it being something else, so use X11 for // backwards compatibility in all cases. "X11" #endif
);
#ifdef XP_UNIX if (IsRunningUnderUbuntuSnap()) {
mPlatform.AppendLiteral("; Ubuntu");
} #endif
#ifdef ANDROID
nsCOMPtr<nsIPropertyBag2> infoService;
infoService = mozilla::components::SystemInfo::Service();
MOZ_ASSERT(infoService, "Could not find a system info service");
nsresult rv;
// Add the Android version number to the Fennec platform identifier.
nsAutoString androidVersion;
rv = infoService->GetPropertyAsAString(u"release_version"_ns, androidVersion);
MOZ_ASSERT_IF(
NS_SUCCEEDED(rv), // Like version "9"
(androidVersion.Length() == 1 && std::isdigit(androidVersion[0])) || // Or like version "8.1", "10", or "12.1"
(androidVersion.Length() >= 2 && std::isdigit(androidVersion[0]) &&
(androidVersion[1] == u'.' || std::isdigit(androidVersion[1]))));
// Spoof version "Android 10" for Android OS versions < 10 to reduce their // fingerprintable user information. For Android OS versions >= 10, report // the real OS version because some enterprise websites only want to permit // clients with recent OS version (like bug 1876742). Two leading digits // in the version string means the version number is >= 10.
mPlatform += " "; if (NS_SUCCEEDED(rv) && androidVersion.Length() >= 2 &&
std::isdigit(androidVersion[0]) && std::isdigit(androidVersion[1])) {
mPlatform += NS_LossyConvertUTF16toASCII(androidVersion);
} else {
mPlatform.AppendLiteral("10");
}
// Add the `Mobile` or `TV` token when running on device. bool isTV;
rv = infoService->GetPropertyAsBool(u"tv"_ns, &isTV); if (NS_SUCCEEDED(rv) && isTV) {
mCompatDevice.AssignLiteral("TV");
} else {
mCompatDevice.AssignLiteral("Mobile");
}
if (Preferences::GetBool(UA_PREF("use_device"), false)) {
mDeviceModelId = mozilla::net::GetDeviceModelId();
} #endif// ANDROID
#ifdefined(XP_IOS) // Freeze the iOS version to 18.0, use an underscore separator to avoid // detection as macOS.
mCompatDevice.AssignLiteral("CPU iPhone OS 18_0 like Mac OS X"); #endif
// Gather OS/CPU. #ifdefined(XP_WIN)
# ifdefined _M_X64 || defined _M_AMD64
mOscpu.AssignLiteral(OSCPU_WIN64); # elif defined(_ARM64_) // Report ARM64 Windows 11+ as x86_64 and Windows 10 as x86. Windows 11+ // supports x86_64 emulation, but Windows 10 only supports x86 emulation. if (IsWin11OrLater()) {
mOscpu.AssignLiteral(OSCPU_WIN64);
} else {
mOscpu.AssignLiteral(OSCPU_WINDOWS);
} # else BOOL isWow64 = FALSE; if (!IsWow64Process(GetCurrentProcess(), &isWow64)) {
isWow64 = FALSE;
} if (isWow64) {
mOscpu.AssignLiteral(OSCPU_WIN64);
} else {
mOscpu.AssignLiteral(OSCPU_WINDOWS);
} # endif
#elifdefined(XP_MACOSX)
mOscpu.AssignLiteral("Intel Mac OS X 10.15"); #elifdefined(ANDROID)
mOscpu.AssignLiteral("Linux armv81"); #elifdefined(XP_IOS)
mOscpu.AssignLiteral("iPhone"); #else
mOscpu.AssignLiteral("Linux x86_64"); #endif
mUserAgentIsDirty = true;
}
#ifdef XP_MACOSX void nsHttpHandler::InitMSAuthorities() { if (!StaticPrefs::network_http_microsoft_entra_sso_enabled()) { return;
}
nsAutoCString authorityList;
if (NS_FAILED(Preferences::GetCString("network.microsoft-sso-authority-list",
authorityList))) { return;
}
mMSAuthorities.Clear();
// Normalize the MS authority list
nsCCharSeparatedTokenizer tokenizer(authorityList, ','); while (tokenizer.hasMoreTokens()) { const nsDependentCSubstring& token = tokenizer.nextToken();
mMSAuthorities.Insert(token);
}
} #endif
uint32_t nsHttpHandler::MaxSocketCount() {
PR_CallOnce(&nsSocketTransportService::gMaxCountInitOnce,
nsSocketTransportService::DiscoverMaxCount); // Don't use the full max count because sockets can be held in // the persistent connection pool for a long time and that could // starve other users.
if (PREF_CHANGED(HTTP_PREF("proxy.version"))) {
nsAutoCString httpVersion;
Preferences::GetCString(HTTP_PREF("proxy.version"), httpVersion); if (!httpVersion.IsVoid()) { if (httpVersion.EqualsLiteral("1.1")) {
mProxyHttpVersion = HttpVersion::v1_1;
} else {
mProxyHttpVersion = HttpVersion::v1_0;
} // it does not make sense to issue a HTTP/0.9 request to a proxy server
}
}
if (PREF_CHANGED(HTTP_PREF("proxy.respect-be-conservative"))) {
rv =
Preferences::GetBool(HTTP_PREF("proxy.respect-be-conservative"), &cVar); if (NS_SUCCEEDED(rv)) {
mBeConservativeForProxy = cVar; if (mConnMgr) {
Unused << mConnMgr->UpdateParam(
nsHttpConnectionMgr::PROXY_BE_CONSERVATIVE, static_cast<int32_t>(mBeConservativeForProxy));
}
}
}
if (PREF_CHANGED(HTTP_PREF("qos"))) {
rv = Preferences::GetInt(HTTP_PREF("qos"), &val); if (NS_SUCCEEDED(rv)) mQoSBits = (uint8_t)std::clamp(val, 0, 0xff);
}
if (PREF_CHANGED(HTTP_PREF("accept-encoding"))) {
nsAutoCString acceptEncodings;
rv = Preferences::GetCString(HTTP_PREF("accept-encoding"), acceptEncodings); if (NS_SUCCEEDED(rv)) {
rv = SetAcceptEncodings(acceptEncodings.get(), false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
if (PREF_CHANGED(HTTP_PREF("accept-encoding.secure"))) {
nsAutoCString acceptEncodings;
rv = Preferences::GetCString(HTTP_PREF("accept-encoding.secure"),
acceptEncodings); if (NS_SUCCEEDED(rv)) {
rv = SetAcceptEncodings(acceptEncodings.get(), true);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
if (PREF_CHANGED(HTTP_PREF("default-socket-type"))) {
nsAutoCString sval;
rv = Preferences::GetCString(HTTP_PREF("default-socket-type"), sval); if (NS_SUCCEEDED(rv)) { if (sval.IsEmpty()) {
mDefaultSocketType.SetIsVoid(true);
} else { // verify that this socket type is actually valid
nsCOMPtr<nsISocketProviderService> sps =
nsSocketProviderService::GetOrCreate(); if (sps) {
nsCOMPtr<nsISocketProvider> sp;
rv = sps->GetSocketProvider(sval.get(), getter_AddRefs(sp)); if (NS_SUCCEEDED(rv)) { // OK, this looks like a valid socket provider.
mDefaultSocketType.Assign(sval);
}
}
}
}
}
if (PREF_CHANGED(HTTP_PREF("prompt-temp-redirect"))) {
rv = Preferences::GetBool(HTTP_PREF("prompt-temp-redirect"), &cVar); if (NS_SUCCEEDED(rv)) {
mPromptTempRedirect = cVar;
}
}
if (PREF_CHANGED(HTTP_PREF("assoc-req.enforce"))) {
cVar = false;
rv = Preferences::GetBool(HTTP_PREF("assoc-req.enforce"), &cVar); if (NS_SUCCEEDED(rv)) mEnforceAssocReq = cVar;
}
// enable Persistent caching for HTTPS - bug#205921 if (PREF_CHANGED(BROWSER_PREF("disk_cache_ssl"))) {
cVar = false;
rv = Preferences::GetBool(BROWSER_PREF("disk_cache_ssl"), &cVar); if (NS_SUCCEEDED(rv)) mEnablePersistentHttpsCaching = cVar;
}
if (PREF_CHANGED(HTTP_PREF("phishy-userpass-length"))) {
rv = Preferences::GetInt(HTTP_PREF("phishy-userpass-length"), &val); if (NS_SUCCEEDED(rv)) {
mPhishyUserPassLength = (uint8_t)std::clamp(val, 0, 0xff);
}
}
if (PREF_CHANGED(HTTP_PREF("http2.timeout"))) {
mSpdyTimeout = PR_SecondsToInterval(
std::clamp(StaticPrefs::network_http_http2_timeout(), 1, 0xffff));
}
if (PREF_CHANGED(HTTP_PREF("http2.chunk-size"))) { // keep this within http/2 ranges of 1 to 2^24-1
mSpdySendingChunkSize = (uint32_t)std::clamp(
StaticPrefs::network_http_http2_chunk_size(), 1, 0xffffff);
}
// The amount of idle seconds on a http2 connection before initiating a // server ping. 0 will disable. if (PREF_CHANGED(HTTP_PREF("http2.ping-threshold"))) {
mSpdyPingThreshold = PR_SecondsToInterval((uint16_t)std::clamp(
StaticPrefs::network_http_http2_ping_threshold(), 0, 0x7fffffff));
}
// The amount of seconds to wait for a http2 ping response before // closing the session. if (PREF_CHANGED(HTTP_PREF("http2.ping-timeout"))) {
mSpdyPingTimeout = PR_SecondsToInterval((uint16_t)std::clamp(
StaticPrefs::network_http_http2_ping_timeout(), 0, 0x7fffffff));
}
if (PREF_CHANGED(HTTP_PREF("altsvc.enabled"))) {
rv = Preferences::GetBool(HTTP_PREF("altsvc.enabled"), &cVar); if (NS_SUCCEEDED(rv)) mEnableAltSvc = cVar;
}
if (PREF_CHANGED(HTTP_PREF("altsvc.oe"))) {
rv = Preferences::GetBool(HTTP_PREF("altsvc.oe"), &cVar); if (NS_SUCCEEDED(rv)) mEnableAltSvcOE = cVar;
}
if (PREF_CHANGED(HTTP_PREF("http2.push-allowance"))) {
mSpdyPushAllowance = static_cast<uint32_t>(
std::clamp(StaticPrefs::network_http_http2_push_allowance(), 1024, static_cast<int32_t>(ASpdySession::kInitialRwin)));
}
if (PREF_CHANGED(HTTP_PREF("http2.pull-allowance"))) {
mSpdyPullAllowance = static_cast<uint32_t>(std::clamp(
StaticPrefs::network_http_http2_pull_allowance(), 1024, 0x7fffffff));
}
if (PREF_CHANGED(HTTP_PREF("http2.default-concurrent"))) {
mDefaultSpdyConcurrent = static_cast<uint32_t>(std::max<int32_t>(
std::min<int32_t>(StaticPrefs::network_http_http2_default_concurrent(),
9999),
1));
}
// If http2.send-buffer-size is non-zero, the size to set the TCP // sendbuffer to once the stream has surpassed this number of bytes uploaded if (PREF_CHANGED(HTTP_PREF("http2.send-buffer-size"))) {
mSpdySendBufferSize = (uint32_t)std::clamp(
StaticPrefs::network_http_http2_send_buffer_size(), 1500, 0x7fffffff);
}
// The maximum amount of time to wait for socket transport to be // established if (PREF_CHANGED(HTTP_PREF("connection-timeout"))) {
rv = Preferences::GetInt(HTTP_PREF("connection-timeout"), &val); if (NS_SUCCEEDED(rv)) { // the pref is in seconds, but the variable is in milliseconds
mConnectTimeout = std::clamp(val, 1, 0xffff) * PR_MSEC_PER_SEC;
}
}
// The maximum amount of time to wait for a tls handshake to finish. if (PREF_CHANGED(HTTP_PREF("tls-handshake-timeout"))) {
rv = Preferences::GetInt(HTTP_PREF("tls-handshake-timeout"), &val); if (NS_SUCCEEDED(rv)) { // the pref is in seconds, but the variable is in milliseconds
mTLSHandshakeTimeout = std::clamp(val, 1, 0xffff) * PR_MSEC_PER_SEC;
}
}
// The maximum number of current global half open sockets allowable // for starting a new speculative connection. if (PREF_CHANGED(HTTP_PREF("speculative-parallel-limit"))) {
rv = Preferences::GetInt(HTTP_PREF("speculative-parallel-limit"), &val); if (NS_SUCCEEDED(rv)) {
mParallelSpeculativeConnectLimit = (uint32_t)std::clamp(val, 0, 1024);
}
}
// Whether or not to block requests for non head js/css items (e.g. media) // while those elements load. if (PREF_CHANGED(HTTP_PREF("rendering-critical-requests-prioritization"))) {
rv = Preferences::GetBool(
HTTP_PREF("rendering-critical-requests-prioritization"), &cVar); if (NS_SUCCEEDED(rv)) mCriticalRequestPrioritization = cVar;
}
// on transition of network.http.diagnostics to true print // a bunch of information to the console if (pref && PREF_CHANGED(HTTP_PREF("diagnostics"))) {
rv = Preferences::GetBool(HTTP_PREF("diagnostics"), &cVar); if (NS_SUCCEEDED(rv) && cVar) { if (mConnMgr) mConnMgr->PrintDiagnostics();
}
}
if (PREF_CHANGED(HTTP_PREF("throttle.enable"))) {
rv = Preferences::GetBool(HTTP_PREF("throttle.enable"), &mThrottleEnabled); if (NS_SUCCEEDED(rv) && mConnMgr) {
Unused << mConnMgr->UpdateParam(nsHttpConnectionMgr::THROTTLING_ENABLED, static_cast<int32_t>(mThrottleEnabled));
}
}
if (PREF_CHANGED(HTTP_PREF("send_window_size"))) {
Unused << Preferences::GetInt(HTTP_PREF("send_window_size"), &val);
mSendWindowSize = val >= 0 ? val : 0;
}
if (PREF_CHANGED(HTTP_PREF("on_click_priority"))) {
Unused << Preferences::GetBool(HTTP_PREF("on_click_priority"),
&mUrgentStartEnabled);
}
if (PREF_CHANGED(HTTP_PREF("tailing.enabled"))) {
Unused << Preferences::GetBool(HTTP_PREF("tailing.enabled"),
&mTailBlockingEnabled);
} if (PREF_CHANGED(HTTP_PREF("tailing.delay-quantum"))) {
val = StaticPrefs::network_http_tailing_delay_quantum();
mTailDelayQuantum = (uint32_t)std::clamp(val, 0, 60000);
} if (PREF_CHANGED(HTTP_PREF("tailing.delay-quantum-after-domcontentloaded"))) {
val = StaticPrefs::
network_http_tailing_delay_quantum_after_domcontentloaded();
mTailDelayQuantumAfterDCL = (uint32_t)std::clamp(val, 0, 60000);
} if (PREF_CHANGED(HTTP_PREF("tailing.delay-max"))) {
val = StaticPrefs::network_http_tailing_delay_max();
mTailDelayMax = (uint32_t)std::clamp(val, 0, 60000);
} if (PREF_CHANGED(HTTP_PREF("tailing.total-max"))) {
val = StaticPrefs::network_http_tailing_total_max();
mTailTotalMax = (uint32_t)std::clamp(val, 0, 60000);
}
if (PREF_CHANGED(HTTP_PREF("focused_window_transaction_ratio"))) { float ratio = 0;
rv = Preferences::GetFloat(HTTP_PREF("focused_window_transaction_ratio"),
&ratio); if (NS_SUCCEEDED(rv)) { if (ratio > 0 && ratio < 1) {
mFocusedWindowTransactionRatio = ratio;
} else {
NS_WARNING("Wrong value for focused_window_transaction_ratio");
}
}
}
// // INTL options //
if (PREF_CHANGED(INTL_ACCEPT_LANGUAGES)) { // We don't want to set the new accept languages here since // this pref is a complex type and it may be racy with flushing // string resources.
mAcceptLanguagesIsDirty = true;
}
// // Tracking options //
// Hint option if (PREF_CHANGED(SAFE_HINT_HEADER_VALUE)) {
cVar = false;
rv = Preferences::GetBool(SAFE_HINT_HEADER_VALUE, &cVar); if (NS_SUCCEEDED(rv)) {
mSafeHintEnabled = cVar;
}
}
// toggle to true anytime a token bucket related pref is changed.. that // includes telemetry and allow-experiments because of the abtest profile bool requestTokenBucketUpdated = false;
// "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256" is the required h2 interop // suite.
if (PREF_CHANGED(H2MANDATORY_SUITE)) {
cVar = false;
rv = Preferences::GetBool(H2MANDATORY_SUITE, &cVar); if (NS_SUCCEEDED(rv)) {
mH2MandatorySuiteEnabled = cVar;
}
}
// network.http.debug-observations if (PREF_CHANGED("network.http.debug-observations")) {
cVar = false;
rv = Preferences::GetBool("network.http.debug-observations", &cVar); if (NS_SUCCEEDED(rv)) {
mDebugObservations = cVar;
}
}
if (PREF_CHANGED(HTTP_PREF("pacing.requests.enabled"))) {
rv = Preferences::GetBool(HTTP_PREF("pacing.requests.enabled"), &cVar); if (NS_SUCCEEDED(rv)) {
mRequestTokenBucketEnabled = cVar;
requestTokenBucketUpdated = true;
}
} if (PREF_CHANGED(HTTP_PREF("pacing.requests.min-parallelism"))) {
rv =
Preferences::GetInt(HTTP_PREF("pacing.requests.min-parallelism"), &val); if (NS_SUCCEEDED(rv)) {
mRequestTokenBucketMinParallelism = static_cast<uint16_t>(std::clamp(val, 1, 1024));
requestTokenBucketUpdated = true;
}
} if (PREF_CHANGED(HTTP_PREF("pacing.requests.hz"))) {
rv = Preferences::GetInt(HTTP_PREF("pacing.requests.hz"), &val); if (NS_SUCCEEDED(rv)) {
mRequestTokenBucketHz = static_cast<uint32_t>(std::clamp(val, 1, 10000));
requestTokenBucketUpdated = true;
}
} if (PREF_CHANGED(HTTP_PREF("pacing.requests.burst"))) {
rv = Preferences::GetInt(HTTP_PREF("pacing.requests.burst"), &val); if (NS_SUCCEEDED(rv)) {
mRequestTokenBucketBurst = val ? val : 1;
requestTokenBucketUpdated = true;
}
} if (requestTokenBucketUpdated) {
MakeNewRequestTokenBucket();
}
// Keepalive values for initial and idle connections. if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_connections"))) {
rv = Preferences::GetBool(
HTTP_PREF("tcp_keepalive.short_lived_connections"), &cVar); if (NS_SUCCEEDED(rv) && cVar != mTCPKeepaliveShortLivedEnabled) {
mTCPKeepaliveShortLivedEnabled = cVar;
}
}
if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_time"))) {
rv = Preferences::GetInt(HTTP_PREF("tcp_keepalive.short_lived_time"), &val); if (NS_SUCCEEDED(rv) && val > 0) {
mTCPKeepaliveShortLivedTimeS = std::clamp(val, 1, 300); // Max 5 mins.
}
}
if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_idle_time"))) {
rv = Preferences::GetInt(HTTP_PREF("tcp_keepalive.short_lived_idle_time"),
&val); if (NS_SUCCEEDED(rv) && val > 0) {
mTCPKeepaliveShortLivedIdleTimeS = std::clamp(val, 1, kMaxTCPKeepIdle);
}
}
// Keepalive values for Long-lived Connections. if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.long_lived_connections"))) {
rv = Preferences::GetBool(HTTP_PREF("tcp_keepalive.long_lived_connections"),
&cVar); if (NS_SUCCEEDED(rv) && cVar != mTCPKeepaliveLongLivedEnabled) {
mTCPKeepaliveLongLivedEnabled = cVar;
}
}
if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.long_lived_idle_time"))) {
rv = Preferences::GetInt(HTTP_PREF("tcp_keepalive.long_lived_idle_time"),
&val); if (NS_SUCCEEDED(rv) && val > 0) {
mTCPKeepaliveLongLivedIdleTimeS = std::clamp(val, 1, kMaxTCPKeepIdle);
}
}
if (imageAcceptPrefChanged) {
nsAutoCString userSetImageAcceptHeader;
if (Preferences::HasUserValue("image.http.accept")) {
rv = Preferences::GetCString("image.http.accept",
userSetImageAcceptHeader); if (NS_FAILED(rv)) {
userSetImageAcceptHeader.Truncate();
}
}
if (userSetImageAcceptHeader.IsEmpty()) {
mImageAcceptHeader.Assign(ImageAcceptHeader());
} else {
mImageAcceptHeader.Assign(userSetImageAcceptHeader);
}
}
if (PREF_CHANGED("network.http.accept") || imageAcceptPrefChanged) {
nsAutoCString userSetDocumentAcceptHeader;
if (Preferences::HasUserValue("network.http.accept")) {
rv = Preferences::GetCString("network.http.accept",
userSetDocumentAcceptHeader); if (NS_FAILED(rv)) {
userSetDocumentAcceptHeader.Truncate();
}
}
if (userSetDocumentAcceptHeader.IsEmpty()) {
mDocumentAcceptHeader.Assign(DocumentAcceptHeader());
} else {
mDocumentAcceptHeader.Assign(userSetDocumentAcceptHeader);
}
}
if (PREF_CHANGED(HTTP_PREF("http3.alt-svc-mapping-for-testing"))) {
nsAutoCString altSvcMappings;
rv = Preferences::GetCString(HTTP_PREF("http3.alt-svc-mapping-for-testing"),
altSvcMappings); if (NS_SUCCEEDED(rv)) { for (const nsACString& tokenSubstring :
nsCCharSeparatedTokenizer(altSvcMappings, ',').ToRange()) {
nsAutoCString token{tokenSubstring};
int32_t index = token.Find(";"); if (index != kNotFound) {
mAltSvcMappingTemptativeMap.InsertOrUpdate(
Substring(token, 0, index),
MakeUnique<nsCString>(Substring(token, index + 1)));
}
}
}
}
if (PREF_CHANGED(HTTP_PREF("http3.enable_qlog"))) { // Initialize the directory.
nsCOMPtr<nsIFile> qlogDir; if (Preferences::GetBool(HTTP_PREF("http3.enable_qlog")) &&
!mHttp3QlogDir.IsEmpty() &&
NS_SUCCEEDED(
NS_NewNativeLocalFile(mHttp3QlogDir, getter_AddRefs(qlogDir)))) { // Here we do main thread IO, but since this only happens // when enabling a developer feature it's not a problem for users.
rv = qlogDir->Create(nsIFile::DIRECTORY_TYPE, 0755); if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
NS_WARNING("Creating qlog dir failed");
}
}
}
#ifdef XP_MACOSX if (XRE_IsParentProcess()) { if (PREF_CHANGED(HTTP_PREF("microsoft-entra-sso.enabled"))) {
rv =
Preferences::GetBool(HTTP_PREF("microsoft-entra-sso.enabled"), &cVar); if (NS_SUCCEEDED(rv) && cVar) {
--> --------------------
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.