diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs index ffd97b9219c2b..3ba40c4655439 100644 --- a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs @@ -130,7 +130,7 @@ public Http3Options() { MaxUnidirectionalStreams = 100; MaxBidirectionalStreams = 100; - Alpn = "h3"; + Alpn = SslApplicationProtocol.Http3.ToString(); } } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs index 279c769f714a2..dca12ee814794 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs @@ -20,9 +20,6 @@ namespace System.Net.Http [SupportedOSPlatform("macos")] internal sealed class Http3Connection : HttpConnectionBase { - // TODO: once HTTP/3 is standardized, create APIs for this. - public static readonly SslApplicationProtocol Http3ApplicationProtocol = new SslApplicationProtocol("h3"); - private readonly HttpConnectionPool _pool; private readonly HttpAuthority? _origin; private readonly HttpAuthority _authority; 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 8f14d1fe66d45..3389946c710e4 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 @@ -295,21 +295,10 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK [SupportedOSPlatformGuard("Windows")] internal static bool IsHttp3Supported() => (OperatingSystem.IsLinux() && !OperatingSystem.IsAndroid()) || OperatingSystem.IsWindows() || OperatingSystem.IsMacOS(); - private static readonly List s_http3ApplicationProtocols = CreateHttp3ApplicationProtocols(); + private static readonly List s_http3ApplicationProtocols = new List() { SslApplicationProtocol.Http3 }; private static readonly List s_http2ApplicationProtocols = new List() { SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 }; private static readonly List s_http2OnlyApplicationProtocols = new List() { SslApplicationProtocol.Http2 }; - private static List CreateHttp3ApplicationProtocols() - { - if (IsHttp3Supported()) - { - // TODO: Once the HTTP/3 versions are part of SslApplicationProtocol, see https://github.com/dotnet/runtime/issues/1293, move this back to field initialization. - return new List() { Http3Connection.Http3ApplicationProtocol }; - } - - return null!; - } - private static SslClientAuthenticationOptions ConstructSslOptions(HttpConnectionPoolManager poolManager, string sslHostName) { Debug.Assert(sslHostName != null); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs index df5b59b500eb3..42c42d43f39bd 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs @@ -639,7 +639,7 @@ public async Task Alpn_H3_Success() return; } - var options = new Http3Options() { Alpn = "h3" }; + var options = new Http3Options() { Alpn = SslApplicationProtocol.Http3.ToString() }; using Http3LoopbackServer server = CreateHttp3LoopbackServer(options); using var clientDone = new SemaphoreSlim(0); @@ -650,7 +650,7 @@ public async Task Alpn_H3_Success() using Http3LoopbackConnection connection = (Http3LoopbackConnection)await server.EstablishGenericConnectionAsync(); SslApplicationProtocol negotiatedAlpn = ExtractMsQuicNegotiatedAlpn(connection); - Assert.Equal(new SslApplicationProtocol("h3"), negotiatedAlpn); + Assert.Equal(SslApplicationProtocol.Http3, negotiatedAlpn); using Http3LoopbackStream stream = await connection.AcceptRequestStreamAsync(); await stream.HandleRequestAsync(); diff --git a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressServer.cs b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressServer.cs index e994e7ed15cb2..c4c05ee6fb1f0 100644 --- a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressServer.cs +++ b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressServer.cs @@ -127,7 +127,7 @@ void ConfigureListenOptions(ListenOptions listenOptions) { host = host.UseQuic(options => { - options.Alpn = "h3"; + options.Alpn = SslApplicationProtocol.Http3.ToString(); options.IdleTimeout = TimeSpan.FromMinutes(1); }); } diff --git a/src/libraries/System.Net.Security/ref/System.Net.Security.cs b/src/libraries/System.Net.Security/ref/System.Net.Security.cs index d31416123ca8e..ded8bc9ffa09f 100644 --- a/src/libraries/System.Net.Security/ref/System.Net.Security.cs +++ b/src/libraries/System.Net.Security/ref/System.Net.Security.cs @@ -120,6 +120,7 @@ public readonly struct SslClientHelloInfo private readonly int _dummyPrimitive; public static readonly System.Net.Security.SslApplicationProtocol Http11; public static readonly System.Net.Security.SslApplicationProtocol Http2; + public static readonly System.Net.Security.SslApplicationProtocol Http3; public SslApplicationProtocol(byte[] protocol) { throw null; } public SslApplicationProtocol(string protocol) { throw null; } public System.ReadOnlyMemory Protocol { get { throw null; } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslApplicationProtocol.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslApplicationProtocol.cs index ebac2d844fab5..f218ce2875128 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslApplicationProtocol.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslApplicationProtocol.cs @@ -10,13 +10,16 @@ namespace System.Net.Security public readonly struct SslApplicationProtocol : IEquatable { private static readonly Encoding s_utf8 = Encoding.GetEncoding(Encoding.UTF8.CodePage, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback); + private static readonly byte[] s_http3Utf8 = new byte[] { 0x68, 0x33 }; // "h3" private static readonly byte[] s_http2Utf8 = new byte[] { 0x68, 0x32 }; // "h2" private static readonly byte[] s_http11Utf8 = new byte[] { 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31 }; // "http/1.1" // Refer to IANA on ApplicationProtocols: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids - // h2 + /// Defines a instance for HTTP 3.0. + public static readonly SslApplicationProtocol Http3 = new SslApplicationProtocol(s_http3Utf8, copy: false); + /// Defines a instance for HTTP 2.0. public static readonly SslApplicationProtocol Http2 = new SslApplicationProtocol(s_http2Utf8, copy: false); - // http/1.1 + /// Defines a instance for HTTP 1.1. public static readonly SslApplicationProtocol Http11 = new SslApplicationProtocol(s_http11Utf8, copy: false); private readonly byte[] _readOnlyProtocol; @@ -77,6 +80,7 @@ public override string ToString() { return arr is null ? string.Empty : + ReferenceEquals(arr, s_http3Utf8) ? "h3" : ReferenceEquals(arr, s_http2Utf8) ? "h2" : ReferenceEquals(arr, s_http11Utf8) ? "http/1.1" : s_utf8.GetString(arr); diff --git a/src/libraries/System.Net.Security/tests/UnitTests/SslApplicationProtocolTests.cs b/src/libraries/System.Net.Security/tests/UnitTests/SslApplicationProtocolTests.cs index 34a11a05d94ea..fe016e6c631ef 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/SslApplicationProtocolTests.cs +++ b/src/libraries/System.Net.Security/tests/UnitTests/SslApplicationProtocolTests.cs @@ -13,6 +13,7 @@ public class SslApplicationProtocolTests [Fact] public void Constants_Values_AreCorrect() { + Assert.Equal(new SslApplicationProtocol(new byte[] { 0x68, 0x33 }), SslApplicationProtocol.Http3); Assert.Equal(new SslApplicationProtocol(new byte[] { 0x68, 0x32 }), SslApplicationProtocol.Http2); Assert.Equal(new SslApplicationProtocol(new byte[] { 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31 }), SslApplicationProtocol.Http11); } @@ -75,6 +76,7 @@ public void ToString_Rendering_Succeeds() { Assert.Equal("http/1.1", SslApplicationProtocol.Http11.ToString()); Assert.Equal("h2", SslApplicationProtocol.Http2.ToString()); + Assert.Equal("h3", SslApplicationProtocol.Http3.ToString()); Assert.Equal("hello", new SslApplicationProtocol("hello").ToString()); Assert.Equal("0x0b 0xee", new SslApplicationProtocol(new byte[] { 0x0B, 0xEE }).ToString()); Assert.Equal(string.Empty, default(SslApplicationProtocol).ToString()); diff --git a/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.cs b/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.cs index 91d40fc744837..354acab9021bd 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.cs +++ b/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.cs @@ -41,7 +41,7 @@ public void ApplicationProtocols_Get_Set_Succeeds() Assert.Null(_clientOptions.ApplicationProtocols); Assert.Null(_serverOptions.ApplicationProtocols); - List applnProtos = new List { SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 }; + List applnProtos = new List { SslApplicationProtocol.Http3, SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 }; _clientOptions.ApplicationProtocols = applnProtos; _serverOptions.ApplicationProtocols = applnProtos;