diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileContentResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileContentResultExecutor.cs index f6763ac01f..445622fd85 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileContentResultExecutor.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileContentResultExecutor.cs @@ -28,12 +28,14 @@ public virtual Task ExecuteAsync(ActionContext context, FileContentResult result throw new ArgumentNullException(nameof(result)); } + AppContext.TryGetSwitch(EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch); var (range, rangeLength, serveBody) = SetHeadersAndLog( context, result, result.FileContents.Length, result.LastModified, - result.EntityTag); + result.EntityTag, + enableRangeProcessingSwitch); if (!serveBody) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileResultExecutorBase.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileResultExecutorBase.cs index 8b3b429ac7..d010fb8d17 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileResultExecutorBase.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileResultExecutorBase.cs @@ -17,6 +17,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal { public class FileResultExecutorBase { + internal const string EnableRangeProcessingSwitch = "Switch.Microsoft.AspNetCore.Mvc.EnableRangeProcessing"; + private const string AcceptRangeHeaderValue = "bytes"; protected const int BufferSize = 64 * 1024; @@ -41,7 +43,8 @@ protected virtual (RangeItemHeaderValue range, long rangeLength, bool serveBody) FileResult result, long? fileLength, DateTimeOffset? lastModified = null, - EntityTagHeaderValue etag = null) + EntityTagHeaderValue etag = null, + bool enableRangeProcessing = true) { if (context == null) { @@ -84,19 +87,23 @@ protected virtual (RangeItemHeaderValue range, long rangeLength, bool serveBody) if (fileLength.HasValue) { - SetAcceptRangeHeader(context); // Assuming the request is not a range request, the Content-Length header is set to the length of the entire file. // If the request is a valid range request, this header is overwritten with the length of the range as part of the // range processing (see method SetContentLength). response.ContentLength = fileLength.Value; - if (HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method)) + + if (enableRangeProcessing) { - if ((preconditionState == PreconditionState.Unspecified || - preconditionState == PreconditionState.ShouldProcess)) + SetAcceptRangeHeader(context); + if (HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method)) { - if (IfRangeValid(context, httpRequestHeaders, lastModified, etag)) + if ((preconditionState == PreconditionState.Unspecified || + preconditionState == PreconditionState.ShouldProcess)) { - return SetRangeHeaders(context, httpRequestHeaders, fileLength.Value); + if (IfRangeValid(context, httpRequestHeaders, lastModified, etag)) + { + return SetRangeHeaders(context, httpRequestHeaders, fileLength.Value); + } } } } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileStreamResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileStreamResultExecutor.cs index 2182e4b617..ffd56aca01 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileStreamResultExecutor.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileStreamResultExecutor.cs @@ -33,12 +33,14 @@ public virtual Task ExecuteAsync(ActionContext context, FileStreamResult result) fileLength = result.FileStream.Length; } + AppContext.TryGetSwitch(EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch); var (range, rangeLength, serveBody) = SetHeadersAndLog( context, result, fileLength, result.LastModified, - result.EntityTag); + result.EntityTag, + enableRangeProcessingSwitch); if (!serveBody) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Mvc.Core/Properties/AssemblyInfo.cs index 18b9d45ba6..723a414854 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Properties/AssemblyInfo.cs @@ -4,4 +4,5 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Core.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileContentResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileContentResultTest.cs index 64977aaee5..4127d3b875 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileContentResultTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileContentResultTest.cs @@ -99,7 +99,7 @@ public async Task WriteFileAsync_CopiesBuffer_ToOutputStream() [InlineData(6, 10, "World", 5)] [InlineData(null, 5, "World", 5)] [InlineData(6, null, "World", 5)] - public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) + public async Task WriteFileAsync_PreconditionStateShouldProcess_RangeRequestIgnored_WritesRangeRequested_IfRangeProcessingOn(long? start, long? end, string expectedString, long contentLength) { // Arrange var contentType = "text/plain"; @@ -134,18 +134,29 @@ public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeReque httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; - Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); - var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, byteArray.Length); - Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); - Assert.Equal(contentLength, httpResponse.ContentLength); - Assert.Equal(expectedString, body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); + var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, byteArray.Length); + Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); + Assert.Equal(contentLength, httpResponse.ContentLength); + Assert.Equal(expectedString, body); + } + else + { + Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); + Assert.Equal(11, httpResponse.ContentLength); + Assert.Equal("Hello World", body); + } } [Fact] - public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest_IfRangeProcessingOn() { // Arrange var contentType = "text/plain"; @@ -179,18 +190,29 @@ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; - Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); - var contentRange = new ContentRangeHeaderValue(0, 4, byteArray.Length); - Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); - Assert.Equal(5, httpResponse.ContentLength); - Assert.Equal("Hello", body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); + var contentRange = new ContentRangeHeaderValue(0, 4, byteArray.Length); + Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); + Assert.Equal(5, httpResponse.ContentLength); + Assert.Equal("Hello", body); + } + else + { + Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); + Assert.Equal(11, httpResponse.ContentLength); + Assert.Equal("Hello World", body); + } } [Fact] - public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() + public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored() { // Arrange var contentType = "text/plain"; @@ -225,7 +247,6 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); Assert.Equal("Hello World", body); @@ -265,7 +286,6 @@ public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnore var body = streamReader.ReadToEndAsync().Result; Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); Assert.Equal("Hello World", body); @@ -303,16 +323,26 @@ public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotS var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; var contentRange = new ContentRangeHeaderValue(byteArray.Length); - Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); - Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); - Assert.Empty(body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); + Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); + Assert.Empty(body); + } + else + { + Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); + Assert.Equal("Hello World", body); + } } [Fact] - public async Task WriteFileAsync_RangeRequested_PreconditionFailed() + public async Task WriteFileAsync_PreconditionFailed() { // Arrange var contentType = "text/plain"; @@ -346,7 +376,6 @@ public async Task WriteFileAsync_RangeRequested_PreconditionFailed() var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; Assert.Equal(StatusCodes.Status412PreconditionFailed, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(11, httpResponse.ContentLength); Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]); Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]); @@ -354,7 +383,7 @@ public async Task WriteFileAsync_RangeRequested_PreconditionFailed() } [Fact] - public async Task WriteFileAsync_RangeRequested_NotModified() + public async Task WriteFileAsync_NotModified() { // Arrange var contentType = "text/plain"; @@ -388,7 +417,6 @@ public async Task WriteFileAsync_RangeRequested_NotModified() var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; Assert.Equal(StatusCodes.Status304NotModified, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(11, httpResponse.ContentLength); Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]); Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileStreamResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileStreamResultTest.cs index e4b342b782..7677676cef 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileStreamResultTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileStreamResultTest.cs @@ -80,7 +80,7 @@ public void Constructor_SetsLastModifiedAndEtag() [InlineData(6, 10, "World", 5)] [InlineData(null, 5, "World", 5)] [InlineData(6, null, "World", 5)] - public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) + public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested_IfRangeProcessingOn(long? start, long? end, string expectedString, long contentLength) { // Arrange var contentType = "text/plain"; @@ -118,17 +118,27 @@ public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeReque var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, byteArray.Length); - Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); - Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); - Assert.Equal(contentLength, httpResponse.ContentLength); - Assert.Equal(expectedString, body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); + Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); + Assert.Equal(contentLength, httpResponse.ContentLength); + Assert.Equal(expectedString, body); + } + else + { + Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); + Assert.Equal("Hello World", body); + } } [Fact] - public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange_IfRangeProcessingOn() { // Arrange var contentType = "text/plain"; @@ -164,14 +174,24 @@ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; - Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); - var contentRange = new ContentRangeHeaderValue(0, 4, byteArray.Length); - Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); - Assert.Equal(5, httpResponse.ContentLength); - Assert.Equal("Hello", body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + var contentRange = new ContentRangeHeaderValue(0, 4, byteArray.Length); + Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); + Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); + Assert.Equal(5, httpResponse.ContentLength); + Assert.Equal("Hello", body); + } + else + { + Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); + Assert.Equal("Hello World", body); + } } [Fact] @@ -253,7 +273,6 @@ public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnore var body = streamReader.ReadToEndAsync().Result; Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); Assert.Equal("Hello World", body); @@ -292,12 +311,23 @@ public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotS var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; var contentRange = new ContentRangeHeaderValue(byteArray.Length); - Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); - Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); - Assert.Empty(body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); + Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); + Assert.Equal(11, httpResponse.ContentLength); + Assert.Empty(body); + } + else + { + Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); + Assert.Equal("Hello World", body); + } } [Fact] @@ -336,7 +366,6 @@ public async Task WriteFileAsync_RangeRequested_PreconditionFailed() var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; Assert.Equal(StatusCodes.Status412PreconditionFailed, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(11, httpResponse.ContentLength); Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]); Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]); @@ -379,7 +408,6 @@ public async Task WriteFileAsync_RangeRequested_NotModified() var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; Assert.Equal(StatusCodes.Status304NotModified, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(11, httpResponse.ContentLength); Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]); Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]); @@ -424,14 +452,23 @@ public async Task WriteFileAsync_RangeRequested_FileLengthZeroOrNull(long? fileL httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; - - var contentRange = new ContentRangeHeaderValue(byteArray.Length); - Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); - Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); - Assert.Empty(body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + var contentRange = new ContentRangeHeaderValue(byteArray.Length); + Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); + Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); + Assert.Empty(body); + } + else + { + Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); + Assert.Empty(body); + } } [Fact] diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FileResultTests.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FileResultTests.cs index b631f22490..383e081609 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FileResultTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FileResultTests.cs @@ -2,11 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -259,12 +259,22 @@ public async Task FileFromStream_ReturnsFile_RangeRequest(long start, long end, var response = await Client.SendAsync(httpRequestMessage); // Assert - Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode); Assert.NotNull(response.Content.Headers.ContentType); Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString()); var body = await response.Content.ReadAsStringAsync(); Assert.NotNull(body); - Assert.Equal(expectedBody, body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode); + Assert.Equal(expectedBody, body); + } + else + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("This is sample text from a stream", body); + } } [Theory] @@ -301,11 +311,21 @@ public async Task FileFromStream_ReturnsFile_RangeRequestNotSatisfiable(string r var response = await Client.SendAsync(httpRequestMessage); // Assert - Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode); - Assert.NotNull(response.Content.Headers.ContentType); - Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString()); var body = await response.Content.ReadAsStringAsync(); - Assert.Empty(body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode); + Assert.NotNull(response.Content.Headers.ContentType); + Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString()); + Assert.Empty(body); + } + else + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("This is sample text from a stream", body); + } } [Fact] @@ -341,12 +361,23 @@ public async Task FileFromStream_ReturnsFileWithFileName_IfRangeHeaderValid_Rang var response = await Client.SendAsync(httpRequestMessage); // Assert - Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode); Assert.NotNull(response.Content.Headers.ContentType); Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString()); var body = await response.Content.ReadAsStringAsync(); Assert.NotNull(body); - Assert.Equal("This is", body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode); + Assert.Equal("This is", body); + } + + else + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("This is sample text from a stream", body); + } } [Fact] @@ -361,10 +392,8 @@ public async Task FileFromStream_ReturnsFileWithFileName_IfRangeHeaderInvalid_Ra var response = await Client.SendAsync(httpRequestMessage); // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content.Headers.ContentType); - Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString()); var body = await response.Content.ReadAsStringAsync(); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("This is sample text from a stream", body); } @@ -399,12 +428,22 @@ public async Task FileFromBinaryData_ReturnsFile_RangeRequest(long start, long e var response = await Client.SendAsync(httpRequestMessage); // Assert - Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode); Assert.NotNull(response.Content.Headers.ContentType); Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString()); var body = await response.Content.ReadAsStringAsync(); Assert.NotNull(body); - Assert.Equal(expectedBody, body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode); + Assert.Equal(expectedBody, body); + } + else + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("This is a sample text from a binary array", body); + } } [Theory] @@ -441,11 +480,24 @@ public async Task FileFromBinaryData_ReturnsFile_RangeRequestNotSatisfiable(stri var response = await Client.SendAsync(httpRequestMessage); // Assert - Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode); Assert.NotNull(response.Content.Headers.ContentType); Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString()); var body = await response.Content.ReadAsStringAsync(); - Assert.Empty(body); + Assert.NotNull(body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode); + Assert.NotNull(response.Content.Headers.ContentType); + Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString()); + Assert.Empty(body); + } + else + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("This is a sample text from a binary array", body); + } } [Fact] @@ -470,7 +522,7 @@ public async Task FileFromBinaryData_ReturnsFileWithFileName() } [Fact] - public async Task FileFromBinaryData_ReturnsFileWithFileName_IfRangeHeaderValid_RangeRequest() + public async Task FileFromBinaryData_ReturnsFileWithFileName_IfRangeHeaderValid() { // Arrange var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromBinaryDataWithFileName_WithEtag"); @@ -480,13 +532,23 @@ public async Task FileFromBinaryData_ReturnsFileWithFileName_IfRangeHeaderValid_ // Act var response = await Client.SendAsync(httpRequestMessage); - // Assert - Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode); + // Assert Assert.NotNull(response.Content.Headers.ContentType); Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString()); var body = await response.Content.ReadAsStringAsync(); Assert.NotNull(body); - Assert.Equal("This is", body); + + if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) + && enableRangeProcessingSwitch) + { + Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode); + Assert.Equal("This is", body); + } + else + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("This is a sample text from a binary array", body); + } } [Fact]