From 812ad819a514ebadc3deeebe047bb90e30473f5b Mon Sep 17 00:00:00 2001 From: Corcodel Iulia <31440913+iuliaco@users.noreply.github.com> Date: Thu, 28 Jul 2022 20:02:57 +0300 Subject: [PATCH] HTTP/3 Made alt-used show only on alt-svc redirect (#72669) * #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 * Update src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs Co-authored-by: Natalia Kondratyeva Co-authored-by: iuliaco Co-authored-by: Natalia Kondratyeva --- .../Net/Http/SocketsHttpHandler/Http3Connection.cs | 16 +++++++---- .../Http/SocketsHttpHandler/HttpConnectionPool.cs | 4 +-- .../FunctionalTests/HttpClientHandlerTest.Http3.cs | 33 ++++++++++++++++++++++ 3 files changed, 45 insertions(+), 8 deletions(-) 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 f0403c4..de79b6c 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 @@ -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()) { 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 d909eef..ebc5c61 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 @@ -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()) 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 af609cf..3823533 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs @@ -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" -- 2.7.4