diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs index df08584b607616..40f865ea9b8605 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs @@ -93,7 +93,7 @@ internal sealed class HttpConnectionPool : IDisposable private bool _http2Enabled; private byte[]? _http2AltSvcOriginUri; internal readonly byte[]? _http2EncodedAuthorityHostHeader; - private readonly bool _http3Enabled; + private bool _http3Enabled; private Http3Connection? _http3Connection; private SemaphoreSlim? _http3ConnectionCreateLock; internal readonly byte[]? _http3EncodedAuthorityHostHeader; @@ -113,7 +113,7 @@ internal sealed class HttpConnectionPool : IDisposable private readonly SslClientAuthenticationOptions? _sslOptionsHttp11; private readonly SslClientAuthenticationOptions? _sslOptionsHttp2; private readonly SslClientAuthenticationOptions? _sslOptionsHttp2Only; - private readonly SslClientAuthenticationOptions? _sslOptionsHttp3; + private SslClientAuthenticationOptions? _sslOptionsHttp3; /// Whether the pool has been used since the last time a cleanup occurred. private bool _usedSinceLastCleanup = true; @@ -146,7 +146,7 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK if (IsHttp3Supported()) { - _http3Enabled = _poolManager.Settings._maxHttpVersion >= HttpVersion.Version30 && QuicConnection.IsSupported; + _http3Enabled = _poolManager.Settings._maxHttpVersion >= HttpVersion.Version30; } switch (kind) @@ -288,15 +288,6 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK _http2EncodedAuthorityHostHeader = HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingToAllocatedArray(H2StaticTable.Authority, hostHeader); _http3EncodedAuthorityHostHeader = QPackEncoder.EncodeLiteralHeaderFieldWithStaticNameReferenceToArray(H3StaticTable.Authority, hostHeader); } - - if (IsHttp3Supported()) - { - if (_http3Enabled) - { - _sslOptionsHttp3 = ConstructSslOptions(poolManager, sslHostName); - _sslOptionsHttp3.ApplicationProtocols = s_http3ApplicationProtocols; - } - } } // Set up for PreAuthenticate. Access to this cache is guarded by a lock on the cache itself. @@ -1047,7 +1038,23 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn !request.IsExtendedConnectRequest) { Debug.Assert(async); - response = await TrySendUsingHttp3Async(request, cancellationToken).ConfigureAwait(false); + if (QuicConnection.IsSupported) + { + if (_sslOptionsHttp3 == null) + { + // deferred creation. We use atomic exchange to be sure all threads point to single object to mimic ctor behavior. + SslClientAuthenticationOptions sslOptionsHttp3 = ConstructSslOptions(_poolManager, _sslOptionsHttp11!.TargetHost!); + sslOptionsHttp3.ApplicationProtocols = s_http3ApplicationProtocols; + Interlocked.CompareExchange(ref _sslOptionsHttp3, sslOptionsHttp3, null); + } + + response = await TrySendUsingHttp3Async(request, cancellationToken).ConfigureAwait(false); + } + else + { + _altSvcEnabled = false; + _http3Enabled = false; + } } if (response is null)