From 2c0c31e8e16ab93877dd45f189c74392466a04cb Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 2 May 2019 14:56:19 -0400 Subject: [PATCH] Fix SendAsync_No100ContinueReceived_RequestBodySentEventually test flakiness (dotnet/corefx#37371) The server in the test was sending down the entire response and then trying to read the data from the client. If the client sent its whole payload and read the response before the server go around to doing the read, the client might close the connection, in which case the read might fail. The fix just changes the server code to only send down the headers, then read the data from the client, and only then finish the response, at which point it's fine if the client closes the connection. Commit migrated from https://github.com/dotnet/corefx/commit/772aa2d1029caa8be3b360168b63dadd42ae788b --- .../Common/tests/System/Net/Http/LoopbackServer.cs | 14 ++++++++++--- .../tests/FunctionalTests/HttpClientHandlerTest.cs | 24 ++++++++++++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs index c2c0e3d..b6a20b4 100644 --- a/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs @@ -305,13 +305,16 @@ namespace System.Net.Test.Common } public static string GetHttpResponse(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null, bool connectionClose = false) => + GetHttpResponseHeaders(statusCode, additionalHeaders, content, connectionClose) + + content; + + public static string GetHttpResponseHeaders(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null, bool connectionClose = false) => $"HTTP/1.1 {(int)statusCode} {GetStatusDescription(statusCode)}\r\n" + (connectionClose ? "Connection: close\r\n" : "") + $"Date: {DateTimeOffset.UtcNow:R}\r\n" + $"Content-Length: {(content == null ? 0 : content.Length)}\r\n" + additionalHeaders + - "\r\n" + - content; + "\r\n"; public static string GetSingleChunkHttpResponse(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null, bool connectionClose = false) => $"HTTP/1.1 {(int)statusCode} {GetStatusDescription(statusCode)}\r\n" + @@ -571,9 +574,14 @@ namespace System.Net.Test.Common return lines; } + public async Task SendResponseAsync(string response) + { + await _writer.WriteAsync(response).ConfigureAwait(false); + } + public async Task SendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null) { - await _writer.WriteAsync(GetHttpResponse(statusCode, additionalHeaders, content)).ConfigureAwait(false); + await SendResponseAsync(GetHttpResponse(statusCode, additionalHeaders, content)).ConfigureAwait(false); } public async Task> ReadRequestHeaderAndSendCustomResponseAsync(string response) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs index 04b5736..883db8b 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs @@ -2064,30 +2064,36 @@ namespace System.Net.Http.Functional.Tests if (IsCurlHandler) return; var clientFinished = new TaskCompletionSource(); - const string TestString = "test"; + const string RequestString = "request"; + const string ResponseString = "response"; await LoopbackServer.CreateClientAndServerAsync(async uri => { using (HttpClient client = CreateHttpClient()) { HttpRequestMessage initialMessage = new HttpRequestMessage(HttpMethod.Post, uri) { Version = VersionFromUseHttp2 }; - initialMessage.Content = new StringContent(TestString); + initialMessage.Content = new StringContent(RequestString); initialMessage.Headers.ExpectContinue = true; - HttpResponseMessage response = await client.SendAsync(initialMessage); + using (HttpResponseMessage response = await client.SendAsync(initialMessage)) + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(ResponseString, await response.Content.ReadAsStringAsync()); + } - Assert.Equal(HttpStatusCode.OK, response.StatusCode); clientFinished.SetResult(true); } }, async server => { await server.AcceptConnectionAsync(async connection => { - // Send final status code 200. - await connection.ReadRequestHeaderAndSendResponseAsync(); + await connection.ReadRequestHeaderAsync(); + await connection.SendResponseAsync(LoopbackServer.GetHttpResponseHeaders(HttpStatusCode.OK, content: ResponseString)); - var result = new char[TestString.Length]; - await connection.ReadBlockAsync(result, 0, TestString.Length); - Assert.Equal(TestString, new string(result)); + var result = new char[RequestString.Length]; + await connection.ReadBlockAsync(result, 0, RequestString.Length); + Assert.Equal(RequestString, new string(result)); + + await connection.SendResponseAsync(ResponseString); await clientFinished.Task; }); -- 2.7.4