From 64689429812ed1f772589aa5abc211795493a54c Mon Sep 17 00:00:00 2001 From: Bar Arnon Date: Wed, 4 Aug 2021 15:32:58 +0300 Subject: [PATCH] Add SslApplicationProtocol.Http3 (#56775) * Add SslApplicationProtocol.Http3 Fix #1293 * Add XML doc * Reuse in Http3Connection * Reuse in tests * HTTP/3 has no negotiation * Use SslApplicationProtocol.Http3.ToString() in tests * Ascending order in ref --- .../Common/tests/System/Net/Http/Http3LoopbackServer.cs | 2 +- .../System/Net/Http/SocketsHttpHandler/Http3Connection.cs | 3 --- .../Net/Http/SocketsHttpHandler/HttpConnectionPool.cs | 13 +------------ .../tests/FunctionalTests/HttpClientHandlerTest.Http3.cs | 4 ++-- .../tests/StressTests/HttpStress/StressServer.cs | 2 +- .../System.Net.Security/ref/System.Net.Security.cs | 1 + .../src/System/Net/Security/SslApplicationProtocol.cs | 8 ++++++-- .../tests/UnitTests/SslApplicationProtocolTests.cs | 2 ++ .../tests/UnitTests/SslAuthenticationOptionsTests.cs | 2 +- 9 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs index ffd97b9..3ba40c4 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 @@ namespace System.Net.Test.Common { 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 279c769..dca12ee 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 8f14d1f..3389946 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 @@ namespace System.Net.Http [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 df5b59b..42c42d4 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 @@ namespace System.Net.Http.Functional.Tests 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 @@ namespace System.Net.Http.Functional.Tests 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 e994e7e..c4c05ee 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 @@ namespace HttpStress { 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 d314161..ded8bc9 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 @@ namespace System.Net.Security 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 ebac2d8..f218ce2 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 @@ namespace System.Net.Security { 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 34a11a0..fe016e6 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 @@ namespace System.Net.Security.Tests [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 @@ namespace System.Net.Security.Tests { 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 91d40fc..354acab 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 @@ namespace System.Net.Security.Tests 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; -- 2.7.4