Respond to RangeHelper refactor (#6348)

Respond to https://github.com/aspnet/StaticFiles/pull/200
This commit is contained in:
Jass Bagga 2017-06-06 11:22:35 -07:00 committed by GitHub
parent f1dd475eae
commit 7ffd88757d
7 changed files with 355 additions and 104 deletions

View File

@ -31,8 +31,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
Unspecified,
NotModified,
ShouldProcess,
PreconditionFailed,
IgnoreRangeRequest
PreconditionFailed
}
protected ILogger Logger { get; }
@ -61,15 +60,6 @@ namespace Microsoft.AspNetCore.Mvc.Internal
var httpRequestHeaders = request.GetTypedHeaders();
var response = context.HttpContext.Response;
var httpResponseHeaders = response.GetTypedHeaders();
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 (lastModified.HasValue)
{
httpResponseHeaders.LastModified = lastModified;
@ -80,24 +70,35 @@ namespace Microsoft.AspNetCore.Mvc.Internal
}
var serveBody = !HttpMethods.IsHead(request.Method);
if (HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method))
var preconditionState = GetPreconditionState(context, httpRequestHeaders, lastModified, etag);
if (preconditionState == PreconditionState.NotModified)
{
var preconditionState = GetPreconditionState(context, httpRequestHeaders, lastModified, etag);
if (request.Headers.ContainsKey(HeaderNames.Range) &&
(preconditionState == PreconditionState.Unspecified ||
preconditionState == PreconditionState.ShouldProcess))
serveBody = false;
response.StatusCode = StatusCodes.Status304NotModified;
}
else if (preconditionState == PreconditionState.PreconditionFailed)
{
serveBody = false;
response.StatusCode = StatusCodes.Status412PreconditionFailed;
}
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))
{
return SetRangeHeaders(context, httpRequestHeaders, fileLength, lastModified, etag);
}
if (preconditionState == PreconditionState.NotModified)
{
serveBody = false;
response.StatusCode = StatusCodes.Status304NotModified;
}
else if (preconditionState == PreconditionState.PreconditionFailed)
{
serveBody = false;
response.StatusCode = StatusCodes.Status412PreconditionFailed;
if ((preconditionState == PreconditionState.Unspecified ||
preconditionState == PreconditionState.ShouldProcess))
{
if (IfRangeValid(context, httpRequestHeaders, lastModified, etag))
{
return SetRangeHeaders(context, httpRequestHeaders, fileLength);
}
}
}
}
@ -155,6 +156,37 @@ namespace Microsoft.AspNetCore.Mvc.Internal
return PreconditionState.Unspecified;
}
internal static bool IfRangeValid(
ActionContext context,
RequestHeaders httpRequestHeaders,
DateTimeOffset? lastModified = null,
EntityTagHeaderValue etag = null)
{
// 14.27 If-Range
var ifRange = httpRequestHeaders.IfRange;
if (ifRange != null)
{
// If the validator given in the If-Range header field matches the
// current validator for the selected representation of the target
// resource, then the server SHOULD process the Range header field as
// requested. If the validator does not match, the server MUST ignore
// the Range header field.
if (ifRange.LastModified.HasValue)
{
if (lastModified.HasValue && lastModified > ifRange.LastModified)
{
return false;
}
}
else if (etag != null && ifRange.EntityTag != null && !ifRange.EntityTag.Compare(etag, useStrongComparison: true))
{
return false;
}
}
return true;
}
// Internal for testing
internal static PreconditionState GetPreconditionState(
ActionContext context,
@ -166,7 +198,6 @@ namespace Microsoft.AspNetCore.Mvc.Internal
var ifNoneMatchState = PreconditionState.Unspecified;
var ifModifiedSinceState = PreconditionState.Unspecified;
var ifUnmodifiedSinceState = PreconditionState.Unspecified;
var ifRangeState = PreconditionState.Unspecified;
// 14.24 If-Match
var ifMatch = httpRequestHeaders.IfMatch;
@ -208,28 +239,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
ifUnmodifiedSinceState = unmodified ? PreconditionState.ShouldProcess : PreconditionState.PreconditionFailed;
}
var ifRange = httpRequestHeaders.IfRange;
if (ifRange != null)
{
// If the validator given in the If-Range header field matches the
// current validator for the selected representation of the target
// resource, then the server SHOULD process the Range header field as
// requested. If the validator does not match, the server MUST ignore
// the Range header field.
if (ifRange.LastModified.HasValue)
{
if (lastModified.HasValue && lastModified > ifRange.LastModified)
{
ifRangeState = PreconditionState.IgnoreRangeRequest;
}
}
else if (etag != null && ifRange.EntityTag != null && !ifRange.EntityTag.Compare(etag, useStrongComparison: true))
{
ifRangeState = PreconditionState.IgnoreRangeRequest;
}
}
var state = GetMaxPreconditionState(ifMatchState, ifNoneMatchState, ifModifiedSinceState, ifUnmodifiedSinceState, ifRangeState);
var state = GetMaxPreconditionState(ifMatchState, ifNoneMatchState, ifModifiedSinceState, ifUnmodifiedSinceState);
return state;
}
@ -250,16 +260,23 @@ namespace Microsoft.AspNetCore.Mvc.Internal
private static (RangeItemHeaderValue range, long rangeLength, bool serveBody) SetRangeHeaders(
ActionContext context,
RequestHeaders httpRequestHeaders,
long? fileLength,
DateTimeOffset? lastModified = null,
EntityTagHeaderValue etag = null)
long? fileLength)
{
var response = context.HttpContext.Response;
var httpResponseHeaders = response.GetTypedHeaders();
// Checked for presence of Range header explicitly before calling this method.
// Range may be null for parsing errors, multiple ranges and when the file length is missing.
var range = fileLength.HasValue ? ParseRange(context, httpRequestHeaders, fileLength.Value, lastModified, etag) : null;
// Range may be null for empty range header, invalid ranges, parsing errors, multiple ranges
// and when the file length is zero.
var (isRangeRequest, range) = RangeHelper.ParseRange(
context.HttpContext,
httpRequestHeaders,
fileLength.Value);
if (!isRangeRequest)
{
return (range: null, rangeLength: 0, serveBody: true);
}
if (range == null)
{
// 14.16 Content-Range - A server sending a response with status code 416 (Requested range not satisfiable)
@ -295,32 +312,6 @@ namespace Microsoft.AspNetCore.Mvc.Internal
return length;
}
private static RangeItemHeaderValue ParseRange(
ActionContext context,
RequestHeaders httpRequestHeaders,
long fileLength,
DateTimeOffset? lastModified = null,
EntityTagHeaderValue etag = null)
{
var httpContext = context.HttpContext;
var response = httpContext.Response;
var range = RangeHelper.ParseRange(httpContext, httpRequestHeaders, lastModified, etag);
if (range != null)
{
var normalizedRanges = RangeHelper.NormalizeRanges(range, fileLength);
if (normalizedRanges == null || normalizedRanges.Count == 0)
{
return null;
}
return normalizedRanges.Single();
}
return null;
}
protected static ILogger CreateLogger<T>(ILoggerFactory factory)
{
if (factory == null)

View File

@ -233,8 +233,47 @@ namespace Microsoft.AspNetCore.Mvc
[Theory]
[InlineData("0-5")]
[InlineData("bytes = 11-0")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(string rangeString)
{
// Arrange
var contentType = "text/plain";
var lastModified = new DateTimeOffset();
var entityTag = new EntityTagHeaderValue("\"Etag\"");
var byteArray = Encoding.ASCII.GetBytes("Hello World");
var result = new FileContentResult(byteArray, contentType)
{
LastModified = lastModified,
EntityTag = entityTag
};
var httpContext = GetHttpContext();
httpContext.Request.Headers[HeaderNames.Range] = rangeString;
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.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);
}
[Theory]
[InlineData("bytes = 12-13")]
[InlineData("bytes = -0")]
public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(string rangeString)
{
// Arrange

View File

@ -378,8 +378,10 @@ namespace Microsoft.AspNetCore.Mvc
Assert.Equal(FileResultExecutorBase.PreconditionState.NotModified, state);
}
[Fact]
public void GetPreconditionState_ShouldNotProcess_IgnoreRangeRequest()
[Theory]
[InlineData("\"NotEtag\"", false)]
[InlineData("\"Etag\"", true)]
public void IfRangeValid_IgnoreRangeRequest(string ifRangeString, bool expected)
{
// Arrange
var actionContext = new ActionContext();
@ -389,19 +391,19 @@ namespace Microsoft.AspNetCore.Mvc
var lastModified = DateTimeOffset.MinValue;
lastModified = new DateTimeOffset(lastModified.Year, lastModified.Month, lastModified.Day, lastModified.Hour, lastModified.Minute, lastModified.Second, TimeSpan.FromSeconds(0));
var etag = new EntityTagHeaderValue("\"Etag\"");
httpRequestHeaders.IfRange = new RangeConditionHeaderValue("\"NotEtag\"");
httpRequestHeaders.IfRange = new RangeConditionHeaderValue(ifRangeString);
httpRequestHeaders.IfModifiedSince = lastModified;
actionContext.HttpContext = httpContext;
// Act
var state = FileResultExecutorBase.GetPreconditionState(
var ifRangeIsValid = FileResultExecutorBase.IfRangeValid(
actionContext,
httpRequestHeaders,
lastModified,
etag);
// Assert
Assert.Equal(FileResultExecutorBase.PreconditionState.IgnoreRangeRequest, state);
Assert.Equal(expected, ifRangeIsValid);
}
private static IServiceCollection CreateServices()

View File

@ -219,9 +219,9 @@ namespace Microsoft.AspNetCore.Mvc
[Theory]
[InlineData("0-5")]
[InlineData("bytes = 11-0")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(string rangeString)
public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(string rangeString)
{
// Arrange
var contentType = "text/plain";
@ -246,6 +246,46 @@ namespace Microsoft.AspNetCore.Mvc
// 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.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);
}
[Theory]
[InlineData("bytes = 12-13")]
[InlineData("bytes = -0")]
public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(string rangeString)
{
// Arrange
var contentType = "text/plain";
var lastModified = new DateTimeOffset();
var entityTag = new EntityTagHeaderValue("\"Etag\"");
var byteArray = Encoding.ASCII.GetBytes("Hello World");
var readStream = new MemoryStream(byteArray);
var result = new FileStreamResult(readStream, contentType)
{
LastModified = lastModified,
EntityTag = entityTag,
};
var httpContext = GetHttpContext();
httpContext.Request.Headers[HeaderNames.Range] = rangeString;
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);

View File

@ -117,6 +117,7 @@ namespace Microsoft.AspNetCore.Mvc
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
var contentRange = new ContentRangeHeaderValue(0, 3, 34);
Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
Assert.Equal(4, httpResponse.ContentLength);
Assert.Equal("File", body);
@ -148,14 +149,46 @@ namespace Microsoft.AspNetCore.Mvc
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<74>", body);
}
[Theory]
[InlineData("0-5")]
[InlineData("bytes = 11-0")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
public async Task WriteFileAsync_RangeRequested_NotSatisfiable(string rangeString)
public async Task WriteFileAsync_RangeRequestIgnored(string rangeString)
{
// Arrange
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
var result = new TestPhysicalFileResult(path, "text/plain");
var httpContext = GetHttpContext();
var requestHeaders = httpContext.Request.GetTypedHeaders();
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
httpContext.Request.Headers[HeaderNames.Range] = rangeString;
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("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
Assert.Equal("FilePathResultTestFile contents<74>", body);
}
[Theory]
[InlineData("bytes = 35-36")]
[InlineData("bytes = -0")]
public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString)
{
// Arrange
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));

View File

@ -191,9 +191,9 @@ namespace Microsoft.AspNetCore.Mvc
[Theory]
[InlineData("0-5")]
[InlineData("bytes = 11-0")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
public async Task WriteFileAsync_RangeRequested_NotSatisfiable(string rangeString)
public async Task WriteFileAsync_RangeRequestIgnored(string rangeString)
{
// Arrange
var path = Path.GetFullPath("helllo.txt");
@ -201,15 +201,58 @@ namespace Microsoft.AspNetCore.Mvc
var result = new TestVirtualFileResult(path, contentType);
var appEnvironment = new Mock<IHostingEnvironment>();
appEnvironment.Setup(app => app.WebRootFileProvider)
.Returns(GetFileProvider(path));
.Returns(GetFileProvider(path));
var httpContext = GetHttpContext();
httpContext.Response.Body = new MemoryStream();
httpContext.RequestServices = new ServiceCollection()
.AddSingleton(appEnvironment.Object)
.AddTransient<TestVirtualFileResultExecutor>()
.AddTransient<ILoggerFactory, LoggerFactory>()
.BuildServiceProvider();
.AddSingleton(appEnvironment.Object)
.AddTransient<TestVirtualFileResultExecutor>()
.AddTransient<ILoggerFactory, LoggerFactory>()
.BuildServiceProvider();
var requestHeaders = httpContext.Request.GetTypedHeaders();
httpContext.Request.Headers[HeaderNames.Range] = rangeString;
requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1);
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("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
Assert.Equal("FilePathResultTestFile contents¡", body);
}
[Theory]
[InlineData("bytes = 35-36")]
[InlineData("bytes = -0")]
public async Task WriteFileAsync_RangeRequestedNotSatisfiable(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);
var appEnvironment = new Mock<IHostingEnvironment>();
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<ILoggerFactory, LoggerFactory>()
.BuildServiceProvider();
var requestHeaders = httpContext.Request.GetTypedHeaders();
httpContext.Request.Headers[HeaderNames.Range] = rangeString;

View File

@ -64,8 +64,28 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
[Theory]
[InlineData("0-6")]
[InlineData("bytes = 11-6")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
public async Task FileFromDisk_CanBeEnabled_WithMiddleware_RangeRequestIgnored(string rangeString)
{
// Arrange
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromDisk");
httpRequestMessage.Headers.TryAddWithoutValidation("Range", rangeString);
// 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);
}
[Theory]
[InlineData("bytes = 35-36")]
[InlineData("bytes = -0")]
public async Task FileFromDisk_CanBeEnabled_WithMiddleware_RangeRequestNotSatisfiable(string rangeString)
{
// Arrange
@ -107,8 +127,28 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
[Theory]
[InlineData("0-6")]
[InlineData("bytes = 11-6")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
public async Task FileFromDisk_CanBeEnabled_WithMiddleware_RangeRequestIgnored_WithLastModifiedAndEtag(string rangeString)
{
// Arrange
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromDiskWithFileName_WithLastModifiedAndEtag");
httpRequestMessage.Headers.TryAddWithoutValidation("Range", rangeString);
// 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);
}
[Theory]
[InlineData("bytes = 35-36")]
[InlineData("bytes = -0")]
public async Task FileFromDisk_CanBeEnabled_WithMiddleware_RangeRequestNotSatisfiable_WithLastModifiedAndEtag(string rangeString)
{
// Arrange
@ -229,8 +269,28 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
[Theory]
[InlineData("0-6")]
[InlineData("bytes = 11-6")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
public async Task FileFromStream_ReturnsFile_RangeRequestIgnored(string rangeString)
{
// Arrange
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromStream");
httpRequestMessage.Headers.TryAddWithoutValidation("Range", rangeString);
// 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);
}
[Theory]
[InlineData("bytes = 35-36")]
[InlineData("bytes = -0")]
public async Task FileFromStream_ReturnsFile_RangeRequestNotSatisfiable(string rangeString)
{
// Arrange
@ -349,8 +409,28 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
[Theory]
[InlineData("0-6")]
[InlineData("bytes = 11-6")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
public async Task FileFromBinaryData_ReturnsFile_RangeRequestIgnored(string rangeString)
{
// Arrange
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromBinaryData");
httpRequestMessage.Headers.TryAddWithoutValidation("Range", rangeString);
// 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);
}
[Theory]
[InlineData("bytes = 45-46")]
[InlineData("bytes = -0")]
public async Task FileFromBinaryData_ReturnsFile_RangeRequestNotSatisfiable(string rangeString)
{
// Arrange
@ -524,8 +604,31 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
[Theory]
[InlineData("0-6")]
[InlineData("bytes = 11-6")]
[InlineData("bytes = ")]
[InlineData("bytes = 1-4, 5-11")]
public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_RangeRequestIgnored(string rangeString)
{
// Arrange
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/EmbeddedFiles/DownloadFileWithFileName");
httpRequestMessage.Headers.TryAddWithoutValidation("Range", rangeString);
// 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);
var contentDisposition = response.Content.Headers.ContentDisposition.ToString();
Assert.NotNull(contentDisposition);
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
}
[Theory]
[InlineData("bytes = 45-46")]
[InlineData("bytes = -0")]
public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_RangeRequestNotSatisfiable(string rangeString)
{
// Arrange