Fix HttpWebRequest when using system proxy settings (dotnet/corefx#31100)
authorDavid Shulman <david.shulman@microsoft.com>
Tue, 17 Jul 2018 02:51:03 +0000 (19:51 -0700)
committerGitHub <noreply@github.com>
Tue, 17 Jul 2018 02:51:03 +0000 (19:51 -0700)
While investigating other HttpClient/HttpWebRequest proxy-related bugs, I discovered that
HttpWebRequest was not honoring system proxy settings as defined on Windows with IE
settings or on Linux using environment variables.

The problem is due to how HttpClient and HttpWebRequest differ in how they represent
the default behavior of using system proxy settings with the various properties. Fixed
HttpWebRequest so that it will translate the system proxy settings to the internal
HttpClient/HttpClientHandler objects.

I also removed an invalid Assert in HttpConnection. This assert was firing when using a proxy
that was defined on the loopback adapter using IPv6 literal "[::1]".  Due to issue dotnet/corefx#28863 with Uri,
the Uri.IdnHost property doesn't have the brackets for IPv6 literals. So, the Assert was
occuring.

I did not add any new CI tests because it is currently not possible to test system proxy settings
in CI since it involves changing machine configuration. But I ran manual tests.

Commit migrated from https://github.com/dotnet/corefx/commit/72119235e294e711871cf453f2ffc66ba17ff23b

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs
src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs

index e9b49f2..97c76ba 100644 (file)
@@ -110,7 +110,6 @@ namespace System.Net.Http
                     Debug.Assert(port != 0);
                     Debug.Assert(sslHostName == null);
                     Debug.Assert(proxyUri != null);
-                    Debug.Assert(proxyUri.IdnHost == host && proxyUri.Port == port);
                     break;
 
                 default:
index 140ca30..860e047 100644 (file)
@@ -2263,6 +2263,18 @@ namespace System.Net.Http.Functional.Tests
                 return;
             }
 
+            if (PlatformDetection.IsFullFramework)
+            {
+                // Skip test on .NET Framework. It will sometimes not throw TaskCanceledException.
+                // Instead it might throw the following top-level and inner exceptions depending
+                // on race conditions.
+                //
+                // System.Net.Http.HttpRequestException : Error while copying content to a stream.
+                // ---- System.IO.IOException : The read operation failed, see inner exception.
+                //-------- System.Net.WebException : The request was aborted: The request was canceled.
+                return;
+            }
+
             await LoopbackServer.CreateServerAsync(async (server1, url1) =>
             {
                 await LoopbackServer.CreateServerAsync(async (server2, url2) =>
@@ -2761,8 +2773,9 @@ namespace System.Net.Http.Functional.Tests
         }
 
         [OuterLoop("Uses external server")]
-        [Theory, MemberData(nameof(EchoServers))] // NOTE: will not work for in-box System.Net.Http.dll due to disposal of request content
-        [ActiveIssue("https://github.com/dotnet/corefx/issues/28882", TargetFrameworkMonikers.NetFramework)]
+        [Theory, MemberData(nameof(EchoServers))]
+        [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, ".NET Framework disposes request content after send")]
+        [ActiveIssue(31104, TestPlatforms.AnyUnix)]
         public async Task PostAsync_ReuseRequestContent_Success(Uri remoteServer)
         {
             const string ContentString = "This is the content string.";
index 55b15ea..a84831a 100644 (file)
@@ -1133,11 +1133,22 @@ namespace System.Net
 
                 Debug.Assert(handler.UseProxy); // Default of handler.UseProxy is true.
                 Debug.Assert(handler.Proxy == null); // Default of handler.Proxy is null.
+
+                // HttpClientHandler default is to use a proxy which is the system proxy.
+                // This is indicated by the properties 'UseProxy == true' and 'Proxy == null'.
+                //
+                // However, HttpWebRequest doesn't have a separate 'UseProxy' property. Instead,
+                // the default of the 'Proxy' property is a non-null IWebProxy object which is the
+                // system default proxy object. If the 'Proxy' property were actually null, then
+                // that means don't use any proxy. 
+                //
+                // So, we need to map the desired HttpWebRequest proxy settings to equivalent
+                // HttpClientHandler settings.
                 if (_proxy == null)
                 {
                     handler.UseProxy = false;
                 }
-                else
+                else if (!object.ReferenceEquals(_proxy, WebRequest.GetSystemWebProxy()))
                 {
                     handler.Proxy = _proxy;
                 }