未验证 提交 3824cb29 编写于 作者: K Katya Sokolova 提交者: GitHub

Handle web socket downgrade when HTTP/2 not enabled (#73843)

* Handle downgrade when HTTP/2 not enabled

* Update src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs
Co-authored-by: NNatalia Kondratyeva <knatalia@microsoft.com>

* feedback

* Force 1.1 for non-secure web request if policy allows
Co-authored-by: NNatalia Kondratyeva <knatalia@microsoft.com>
上级 280c373c
......@@ -88,7 +88,14 @@ public static async ValueTask<SslStream> EstablishSslConnectionAsync(SslClientAu
throw CancellationHelper.CreateOperationCanceledException(e, cancellationToken);
}
throw new HttpRequestException(SR.net_http_ssl_connection_failed, e);
HttpRequestException ex = new HttpRequestException(SR.net_http_ssl_connection_failed, e);
if (request.IsExtendedConnectRequest)
{
// Extended connect request is negotiating strictly for ALPN = "h2" because HttpClient is unaware of a possible downgrade.
// At this point, SSL connection for HTTP / 2 failed, and the exception should indicate the reason for the external client / user.
ex.Data["HTTP2_ENABLED"] = false;
}
throw ex;
}
// Handle race condition if cancellation happens after SSL auth completes but before the registration is disposed
......
......@@ -426,7 +426,13 @@ private static void ThrowGetVersionException(HttpRequestMessage request, int des
{
Debug.Assert(desiredVersion == 2 || desiredVersion == 3);
throw new HttpRequestException(SR.Format(SR.net_http_requested_version_cannot_establish, request.Version, request.VersionPolicy, desiredVersion), inner);
HttpRequestException ex = new HttpRequestException(SR.Format(SR.net_http_requested_version_cannot_establish, request.Version, request.VersionPolicy, desiredVersion), inner);
if (request.IsExtendedConnectRequest && desiredVersion == 2)
{
ex.Data["HTTP2_ENABLED"] = false;
}
throw ex;
}
private bool CheckExpirationOnGet(HttpConnectionBase connection)
......@@ -1122,12 +1128,7 @@ public async ValueTask<HttpResponseMessage> SendWithVersionDetectionAndRetryAsyn
// Throw if fallback is not allowed by the version policy.
if (request.VersionPolicy != HttpVersionPolicy.RequestVersionOrLower)
{
HttpRequestException exception = new HttpRequestException(SR.Format(SR.net_http_requested_version_server_refused, request.Version, request.VersionPolicy), e);
if (request.IsExtendedConnectRequest)
{
exception.Data["HTTP2_ENABLED"] = false;
}
throw exception;
throw new HttpRequestException(SR.Format(SR.net_http_requested_version_server_refused, request.Version, request.VersionPolicy), e);
}
if (NetEventSource.Log.IsEnabled())
......
......@@ -53,7 +53,8 @@ public async Task ConnectAsync(Uri uri, HttpMessageInvoker? invoker, Cancellatio
bool disposeResponse = false;
bool tryDowngrade = false;
// force non-secure request to 1.1 whenever it is possible as HttpClient does
bool tryDowngrade = uri.Scheme == UriScheme.Ws && (options.HttpVersion == HttpVersion.Version11 || options.HttpVersionPolicy == HttpVersionPolicy.RequestVersionOrLower);
try
{
......@@ -63,7 +64,7 @@ public async Task ConnectAsync(Uri uri, HttpMessageInvoker? invoker, Cancellatio
{
HttpRequestMessage request;
if (!tryDowngrade && options.HttpVersion >= HttpVersion.Version20
|| (options.HttpVersion == HttpVersion.Version11 && options.HttpVersionPolicy == HttpVersionPolicy.RequestVersionOrHigher))
|| (options.HttpVersion == HttpVersion.Version11 && options.HttpVersionPolicy == HttpVersionPolicy.RequestVersionOrHigher && uri.Scheme == UriScheme.Wss))
{
if (options.HttpVersion > HttpVersion.Version20 && options.HttpVersionPolicy != HttpVersionPolicy.RequestVersionOrLower)
{
......
......@@ -26,6 +26,11 @@ public class ClientWebSocketTestBase
new object[] { o[0], false },
new object[] { o[0], true }
}).ToArray();
public static readonly object[][] SecureEchoServersAndBoolean = new object[][]
{
new object[] { Test.Common.Configuration.WebSockets.SecureRemoteEchoServer, false },
new object[] { Test.Common.Configuration.WebSockets.SecureRemoteEchoServer, true }
};
public const int TimeOutMilliseconds = 30000;
public const int CloseDescriptionMaxLength = 123;
......
......@@ -96,6 +96,59 @@ public async Task ConnectAsync_VersionNotSupported_WithSsl_Throws()
);
}
[OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))]
[Theory]
[MemberData(nameof(SecureEchoServersAndBoolean))]
[SkipOnPlatform(TestPlatforms.Browser, "System.Net.Sockets is not supported on this platform")]
public async Task ConnectAsync_Http11Server_DowngradeFail(Uri server, bool useHandler)
{
using (var cws = new ClientWebSocket())
using (var cts = new CancellationTokenSource(TimeOutMilliseconds))
{
cws.Options.HttpVersion = HttpVersion.Version20;
cws.Options.HttpVersionPolicy = Http.HttpVersionPolicy.RequestVersionExact;
Task t;
if (useHandler)
{
var handler = new SocketsHttpHandler();
t = cws.ConnectAsync(server, new HttpMessageInvoker(handler), cts.Token);
}
else
{
t = cws.ConnectAsync(server, cts.Token);
}
var ex = await Assert.ThrowsAnyAsync<WebSocketException>(() => t);
Assert.IsType<HttpRequestException>(ex.InnerException);
Assert.True(ex.InnerException.Data.Contains("HTTP2_ENABLED"));
Assert.Equal(WebSocketState.Closed, cws.State);
}
}
[OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))]
[Theory]
[MemberData(nameof(EchoServersAndBoolean))]
[SkipOnPlatform(TestPlatforms.Browser, "System.Net.Sockets is not supported on this platform")]
public async Task ConnectAsync_Http11Server_DowngradeSuccess(Uri server, bool useHandler)
{
using (var cws = new ClientWebSocket())
using (var cts = new CancellationTokenSource(TimeOutMilliseconds))
{
cws.Options.HttpVersion = HttpVersion.Version20;
cws.Options.HttpVersionPolicy = Http.HttpVersionPolicy.RequestVersionOrLower;
if (useHandler)
{
var handler = new SocketsHttpHandler();
await cws.ConnectAsync(server, new HttpMessageInvoker(handler), cts.Token);
}
else
{
await cws.ConnectAsync(server, cts.Token);
}
Assert.Equal(WebSocketState.Open, cws.State);
}
}
[Theory]
[InlineData(false)]
[InlineData(true)]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册