From fce788b6aedb5a9fc1eeda7caef6cd4648a8feda Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 23 Jun 2017 17:55:55 -0700 Subject: [PATCH] #339 Don't send chunked responses for HEAD requests --- .../RequestProcessing/Response.cs | 4 +- .../Listener/ResponseHeaderTests.cs | 67 +++++++++++++------ 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs index ec766cd..427f1a1 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs @@ -384,9 +384,9 @@ internal HttpApi.HTTP_FLAGS ComputeHeaders(long writeCount, bool endOfRequest = // The application is performing it's own chunking. _boundaryType = BoundaryType.PassThrough; } - else if (endOfRequest && !(isHeadRequest && statusCanHaveBody)) // HEAD requests should always end without a body. Assume a GET response would have a body. + else if (endOfRequest) { - if (statusCanHaveBody) + if (!isHeadRequest && statusCanHaveBody) { Headers[HttpKnownHeaderNames.ContentLength] = Constants.Zero; } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs index 3ba6cba..9820247 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs @@ -14,8 +14,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { - public class ResponseHeaderTests + public class ResponseHeaderTests : IDisposable { + private HttpClient _client = new HttpClient(); + + void IDisposable.Dispose() + { + _client.Dispose(); + } + [ConditionalFact] public async Task ResponseHeaders_11Request_ServerSendsDefaultHeaders() { @@ -74,12 +81,18 @@ public async Task ResponseHeaders_11HeadRequest_ServerSendsDefaultHeaders() HttpResponseMessage response = await responseTask; response.EnsureSuccessStatusCode(); - Assert.Equal(3, response.Headers.Count()); - Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.Equal(2, response.Headers.Count()); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); Assert.True(response.Headers.Date.HasValue); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.False(response.Content.Headers.Contains("Content-Length")); Assert.Equal(0, response.Content.Headers.Count()); + + // Send a second request to check that the connection wasn't corrupted. + responseTask = SendHeadRequestAsync(address); + context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Dispose(); + response = await responseTask; } } @@ -103,6 +116,12 @@ public async Task ResponseHeaders_10HeadRequest_ServerSendsDefaultHeaders() Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.False(response.Content.Headers.Contains("Content-Length")); Assert.Equal(0, response.Content.Headers.Count()); + + // Send a second request to check that the connection wasn't corrupted. + responseTask = SendHeadRequestAsync(address); + context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Dispose(); + response = await responseTask; } } @@ -126,6 +145,12 @@ public async Task ResponseHeaders_11HeadRequestWithContentLength_Success() Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.Equal(1, response.Content.Headers.Count()); Assert.Equal(20, response.Content.Headers.ContentLength); + + // Send a second request to check that the connection wasn't corrupted. + responseTask = SendHeadRequestAsync(address); + context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Dispose(); + response = await responseTask; } } @@ -172,6 +197,12 @@ public async Task ResponseHeaders_11HeadRequestStatusCodeWithoutBody_NoContentLe Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.False(response.Content.Headers.Contains("Content-Length")); Assert.Equal(0, response.Content.Headers.Count()); + + // Send a second request to check that the connection wasn't corrupted. + responseTask = SendHeadRequestAsync(address); + context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Dispose(); + response = await responseTask; } } @@ -484,32 +515,26 @@ public async Task AddingControlCharactersToHeadersThrows(string key, string valu private async Task SendRequestAsync(string uri, bool usehttp11 = true, bool sendKeepAlive = false) { - using (HttpClient client = new HttpClient()) + var request = new HttpRequestMessage(HttpMethod.Get, uri); + if (!usehttp11) { - var request = new HttpRequestMessage(HttpMethod.Get, uri); - if (!usehttp11) - { - request.Version = new Version(1, 0); - } - if (sendKeepAlive) - { - request.Headers.Add("Connection", "Keep-Alive"); - } - return await client.SendAsync(request); + request.Version = new Version(1, 0); + } + if (sendKeepAlive) + { + request.Headers.Add("Connection", "Keep-Alive"); } + return await _client.SendAsync(request); } private async Task SendHeadRequestAsync(string uri, bool usehttp11 = true) { - using (HttpClient client = new HttpClient()) + var request = new HttpRequestMessage(HttpMethod.Head, uri); + if (!usehttp11) { - var request = new HttpRequestMessage(HttpMethod.Head, uri); - if (!usehttp11) - { - request.Version = new Version(1, 0); - } - return await client.SendAsync(request); + request.Version = new Version(1, 0); } + return await _client.SendAsync(request); } } } \ No newline at end of file