diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs b/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs
index ec3f58a6e8..faac451c28 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs
@@ -1088,6 +1088,20 @@ namespace Microsoft.AspNetCore.Mvc
public virtual FileContentResult File(byte[] fileContents, string contentType)
=> File(fileContents, contentType, fileDownloadName: null);
+ ///
+ /// Returns a file with the specified as content (),
+ /// and the specified as the Content-Type.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The file contents.
+ /// The Content-Type of the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual FileContentResult File(byte[] fileContents, string contentType, bool enableRangeProcessing)
+ => File(fileContents, contentType, fileDownloadName: null, enableRangeProcessing: enableRangeProcessing);
+
///
/// Returns a file with the specified as content (), the
/// specified as the Content-Type and the specified as the suggested file name.
@@ -1102,6 +1116,25 @@ namespace Microsoft.AspNetCore.Mvc
public virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName)
=> new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName };
+ ///
+ /// Returns a file with the specified as content (), the
+ /// specified as the Content-Type and the specified as the suggested file name.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The file contents.
+ /// The Content-Type of the file.
+ /// The suggested file name.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName, bool enableRangeProcessing)
+ => new FileContentResult(fileContents, contentType)
+ {
+ FileDownloadName = fileDownloadName,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+
///
/// Returns a file with the specified as content (),
/// and the specified as the Content-Type.
@@ -1123,6 +1156,29 @@ namespace Microsoft.AspNetCore.Mvc
};
}
+ ///
+ /// Returns a file with the specified as content (),
+ /// and the specified as the Content-Type.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The file contents.
+ /// The Content-Type of the file.
+ /// The of when the file was last modified.
+ /// The associated with the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual FileContentResult File(byte[] fileContents, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
+ {
+ return new FileContentResult(fileContents, contentType)
+ {
+ LastModified = lastModified,
+ EntityTag = entityTag,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+ }
+
///
/// Returns a file with the specified as content (), the
/// specified as the Content-Type, and the specified as the suggested file name.
@@ -1146,6 +1202,31 @@ namespace Microsoft.AspNetCore.Mvc
};
}
+ ///
+ /// Returns a file with the specified as content (), the
+ /// specified as the Content-Type, and the specified as the suggested file name.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The file contents.
+ /// The Content-Type of the file.
+ /// The suggested file name.
+ /// The of when the file was last modified.
+ /// The associated with the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
+ {
+ return new FileContentResult(fileContents, contentType)
+ {
+ LastModified = lastModified,
+ EntityTag = entityTag,
+ FileDownloadName = fileDownloadName,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+ }
+
///
/// Returns a file in the specified (), with the
/// specified as the Content-Type.
@@ -1159,6 +1240,20 @@ namespace Microsoft.AspNetCore.Mvc
public virtual FileStreamResult File(Stream fileStream, string contentType)
=> File(fileStream, contentType, fileDownloadName: null);
+ ///
+ /// Returns a file in the specified (), with the
+ /// specified as the Content-Type.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The with the contents of the file.
+ /// The Content-Type of the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual FileStreamResult File(Stream fileStream, string contentType, bool enableRangeProcessing)
+ => File(fileStream, contentType, fileDownloadName: null, enableRangeProcessing: enableRangeProcessing);
+
///
/// Returns a file in the specified () with the
/// specified as the Content-Type and the
@@ -1174,6 +1269,26 @@ namespace Microsoft.AspNetCore.Mvc
public virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName)
=> new FileStreamResult(fileStream, contentType) { FileDownloadName = fileDownloadName };
+ ///
+ /// Returns a file in the specified () with the
+ /// specified as the Content-Type and the
+ /// specified as the suggested file name.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The with the contents of the file.
+ /// The Content-Type of the file.
+ /// The suggested file name.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName, bool enableRangeProcessing)
+ => new FileStreamResult(fileStream, contentType)
+ {
+ FileDownloadName = fileDownloadName,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+
///
/// Returns a file in the specified (),
/// and the specified as the Content-Type.
@@ -1195,6 +1310,29 @@ namespace Microsoft.AspNetCore.Mvc
};
}
+ ///
+ /// Returns a file in the specified (),
+ /// and the specified as the Content-Type.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The with the contents of the file.
+ /// The Content-Type of the file.
+ /// The of when the file was last modified.
+ /// The associated with the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual FileStreamResult File(Stream fileStream, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
+ {
+ return new FileStreamResult(fileStream, contentType)
+ {
+ LastModified = lastModified,
+ EntityTag = entityTag,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+ }
+
///
/// Returns a file in the specified (), the
/// specified as the Content-Type, and the specified as the suggested file name.
@@ -1218,6 +1356,31 @@ namespace Microsoft.AspNetCore.Mvc
};
}
+ ///
+ /// Returns a file in the specified (), the
+ /// specified as the Content-Type, and the specified as the suggested file name.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The with the contents of the file.
+ /// The Content-Type of the file.
+ /// The suggested file name.
+ /// The of when the file was last modified.
+ /// The associated with the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
+ {
+ return new FileStreamResult(fileStream, contentType)
+ {
+ LastModified = lastModified,
+ EntityTag = entityTag,
+ FileDownloadName = fileDownloadName,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+ }
+
///
/// Returns the file specified by () with the
/// specified as the Content-Type.
@@ -1231,6 +1394,20 @@ namespace Microsoft.AspNetCore.Mvc
public virtual VirtualFileResult File(string virtualPath, string contentType)
=> File(virtualPath, contentType, fileDownloadName: null);
+ ///
+ /// Returns the file specified by () with the
+ /// specified as the Content-Type.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The virtual path of the file to be returned.
+ /// The Content-Type of the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual VirtualFileResult File(string virtualPath, string contentType, bool enableRangeProcessing)
+ => File(virtualPath, contentType, fileDownloadName: null, enableRangeProcessing: enableRangeProcessing);
+
///
/// Returns the file specified by () with the
/// specified as the Content-Type and the
@@ -1246,6 +1423,26 @@ namespace Microsoft.AspNetCore.Mvc
public virtual VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName)
=> new VirtualFileResult(virtualPath, contentType) { FileDownloadName = fileDownloadName };
+ ///
+ /// Returns the file specified by () with the
+ /// specified as the Content-Type and the
+ /// specified as the suggested file name.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The virtual path of the file to be returned.
+ /// The Content-Type of the file.
+ /// The suggested file name.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName, bool enableRangeProcessing)
+ => new VirtualFileResult(virtualPath, contentType)
+ {
+ FileDownloadName = fileDownloadName,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+
///
/// Returns the file specified by (), and the
/// specified as the Content-Type.
@@ -1267,6 +1464,29 @@ namespace Microsoft.AspNetCore.Mvc
};
}
+ ///
+ /// Returns the file specified by (), and the
+ /// specified as the Content-Type.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The virtual path of the file to be returned.
+ /// The Content-Type of the file.
+ /// The of when the file was last modified.
+ /// The associated with the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual VirtualFileResult File(string virtualPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
+ {
+ return new VirtualFileResult(virtualPath, contentType)
+ {
+ LastModified = lastModified,
+ EntityTag = entityTag,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+ }
+
///
/// Returns the file specified by (), the
/// specified as the Content-Type, and the specified as the suggested file name.
@@ -1290,6 +1510,31 @@ namespace Microsoft.AspNetCore.Mvc
};
}
+ ///
+ /// Returns the file specified by (), the
+ /// specified as the Content-Type, and the specified as the suggested file name.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The virtual path of the file to be returned.
+ /// The Content-Type of the file.
+ /// The suggested file name.
+ /// The of when the file was last modified.
+ /// The associated with the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
+ {
+ return new VirtualFileResult(virtualPath, contentType)
+ {
+ LastModified = lastModified,
+ EntityTag = entityTag,
+ FileDownloadName = fileDownloadName,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+ }
+
///
/// Returns the file specified by () with the
/// specified as the Content-Type.
@@ -1303,6 +1548,20 @@ namespace Microsoft.AspNetCore.Mvc
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType)
=> PhysicalFile(physicalPath, contentType, fileDownloadName: null);
+ ///
+ /// Returns the file specified by () with the
+ /// specified as the Content-Type.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The physical path of the file to be returned.
+ /// The Content-Type of the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, bool enableRangeProcessing)
+ => PhysicalFile(physicalPath, contentType, fileDownloadName: null, enableRangeProcessing: enableRangeProcessing);
+
///
/// Returns the file specified by () with the
/// specified as the Content-Type and the
@@ -1321,6 +1580,30 @@ namespace Microsoft.AspNetCore.Mvc
string fileDownloadName)
=> new PhysicalFileResult(physicalPath, contentType) { FileDownloadName = fileDownloadName };
+ ///
+ /// Returns the file specified by () with the
+ /// specified as the Content-Type and the
+ /// specified as the suggested file name.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The physical path of the file to be returned.
+ /// The Content-Type of the file.
+ /// The suggested file name.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual PhysicalFileResult PhysicalFile(
+ string physicalPath,
+ string contentType,
+ string fileDownloadName,
+ bool enableRangeProcessing)
+ => new PhysicalFileResult(physicalPath, contentType)
+ {
+ FileDownloadName = fileDownloadName,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+
///
/// Returns the file specified by (), and
/// the specified as the Content-Type.
@@ -1342,6 +1625,29 @@ namespace Microsoft.AspNetCore.Mvc
};
}
+ ///
+ /// Returns the file specified by (), and
+ /// the specified as the Content-Type.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The physical path of the file to be returned.
+ /// The Content-Type of the file.
+ /// The of when the file was last modified.
+ /// The associated with the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
+ {
+ return new PhysicalFileResult(physicalPath, contentType)
+ {
+ LastModified = lastModified,
+ EntityTag = entityTag,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+ }
+
///
/// Returns the file specified by (), the
/// specified as the Content-Type, and the specified as the suggested file name.
@@ -1365,6 +1671,31 @@ namespace Microsoft.AspNetCore.Mvc
};
}
+ ///
+ /// Returns the file specified by (), the
+ /// specified as the Content-Type, and the specified as the suggested file name.
+ /// This supports range requests ( or
+ /// if the range is not satisfiable).
+ ///
+ /// The physical path of the file to be returned.
+ /// The Content-Type of the file.
+ /// The suggested file name.
+ /// The of when the file was last modified.
+ /// The associated with the file.
+ /// Set to true to enable range requests processing.
+ /// The created for the response.
+ [NonAction]
+ public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
+ {
+ return new PhysicalFileResult(physicalPath, contentType)
+ {
+ LastModified = lastModified,
+ EntityTag = entityTag,
+ FileDownloadName = fileDownloadName,
+ EnableRangeProcessing = enableRangeProcessing,
+ };
+ }
+
///
/// Creates an that produces an response.
///
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/FileResult.cs b/src/Microsoft.AspNetCore.Mvc.Core/FileResult.cs
index dea1dff3e3..6b3b7743f2 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/FileResult.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/FileResult.cs
@@ -52,5 +52,10 @@ namespace Microsoft.AspNetCore.Mvc
/// Gets or sets the etag associated with the .
///
public EntityTagHeaderValue EntityTag { get; set; }
+
+ ///
+ /// Gets or sets the value that enables range processing for the .
+ ///
+ public bool EnableRangeProcessing { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileContentResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileContentResultExecutor.cs
index af8cfe17cf..0739c522d4 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileContentResultExecutor.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileContentResultExecutor.cs
@@ -33,6 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
context,
result,
result.FileContents.Length,
+ result.EnableRangeProcessing,
result.LastModified,
result.EntityTag);
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileResultExecutorBase.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileResultExecutorBase.cs
index 8e2a9e6b80..6bd8939bc7 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileResultExecutorBase.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileResultExecutorBase.cs
@@ -41,6 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
ActionContext context,
FileResult result,
long? fileLength,
+ bool enableRangeProcessing,
DateTimeOffset? lastModified = null,
EntityTagHeaderValue etag = null)
{
@@ -59,54 +60,55 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
var request = context.HttpContext.Request;
var httpRequestHeaders = request.GetTypedHeaders();
+ var preconditionState = GetPreconditionState(httpRequestHeaders, lastModified, etag);
+
var response = context.HttpContext.Response;
- var httpResponseHeaders = response.GetTypedHeaders();
- if (lastModified.HasValue)
- {
- httpResponseHeaders.LastModified = lastModified;
- }
- if (etag != null)
- {
- httpResponseHeaders.ETag = etag;
- }
+ SetLastModifiedAndEtagHeaders(response, lastModified, etag);
var serveBody = !HttpMethods.IsHead(request.Method);
- var preconditionState = GetPreconditionState(context, httpRequestHeaders, lastModified, etag);
+
+ // Short circuit if the preconditional headers process to 304 (NotModified) or 412 (PreconditionFailed)
if (preconditionState == PreconditionState.NotModified)
{
serveBody = false;
response.StatusCode = StatusCodes.Status304NotModified;
+ return (range: null, rangeLength: 0, serveBody);
}
else if (preconditionState == PreconditionState.PreconditionFailed)
{
serveBody = false;
response.StatusCode = StatusCodes.Status412PreconditionFailed;
+ return (range: null, rangeLength: 0, 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.
+ // Assuming the request is not a range request, and the response body is not empty, 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).
if (serveBody)
{
response.ContentLength = fileLength.Value;
}
- if (HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method))
+
+ // Handle range request
+ if (enableRangeProcessing)
{
- if ((preconditionState == PreconditionState.Unspecified ||
- preconditionState == PreconditionState.ShouldProcess))
+ SetAcceptRangeHeader(response);
+
+ // If the request method is HEAD or GET, PreconditionState is Unspecified or ShouldProcess, and IfRange header is valid,
+ // range should be processed and Range headers should be set
+ if ((HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method))
+ && (preconditionState == PreconditionState.Unspecified || preconditionState == PreconditionState.ShouldProcess)
+ && (IfRangeValid(httpRequestHeaders, lastModified, etag)))
{
- if (IfRangeValid(context, httpRequestHeaders, lastModified, etag))
- {
- return SetRangeHeaders(context, httpRequestHeaders, fileLength.Value);
- }
+ return SetRangeHeaders(context, httpRequestHeaders, fileLength.Value);
}
}
}
- return (range: null, rangeLength: 0, serveBody: serveBody);
+ return (range: null, rangeLength: 0, serveBody);
}
private static void SetContentType(ActionContext context, FileResult result)
@@ -130,38 +132,25 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
}
}
- private static void SetAcceptRangeHeader(ActionContext context)
+ private static void SetLastModifiedAndEtagHeaders(HttpResponse response, DateTimeOffset? lastModified, EntityTagHeaderValue etag)
+ {
+ var httpResponseHeaders = response.GetTypedHeaders();
+ if (lastModified.HasValue)
+ {
+ httpResponseHeaders.LastModified = lastModified;
+ }
+ if (etag != null)
+ {
+ httpResponseHeaders.ETag = etag;
+ }
+ }
+
+ private static void SetAcceptRangeHeader(HttpResponse response)
{
- var response = context.HttpContext.Response;
response.Headers[HeaderNames.AcceptRanges] = AcceptRangeHeaderValue;
}
- private static PreconditionState GetEtagMatchState(
- IList etagHeader,
- EntityTagHeaderValue etag,
- PreconditionState matchFoundState,
- PreconditionState matchNotFoundState)
- {
- if (etagHeader != null && etagHeader.Any())
- {
- var state = matchNotFoundState;
- foreach (var entityTag in etagHeader)
- {
- if (entityTag.Equals(EntityTagHeaderValue.Any) || entityTag.Compare(etag, useStrongComparison: true))
- {
- state = matchFoundState;
- break;
- }
- }
-
- return state;
- }
-
- return PreconditionState.Unspecified;
- }
-
internal static bool IfRangeValid(
- ActionContext context,
RequestHeaders httpRequestHeaders,
DateTimeOffset? lastModified = null,
EntityTagHeaderValue etag = null)
@@ -193,7 +182,6 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
// Internal for testing
internal static PreconditionState GetPreconditionState(
- ActionContext context,
RequestHeaders httpRequestHeaders,
DateTimeOffset? lastModified = null,
EntityTagHeaderValue etag = null)
@@ -247,6 +235,30 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
return state;
}
+ private static PreconditionState GetEtagMatchState(
+ IList etagHeader,
+ EntityTagHeaderValue etag,
+ PreconditionState matchFoundState,
+ PreconditionState matchNotFoundState)
+ {
+ if (etagHeader != null && etagHeader.Any())
+ {
+ var state = matchNotFoundState;
+ foreach (var entityTag in etagHeader)
+ {
+ if (entityTag.Equals(EntityTagHeaderValue.Any) || entityTag.Compare(etag, useStrongComparison: true))
+ {
+ state = matchFoundState;
+ break;
+ }
+ }
+
+ return state;
+ }
+
+ return PreconditionState.Unspecified;
+ }
+
private static PreconditionState GetMaxPreconditionState(params PreconditionState[] states)
{
var max = PreconditionState.Unspecified;
@@ -281,6 +293,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
return (range: null, rangeLength: 0, serveBody: true);
}
+ // Requested range is not satisfiable
if (range == null)
{
// 14.16 Content-Range - A server sending a response with status code 416 (Requested range not satisfiable)
@@ -292,23 +305,23 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
return (range: null, rangeLength: 0, serveBody: false);
}
+ response.StatusCode = StatusCodes.Status206PartialContent;
httpResponseHeaders.ContentRange = new ContentRangeHeaderValue(
range.From.Value,
range.To.Value,
fileLength);
- response.StatusCode = StatusCodes.Status206PartialContent;
// Overwrite the Content-Length header for valid range requests with the range length.
- var rangeLength = SetContentLength(context, range);
+ var rangeLength = SetContentLength(response, range);
+
return (range, rangeLength, serveBody: true);
}
- private static long SetContentLength(ActionContext context, RangeItemHeaderValue range)
+ private static long SetContentLength(HttpResponse response, RangeItemHeaderValue range)
{
var start = range.From.Value;
var end = range.To.Value;
var length = end - start + 1;
- var response = context.HttpContext.Response;
response.ContentLength = length;
return length;
}
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileStreamResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileStreamResultExecutor.cs
index 97bda5988f..72a4d53cb5 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileStreamResultExecutor.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileStreamResultExecutor.cs
@@ -38,6 +38,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
context,
result,
fileLength,
+ result.EnableRangeProcessing,
result.LastModified,
result.EntityTag);
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/PhysicalFileResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/PhysicalFileResultExecutor.cs
index c2ea1a624d..e36d22a3d9 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/PhysicalFileResultExecutor.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/PhysicalFileResultExecutor.cs
@@ -44,6 +44,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
context,
result,
fileInfo.Length,
+ result.EnableRangeProcessing,
lastModified,
result.EntityTag);
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/VirtualFileResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/VirtualFileResultExecutor.cs
index 694b58e84a..42b0b2a669 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/VirtualFileResultExecutor.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/VirtualFileResultExecutor.cs
@@ -14,7 +14,7 @@ using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Mvc.Infrastructure
{
- public class VirtualFileResultExecutor : FileResultExecutorBase , IActionResultExecutor
+ public class VirtualFileResultExecutor : FileResultExecutorBase, IActionResultExecutor
{
private readonly IHostingEnvironment _hostingEnvironment;
@@ -54,6 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
context,
result,
fileInfo.Length,
+ result.EnableRangeProcessing,
lastModified,
result.EntityTag);
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs
index c2f10b2fc0..48afdc739f 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs
@@ -1632,14 +1632,33 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Same(fileContents, result.FileContents);
Assert.Equal("application/pdf", result.ContentType.ToString());
Assert.Equal(string.Empty, result.FileDownloadName);
+ Assert.False(result.EnableRangeProcessing);
+ }
+
+ [Fact]
+ public void File_WithContents_EnableRangeProcessing()
+ {
+ // Arrange
+ var controller = new TestableController();
+ var fileContents = new byte[0];
+
+ // Act
+ var result = controller.File(fileContents, "application/pdf", true);
+
+ // Assert
+ Assert.NotNull(result);
+ Assert.Same(fileContents, result.FileContents);
+ Assert.Equal("application/pdf", result.ContentType.ToString());
+ Assert.Equal(string.Empty, result.FileDownloadName);
+ Assert.True(result.EnableRangeProcessing);
}
[Theory]
- [InlineData(null, null)]
- [InlineData(null, "\"Etag\"")]
- [InlineData("05/01/2008 +1:00", null)]
- [InlineData("05/01/2008 +1:00", "\"Etag\"")]
- public void File_WithContents_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
+ [InlineData(null, null, false)]
+ [InlineData(null, "\"Etag\"", false)]
+ [InlineData("05/01/2008 +1:00", null, true)]
+ [InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
+ public void File_WithContents_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
{
// Arrange
var controller = new TestableController();
@@ -1648,7 +1667,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
// Act
- var result = controller.File(fileContents, "application/pdf", lastModified, entityTag);
+ var result = controller.File(fileContents, "application/pdf", lastModified, entityTag, enableRangeProcessing);
// Assert
Assert.NotNull(result);
@@ -1657,6 +1676,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Equal(string.Empty, result.FileDownloadName);
Assert.Equal(lastModified, result.LastModified);
Assert.Equal(entityTag, result.EntityTag);
+ Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
}
[Fact]
@@ -1674,14 +1694,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Same(fileContents, result.FileContents);
Assert.Equal("application/pdf", result.ContentType.ToString());
Assert.Equal("someDownloadName", result.FileDownloadName);
+ Assert.False(result.EnableRangeProcessing);
}
[Theory]
- [InlineData(null, null)]
- [InlineData(null, "\"Etag\"")]
- [InlineData("05/01/2008 +1:00", null)]
- [InlineData("05/01/2008 +1:00", "\"Etag\"")]
- public void File_WithContentsAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
+ [InlineData(null, null, false)]
+ [InlineData(null, "\"Etag\"", false)]
+ [InlineData("05/01/2008 +1:00", null, true)]
+ [InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
+ public void File_WithContentsAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
{
// Arrange
var controller = new TestableController();
@@ -1690,7 +1711,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
// Act
- var result = controller.File(fileContents, "application/pdf", "someDownloadName", lastModified, entityTag);
+ var result = controller.File(fileContents, "application/pdf", "someDownloadName", lastModified, entityTag, enableRangeProcessing);
// Assert
Assert.NotNull(result);
@@ -1699,6 +1720,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Equal("someDownloadName", result.FileDownloadName);
Assert.Equal(lastModified, result.LastModified);
Assert.Equal(entityTag, result.EntityTag);
+ Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
}
[Fact]
@@ -1716,14 +1738,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Equal(path, result.FileName);
Assert.Equal("application/pdf", result.ContentType.ToString());
Assert.Equal(string.Empty, result.FileDownloadName);
+ Assert.False(result.EnableRangeProcessing);
}
[Theory]
- [InlineData(null, null)]
- [InlineData(null, "\"Etag\"")]
- [InlineData("05/01/2008 +1:00", null)]
- [InlineData("05/01/2008 +1:00", "\"Etag\"")]
- public void File_WithPath_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
+ [InlineData(null, null, false)]
+ [InlineData(null, "\"Etag\"", false)]
+ [InlineData("05/01/2008 +1:00", null, true)]
+ [InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
+ public void File_WithPath_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
{
// Arrange
var controller = new TestableController();
@@ -1732,7 +1755,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
// Act
- var result = controller.File(path, "application/pdf", lastModified, entityTag);
+ var result = controller.File(path, "application/pdf", lastModified, entityTag, enableRangeProcessing);
// Assert
Assert.NotNull(result);
@@ -1741,6 +1764,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Equal(string.Empty, result.FileDownloadName);
Assert.Equal(lastModified, result.LastModified);
Assert.Equal(entityTag, result.EntityTag);
+ Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
}
[Fact]
@@ -1758,14 +1782,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Equal(path, result.FileName);
Assert.Equal("application/pdf", result.ContentType.ToString());
Assert.Equal("someDownloadName", result.FileDownloadName);
+ Assert.False(result.EnableRangeProcessing);
}
[Theory]
- [InlineData(null, null)]
- [InlineData(null, "\"Etag\"")]
- [InlineData("05/01/2008 +1:00", null)]
- [InlineData("05/01/2008 +1:00", "\"Etag\"")]
- public void File_WithPathAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
+ [InlineData(null, null, false)]
+ [InlineData(null, "\"Etag\"", false)]
+ [InlineData("05/01/2008 +1:00", null, true)]
+ [InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
+ public void File_WithPathAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
{
// Arrange
var controller = new TestableController();
@@ -1774,7 +1799,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
// Act
- var result = controller.File(path, "application/pdf", "someDownloadName", lastModified, entityTag);
+ var result = controller.File(path, "application/pdf", "someDownloadName", lastModified, entityTag, enableRangeProcessing);
// Assert
Assert.NotNull(result);
@@ -1783,6 +1808,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Equal("someDownloadName", result.FileDownloadName);
Assert.Equal(lastModified, result.LastModified);
Assert.Equal(entityTag, result.EntityTag);
+ Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
}
[Fact]
@@ -1805,14 +1831,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Same(fileStream, result.FileStream);
Assert.Equal("application/pdf", result.ContentType.ToString());
Assert.Equal(string.Empty, result.FileDownloadName);
+ Assert.False(result.EnableRangeProcessing);
}
[Theory]
- [InlineData(null, null)]
- [InlineData(null, "\"Etag\"")]
- [InlineData("05/01/2008 +1:00", null)]
- [InlineData("05/01/2008 +1:00", "\"Etag\"")]
- public void File_WithStream_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
+ [InlineData(null, null, false)]
+ [InlineData(null, "\"Etag\"", false)]
+ [InlineData("05/01/2008 +1:00", null, true)]
+ [InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
+ public void File_WithStream_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
{
// Arrange
var mockHttpContext = new Mock();
@@ -1826,7 +1853,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
// Act
- var result = controller.File(fileStream, "application/pdf", lastModified, entityTag);
+ var result = controller.File(fileStream, "application/pdf", lastModified, entityTag, enableRangeProcessing);
// Assert
Assert.NotNull(result);
@@ -1835,6 +1862,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Equal(string.Empty, result.FileDownloadName);
Assert.Equal(lastModified, result.LastModified);
Assert.Equal(entityTag, result.EntityTag);
+ Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
}
[Fact]
@@ -1856,14 +1884,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Same(fileStream, result.FileStream);
Assert.Equal("application/pdf", result.ContentType.ToString());
Assert.Equal("someDownloadName", result.FileDownloadName);
+ Assert.False(result.EnableRangeProcessing);
}
[Theory]
- [InlineData(null, null)]
- [InlineData(null, "\"Etag\"")]
- [InlineData("05/01/2008 +1:00", null)]
- [InlineData("05/01/2008 +1:00", "\"Etag\"")]
- public void File_WithStreamAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
+ [InlineData(null, null, false)]
+ [InlineData(null, "\"Etag\"", false)]
+ [InlineData("05/01/2008 +1:00", null, true)]
+ [InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
+ public void File_WithStreamAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
{
// Arrange
var mockHttpContext = new Mock();
@@ -1876,7 +1905,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
// Act
- var result = controller.File(fileStream, "application/pdf", "someDownloadName", lastModified, entityTag);
+ var result = controller.File(fileStream, "application/pdf", "someDownloadName", lastModified, entityTag, enableRangeProcessing);
// Assert
Assert.NotNull(result);
@@ -1885,6 +1914,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Equal("someDownloadName", result.FileDownloadName);
Assert.Equal(lastModified, result.LastModified);
Assert.Equal(entityTag, result.EntityTag);
+ Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
}
[Fact]
@@ -2738,7 +2768,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
var controller = new TestableController();
// Act
- var result = controller.RedirectToPage("page", "handler", new { test = "value"});
+ var result = controller.RedirectToPage("page", "handler", new { test = "value" });
// Assert
Assert.Equal("page", result.PageName);
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileContentResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileContentResultTest.cs
index ff0ee343cf..e2d0dd087d 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileContentResultTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileContentResultTest.cs
@@ -8,7 +8,6 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
-using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.TestCommon;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
@@ -111,7 +110,8 @@ namespace Microsoft.AspNetCore.Mvc
var result = new FileContentResult(byteArray, contentType)
{
LastModified = lastModified,
- EntityTag = entityTag
+ EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -135,18 +135,18 @@ namespace Microsoft.AspNetCore.Mvc
httpResponse.Body.Seek(0, SeekOrigin.Begin);
var streamReader = new StreamReader(httpResponse.Body);
var body = streamReader.ReadToEndAsync().Result;
+ Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
+ Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
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);
}
[Fact]
- public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange()
+ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest()
{
// Arrange
var contentType = "text/plain";
@@ -157,7 +157,8 @@ namespace Microsoft.AspNetCore.Mvc
var result = new FileContentResult(byteArray, contentType)
{
LastModified = lastModified,
- EntityTag = entityTag
+ EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -180,18 +181,28 @@ namespace Microsoft.AspNetCore.Mvc
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 (result.EnableRangeProcessing)
+ {
+ 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_RangeProcessingNotEnabled_RangeRequestIgnored()
{
// Arrange
var contentType = "text/plain";
@@ -205,6 +216,48 @@ namespace Microsoft.AspNetCore.Mvc
EntityTag = entityTag
};
+ var httpContext = GetHttpContext();
+ var requestHeaders = httpContext.Request.GetTypedHeaders();
+ requestHeaders.IfMatch = new[]
+ {
+ new EntityTagHeaderValue("\"Etag\""),
+ };
+ requestHeaders.Range = new RangeHeaderValue(0, 4);
+ requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\""));
+ httpContext.Request.Method = HttpMethods.Get;
+ httpContext.Response.Body = new MemoryStream();
+ var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
+
+ // Act
+ await result.ExecuteResultAsync(actionContext);
+
+ // Assert
+ var httpResponse = actionContext.HttpContext.Response;
+ httpResponse.Body.Seek(0, SeekOrigin.Begin);
+ var streamReader = new StreamReader(httpResponse.Body);
+ var body = streamReader.ReadToEndAsync().Result;
+ Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
+ Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
+ Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
+ Assert.Equal("Hello World", body);
+ }
+
+ [Fact]
+ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored()
+ {
+ // Arrange
+ var contentType = "text/plain";
+ var lastModified = DateTimeOffset.MinValue.AddDays(1);
+ var entityTag = new EntityTagHeaderValue("\"Etag\"");
+ var byteArray = Encoding.ASCII.GetBytes("Hello World");
+
+ var result = new FileContentResult(byteArray, contentType)
+ {
+ LastModified = lastModified,
+ EntityTag = entityTag,
+ EnableRangeProcessing = true,
+ };
+
var httpContext = GetHttpContext();
var requestHeaders = httpContext.Request.GetTypedHeaders();
requestHeaders.IfMatch = new[]
@@ -226,7 +279,6 @@ namespace Microsoft.AspNetCore.Mvc
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);
@@ -247,7 +299,8 @@ namespace Microsoft.AspNetCore.Mvc
var result = new FileContentResult(byteArray, contentType)
{
LastModified = lastModified,
- EntityTag = entityTag
+ EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -266,7 +319,6 @@ namespace Microsoft.AspNetCore.Mvc
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);
@@ -286,7 +338,8 @@ namespace Microsoft.AspNetCore.Mvc
var result = new FileContentResult(byteArray, contentType)
{
LastModified = lastModified,
- EntityTag = entityTag
+ EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -304,16 +357,16 @@ namespace Microsoft.AspNetCore.Mvc
var streamReader = new StreamReader(httpResponse.Body);
var body = streamReader.ReadToEndAsync().Result;
var contentRange = new ContentRangeHeaderValue(byteArray.Length);
+ Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
+ Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
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);
}
[Fact]
- public async Task WriteFileAsync_RangeRequested_PreconditionFailed()
+ public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored()
{
// Arrange
var contentType = "text/plain";
@@ -324,7 +377,8 @@ namespace Microsoft.AspNetCore.Mvc
var result = new FileContentResult(byteArray, contentType)
{
LastModified = lastModified,
- EntityTag = entityTag
+ EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -347,7 +401,6 @@ namespace Microsoft.AspNetCore.Mvc
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.Null(httpResponse.ContentLength);
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
@@ -355,7 +408,7 @@ namespace Microsoft.AspNetCore.Mvc
}
[Fact]
- public async Task WriteFileAsync_RangeRequested_NotModified()
+ public async Task WriteFileAsync_NotModified_RangeRequestedIgnored()
{
// Arrange
var contentType = "text/plain";
@@ -366,7 +419,8 @@ namespace Microsoft.AspNetCore.Mvc
var result = new FileContentResult(byteArray, contentType)
{
LastModified = lastModified,
- EntityTag = entityTag
+ EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -389,7 +443,6 @@ namespace Microsoft.AspNetCore.Mvc
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.Null(httpResponse.ContentLength);
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileResultTest.cs
index a520b04c38..ce8db7449e 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileResultTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileResultTest.cs
@@ -297,7 +297,6 @@ namespace Microsoft.AspNetCore.Mvc
// Act
var state = FileResultExecutorBase.GetPreconditionState(
- actionContext,
httpRequestHeaders,
lastModified,
etag);
@@ -334,7 +333,6 @@ namespace Microsoft.AspNetCore.Mvc
// Act
var state = FileResultExecutorBase.GetPreconditionState(
- actionContext,
httpRequestHeaders,
lastModified,
etag);
@@ -370,7 +368,6 @@ namespace Microsoft.AspNetCore.Mvc
// Act
var state = FileResultExecutorBase.GetPreconditionState(
- actionContext,
httpRequestHeaders,
lastModified,
etag);
@@ -398,7 +395,6 @@ namespace Microsoft.AspNetCore.Mvc
// Act
var ifRangeIsValid = FileResultExecutorBase.IfRangeValid(
- actionContext,
httpRequestHeaders,
lastModified,
etag);
@@ -460,7 +456,7 @@ namespace Microsoft.AspNetCore.Mvc
public Task ExecuteAsync(ActionContext context, EmptyFileResult result)
{
- SetHeadersAndLog(context, result, 0L);
+ SetHeadersAndLog(context, result, 0L, true);
result.WasWriteFileCalled = true;
return Task.FromResult(0);
}
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileStreamResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileStreamResultTest.cs
index 48bd5574fa..eea79e044f 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileStreamResultTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileStreamResultTest.cs
@@ -10,7 +10,6 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
-using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.TestCommon;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
@@ -95,6 +94,7 @@ namespace Microsoft.AspNetCore.Mvc
{
LastModified = lastModified,
EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -119,11 +119,11 @@ namespace Microsoft.AspNetCore.Mvc
var streamReader = new StreamReader(httpResponse.Body);
var body = streamReader.ReadToEndAsync().Result;
var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, byteArray.Length);
+ Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
+ Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
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);
}
@@ -143,6 +143,7 @@ namespace Microsoft.AspNetCore.Mvc
{
LastModified = lastModified,
EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -165,16 +166,59 @@ namespace Microsoft.AspNetCore.Mvc
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]);
+ 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);
}
+ [Fact]
+ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored()
+ {
+ // Arrange
+ var contentType = "text/plain";
+ var lastModified = DateTimeOffset.MinValue;
+ var entityTag = new EntityTagHeaderValue("\"Etag\"");
+ var byteArray = Encoding.ASCII.GetBytes("Hello World");
+ var readStream = new MemoryStream(byteArray);
+ readStream.SetLength(11);
+
+ var result = new FileStreamResult(readStream, contentType)
+ {
+ LastModified = lastModified,
+ EntityTag = entityTag,
+ };
+
+ var httpContext = GetHttpContext();
+ var requestHeaders = httpContext.Request.GetTypedHeaders();
+ requestHeaders.IfMatch = new[]
+ {
+ new EntityTagHeaderValue("\"Etag\""),
+ };
+ requestHeaders.Range = new RangeHeaderValue(0, 4);
+ requestHeaders.IfRange = new RangeConditionHeaderValue(DateTimeOffset.MinValue);
+ httpContext.Request.Method = HttpMethods.Get;
+ httpContext.Response.Body = new MemoryStream();
+ var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
+
+ // Act
+ await result.ExecuteResultAsync(actionContext);
+
+ // Assert
+ var httpResponse = actionContext.HttpContext.Response;
+ httpResponse.Body.Seek(0, SeekOrigin.Begin);
+ var streamReader = new StreamReader(httpResponse.Body);
+ var body = streamReader.ReadToEndAsync().Result;
+ Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
+ Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
+ Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
+ Assert.Equal("Hello World", body);
+ }
+
[Fact]
public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored()
{
@@ -190,6 +234,7 @@ namespace Microsoft.AspNetCore.Mvc
{
LastModified = lastModified,
EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -235,6 +280,7 @@ namespace Microsoft.AspNetCore.Mvc
{
LastModified = lastModified,
EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -254,7 +300,6 @@ namespace Microsoft.AspNetCore.Mvc
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);
@@ -276,6 +321,7 @@ namespace Microsoft.AspNetCore.Mvc
{
LastModified = lastModified,
EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -293,11 +339,12 @@ namespace Microsoft.AspNetCore.Mvc
var streamReader = new StreamReader(httpResponse.Body);
var body = streamReader.ReadToEndAsync().Result;
var contentRange = new ContentRangeHeaderValue(byteArray.Length);
+ Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
+ Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
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.Equal(11, httpResponse.ContentLength);
Assert.Empty(body);
}
@@ -315,6 +362,7 @@ namespace Microsoft.AspNetCore.Mvc
{
LastModified = lastModified,
EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -337,7 +385,6 @@ namespace Microsoft.AspNetCore.Mvc
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.Null(httpResponse.ContentLength);
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
@@ -345,7 +392,7 @@ namespace Microsoft.AspNetCore.Mvc
}
[Fact]
- public async Task WriteFileAsync_RangeRequested_NotModified()
+ public async Task WriteFileAsync_NotModified_RangeRequestedIgnored()
{
// Arrange
var contentType = "text/plain";
@@ -358,6 +405,7 @@ namespace Microsoft.AspNetCore.Mvc
{
LastModified = lastModified,
EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -380,7 +428,6 @@ namespace Microsoft.AspNetCore.Mvc
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.Null(httpResponse.ContentLength);
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
@@ -404,6 +451,7 @@ namespace Microsoft.AspNetCore.Mvc
{
LastModified = lastModified,
EntityTag = entityTag,
+ EnableRangeProcessing = true,
};
var httpContext = GetHttpContext();
@@ -425,13 +473,12 @@ namespace Microsoft.AspNetCore.Mvc
httpResponse.Body.Seek(0, SeekOrigin.Begin);
var streamReader = new StreamReader(httpResponse.Body);
var body = streamReader.ReadToEndAsync().Result;
-
+ Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
+ Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
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);
}
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/PhysicalFileResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/PhysicalFileResultTest.cs
index 683f11bf00..69dd1a4550 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/PhysicalFileResultTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/PhysicalFileResultTest.cs
@@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
-using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.TestCommon;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
@@ -63,6 +62,7 @@ namespace Microsoft.AspNetCore.Mvc
// Arrange
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
var result = new TestPhysicalFileResult(path, "text/plain");
+ result.EnableRangeProcessing = true;
var httpContext = GetHttpContext();
var requestHeaders = httpContext.Request.GetTypedHeaders();
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
@@ -97,6 +97,7 @@ namespace Microsoft.AspNetCore.Mvc
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
var result = new TestPhysicalFileResult(path, "text/plain");
var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\"");
+ result.EnableRangeProcessing = true;
var httpContext = GetHttpContext();
var requestHeaders = httpContext.Request.GetTypedHeaders();
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
@@ -124,12 +125,42 @@ namespace Microsoft.AspNetCore.Mvc
Assert.Equal("File", body);
}
+ [Fact]
+ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored()
+ {
+ // Arrange
+ var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
+ var result = new TestPhysicalFileResult(path, "text/plain");
+ var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\"");
+ var httpContext = GetHttpContext();
+ var requestHeaders = httpContext.Request.GetTypedHeaders();
+ requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
+ requestHeaders.Range = new RangeHeaderValue(0, 3);
+ requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\""));
+ httpContext.Request.Method = HttpMethods.Get;
+ httpContext.Response.Body = new MemoryStream();
+ var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
+
+ // Act
+ await result.ExecuteResultAsync(actionContext);
+
+ // Assert
+ var httpResponse = actionContext.HttpContext.Response;
+ httpResponse.Body.Seek(0, SeekOrigin.Begin);
+ var streamReader = new StreamReader(httpResponse.Body);
+ var body = streamReader.ReadToEndAsync().Result;
+ Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
+ Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
+ Assert.Equal("FilePathResultTestFile contents�", body);
+ }
+
[Fact]
public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored()
{
// Arrange
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
var result = new TestPhysicalFileResult(path, "text/plain");
+ result.EnableRangeProcessing = true;
var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\"");
var httpContext = GetHttpContext();
var requestHeaders = httpContext.Request.GetTypedHeaders();
@@ -149,7 +180,6 @@ namespace Microsoft.AspNetCore.Mvc
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.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
Assert.Equal("FilePathResultTestFile contents�", body);
}
@@ -158,7 +188,7 @@ namespace Microsoft.AspNetCore.Mvc
[InlineData("0-5")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
- public async Task WriteFileAsync_RangeRequestIgnored(string rangeString)
+ public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString)
{
// Arrange
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
@@ -180,7 +210,6 @@ namespace Microsoft.AspNetCore.Mvc
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.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
Assert.Equal("FilePathResultTestFile contents�", body);
@@ -194,6 +223,7 @@ namespace Microsoft.AspNetCore.Mvc
// Arrange
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
var result = new TestPhysicalFileResult(path, "text/plain");
+ result.EnableRangeProcessing = true;
var httpContext = GetHttpContext();
var requestHeaders = httpContext.Request.GetTypedHeaders();
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
@@ -224,6 +254,7 @@ namespace Microsoft.AspNetCore.Mvc
// Arrange
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
var result = new TestPhysicalFileResult(path, "text/plain");
+ result.EnableRangeProcessing = true;
var httpContext = GetHttpContext();
var requestHeaders = httpContext.Request.GetTypedHeaders();
requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue;
@@ -241,7 +272,6 @@ namespace Microsoft.AspNetCore.Mvc
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.Null(httpResponse.ContentLength);
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
@@ -254,6 +284,7 @@ namespace Microsoft.AspNetCore.Mvc
// Arrange
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
var result = new TestPhysicalFileResult(path, "text/plain");
+ result.EnableRangeProcessing = true;
var httpContext = GetHttpContext();
var requestHeaders = httpContext.Request.GetTypedHeaders();
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue.AddDays(1);
@@ -271,7 +302,6 @@ namespace Microsoft.AspNetCore.Mvc
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.Null(httpResponse.ContentLength);
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
@@ -321,16 +351,16 @@ namespace Microsoft.AspNetCore.Mvc
}
[Theory]
- [InlineData(0, 3, "File", 4)]
- [InlineData(8, 13, "Result", 6)]
- [InlineData(null, 3, "ts¡", 3)]
- [InlineData(8, null, "ResultTestFile contents¡", 26)]
- public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, string expectedString, long contentLength)
+ [InlineData(0, 3, 4)]
+ [InlineData(8, 13, 6)]
+ [InlineData(null, 3, 3)]
+ [InlineData(8, null, 26)]
+ public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, long contentLength)
{
// Arrange
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
var result = new TestPhysicalFileResult(path, "text/plain");
-
+ result.EnableRangeProcessing = true;
var sendFile = new TestSendFileFeature();
var httpContext = GetHttpContext();
httpContext.Features.Set(sendFile);
@@ -351,7 +381,7 @@ namespace Microsoft.AspNetCore.Mvc
Assert.Equal(Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")), sendFile.Name);
Assert.Equal(start, sendFile.Offset);
Assert.Equal(contentLength, sendFile.Length);
- Assert.Equal(CancellationToken.None, sendFile.Token);
+ Assert.Equal(CancellationToken.None, sendFile.Token);
var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, 34);
Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode);
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/VirtualFileResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/VirtualFileResultTest.cs
index aaf10c7cb4..21a20fb637 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/VirtualFileResultTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/VirtualFileResultTest.cs
@@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
-using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.TestCommon;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
@@ -66,6 +65,7 @@ namespace Microsoft.AspNetCore.Mvc
var path = Path.GetFullPath("helllo.txt");
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
var result = new TestVirtualFileResult(path, contentType);
+ result.EnableRangeProcessing = true;
var appEnvironment = new Mock();
appEnvironment.Setup(app => app.WebRootFileProvider)
.Returns(GetFileProvider(path));
@@ -110,6 +110,7 @@ namespace Microsoft.AspNetCore.Mvc
var path = Path.GetFullPath("helllo.txt");
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
var result = new TestVirtualFileResult(path, contentType);
+ result.EnableRangeProcessing = true;
var appEnvironment = new Mock();
appEnvironment.Setup(app => app.WebRootFileProvider)
.Returns(GetFileProvider(path));
@@ -148,6 +149,47 @@ namespace Microsoft.AspNetCore.Mvc
Assert.Equal("File", body);
}
+ [Fact]
+ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored()
+ {
+ // Arrange
+ var path = Path.GetFullPath("helllo.txt");
+ var contentType = "text/plain; charset=us-ascii; p1=p1-value";
+ var result = new TestVirtualFileResult(path, contentType);
+ var appEnvironment = new Mock();
+ appEnvironment.Setup(app => app.WebRootFileProvider)
+ .Returns(GetFileProvider(path));
+
+ var httpContext = GetHttpContext();
+ httpContext.Response.Body = new MemoryStream();
+ httpContext.RequestServices = new ServiceCollection()
+ .AddSingleton(appEnvironment.Object)
+ .AddTransient, TestVirtualFileResultExecutor>()
+ .AddTransient()
+ .BuildServiceProvider();
+
+ var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\"");
+ var requestHeaders = httpContext.Request.GetTypedHeaders();
+ requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
+ requestHeaders.Range = new RangeHeaderValue(0, 3);
+ requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\""));
+ httpContext.Request.Method = HttpMethods.Get;
+ httpContext.Response.Body = new MemoryStream();
+ var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
+
+ // Act
+ await result.ExecuteResultAsync(actionContext);
+
+ // Assert
+ var httpResponse = actionContext.HttpContext.Response;
+ httpResponse.Body.Seek(0, SeekOrigin.Begin);
+ var streamReader = new StreamReader(httpResponse.Body);
+ var body = streamReader.ReadToEndAsync().Result;
+ Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
+ Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
+ Assert.Equal("FilePathResultTestFile contents¡", body);
+ }
+
[Fact]
public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored()
{
@@ -155,6 +197,7 @@ namespace Microsoft.AspNetCore.Mvc
var path = Path.GetFullPath("helllo.txt");
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
var result = new TestVirtualFileResult(path, contentType);
+ result.EnableRangeProcessing = true;
var appEnvironment = new Mock();
appEnvironment.Setup(app => app.WebRootFileProvider)
.Returns(GetFileProvider(path));
@@ -186,7 +229,6 @@ namespace Microsoft.AspNetCore.Mvc
var body = streamReader.ReadToEndAsync().Result;
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
- Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
Assert.Equal("FilePathResultTestFile contents¡", body);
}
@@ -194,12 +236,13 @@ namespace Microsoft.AspNetCore.Mvc
[InlineData("0-5")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
- public async Task WriteFileAsync_RangeRequestIgnored(string rangeString)
+ public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString)
{
// Arrange
var path = Path.GetFullPath("helllo.txt");
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
var result = new TestVirtualFileResult(path, contentType);
+ result.EnableRangeProcessing = true;
var appEnvironment = new Mock();
appEnvironment.Setup(app => app.WebRootFileProvider)
.Returns(GetFileProvider(path));
@@ -228,7 +271,6 @@ namespace Microsoft.AspNetCore.Mvc
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.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
Assert.Equal("FilePathResultTestFile contents¡", body);
@@ -243,6 +285,7 @@ namespace Microsoft.AspNetCore.Mvc
var path = Path.GetFullPath("helllo.txt");
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
var result = new TestVirtualFileResult(path, contentType);
+ result.EnableRangeProcessing = true;
var appEnvironment = new Mock();
appEnvironment.Setup(app => app.WebRootFileProvider)
.Returns(GetFileProvider(path));
@@ -285,6 +328,7 @@ namespace Microsoft.AspNetCore.Mvc
var path = Path.GetFullPath("helllo.txt");
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
var result = new TestVirtualFileResult(path, contentType);
+ result.EnableRangeProcessing = true;
var appEnvironment = new Mock();
appEnvironment.Setup(app => app.WebRootFileProvider)
.Returns(GetFileProvider(path));
@@ -313,7 +357,6 @@ namespace Microsoft.AspNetCore.Mvc
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.Null(httpResponse.ContentLength);
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
@@ -327,6 +370,7 @@ namespace Microsoft.AspNetCore.Mvc
var path = Path.GetFullPath("helllo.txt");
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
var result = new TestVirtualFileResult(path, contentType);
+ result.EnableRangeProcessing = true;
var appEnvironment = new Mock();
appEnvironment.Setup(app => app.WebRootFileProvider)
.Returns(GetFileProvider(path));
@@ -355,7 +399,6 @@ namespace Microsoft.AspNetCore.Mvc
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.Null(httpResponse.ContentLength);
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
@@ -454,6 +497,7 @@ namespace Microsoft.AspNetCore.Mvc
var result = new TestVirtualFileResult(path, "text/plain")
{
FileProvider = GetFileProvider(path),
+ EnableRangeProcessing = true,
};
var sendFile = new TestSendFileFeature();
diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FileResultTests.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FileResultTests.cs
index b631f22490..e5733a558e 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.Infrastructure;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
@@ -189,6 +189,24 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
}
+ [Fact]
+ public async Task FileFromDisk_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
+ {
+ // Arrange
+ var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromDiskWithFileName");
+ httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
+
+ // Act
+ 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("This is a sample text file", body);
+ }
+
[Fact]
public async Task FileFromDisk_ReturnsFileWithFileName_IfRangeHeaderValid_RangeRequest_WithLastModifiedAndEtag()
{
@@ -259,11 +277,11 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
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(HttpStatusCode.PartialContent, response.StatusCode);
Assert.Equal(expectedBody, body);
}
@@ -299,12 +317,12 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Act
var response = await Client.SendAsync(httpRequestMessage);
+ var body = await response.Content.ReadAsStringAsync();
// 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);
}
@@ -329,6 +347,24 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
}
+ [Fact]
+ public async Task FileFromStream_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
+ {
+ // Arrange
+ var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromStreamWithFileName");
+ httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
+
+ // Act
+ 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("This is sample text from a stream", body);
+ }
+
[Fact]
public async Task FileFromStream_ReturnsFileWithFileName_IfRangeHeaderValid_RangeRequest()
{
@@ -339,13 +375,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Act
var response = await Client.SendAsync(httpRequestMessage);
+ var body = await response.Content.ReadAsStringAsync();
// 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(HttpStatusCode.PartialContent, response.StatusCode);
Assert.Equal("This is", body);
}
@@ -361,10 +397,8 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
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);
}
@@ -397,13 +431,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Act
var response = await Client.SendAsync(httpRequestMessage);
+ var body = await response.Content.ReadAsStringAsync();
// 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(HttpStatusCode.PartialContent, response.StatusCode);
Assert.Equal(expectedBody, body);
}
@@ -439,12 +473,15 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Act
var response = await Client.SendAsync(httpRequestMessage);
+ var body = await response.Content.ReadAsStringAsync();
// Assert
+ Assert.NotNull(response.Content.Headers.ContentType);
+ Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
+ Assert.NotNull(body);
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);
}
@@ -470,7 +507,25 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
}
[Fact]
- public async Task FileFromBinaryData_ReturnsFileWithFileName_IfRangeHeaderValid_RangeRequest()
+ public async Task FileFromBinaryData_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
+ {
+ // Arrange
+ var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromBinaryDataWithFileName");
+ httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
+
+ // Act
+ 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("This is a sample text from a binary array", body);
+ }
+
+ [Fact]
+ public async Task FileFromBinaryData_ReturnsFileWithFileName_IfRangeHeaderValid()
{
// Arrange
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromBinaryDataWithFileName_WithEtag");
@@ -479,13 +534,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Act
var response = await Client.SendAsync(httpRequestMessage);
+ var body = await response.Content.ReadAsStringAsync();
- // 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(HttpStatusCode.PartialContent, response.StatusCode);
Assert.Equal("This is", body);
}
@@ -557,6 +612,24 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
}
+ [Fact]
+ public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
+ {
+ // Arrange
+ var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/EmbeddedFiles/DownloadFileWithFileName_RangeProcessingNotEnabled");
+ httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
+
+ // Act
+ 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("Sample text file as embedded resource.", body);
+ }
+
[Fact]
public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_IfRangeHeaderValid_RangeRequest()
{
diff --git a/test/WebSites/FilesWebSite/Controllers/DownloadFilesController.cs b/test/WebSites/FilesWebSite/Controllers/DownloadFilesController.cs
index e86e211932..7b23292272 100644
--- a/test/WebSites/FilesWebSite/Controllers/DownloadFilesController.cs
+++ b/test/WebSites/FilesWebSite/Controllers/DownloadFilesController.cs
@@ -22,7 +22,7 @@ namespace FilesWebSite
public IActionResult DownloadFromDisk()
{
var path = Path.Combine(_hostingEnvironment.ContentRootPath, "sample.txt");
- return PhysicalFile(path, "text/plain");
+ return PhysicalFile(path, "text/plain", true);
}
public IActionResult DownloadFromDisk_WithLastModifiedAndEtag()
@@ -30,7 +30,7 @@ namespace FilesWebSite
var path = Path.Combine(_hostingEnvironment.ContentRootPath, "sample.txt");
var lastModified = new DateTimeOffset(year: 1999, month: 11, day: 04, hour: 3, minute: 0, second: 0, offset: new TimeSpan(0));
var entityTag = new EntityTagHeaderValue("\"Etag\"");
- return PhysicalFile(path, "text/plain", lastModified, entityTag);
+ return PhysicalFile(path, "text/plain", lastModified, entityTag, true);
}
public IActionResult DownloadFromDiskWithFileName()
@@ -44,7 +44,7 @@ namespace FilesWebSite
var path = Path.Combine(_hostingEnvironment.ContentRootPath, "sample.txt");
var lastModified = new DateTimeOffset(year: 1999, month: 11, day: 04, hour: 3, minute: 0, second: 0, offset: new TimeSpan(0));
var entityTag = new EntityTagHeaderValue("\"Etag\"");
- return PhysicalFile(path, "text/plain", "downloadName.txt", lastModified, entityTag);
+ return PhysicalFile(path, "text/plain", "downloadName.txt", lastModified, entityTag, true);
}
public IActionResult DownloadFromStream()
@@ -55,7 +55,7 @@ namespace FilesWebSite
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
- return File(stream, "text/plain");
+ return File(stream, "text/plain", true);
}
public IActionResult DownloadFromStreamWithFileName()
@@ -77,13 +77,13 @@ namespace FilesWebSite
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
var entityTag = new EntityTagHeaderValue("\"Etag\"");
- return File(stream, "text/plain", "downloadName.txt", lastModified: null, entityTag: entityTag);
+ return File(stream, "text/plain", "downloadName.txt", lastModified: null, entityTag: entityTag, enableRangeProcessing: true);
}
public IActionResult DownloadFromBinaryData()
{
var data = Encoding.UTF8.GetBytes("This is a sample text from a binary array");
- return File(data, "text/plain");
+ return File(data, "text/plain", true);
}
public IActionResult DownloadFromBinaryDataWithFileName()
@@ -96,7 +96,7 @@ namespace FilesWebSite
{
var data = Encoding.UTF8.GetBytes("This is a sample text from a binary array");
var entityTag = new EntityTagHeaderValue("\"Etag\"");
- return File(data, "text/plain", "downloadName.txt", lastModified: null, entityTag: entityTag);
+ return File(data, "text/plain", "downloadName.txt", lastModified: null, entityTag: entityTag, enableRangeProcessing: true);
}
}
}
diff --git a/test/WebSites/FilesWebSite/Controllers/EmbeddedFilesController.cs b/test/WebSites/FilesWebSite/Controllers/EmbeddedFilesController.cs
index 758aea7b7d..64e834742d 100644
--- a/test/WebSites/FilesWebSite/Controllers/EmbeddedFilesController.cs
+++ b/test/WebSites/FilesWebSite/Controllers/EmbeddedFilesController.cs
@@ -14,7 +14,17 @@ namespace FilesWebSite
return new VirtualFileResult("/Greetings.txt", "text/plain")
{
FileProvider = new EmbeddedFileProvider(GetType().GetTypeInfo().Assembly, "FilesWebSite.EmbeddedResources"),
- FileDownloadName = "downloadName.txt"
+ FileDownloadName = "downloadName.txt",
+ EnableRangeProcessing = true,
+ };
+ }
+
+ public IActionResult DownloadFileWithFileName_RangeProcessingNotEnabled()
+ {
+ return new VirtualFileResult("/Greetings.txt", "text/plain")
+ {
+ FileProvider = new EmbeddedFileProvider(GetType().GetTypeInfo().Assembly, "FilesWebSite.EmbeddedResources"),
+ FileDownloadName = "downloadName.txt",
};
}
@@ -23,7 +33,8 @@ namespace FilesWebSite
var file = new VirtualFileResult("/Greetings.txt", "text/plain")
{
FileProvider = new EmbeddedFileProvider(GetType().GetTypeInfo().Assembly, "FilesWebSite.EmbeddedResources"),
- FileDownloadName = "downloadName.txt"
+ FileDownloadName = "downloadName.txt",
+ EnableRangeProcessing = true,
};
file.EntityTag = new Microsoft.Net.Http.Headers.EntityTagHeaderValue("\"Etag\"");