Skip to content

Commit ecdfb14

Browse files
Allow trimming out HTTP3 support (#117012)
Fixes #77420. This is a meaningful saving to leave on the table. For following app: ```csharp Console.WriteLine(new HttpClient().GetStringAsync("https://bing.com").Result); ``` PublishAot without this switch: 4.91 MB PublishAot with this switch: 4.14 MB We might even go as far as disabling HTTP3 on native AOT by default since #73290 reached the dreaded Future milestone.
1 parent b509ab1 commit ecdfb14

File tree

6 files changed

+60
-22
lines changed

6 files changed

+60
-22
lines changed

src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Diagnostics.CodeAnalysis;
6+
using System.Runtime.Versioning;
67

78
namespace System.Net.Http
89
{
@@ -38,12 +39,16 @@ internal static class SocketsHttpHandler
3839
"DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_HTTP2SUPPORT",
3940
true);
4041

41-
// Default to allowing HTTP/3, but enable that to be overridden by an
42+
// Default to allowing HTTP/3 on platforms where we have QUIC, but enable that to be overridden by an
4243
// AppContext switch, or by an environment variable being set to false/0.
44+
[SupportedOSPlatformGuard("linux")]
45+
[SupportedOSPlatformGuard("macOS")]
46+
[SupportedOSPlatformGuard("windows")]
47+
[FeatureSwitchDefinition("System.Net.SocketsHttpHandler.Http3Support")]
4348
public static bool AllowHttp3 { get; } = RuntimeSettingParser.QueryRuntimeSettingSwitch(
4449
"System.Net.SocketsHttpHandler.Http3Support",
4550
"DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_HTTP3SUPPORT",
46-
true);
51+
(OperatingSystem.IsLinux() && !OperatingSystem.IsAndroid()) || OperatingSystem.IsWindows() || OperatingSystem.IsMacOS());
4752

4853
// Switch to disable the HTTP/2 dynamic window scaling algorithm. Enabled by default.
4954
public static bool DisableDynamicHttp2WindowSizing { get; } = RuntimeSettingParser.QueryRuntimeSettingSwitch(

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ internal sealed partial class HttpConnectionPool
2525
/// <summary>The time, in milliseconds, that an authority should remain in <see cref="_altSvcBlocklist"/>.</summary>
2626
private const int AltSvcBlocklistTimeoutInMilliseconds = 10 * 60 * 1000;
2727

28-
[SupportedOSPlatformGuard("linux")]
29-
[SupportedOSPlatformGuard("macOS")]
30-
[SupportedOSPlatformGuard("windows")]
31-
internal static bool IsHttp3Supported() => (OperatingSystem.IsLinux() && !OperatingSystem.IsAndroid()) || OperatingSystem.IsWindows() || OperatingSystem.IsMacOS();
32-
3328
/// <summary>List of available HTTP/3 connections stored in the pool.</summary>
3429
private List<Http3Connection>? _availableHttp3Connections;
3530
/// <summary>The number of HTTP/3 connections associated with the pool, including in use, available, and pending.</summary>
@@ -67,7 +62,7 @@ internal sealed partial class HttpConnectionPool
6762
[SupportedOSPlatform("macos")]
6863
private async ValueTask<HttpResponseMessage?> TrySendUsingHttp3Async(HttpRequestMessage request, CancellationToken cancellationToken)
6964
{
70-
Debug.Assert(IsHttp3Supported());
65+
Debug.Assert(GlobalHttpSettings.SocketsHttpHandler.AllowHttp3);
7166

7267
Debug.Assert(_kind == HttpConnectionKind.Https);
7368
Debug.Assert(_http3Enabled);
@@ -135,7 +130,7 @@ internal sealed partial class HttpConnectionPool
135130
[SupportedOSPlatform("macos")]
136131
private bool TryGetPooledHttp3Connection(HttpRequestMessage request, [NotNullWhen(true)] out Http3Connection? connection, [NotNullWhen(false)] out HttpConnectionWaiter<Http3Connection?>? waiter, out bool streamAvailable)
137132
{
138-
Debug.Assert(IsHttp3Supported());
133+
Debug.Assert(GlobalHttpSettings.SocketsHttpHandler.AllowHttp3);
139134

140135
// Look for a usable connection.
141136
while (true)
@@ -210,7 +205,7 @@ private bool TryGetPooledHttp3Connection(HttpRequestMessage request, [NotNullWhe
210205
[SupportedOSPlatform("macos")]
211206
private void CheckForHttp3ConnectionInjection()
212207
{
213-
Debug.Assert(IsHttp3Supported());
208+
Debug.Assert(GlobalHttpSettings.SocketsHttpHandler.AllowHttp3);
214209

215210
Debug.Assert(HasSyncObjLock);
216211

@@ -249,7 +244,7 @@ private void CheckForHttp3ConnectionInjection()
249244
[SupportedOSPlatform("macos")]
250245
private async Task InjectNewHttp3ConnectionAsync(RequestQueue<Http3Connection?>.QueueItem queueItem)
251246
{
252-
Debug.Assert(IsHttp3Supported());
247+
Debug.Assert(GlobalHttpSettings.SocketsHttpHandler.AllowHttp3);
253248

254249
if (NetEventSource.Log.IsEnabled()) Trace("Creating new HTTP/3 connection for pool.");
255250

@@ -332,7 +327,7 @@ private async Task InjectNewHttp3ConnectionAsync(RequestQueue<Http3Connection?>.
332327
[SupportedOSPlatform("macos")]
333328
private void HandleHttp3ConnectionFailure(HttpConnectionWaiter<Http3Connection?> requestWaiter, Exception? e)
334329
{
335-
Debug.Assert(IsHttp3Supported());
330+
Debug.Assert(GlobalHttpSettings.SocketsHttpHandler.AllowHttp3);
336331

337332
if (NetEventSource.Log.IsEnabled()) Trace($"HTTP3 connection failed: {e}");
338333

@@ -363,7 +358,7 @@ private void HandleHttp3ConnectionFailure(HttpConnectionWaiter<Http3Connection?>
363358
[SupportedOSPlatform("macos")]
364359
private void ReturnHttp3Connection(Http3Connection connection, bool isNewConnection, HttpConnectionWaiter<Http3Connection?>? initialRequestWaiter = null)
365360
{
366-
Debug.Assert(IsHttp3Supported());
361+
Debug.Assert(GlobalHttpSettings.SocketsHttpHandler.AllowHttp3);
367362

368363
if (NetEventSource.Log.IsEnabled()) connection.Trace($"{nameof(isNewConnection)}={isNewConnection}");
369364

@@ -485,7 +480,7 @@ private void ReturnHttp3Connection(Http3Connection connection, bool isNewConnect
485480
[SupportedOSPlatform("macos")]
486481
private void DisableHttp3Connection(Http3Connection connection)
487482
{
488-
Debug.Assert(IsHttp3Supported());
483+
Debug.Assert(GlobalHttpSettings.SocketsHttpHandler.AllowHttp3);
489484

490485
if (NetEventSource.Log.IsEnabled()) connection.Trace("");
491486

@@ -528,7 +523,7 @@ async Task DisableHttp3ConnectionAsync(Http3Connection connection)
528523
[SupportedOSPlatform("macos")]
529524
public void InvalidateHttp3Connection(Http3Connection connection, bool dispose = true)
530525
{
531-
Debug.Assert(IsHttp3Supported());
526+
Debug.Assert(GlobalHttpSettings.SocketsHttpHandler.AllowHttp3);
532527

533528
if (NetEventSource.Log.IsEnabled()) connection.Trace("");
534529

@@ -564,7 +559,7 @@ public void InvalidateHttp3Connection(Http3Connection connection, bool dispose =
564559
[SupportedOSPlatform("macos")]
565560
private static int ScavengeHttp3ConnectionList(List<Http3Connection> list, ref List<HttpConnectionBase>? toDispose, long nowTicks, TimeSpan pooledConnectionLifetime, TimeSpan pooledConnectionIdleTimeout)
566561
{
567-
Debug.Assert(IsHttp3Supported());
562+
Debug.Assert(GlobalHttpSettings.SocketsHttpHandler.AllowHttp3);
568563

569564
int freeIndex = 0;
570565
while (freeIndex < list.Count && list[freeIndex].IsUsable(nowTicks, pooledConnectionLifetime, pooledConnectionIdleTimeout))

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
8585

8686
_http2Enabled = _poolManager.Settings._maxHttpVersion >= HttpVersion.Version20;
8787

88-
if (IsHttp3Supported())
88+
if (GlobalHttpSettings.SocketsHttpHandler.AllowHttp3)
8989
{
9090
_http3Enabled = _poolManager.Settings._maxHttpVersion >= HttpVersion.Version30;
9191
}
@@ -227,7 +227,7 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
227227
_http2EncodedAuthorityHostHeader = HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingToAllocatedArray(H2StaticTable.Authority, hostHeader);
228228
}
229229

230-
if (IsHttp3Supported() && _http3Enabled)
230+
if (GlobalHttpSettings.SocketsHttpHandler.AllowHttp3 && _http3Enabled)
231231
{
232232
_http3EncodedAuthorityHostHeader = QPackEncoder.EncodeLiteralHeaderFieldWithStaticNameReferenceToArray(H3StaticTable.Authority, hostHeader);
233233
}
@@ -244,7 +244,7 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
244244
{
245245
_http2RequestQueue = new RequestQueue<Http2Connection?>();
246246
}
247-
if (IsHttp3Supported() && _http3Enabled)
247+
if (GlobalHttpSettings.SocketsHttpHandler.AllowHttp3 && _http3Enabled)
248248
{
249249
_http3RequestQueue = new RequestQueue<Http3Connection?>();
250250
}
@@ -400,7 +400,7 @@ public async ValueTask<HttpResponseMessage> SendWithVersionDetectionAndRetryAsyn
400400
HttpResponseMessage? response = null;
401401

402402
// Use HTTP/3 if possible.
403-
if (IsHttp3Supported() && // guard to enable trimming HTTP/3 support
403+
if (GlobalHttpSettings.SocketsHttpHandler.AllowHttp3 && // guard to enable trimming HTTP/3 support
404404
_http3Enabled &&
405405
(request.Version.Major >= 3 || (request.VersionPolicy == HttpVersionPolicy.RequestVersionOrHigher && IsSecure)) &&
406406
!request.IsExtendedConnectRequest)
@@ -913,7 +913,7 @@ public void Dispose()
913913
_availableHttp2Connections.Clear();
914914
}
915915

916-
if (IsHttp3Supported() && _availableHttp3Connections is not null)
916+
if (GlobalHttpSettings.SocketsHttpHandler.AllowHttp3 && _availableHttp3Connections is not null)
917917
{
918918
toDispose ??= new();
919919
toDispose.AddRange(_availableHttp3Connections);
@@ -989,7 +989,7 @@ public bool CleanCacheAndDisposeIfUnused()
989989
// Note: Http11 connections will decrement the _associatedHttp11ConnectionCount when disposed.
990990
// Http2 connections will not, hence the difference in handing _associatedHttp2ConnectionCount.
991991
}
992-
if (IsHttp3Supported() && _availableHttp3Connections is not null)
992+
if (GlobalHttpSettings.SocketsHttpHandler.AllowHttp3 && _availableHttp3Connections is not null)
993993
{
994994
int removed = ScavengeHttp3ConnectionList(_availableHttp3Connections, ref toDispose, nowTicks, pooledConnectionLifetime, pooledConnectionIdleTimeout);
995995
_associatedHttp3ConnectionCount -= removed;

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RuntimeSettingParser.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public static bool QueryRuntimeSettingSwitch(string appCtxSettingName, string en
1515
bool value;
1616

1717
// First check for the AppContext switch, giving it priority over the environment variable.
18+
// This being first is important for correctness of all callers marked [FeatureSwitchDefinition].
1819
if (AppContext.TryGetSwitch(appCtxSettingName, out value))
1920
{
2021
return value;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.IO;
6+
using System.Reflection;
7+
using System.Net;
8+
using System.Net.Http;
9+
10+
try
11+
{
12+
_ = new HttpClient().GetStringAsync("https://bing.com").Result;
13+
}
14+
catch { }
15+
16+
try
17+
{
18+
var a = Assembly.Load("System.Net.Quic");
19+
bool hasTypes = false;
20+
foreach (var t in a.GetTypes())
21+
{
22+
Console.WriteLine(t);
23+
hasTypes = true;
24+
}
25+
26+
if (!hasTypes)
27+
return 100;
28+
}
29+
catch (FileNotFoundException)
30+
{
31+
return 100;
32+
}
33+
34+
return -1;

src/libraries/System.Net.Http/tests/TrimmingTests/System.Net.Http.TrimmingTests.proj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
<TestConsoleAppSourceFiles Include="DiagnosticsHandlerTrimmedTest.cs">
1010
<DisabledFeatureSwitches>System.Net.Http.EnableActivityPropagation</DisabledFeatureSwitches>
1111
</TestConsoleAppSourceFiles>
12+
<TestConsoleAppSourceFiles Include="QuicTrimmedTest.cs">
13+
<DisabledFeatureSwitches>System.Net.SocketsHttpHandler.Http3Support</DisabledFeatureSwitches>
14+
</TestConsoleAppSourceFiles>
1215
</ItemGroup>
1316

1417
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.targets))" />

0 commit comments

Comments
 (0)