From 88114568b9f1c9708c0e1fecd11d90978fa600c4 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 31 Aug 2016 14:09:17 -0700 Subject: [PATCH] #167 Prevent duplicate Content-Length headers --- .../RequestProcessing/Response.cs | 22 ++++++++----------- .../RequestProcessing/ResponseStream.cs | 10 ++++----- .../ResponseCachingTests.cs | 3 +-- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 07622b5a87..534529e198 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -338,11 +338,6 @@ namespace Microsoft.Net.Http.Server _responseState = ResponseState.Started; var reasonPhrase = GetReasonPhrase(StatusCode); - /* - if (m_BoundaryType==BoundaryType.Raw) { - use HTTP_SEND_RESPONSE_FLAG_RAW_HEADER; - } - */ uint statusCode; uint bytesSent; List pinnedHeaders = SerializeHeaders(isOpaqueUpgrade); @@ -414,7 +409,7 @@ namespace Microsoft.Net.Http.Server return statusCode; } - internal HttpApi.HTTP_FLAGS ComputeHeaders(bool endOfRequest = false) + internal HttpApi.HTTP_FLAGS ComputeHeaders(long writeCount, bool endOfRequest = false) { // 401 if (StatusCode == (ushort)HttpStatusCode.Unauthorized) @@ -456,6 +451,13 @@ namespace Microsoft.Net.Http.Server _boundaryType = BoundaryType.ContentLength; // ComputeLeftToWrite checks for HEAD requests when setting _leftToWrite _expectedBodyLength = responseContentLength.Value; + if (responseContentLength.Value == writeCount && !isHeadRequest) + { + // A single write with the whole content-length. Http.Sys will set the content-length for us in this scenario. + // If we don't remove it then range requests served from cache will have two. + // https://github.com/aspnet/WebListener/issues/167 + ContentLength = null; + } } else if (responseChunkedSet) { @@ -495,7 +497,6 @@ namespace Microsoft.Net.Http.Server flags = HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; } - Headers.IsReadOnly = true; // Prohibit further modifications. return flags; } @@ -511,12 +512,7 @@ namespace Microsoft.Net.Http.Server HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; List pinnedHeaders; GCHandle gcHandle; - /* - // here we would check for BoundaryType.Raw, in this case we wouldn't need to do anything - if (m_BoundaryType==BoundaryType.Raw) { - return null; - } - */ + if (Headers.Count == 0) { return null; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 4d23aafa68..ddb009ee6f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -137,7 +137,7 @@ namespace Microsoft.Net.Http.Server } // Make sure all validation is performed before this computes the headers - var flags = ComputeLeftToWrite(endOfRequest); + var flags = ComputeLeftToWrite(data.Count, endOfRequest); if (!_inOpaqueMode && endOfRequest && _leftToWrite > 0) { _requestContext.Abort(); @@ -315,7 +315,7 @@ namespace Microsoft.Net.Http.Server } // Make sure all validation is performed before this computes the headers - var flags = ComputeLeftToWrite(); + var flags = ComputeLeftToWrite(data.Count); if (_leftToWrite != data.Count) { flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; @@ -438,12 +438,12 @@ namespace Microsoft.Net.Http.Server _requestContext.Abort(); } - private HttpApi.HTTP_FLAGS ComputeLeftToWrite(bool endOfRequest = false) + private HttpApi.HTTP_FLAGS ComputeLeftToWrite(long writeCount, bool endOfRequest = false) { var flags = HttpApi.HTTP_FLAGS.NONE; if (!_requestContext.Response.HasComputedHeaders) { - flags = _requestContext.Response.ComputeHeaders(endOfRequest); + flags = _requestContext.Response.ComputeHeaders(writeCount, endOfRequest); } if (_leftToWrite == long.MinValue) { @@ -591,7 +591,7 @@ namespace Microsoft.Net.Http.Server } // Make sure all validation is performed before this computes the headers - var flags = ComputeLeftToWrite(); + var flags = ComputeLeftToWrite(count.Value); uint statusCode; uint bytesSent = 0; var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index 349f93ecfe..63bf4e3537 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -1000,8 +1000,7 @@ namespace Microsoft.Net.Http.Server } } - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "Cached response contains duplicate Content-Length headers (#167).")] + [Fact] public async Task Caching_RequestRangeFromCachedFile_ServedFromCache() { string address;