diff --git a/src/Testing/src/HttpClientSlim.cs b/src/Testing/src/HttpClientSlim.cs index 6214ffefc1..890ec2d160 100644 --- a/src/Testing/src/HttpClientSlim.cs +++ b/src/Testing/src/HttpClientSlim.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Http; using System.Net.Security; using System.Net.Sockets; +using System.Runtime.InteropServices; using System.Security.Authentication; using System.Text; using System.Threading.Tasks; @@ -24,17 +25,20 @@ namespace Microsoft.AspNetCore.Testing public static async Task GetStringAsync(Uri requestUri, bool validateCertificate = true) { - using (var stream = await GetStream(requestUri, validateCertificate).ConfigureAwait(false)) + return await RetryRequest(async () => { - using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true)) + using (var stream = await GetStream(requestUri, validateCertificate).ConfigureAwait(false)) { - await writer.WriteAsync($"GET {requestUri.PathAndQuery} HTTP/1.0\r\n").ConfigureAwait(false); - await writer.WriteAsync($"Host: {GetHost(requestUri)}\r\n").ConfigureAwait(false); - await writer.WriteAsync("\r\n").ConfigureAwait(false); - } + using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true)) + { + await writer.WriteAsync($"GET {requestUri.PathAndQuery} HTTP/1.0\r\n").ConfigureAwait(false); + await writer.WriteAsync($"Host: {GetHost(requestUri)}\r\n").ConfigureAwait(false); + await writer.WriteAsync("\r\n").ConfigureAwait(false); + } - return await ReadResponse(stream).ConfigureAwait(false); - } + return await ReadResponse(stream).ConfigureAwait(false); + } + }); } internal static string GetHost(Uri requestUri) @@ -62,21 +66,24 @@ namespace Microsoft.AspNetCore.Testing public static async Task PostAsync(Uri requestUri, HttpContent content, bool validateCertificate = true) { - using (var stream = await GetStream(requestUri, validateCertificate)) + return await RetryRequest(async () => { - using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true)) + using (var stream = await GetStream(requestUri, validateCertificate)) { - await writer.WriteAsync($"POST {requestUri.PathAndQuery} HTTP/1.0\r\n").ConfigureAwait(false); - await writer.WriteAsync($"Host: {requestUri.Authority}\r\n").ConfigureAwait(false); - await writer.WriteAsync($"Content-Type: {content.Headers.ContentType}\r\n").ConfigureAwait(false); - await writer.WriteAsync($"Content-Length: {content.Headers.ContentLength}\r\n").ConfigureAwait(false); - await writer.WriteAsync("\r\n").ConfigureAwait(false); + using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true)) + { + await writer.WriteAsync($"POST {requestUri.PathAndQuery} HTTP/1.0\r\n").ConfigureAwait(false); + await writer.WriteAsync($"Host: {requestUri.Authority}\r\n").ConfigureAwait(false); + await writer.WriteAsync($"Content-Type: {content.Headers.ContentType}\r\n").ConfigureAwait(false); + await writer.WriteAsync($"Content-Length: {content.Headers.ContentLength}\r\n").ConfigureAwait(false); + await writer.WriteAsync("\r\n").ConfigureAwait(false); + } + + await content.CopyToAsync(stream).ConfigureAwait(false); + + return await ReadResponse(stream).ConfigureAwait(false); } - - await content.CopyToAsync(stream).ConfigureAwait(false); - - return await ReadResponse(stream).ConfigureAwait(false); - } + }); } private static async Task ReadResponse(Stream stream) @@ -94,6 +101,33 @@ namespace Microsoft.AspNetCore.Testing } } + private static async Task RetryRequest(Func> retryBlock) + { + var retryCount = 1; + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + retryCount = 3; + } + + for (var retry = 0; retry < retryCount; retry++) + { + try + { + return await retryBlock().ConfigureAwait(false); + } + catch (InvalidDataException) + { + if (retry == retryCount - 1) + { + throw; + } + } + } + + // This will never be hit. + throw new NotSupportedException(); + } + private static HttpStatusCode GetStatus(string response) { var statusStart = response.IndexOf(' ') + 1;