Mark failing tests with issue.
authorLakshmi Priya Sekar <lasekar@microsoft.com>
Wed, 14 Feb 2018 02:07:33 +0000 (18:07 -0800)
committerLakshmi Priya Sekar <lasekar@microsoft.com>
Thu, 15 Feb 2018 01:24:03 +0000 (17:24 -0800)
Commit migrated from https://github.com/dotnet/corefx/commit/828468a258cfba872c84c3976835e9c664f68dee

src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs
src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs
src/libraries/System.Net.Http/tests/FunctionalTests/TestHelper.cs

index c04dbd5..ed58e2a 100644 (file)
@@ -7,7 +7,9 @@ using System.IO;
 using System.Net.Security;
 using System.Net.Sockets;
 using System.Security.Authentication;
+using System.Security.Cryptography;
 using System.Text;
+using System.Threading;
 using System.Threading.Tasks;
 
 namespace System.Net.Test.Common
@@ -15,15 +17,9 @@ namespace System.Net.Test.Common
     public sealed class LoopbackServer : IDisposable
     {
         private Socket _listenSocket;
-        private enum AuthenticationProtocols
-        {
-            Basic,
-            Digest,
-            None
-        }
-
         private Options _options;
         private Uri _uri;
+
         // Use CreateServerAsync or similar to create
         private LoopbackServer(Socket listenSocket, Options options)
         {
@@ -31,7 +27,7 @@ namespace System.Net.Test.Common
             _options = options;
 
             var localEndPoint = (IPEndPoint)listenSocket.LocalEndPoint;
-                string host = options.Address.AddressFamily == AddressFamily.InterNetworkV6 ? 
+            string host = options.Address.AddressFamily == AddressFamily.InterNetworkV6 ?
                 $"[{localEndPoint.Address}]" :
                 localEndPoint.Address.ToString();
 
@@ -68,84 +64,260 @@ namespace System.Net.Test.Common
                 {
                     await funcAsync(server);
                 }
-        public static Task<List<string>> ReadRequestAndAuthenticateAsync(Socket server, string response, Options options)
-        {
-            return AcceptSocketAsync(server, (s, stream, reader, writer) => ValidateAuthenticationAsync(s, reader, writer, response, options), options);
+            }
         }
 
-            }
+        public static Task CreateServerAsync(Func<LoopbackServer, Uri, Task> funcAsync, Options options = null)
+        {
+            return CreateServerAsync(server => funcAsync(server, server.Uri), options);
         }
 
-        public static async Task<List<string>> ValidateAuthenticationAsync(Socket s, StreamReader reader, StreamWriter writer, string response, Options options)
+        public static Task CreateClientAndServerAsync(Func<Uri, Task> clientFunc, Func<LoopbackServer, Task> serverFunc)
         {
-            // Send unauthorized response from server.
-            await ReadWriteAcceptedAsync(s, reader, writer, response);
-
-            // Read the request method.
-            string line = await reader.ReadLineAsync().ConfigureAwait(false);
-            int index = line != null ? line.IndexOf(' ') : -1;
-            string requestMethod = null;
-            if (index != -1)
+            return CreateServerAsync(async server =>
             {
-                requestMethod = line.Substring(0, index);
-            }
+                Task clientTask = clientFunc(server.Uri);
+                Task serverTask = serverFunc(server);
+
+                await new Task[] { clientTask, serverTask }.WhenAllOrAnyFailed();
+            });
+        }
 
-            // Read the authorization header from client.
-            AuthenticationProtocols protocol = AuthenticationProtocols.None;
-            string clientResponse = null;
-            while (!string.IsNullOrEmpty(line = await reader.ReadLineAsync().ConfigureAwait(false)))
+        public async Task AcceptConnectionAsync(Func<Connection, Task> funcAsync)
+        {
+            using (Socket s = await _listenSocket.AcceptAsync().ConfigureAwait(false))
             {
-                if (line.StartsWith("Authorization"))
+                s.NoDelay = true;
+
+                Stream stream = new NetworkStream(s, ownsSocket: false);
+                if (_options.UseSsl)
                 {
-                    clientResponse = line;
-                    if (line.Contains(nameof(AuthenticationProtocols.Basic)))
-                    {
-                        protocol = AuthenticationProtocols.Basic;
-                        break;
-                    }
-                    else if (line.Contains(nameof(AuthenticationProtocols.Digest)))
+                    var sslStream = new SslStream(stream, false, delegate
+                    { return true; });
+                    using (var cert = Configuration.Certificates.GetServerCertificate())
                     {
-                        protocol = AuthenticationProtocols.Digest;
-                        break;
+                        await sslStream.AuthenticateAsServerAsync(
+                            cert,
+                            clientCertificateRequired: true, // allowed but not required
+                            enabledSslProtocols: _options.SslProtocols,
+                            checkCertificateRevocation: false).ConfigureAwait(false);
                     }
+                    stream = sslStream;
+                }
+
+                if (_options.StreamWrapper != null)
+                {
+                    stream = _options.StreamWrapper(stream);
+                }
+
+                using (var connection = new Connection(s, stream))
+                {
+                    await funcAsync(connection);
                 }
             }
+        }
 
-            bool success = false;
-            switch (protocol)
+        public async Task<List<string>> AcceptConnectionSendCustomResponseAndCloseAsync(string response)
+        {
+            List<string> lines = null;
+
+            // Note, we assume there's no request body.  
+            // We'll close the connection after reading the request header and sending the response.
+            await AcceptConnectionAsync(async connection =>
+            {
+                lines = await connection.ReadRequestHeaderAndSendCustomResponseAsync(response);
+            });
+
+            return lines;
+        }
+
+        public async Task<List<string>> AcceptConnectionPerformAuthenticationAndCloseAsync(string authenticateHeaders)
+        {
+            List<string> lines = null;
+            await AcceptConnectionAsync(async connection =>
             {
-                case AuthenticationProtocols.Basic:
-                    success = IsBasicAuthTokenValid(line, options);
-                    break;
-
-                case AuthenticationProtocols.Digest:
-                    // Read the request content.
-                    string requestContent = null;
-                    while (!string.IsNullOrEmpty(line = await reader.ReadLineAsync().ConfigureAwait(false)))
+                await connection.ReadRequestHeaderAndSendResponseAsync(HttpStatusCode.Unauthorized, authenticateHeaders);
+
+                lines = await connection.ReadRequestHeaderAsync();
+                if (lines.Count == 0)
+                {
+                    await connection.SendResponseAsync(HttpStatusCode.Unauthorized, authenticateHeaders);
+                    return;
+                }
+
+                int index = lines[0] != null ? lines[0].IndexOf(' ') : -1;
+                string requestMethod = null;
+                if (index != -1)
+                {
+                    requestMethod = lines[0].Substring(0, index);
+                }
+
+                // Read the authorization header from client.
+                AuthenticationProtocols protocol = AuthenticationProtocols.None;
+                string clientResponse = null;
+                for (int i = 1; i < lines.Count; i++)
+                {
+                    if (lines[i].StartsWith("Authorization"))
                     {
-                        if (line.Contains("Content-Length"))
+                        clientResponse = lines[i];
+                        if (lines[i].Contains(nameof(AuthenticationProtocols.Basic)))
+                        {
+                            protocol = AuthenticationProtocols.Basic;
+                            break;
+                        }
+                        else if (lines[i].Contains(nameof(AuthenticationProtocols.Digest)))
                         {
-                            line = await reader.ReadLineAsync().ConfigureAwait(false);
-                            while (!string.IsNullOrEmpty(line = await reader.ReadLineAsync().ConfigureAwait(false)))
-                            {
-                                requestContent += line;
-                            }
+                            protocol = AuthenticationProtocols.Digest;
+                            break;
                         }
                     }
+                }
 
-                    success = IsDigestAuthTokenValid(clientResponse, requestContent, requestMethod, options);
-                    break;
-            }
+                bool success = false;
+                switch (protocol)
+                {
+                    case AuthenticationProtocols.Basic:
+                        success = IsBasicAuthTokenValid(clientResponse, _options);
+                        break;
+
+                    case AuthenticationProtocols.Digest:
+                        // Read the request content.
+                        string requestContent = await connection.ReadRequestContentAsync();
+                        success = IsDigestAuthTokenValid(clientResponse, requestContent, requestMethod, _options);
+                        break;
+                }
+
+                if (success)
+                {
+                    await connection.SendResponseAsync();
+                }
+                else
+                {
+                    await connection.SendResponseAsync(HttpStatusCode.Unauthorized, authenticateHeaders);
+                }
+            });
 
-            if (success)
+            return lines;
+        }
+
+        public async Task<List<string>> AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null)
+        {
+            List<string> lines = null;
+
+            // Note, we assume there's no request body.  
+            // We'll close the connection after reading the request header and sending the response.
+            await AcceptConnectionAsync(async connection =>
             {
-                await writer.WriteAsync(DefaultHttpResponse).ConfigureAwait(false);
-            }
-            else
+                lines = await connection.ReadRequestHeaderAndSendResponseAsync(statusCode, additionalHeaders, content);
+            });
+
+            return lines;
+        }
+
+        // Stolen from HttpStatusDescription code in the product code
+        private static string GetStatusDescription(HttpStatusCode code)
+        {
+            switch ((int)code)
             {
-                await writer.WriteAsync(response).ConfigureAwait(false);
+                case 100:
+                    return "Continue";
+                case 101:
+                    return "Switching Protocols";
+                case 102:
+                    return "Processing";
+
+                case 200:
+                    return "OK";
+                case 201:
+                    return "Created";
+                case 202:
+                    return "Accepted";
+                case 203:
+                    return "Non-Authoritative Information";
+                case 204:
+                    return "No Content";
+                case 205:
+                    return "Reset Content";
+                case 206:
+                    return "Partial Content";
+                case 207:
+                    return "Multi-Status";
+
+                case 300:
+                    return "Multiple Choices";
+                case 301:
+                    return "Moved Permanently";
+                case 302:
+                    return "Found";
+                case 303:
+                    return "See Other";
+                case 304:
+                    return "Not Modified";
+                case 305:
+                    return "Use Proxy";
+                case 307:
+                    return "Temporary Redirect";
+
+                case 400:
+                    return "Bad Request";
+                case 401:
+                    return "Unauthorized";
+                case 402:
+                    return "Payment Required";
+                case 403:
+                    return "Forbidden";
+                case 404:
+                    return "Not Found";
+                case 405:
+                    return "Method Not Allowed";
+                case 406:
+                    return "Not Acceptable";
+                case 407:
+                    return "Proxy Authentication Required";
+                case 408:
+                    return "Request Timeout";
+                case 409:
+                    return "Conflict";
+                case 410:
+                    return "Gone";
+                case 411:
+                    return "Length Required";
+                case 412:
+                    return "Precondition Failed";
+                case 413:
+                    return "Request Entity Too Large";
+                case 414:
+                    return "Request-Uri Too Long";
+                case 415:
+                    return "Unsupported Media Type";
+                case 416:
+                    return "Requested Range Not Satisfiable";
+                case 417:
+                    return "Expectation Failed";
+                case 422:
+                    return "Unprocessable Entity";
+                case 423:
+                    return "Locked";
+                case 424:
+                    return "Failed Dependency";
+                case 426:
+                    return "Upgrade Required"; // RFC 2817
+
+                case 500:
+                    return "Internal Server Error";
+                case 501:
+                    return "Not Implemented";
+                case 502:
+                    return "Bad Gateway";
+                case 503:
+                    return "Service Unavailable";
+                case 504:
+                    return "Gateway Timeout";
+                case 505:
+                    return "Http Version Not Supported";
+                case 507:
+                    return "Insufficient Storage";
             }
-
             return null;
         }
 
@@ -362,151 +534,12 @@ namespace System.Net.Test.Common
             }
         }
 
-        public static Task CreateServerAsync(Func<LoopbackServer, Uri, Task> funcAsync, Options options = null)
-        {
-            return CreateServerAsync(server => funcAsync(server, server.Uri), options);
-        }
-
-        public static Task CreateClientAndServerAsync(Func<Uri, Task> clientFunc, Func<LoopbackServer, Task> serverFunc)
-        {
-            return CreateServerAsync(async server =>
-            {
-                Task clientTask = clientFunc(server.Uri);
-                Task serverTask = serverFunc(server);
-
-                await new Task[] { clientTask, serverTask }.WhenAllOrAnyFailed();
-            });
-        }
-
-        public async Task AcceptConnectionAsync(Func<Connection, Task> funcAsync)
-        {
-            using (Socket s = await _listenSocket.AcceptAsync().ConfigureAwait(false))
-            {
-                s.NoDelay = true;
-
-                Stream stream = new NetworkStream(s, ownsSocket: false);
-                if (_options.UseSsl)
-                {
-                    var sslStream = new SslStream(stream, false, delegate
-                    { return true; });
-                    using (var cert = Configuration.Certificates.GetServerCertificate())
-                    {
-                        await sslStream.AuthenticateAsServerAsync(
-                            cert,
-                            clientCertificateRequired: true, // allowed but not required
-                            enabledSslProtocols: _options.SslProtocols,
-                            checkCertificateRevocation: false).ConfigureAwait(false);
-                    }
-                    stream = sslStream;
-                }
-
-                if (_options.StreamWrapper != null)
-                {
-                    stream = _options.StreamWrapper(stream);
-                }
-
-                using (var connection = new Connection(s, stream))
-                {
-                    await funcAsync(connection);
-                }
-            }
-        }
-
-        public async Task<List<string>> AcceptConnectionSendCustomResponseAndCloseAsync(string response)
-        {
-            List<string> lines = null;
-
-            // Note, we assume there's no request body.  
-            // We'll close the connection after reading the request header and sending the response.
-            await AcceptConnectionAsync(async connection =>
-            {
-                lines = await connection.ReadRequestHeaderAndSendCustomResponseAsync(response);
-            });
-
-            return lines;
-        }
-
-        public async Task<List<string>> AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null)
-        {
-            List<string> lines = null;
-
-            // Note, we assume there's no request body.  
-            // We'll close the connection after reading the request header and sending the response.
-            await AcceptConnectionAsync(async connection =>
-            {
-                lines = await connection.ReadRequestHeaderAndSendResponseAsync(statusCode, additionalHeaders, content);
-            });
-
-            return lines;
-        }
-
-        // Stolen from HttpStatusDescription code in the product code
-        private static string GetStatusDescription(HttpStatusCode code)
-        {
-            switch ((int)code)
-            {
-                case 100: return "Continue";
-                case 101: return "Switching Protocols";
-                case 102: return "Processing";
-
-                case 200: return "OK";
-                case 201: return "Created";
-                case 202: return "Accepted";
-                case 203: return "Non-Authoritative Information";
-                case 204: return "No Content";
-                case 205: return "Reset Content";
-                case 206: return "Partial Content";
-                case 207: return "Multi-Status";
-
-                case 300: return "Multiple Choices";
-                case 301: return "Moved Permanently";
-                case 302: return "Found";
-                case 303: return "See Other";
-                case 304: return "Not Modified";
-                case 305: return "Use Proxy";
-                case 307: return "Temporary Redirect";
-
-                case 400: return "Bad Request";
-                case 401: return "Unauthorized";
-                case 402: return "Payment Required";
-                case 403: return "Forbidden";
-                case 404: return "Not Found";
-                case 405: return "Method Not Allowed";
-                case 406: return "Not Acceptable";
-                case 407: return "Proxy Authentication Required";
-                case 408: return "Request Timeout";
-                case 409: return "Conflict";
-                case 410: return "Gone";
-                case 411: return "Length Required";
-                case 412: return "Precondition Failed";
-                case 413: return "Request Entity Too Large";
-                case 414: return "Request-Uri Too Long";
-                case 415: return "Unsupported Media Type";
-                case 416: return "Requested Range Not Satisfiable";
-                case 417: return "Expectation Failed";
-                case 422: return "Unprocessable Entity";
-                case 423: return "Locked";
-                case 424: return "Failed Dependency";
-                case 426: return "Upgrade Required"; // RFC 2817
-
-                case 500: return "Internal Server Error";
-                case 501: return "Not Implemented";
-                case 502: return "Bad Gateway";
-                case 503: return "Service Unavailable";
-                case 504: return "Gateway Timeout";
-                case 505: return "Http Version Not Supported";
-                case 507: return "Insufficient Storage";
-            }
-            return null;
-        }
-
         public static string GetHttpResponse(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null) =>
             $"HTTP/1.1 {(int)statusCode} {GetStatusDescription(statusCode)}\r\n" +
             $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
-            $"Content-Length: {(content == null ? 0 : content.Length)}\r\n" + 
-            additionalHeaders +
-            "\r\n" + 
-            content;
+            $"Content-Length: {(content == null ? 0 : content.Length)}\r\n" +
+            additionalHeaders + "\r\n" +
+            content + "\r\n";
 
         public class Options
         {
@@ -516,6 +549,16 @@ namespace System.Net.Test.Common
             public SslProtocols SslProtocols { get; set; } = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
             public bool WebSocketEndpoint { get; set; } = false;
             public Func<Stream, Stream> StreamWrapper { get; set; }
+            public string Username { get; set; }
+            public string Domain { get; set; }
+            public string Password { get; set; }
+        }
+
+        private enum AuthenticationProtocols
+        {
+            Basic,
+            Digest,
+            None
         }
 
         public sealed class Connection : IDisposable
@@ -561,8 +604,7 @@ namespace System.Net.Test.Common
             {
                 var lines = new List<string>();
                 string line;
-                while (!string.IsNullOrEmpty(line = reader.ReadLine()));
-                    ;
+                while (!string.IsNullOrEmpty(line = await _reader.ReadLineAsync().ConfigureAwait(false)))
                 {
                     lines.Add(line);
                 }
@@ -570,6 +612,25 @@ namespace System.Net.Test.Common
                 return lines;
             }
 
+            public async Task<string> ReadRequestContentAsync()
+            {
+                StringBuilder sb = new StringBuilder();
+                string line;
+                while (!string.IsNullOrEmpty(line = await _reader.ReadLineAsync().ConfigureAwait(false)))
+                {
+                    if (line.Contains("Content-Length"))
+                    {
+                        line = await _reader.ReadLineAsync().ConfigureAwait(false);
+                        while (!string.IsNullOrEmpty(line = await _reader.ReadLineAsync().ConfigureAwait(false)))
+                        {
+                            sb.Append(line);
+                        }
+                    }
+                }
+
+                return sb.ToString();
+            }
+
             public async Task SendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null)
             {
                 await _writer.WriteAsync(GetHttpResponse(statusCode, additionalHeaders, content));
index 531f636..515e993 100644 (file)
@@ -34,45 +34,58 @@ namespace System.Net.Http.Functional.Tests
         [MemberData(nameof(Authentication_TestData))]
         public async Task HttpClientHandler_Authentication_Succeeds(string authenticateHeader, bool result)
         {
+            if (IsCurlHandler && authenticateHeader.Contains("Digest"))
+            {
+                // TODO: #27113: Fix failing authentication test cases on different httpclienthandlers.
+                return;
+            }
+
             var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password };
             await LoopbackServer.CreateServerAsync(async (server, url) =>
             {
-                string serverResponse = $"HTTP/1.1 401 UnAuthorized\r\nDate: {DateTimeOffset.UtcNow:R}\r\nWWW-Authenticate: {authenticateHeader}\r\nContent-Length: 0\r\n\r\n";
+                string serverAuthenticateHeader = $"WWW-Authenticate: {authenticateHeader}";
                 HttpClientHandler handler = CreateHttpClientHandler();
                 Task serverTask = result ?
-                    LoopbackServer.ReadRequestAndAuthenticateAsync(server, serverResponse, options) :
-                    LoopbackServer.ReadRequestAndSendResponseAsync(server, serverResponse, options);
-                await TestHelper.WhenAllCompletedOrAnyFailed(_createAndValidateRequest(handler, url, result ? HttpStatusCode.OK : HttpStatusCode.Unauthorized, _credentials), serverTask);
+                    server.AcceptConnectionPerformAuthenticationAndCloseAsync(serverAuthenticateHeader) :
+                    server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, serverAuthenticateHeader);
+
+                await TestHelper.WhenAllCompletedOrAnyFailedWithTimeout(TestHelper.PassingTestTimeoutMilliseconds,
+                    _createAndValidateRequest(handler, url, result ? HttpStatusCode.OK : HttpStatusCode.Unauthorized, _credentials), serverTask);
             }, options);
         }
 
         [Theory]
-        [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\"")]
+        [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5")]
         [InlineData("WWW-Authenticate: Basic realm=\"hello1\"\r\nWWW-Authenticate: Basic realm=\"hello2\"")]
         [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Basic realm=\"hello\"")]
-        [InlineData("WWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\"\r\nWWW-Authenticate: Basic realm=\"hello\"")]
+        [InlineData("WWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: Basic realm=\"hello\"")]
         public async void HttpClientHandler_MultipleAuthenticateHeaders_Succeeds(string authenticateHeader)
         {
+            if (IsCurlHandler && authenticateHeader.Contains("Digest"))
+            {
+                // TODO: #27113: Fix failing authentication test cases on different httpclienthandlers.
+                return;
+            }
+
             var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password };
             await LoopbackServer.CreateServerAsync(async (server, url) =>
             {
-                string serverResponse = $"HTTP/1.1 401 UnAuthorized\r\nDate: {DateTimeOffset.UtcNow:R}\r\n{authenticateHeader}\r\nContent-Length: 0\r\n\r\n";
                 HttpClientHandler handler = CreateHttpClientHandler();
-                Task serverTask = LoopbackServer.ReadRequestAndAuthenticateAsync(server, serverResponse, options);
+                Task serverTask = server.AcceptConnectionPerformAuthenticationAndCloseAsync(authenticateHeader);
                 await TestHelper.WhenAllCompletedOrAnyFailed(_createAndValidateRequest(handler, url, HttpStatusCode.OK, _credentials), serverTask);
             }, options);
         }
 
         [Theory]
-        [InlineData("HTTP/1.1 401 UnAuthorized\r\nWWW-Authenticate: Basic realm=\"hello\"\r\nContent-Length: 0\r\n\r\n")]
-        [InlineData("HTTP/1.1 401 UnAuthorized\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"testnonce\"\r\nContent-Length: 0\r\n\r\n")]
-        public async void HttpClientHandler_IncorrectCredentials_Fails(string serverResponse)
+        [InlineData("WWW-Authenticate: Basic realm=\"hello\"")]
+        [InlineData("WWW-Authenticate: Digest realm=\"hello\", nonce=\"testnonce\"")]
+        public async void HttpClientHandler_IncorrectCredentials_Fails(string authenticateHeader)
         {
             var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password };
             await LoopbackServer.CreateServerAsync(async (server, url) =>
             {
                 HttpClientHandler handler = CreateHttpClientHandler();
-                Task serverTask = LoopbackServer.ReadRequestAndAuthenticateAsync(server, serverResponse, options);
+                Task serverTask = server.AcceptConnectionPerformAuthenticationAndCloseAsync(authenticateHeader);
                 await TestHelper.WhenAllCompletedOrAnyFailed(_createAndValidateRequest(handler, url, HttpStatusCode.Unauthorized, new NetworkCredential("wronguser", "wrongpassword")), serverTask);
             }, options);
         }
@@ -82,20 +95,24 @@ namespace System.Net.Http.Functional.Tests
             yield return new object[] { "Basic realm=\"testrealm\"", true };
             yield return new object[] { "Basic ", true };
             yield return new object[] { "Basic realm=withoutquotes", true };
-            yield return new object[] { "Basic something, Digest something", false };
 
             // Add digest tests fail on CurlHandler.
-            if (PlatformDetection.IsWindows)
+            // TODO: #27113: Fix failing authentication test cases on different httpclienthandlers.
+            yield return new object[] { "Digest realm=\"testrealm\" nonce=\"testnonce\"", false };
+            yield return new object[] { $"Digest realm=\"testrealm\", nonce=\"{Convert.ToBase64String(Encoding.UTF8.GetBytes($"{DateTimeOffset.UtcNow}:XMh;z+$5|`i6Hx}}\", qop=auth-int, algorithm=MD5"))}\"", true };
+            yield return new object[] { "Digest realm=\"api@example.org\", qop=\"auth\", algorithm=MD5-sess, nonce=\"5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK\", " +
+                    "opaque=\"HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS\", charset=UTF-8, userhash=true", true };
+            yield return new object[] { $"Basic realm=\"testrealm\", " +
+                    $"Digest realm=\"testrealm\", nonce=\"{Convert.ToBase64String(Encoding.UTF8.GetBytes($"{DateTimeOffset.UtcNow}:XMh;z+$5|`i6Hx}}"))}\", algorithm=MD5", true };
+
+            if (PlatformDetection.IsNetCore)
             {
-                yield return new object[] { "Digest realm=\"testrealm\" nonce=\"testnonce\"", false };
-                yield return new object[] { $"Digest realm=\"testrealm\", nonce=\"{Convert.ToBase64String(Encoding.UTF8.GetBytes($"{DateTimeOffset.UtcNow}:XMh;z+$5|`i6Hx}}\", qop=auth-int"))}\"", true };
-                yield return new object[] { "Digest realm=\"api@example.org\", qop=\"auth\", algorithm=MD5-sess, nonce=\"5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK\", " +
-                "opaque=\"HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS\", charset=UTF-8, userhash=true", true };
+                // These fail on full framework runs.
+                // TODO: #27113: Fix failing authentication test cases on different httpclienthandlers.
                 yield return new object[] { "Digest realm=\"testrealm1\", nonce=\"testnonce1\" Digest realm=\"testrealm2\", nonce=\"testnonce2\"", false };
-                yield return new object[] { $"Basic realm=\"testrealm\", " +
-                $"Digest realm=\"testrealm\", nonce=\"{Convert.ToBase64String(Encoding.UTF8.GetBytes($"{DateTimeOffset.UtcNow}:XMh;z+$5|`i6Hx}}"))}\", algorithm=MD5", true };
+                yield return new object[] { "Basic something, Digest something", false };
                 yield return new object[] { $"Digest realm=\"testrealm\", nonce=\"testnonce\", algorithm=MD5 " +
-                $"Basic realm=\"testrealm\"", false };
+                    $"Basic realm=\"testrealm\"", false };
             }
         }
     }
index 8ae2d43..63954d7 100644 (file)
@@ -149,6 +149,7 @@ namespace System.Net.Http.Functional.Tests
         public static IEnumerable<object[]> Authentication_SocketsHttpHandler_TestData()
         {
             // These test cases pass on SocketsHttpHandler, fail everywhere else.
+            // TODO: #27113: Fix failing authentication test cases on different httpclienthandlers.
             yield return new object[] { "Basic realm=\"testrealm1\" basic realm=\"testrealm1\"", true };
             yield return new object[] { "Basic something digest something", true };
             yield return new object[] { "Digest ", false };
index dc2f485..e60aa76 100644 (file)
@@ -16,6 +16,7 @@ namespace System.Net.Http.Functional.Tests
 {
     public static class TestHelper
     {
+        public static int PassingTestTimeoutMilliseconds => 60 * 1000;
         public static bool JsonMessageContainsKeyValue(string message, string key, string value)
         {
             // TODO (#5525): Align with the rest of tests w.r.t response parsing once the test server is finalized.
@@ -88,6 +89,11 @@ namespace System.Net.Http.Functional.Tests
             return TaskTimeoutExtensions.WhenAllOrAnyFailed(tasks);
         }
 
+        public static Task WhenAllCompletedOrAnyFailedWithTimeout(int timeoutInMilliseconds, params Task[] tasks)
+        {
+            return TaskTimeoutExtensions.WhenAllOrAnyFailed(tasks, timeoutInMilliseconds);
+        }
+
         public static Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> AllowAllCertificates = (_, __, ___, ____) => true;
 
         public static IPAddress GetIPv6LinkLocalAddress() =>