SocketHttpHandler: include host+IP information in HttpRequestException (#38131)
authorAnton Firszov <Anton.Firszov@microsoft.com>
Wed, 8 Jul 2020 17:34:05 +0000 (19:34 +0200)
committerGitHub <noreply@github.com>
Wed, 8 Jul 2020 17:34:05 +0000 (19:34 +0200)
Fix #1326 by appending host:port info to HttpRequestException's message when connection fails.

Didn't change the inner SocketException, since it would require subclassing SocketException, which would add unnecessary complexity here.

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs

index 4be4a62..ab6047e 100644 (file)
@@ -76,7 +76,7 @@ namespace System.Net.Http
             }
             catch (Exception error) when (!(error is OperationCanceledException))
             {
-                throw CreateWrappedException(error, cancellationToken);
+                throw CreateWrappedException(error, host, port, cancellationToken);
             }
             finally
             {
@@ -100,7 +100,7 @@ namespace System.Net.Http
             catch (Exception e)
             {
                 socket.Dispose();
-                throw CreateWrappedException(e, cancellationToken);
+                throw CreateWrappedException(e, host, port, cancellationToken);
             }
 
             return new NetworkStream(socket, ownsSocket: true);
@@ -242,18 +242,18 @@ namespace System.Net.Http
 
             if (lastException != null)
             {
-                throw CreateWrappedException(lastException, cancellationToken);
+                throw CreateWrappedException(lastException, host, port, cancellationToken);
             }
 
             // TODO: find correct exception to throw here.
             throw new HttpRequestException("No host found.");
         }
 
-        private static Exception CreateWrappedException(Exception error, CancellationToken cancellationToken)
+        private static Exception CreateWrappedException(Exception error, string host, int port, CancellationToken cancellationToken)
         {
             return CancellationHelper.ShouldWrapInOperationCanceledException(error, cancellationToken) ?
                 CancellationHelper.CreateOperationCanceledException(error, cancellationToken) :
-                new HttpRequestException(error.Message, error, RequestRetryType.RetryOnNextProxy);
+                new HttpRequestException($"{error.Message} ({host}:{port})", error, RequestRetryType.RetryOnNextProxy);
         }
     }
 }
index 1237572..5a23a73 100644 (file)
@@ -6,6 +6,7 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
+using System.Net.Sockets;
 using System.Net.Test.Common;
 using System.Text;
 using System.Threading;
@@ -207,6 +208,20 @@ namespace System.Net.Http.Functional.Tests
         }
 
         [Fact]
+        [OuterLoop("Failing connection attempts take long on windows")]
+        public async Task GetContentAsync_WhenCanNotConnect_ExceptionContainsHostInfo()
+        {
+            using Socket portReserver = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+            portReserver.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+            IPEndPoint ep = (IPEndPoint)portReserver.LocalEndPoint;
+
+            using var client = CreateHttpClient();
+
+            HttpRequestException ex = await Assert.ThrowsAsync<HttpRequestException>(() => client.GetStreamAsync($"http://localhost:{ep.Port}"));
+            Assert.Contains($"localhost:{ep.Port}", ex.Message);
+        }
+
+        [Fact]
         public async Task GetContentAsync_NullResponse_Throws()
         {
             using (var client = new HttpClient(new CustomResponseHandler((r,c) => Task.FromResult<HttpResponseMessage>(null))))