HTTP/3 Made alt-used show only on alt-svc redirect (#72669)
authorCorcodel Iulia <31440913+iuliaco@users.noreply.github.com>
Thu, 28 Jul 2022 17:02:57 +0000 (20:02 +0300)
committerGitHub <noreply@github.com>
Thu, 28 Jul 2022 17:02:57 +0000 (19:02 +0200)
* #56876 issue test

* Implemented Alt-Used compliance

* resolved code review

* changed variable name

* removed white spaces

* Update src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs

Co-authored-by: Natalia Kondratyeva <knatalia@microsoft.com>
* Update src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs

Co-authored-by: Natalia Kondratyeva <knatalia@microsoft.com>
Co-authored-by: iuliaco <t-icorcodel@microsoft.com>
Co-authored-by: Natalia Kondratyeva <knatalia@microsoft.com>
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

index f0403c4..de79b6c 100644 (file)
@@ -23,7 +23,7 @@ namespace System.Net.Http
         private readonly HttpConnectionPool _pool;
         private readonly HttpAuthority? _origin;
         private readonly HttpAuthority _authority;
-        private readonly byte[] _altUsedEncodedHeader;
+        private readonly byte[]? _altUsedEncodedHeader;
         private QuicConnection? _connection;
         private Task? _connectionClosedTask;
 
@@ -54,7 +54,7 @@ namespace System.Net.Http
         public HttpAuthority Authority => _authority;
         public HttpConnectionPool Pool => _pool;
         public int MaximumRequestHeadersLength => _maximumHeadersLength;
-        public byte[] AltUsedEncodedHeaderBytes => _altUsedEncodedHeader;
+        public byte[]? AltUsedEncodedHeaderBytes => _altUsedEncodedHeader;
         public Exception? AbortException => Volatile.Read(ref _abortException);
         private object SyncObj => _activeRequests;
 
@@ -70,16 +70,20 @@ namespace System.Net.Http
             }
         }
 
-        public Http3Connection(HttpConnectionPool pool, HttpAuthority? origin, HttpAuthority authority, QuicConnection connection)
+        public Http3Connection(HttpConnectionPool pool, HttpAuthority? origin, HttpAuthority authority, QuicConnection connection, bool includeAltUsedHeader)
         {
             _pool = pool;
             _origin = origin;
             _authority = authority;
             _connection = connection;
 
-            bool altUsedDefaultPort = pool.Kind == HttpConnectionKind.Http && authority.Port == HttpConnectionPool.DefaultHttpPort || pool.Kind == HttpConnectionKind.Https && authority.Port == HttpConnectionPool.DefaultHttpsPort;
-            string altUsedValue = altUsedDefaultPort ? authority.IdnHost : string.Create(CultureInfo.InvariantCulture, $"{authority.IdnHost}:{authority.Port}");
-            _altUsedEncodedHeader = QPack.QPackEncoder.EncodeLiteralHeaderFieldWithoutNameReferenceToArray(KnownHeaders.AltUsed.Name, altUsedValue);
+            if (includeAltUsedHeader)
+            {
+                bool altUsedDefaultPort = pool.Kind == HttpConnectionKind.Http && authority.Port == HttpConnectionPool.DefaultHttpPort || pool.Kind == HttpConnectionKind.Https && authority.Port == HttpConnectionPool.DefaultHttpsPort;
+                string altUsedValue = altUsedDefaultPort ? authority.IdnHost : string.Create(CultureInfo.InvariantCulture, $"{authority.IdnHost}:{authority.Port}");
+                _altUsedEncodedHeader = QPack.QPackEncoder.EncodeLiteralHeaderFieldWithoutNameReferenceToArray(KnownHeaders.AltUsed.Name, altUsedValue);
+            }
+
 
             if (HttpTelemetry.Log.IsEnabled())
             {
index d909eef..ebc5c61 100644 (file)
@@ -921,8 +921,8 @@ namespace System.Net.Http
                     throw new HttpRequestException("QUIC connected but no HTTP/3 indicated via ALPN.", null, RequestRetryType.RetryOnSameOrNextProxy);
                 }
 #endif
-
-                http3Connection = new Http3Connection(this, _originAuthority, authority, quicConnection);
+                // if the authority was sent as an option through alt-svc then include alt-used header
+                http3Connection = new Http3Connection(this, _originAuthority, authority, quicConnection, includeAltUsedHeader: _http3Authority == authority);
                 _http3Connection = http3Connection;
 
                 if (NetEventSource.Log.IsEnabled())
index af609cf..3823533 100644 (file)
@@ -1028,6 +1028,39 @@ namespace System.Net.Http.Functional.Tests
         }
 
         [Fact]
+        public async Task AltSvcNotUsed_AltUsedHeaderNotPresent()
+        {
+            using Http3LoopbackServer server = CreateHttp3LoopbackServer();
+
+            Http3LoopbackConnection connection = null;
+            HttpRequestData requestData = null;
+            Task serverTask = Task.Run(async () =>
+            {
+                connection = (Http3LoopbackConnection)await server.EstablishGenericConnectionAsync();
+                requestData = await connection.ReadRequestDataAsync(readBody: false);
+                Assert.NotNull(connection);
+                Assert.Equal(0, requestData.GetHeaderValueCount("alt-used"));
+                await connection.SendResponseAsync();
+            });
+
+            using HttpClient client = CreateHttpClient();
+            using HttpRequestMessage request = new()
+            {
+                Method = HttpMethod.Get,
+                RequestUri = server.Address,
+                Version = HttpVersion30,
+                VersionPolicy = HttpVersionPolicy.RequestVersionExact
+            };
+
+            HttpResponseMessage response = await client.SendAsync(request).WaitAsync(TimeSpan.FromSeconds(10));
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version30, response.Version);
+
+            await serverTask;
+            await connection.DisposeAsync();
+        }
+
+        [Fact]
         public async Task Alpn_NonH3_NegotiationFailure()
         {
             var options = new Http3Options() { Alpn = "h3-29" }; // anything other than "h3"