public async Task WriteFileAsync_WritesResponse_InChunksOfFourKilobytes() { // Arrange var mockReadStream = new Mock <Stream>(); mockReadStream.SetupSequence(s => s.ReadAsync(It.IsAny <byte[]>(), 0, 0x1000, CancellationToken.None)) .Returns(Task.FromResult(0x1000)) .Returns(Task.FromResult(0x500)) .Returns(Task.FromResult(0)); var mockBodyStream = new Mock <Stream>(); mockBodyStream .Setup(s => s.WriteAsync(It.IsAny <byte[]>(), 0, 0x1000, CancellationToken.None)) .Returns(Task.FromResult(0)); mockBodyStream .Setup(s => s.WriteAsync(It.IsAny <byte[]>(), 0, 0x500, CancellationToken.None)) .Returns(Task.FromResult(0)); var result = new FileStreamResult(mockReadStream.Object, "text/plain"); var httpContext = GetHttpContext(); httpContext.Response.Body = mockBodyStream.Object; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act await result.ExecuteResultAsync(actionContext); // Assert mockReadStream.Verify(); mockBodyStream.Verify(); }
public async Task DisablesResponseBuffering_IfBufferingFeatureAvailable() { // Arrange var expectedContentType = "text/foo; charset=us-ascii"; var expected = Encoding.ASCII.GetBytes("Test data"); var originalStream = new MemoryStream(expected); var httpContext = GetHttpContext(); var bufferingFeature = new TestBufferingFeature(); httpContext.Features.Set <IHttpBufferingFeature>(bufferingFeature); var outStream = new MemoryStream(); httpContext.Response.Body = outStream; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var result = new FileStreamResult(originalStream, expectedContentType); // Act await result.ExecuteResultAsync(actionContext); // Assert var outBytes = outStream.ToArray(); Assert.Equal(expected, outBytes); Assert.Equal(expectedContentType, httpContext.Response.ContentType); Assert.True(bufferingFeature.DisableResponseBufferingInvoked); }
public async Task WriteFileAsync_WritesResponse_InChunksOfFourKilobytes() { // Arrange var mockReadStream = new Mock<Stream>(); mockReadStream.SetupSequence(s => s.ReadAsync(It.IsAny<byte[]>(), 0, 0x1000, CancellationToken.None)) .Returns(Task.FromResult(0x1000)) .Returns(Task.FromResult(0x500)) .Returns(Task.FromResult(0)); var mockBodyStream = new Mock<Stream>(); mockBodyStream .Setup(s => s.WriteAsync(It.IsAny<byte[]>(), 0, 0x1000, CancellationToken.None)) .Returns(Task.FromResult(0)); mockBodyStream .Setup(s => s.WriteAsync(It.IsAny<byte[]>(), 0, 0x500, CancellationToken.None)) .Returns(Task.FromResult(0)); var result = new FileStreamResult(mockReadStream.Object, "text/plain"); var httpContext = GetHttpContext(); httpContext.Response.Body = mockBodyStream.Object; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act await result.ExecuteResultAsync(actionContext); // Assert mockReadStream.Verify(); mockBodyStream.Verify(); }
public async Task WriteFileAsync_CopiesProvidedStream_ToOutputStream() { // Arrange // Generate an array of bytes with a predictable pattern // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12, 13 var originalBytes = Enumerable.Range(0, 0x1234) .Select(b => (byte)(b % 20)).ToArray(); var originalStream = new MemoryStream(originalBytes); var httpContext = GetHttpContext(); var outStream = new MemoryStream(); httpContext.Response.Body = outStream; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var result = new FileStreamResult(originalStream, "text/plain"); // Act await result.ExecuteResultAsync(actionContext); // Assert var outBytes = outStream.ToArray(); Assert.True(originalBytes.SequenceEqual(outBytes)); Assert.False(originalStream.CanSeek); }
public async Task SetsSuppliedContentTypeAndEncoding() { // Arrange var expectedContentType = "text/foo; charset=us-ascii"; // Generate an array of bytes with a predictable pattern // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12, 13 var originalBytes = Enumerable.Range(0, 0x1234) .Select(b => (byte)(b % 20)).ToArray(); var originalStream = new MemoryStream(originalBytes); var httpContext = GetHttpContext(); var outStream = new MemoryStream(); httpContext.Response.Body = outStream; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var result = new FileStreamResult(originalStream, expectedContentType); // Act await result.ExecuteResultAsync(actionContext); // Assert var outBytes = outStream.ToArray(); Assert.True(originalBytes.SequenceEqual(outBytes)); Assert.Equal(expectedContentType, httpContext.Response.ContentType); Assert.False(originalStream.CanSeek); }
public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested_IfRangeProcessingOn(long?start, long?end, string expectedString, long contentLength) { // 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); readStream.SetLength(11); var result = new FileStreamResult(readStream, contentType) { LastModified = lastModified, EntityTag = entityTag, }; var httpContext = GetHttpContext(); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.Range = new RangeHeaderValue(start, end); requestHeaders.IfMatch = new[] { 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 start = start ?? 11 - end; end = start + contentLength - 1; var httpResponse = actionContext.HttpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); 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]); if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) && enableRangeProcessingSwitch) { Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.Equal(contentLength, httpResponse.ContentLength); Assert.Equal(expectedString, body); } else { Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); Assert.Equal("Hello World", body); } }
public async Task WriteFileAsync_RangeRequested_FileLengthZeroOrNull(long?fileLength) { // Arrange var contentType = "text/plain"; var lastModified = new DateTimeOffset(); var entityTag = new EntityTagHeaderValue("\"Etag\""); var byteArray = Encoding.ASCII.GetBytes(""); var readStream = new MemoryStream(byteArray); fileLength = fileLength ?? 0L; readStream.SetLength(fileLength.Value); var result = new FileStreamResult(readStream, contentType) { LastModified = lastModified, EntityTag = entityTag, }; var httpContext = GetHttpContext(); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.Range = new RangeHeaderValue(0, 5); requestHeaders.IfMatch = new[] { 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(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); if (AppContext.TryGetSwitch(FileResultExecutorBase.EnableRangeProcessingSwitch, out var enableRangeProcessingSwitch) && enableRangeProcessingSwitch) { var contentRange = new ContentRangeHeaderValue(byteArray.Length); Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]); Assert.Empty(body); } else { Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); Assert.Empty(body); } }
public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() { // 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, EnableRangeProcessing = true, }; 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(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); Assert.False(readStream.CanSeek); }
public async Task WriteFileAsync_NotModified_RangeRequestedIgnored() { // 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, EnableRangeProcessing = true, }; var httpContext = GetHttpContext(); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.IfNoneMatch = new[] { new EntityTagHeaderValue("\"Etag\""), }; httpContext.Request.Headers.Range = "bytes = 0-6"; 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 = await streamReader.ReadToEndAsync(); Assert.Equal(StatusCodes.Status304NotModified, httpResponse.StatusCode); Assert.Null(httpResponse.ContentLength); Assert.Empty(httpResponse.Headers.ContentRange); Assert.False(httpResponse.Headers.ContainsKey(HeaderNames.ContentType)); Assert.NotEmpty(httpResponse.Headers.LastModified); Assert.Empty(body); Assert.False(readStream.CanSeek); }
public async Task WriteFileAsync_RangeRequested_PreconditionFailed() { // 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(); var requestHeaders = httpContext.Request.GetTypedHeaders(); requestHeaders.IfMatch = new[] { new EntityTagHeaderValue("\"NotEtag\""), }; httpContext.Request.Headers[HeaderNames.Range] = "bytes = 0-6"; 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.Status412PreconditionFailed, httpResponse.StatusCode); Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]); Assert.Equal(11, httpResponse.ContentLength); Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]); Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]); Assert.Empty(body); }
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, EnableRangeProcessing = true, }; 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; 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(11, httpResponse.ContentLength); Assert.Empty(body); Assert.False(readStream.CanSeek); }
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 readStream = new MemoryStream(byteArray); var result = new FileStreamResult(readStream, contentType) { LastModified = lastModified, EntityTag = entityTag, }; var httpContext = GetHttpContext(); var requestHeaders = httpContext.Request.GetTypedHeaders(); 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(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]); Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]); Assert.Equal("Hello World", body); }
protected override Task ExecuteAsync( HttpContext httpContext, Stream stream, string contentType, DateTimeOffset?lastModified = null, EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { httpContext.RequestServices = new ServiceCollection() .AddSingleton <ILoggerFactory, NullLoggerFactory>() .AddSingleton <IActionResultExecutor <FileStreamResult>, FileStreamResultExecutor>() .BuildServiceProvider(); var actionContext = new ActionContext(httpContext, new(), new()); var fileStreamResult = new FileStreamResult(stream, contentType) { LastModified = lastModified, EntityTag = entityTag, EnableRangeProcessing = enableRangeProcessing }; return(fileStreamResult.ExecuteResultAsync(actionContext)); }
public async Task HeadRequest_DoesNotWriteToBody_AndClosesReadStream() { // Arrange var readStream = new MemoryStream(Encoding.UTF8.GetBytes("Hello, World!")); var httpContext = GetHttpContext(); httpContext.Request.Method = "HEAD"; var outStream = new MemoryStream(); httpContext.Response.Body = outStream; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var result = new FileStreamResult(readStream, "text/plain"); // Act await result.ExecuteResultAsync(actionContext); // Assert Assert.False(readStream.CanSeek); Assert.Equal(200, httpContext.Response.StatusCode); Assert.Equal(0, httpContext.Response.Body.Length); }
public async Task DisablesResponseBuffering_IfBufferingFeatureAvailable() { // Arrange var expectedContentType = "text/foo; charset=us-ascii"; var expected = Encoding.ASCII.GetBytes("Test data"); var originalStream = new MemoryStream(expected); var httpContext = GetHttpContext(); var bufferingFeature = new TestBufferingFeature(); httpContext.Features.Set<IHttpBufferingFeature>(bufferingFeature); var outStream = new MemoryStream(); httpContext.Response.Body = outStream; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var result = new FileStreamResult(originalStream, expectedContentType); // Act await result.ExecuteResultAsync(actionContext); // Assert var outBytes = outStream.ToArray(); Assert.Equal(expected, outBytes); Assert.Equal(expectedContentType, httpContext.Response.ContentType); Assert.True(bufferingFeature.DisableResponseBufferingInvoked); }
public async Task SetsSuppliedContentTypeAndEncoding() { // Arrange var expectedContentType = "text/foo; charset=us-ascii"; // Generate an array of bytes with a predictable pattern // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12, 13 var originalBytes = Enumerable.Range(0, 0x1234) .Select(b => (byte)(b % 20)).ToArray(); var originalStream = new MemoryStream(originalBytes); var httpContext = GetHttpContext(); var outStream = new MemoryStream(); httpContext.Response.Body = outStream; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var result = new FileStreamResult(originalStream, expectedContentType); // Act await result.ExecuteResultAsync(actionContext); // Assert var outBytes = outStream.ToArray(); Assert.True(originalBytes.SequenceEqual(outBytes)); Assert.Equal(expectedContentType, httpContext.Response.ContentType); }
public async Task WriteFileAsync_CopiesProvidedStream_ToOutputStream() { // Arrange // Generate an array of bytes with a predictable pattern // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12, 13 var originalBytes = Enumerable.Range(0, 0x1234) .Select(b => (byte)(b % 20)).ToArray(); var originalStream = new MemoryStream(originalBytes); var httpContext = GetHttpContext(); var outStream = new MemoryStream(); httpContext.Response.Body = outStream; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var result = new FileStreamResult(originalStream, "text/plain"); // Act await result.ExecuteResultAsync(actionContext); // Assert var outBytes = outStream.ToArray(); Assert.True(originalBytes.SequenceEqual(outBytes)); }