Add SslApplicationProtocol.Http3 (#56775)
authorBar Arnon <i3arnon@gmail.com>
Wed, 4 Aug 2021 12:32:58 +0000 (15:32 +0300)
committerGitHub <noreply@github.com>
Wed, 4 Aug 2021 12:32:58 +0000 (14:32 +0200)
* 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

src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs
src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressServer.cs
src/libraries/System.Net.Security/ref/System.Net.Security.cs
src/libraries/System.Net.Security/src/System/Net/Security/SslApplicationProtocol.cs
src/libraries/System.Net.Security/tests/UnitTests/SslApplicationProtocolTests.cs
src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.cs

index ffd97b9..3ba40c4 100644 (file)
@@ -130,7 +130,7 @@ namespace System.Net.Test.Common
         {
             MaxUnidirectionalStreams = 100;
             MaxBidirectionalStreams = 100;
-            Alpn = "h3";
+            Alpn = SslApplicationProtocol.Http3.ToString();
         }
     }
 }
index 279c769..dca12ee 100644 (file)
@@ -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;
index 8f14d1f..3389946 100644 (file)
@@ -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<SslApplicationProtocol> s_http3ApplicationProtocols = CreateHttp3ApplicationProtocols();
+        private static readonly List<SslApplicationProtocol> s_http3ApplicationProtocols = new List<SslApplicationProtocol>() { SslApplicationProtocol.Http3 };
         private static readonly List<SslApplicationProtocol> s_http2ApplicationProtocols = new List<SslApplicationProtocol>() { SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 };
         private static readonly List<SslApplicationProtocol> s_http2OnlyApplicationProtocols = new List<SslApplicationProtocol>() { SslApplicationProtocol.Http2 };
 
-        private static List<SslApplicationProtocol> 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<SslApplicationProtocol>() { Http3Connection.Http3ApplicationProtocol };
-            }
-
-            return null!;
-        }
-
         private static SslClientAuthenticationOptions ConstructSslOptions(HttpConnectionPoolManager poolManager, string sslHostName)
         {
             Debug.Assert(sslHostName != null);
index df5b59b..42c42d4 100644 (file)
@@ -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();
index e994e7e..c4c05ee 100644 (file)
@@ -127,7 +127,7 @@ namespace HttpStress
                 {
                     host = host.UseQuic(options =>
                     {
-                        options.Alpn = "h3";
+                        options.Alpn = SslApplicationProtocol.Http3.ToString();
                         options.IdleTimeout = TimeSpan.FromMinutes(1);
                     });
                 }
index d314161..ded8bc9 100644 (file)
@@ -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<byte> Protocol { get { throw null; } }
index ebac2d8..f218ce2 100644 (file)
@@ -10,13 +10,16 @@ namespace System.Net.Security
     public readonly struct SslApplicationProtocol : IEquatable<SslApplicationProtocol>
     {
         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
+        /// <summary>Defines a <see cref="SslApplicationProtocol"/> instance for HTTP 3.0.</summary>
+        public static readonly SslApplicationProtocol Http3 = new SslApplicationProtocol(s_http3Utf8, copy: false);
+        /// <summary>Defines a <see cref="SslApplicationProtocol"/> instance for HTTP 2.0.</summary>
         public static readonly SslApplicationProtocol Http2 = new SslApplicationProtocol(s_http2Utf8, copy: false);
-        // http/1.1
+        /// <summary>Defines a <see cref="SslApplicationProtocol"/> instance for HTTP 1.1.</summary>
         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);
index 34a11a0..fe016e6 100644 (file)
@@ -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());
index 91d40fc..354acab 100644 (file)
@@ -41,7 +41,7 @@ namespace System.Net.Security.Tests
             Assert.Null(_clientOptions.ApplicationProtocols);
             Assert.Null(_serverOptions.ApplicationProtocols);
 
-            List<SslApplicationProtocol> applnProtos = new List<SslApplicationProtocol> { SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 };
+            List<SslApplicationProtocol> applnProtos = new List<SslApplicationProtocol> { SslApplicationProtocol.Http3, SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 };
             _clientOptions.ApplicationProtocols = applnProtos;
             _serverOptions.ApplicationProtocols = applnProtos;