diff --git a/src/Microsoft.AspNetCore.Http.Extensions/SendFileResponseExtensions.cs b/src/Microsoft.AspNetCore.Http.Extensions/SendFileResponseExtensions.cs index cbddfe97c9..74c0422ef4 100644 --- a/src/Microsoft.AspNetCore.Http.Extensions/SendFileResponseExtensions.cs +++ b/src/Microsoft.AspNetCore.Http.Extensions/SendFileResponseExtensions.cs @@ -22,8 +22,7 @@ namespace Microsoft.AspNetCore.Http /// /// The file. /// The . - public static Task SendFileAsync(this HttpResponse response, IFileInfo file, - CancellationToken cancellationToken = default(CancellationToken)) + public static Task SendFileAsync(this HttpResponse response, IFileInfo file, CancellationToken cancellationToken = default) { if (response == null) { @@ -34,7 +33,7 @@ namespace Microsoft.AspNetCore.Http throw new ArgumentNullException(nameof(file)); } - return response.SendFileAsync(file, 0, null, cancellationToken); + return SendFileAsyncCore(response, file, 0, null, cancellationToken); } /// @@ -46,8 +45,7 @@ namespace Microsoft.AspNetCore.Http /// The number of bytes to send, or null to send the remainder of the file. /// /// - public static async Task SendFileAsync(this HttpResponse response, IFileInfo file, long offset, long? count, - CancellationToken cancellationToken = default(CancellationToken)) + public static Task SendFileAsync(this HttpResponse response, IFileInfo file, long offset, long? count, CancellationToken cancellationToken = default) { if (response == null) { @@ -57,10 +55,62 @@ namespace Microsoft.AspNetCore.Http { throw new ArgumentNullException(nameof(file)); } - CheckRange(offset, count, file.Length); + return SendFileAsyncCore(response, file, offset, count, cancellationToken); + } + + /// + /// Sends the given file using the SendFile extension. + /// + /// + /// The full path to the file. + /// The . + /// + public static Task SendFileAsync(this HttpResponse response, string fileName, CancellationToken cancellationToken = default) + { + if (response == null) + { + throw new ArgumentNullException(nameof(response)); + } + + if (fileName == null) + { + throw new ArgumentNullException(nameof(fileName)); + } + + return SendFileAsyncCore(response, fileName, 0, null, cancellationToken); + } + + /// + /// Sends the given file using the SendFile extension. + /// + /// + /// The full path to the file. + /// The offset in the file. + /// The number of bytes to send, or null to send the remainder of the file. + /// + /// + public static Task SendFileAsync(this HttpResponse response, string fileName, long offset, long? count, CancellationToken cancellationToken = default) + { + if (response == null) + { + throw new ArgumentNullException(nameof(response)); + } + + if (fileName == null) + { + throw new ArgumentNullException(nameof(fileName)); + } + + return SendFileAsyncCore(response, fileName, offset, count, cancellationToken); + } + + private static async Task SendFileAsyncCore(HttpResponse response, IFileInfo file, long offset, long? count, CancellationToken cancellationToken) + { if (string.IsNullOrEmpty(file.PhysicalPath)) { + CheckRange(offset, count, file.Length); + using (var fileContent = file.CreateReadStream()) { if (offset > 0) @@ -76,63 +126,19 @@ namespace Microsoft.AspNetCore.Http } } - /// - /// Sends the given file using the SendFile extension. - /// - /// - /// The full path to the file. - /// The . - /// - public static Task SendFileAsync(this HttpResponse response, string fileName, - CancellationToken cancellationToken = default(CancellationToken)) + private static Task SendFileAsyncCore(HttpResponse response, string fileName, long offset, long? count, CancellationToken cancellationToken = default) { - if (response == null) - { - throw new ArgumentNullException(nameof(response)); - } - - if (fileName == null) - { - throw new ArgumentNullException(nameof(fileName)); - } - - return response.SendFileAsync(fileName, 0, null, cancellationToken); - } - - /// - /// Sends the given file using the SendFile extension. - /// - /// - /// The full path to the file. - /// The offset in the file. - /// The number of bytes to send, or null to send the remainder of the file. - /// - /// - public static Task SendFileAsync(this HttpResponse response, string fileName, long offset, long? count, - CancellationToken cancellationToken = default(CancellationToken)) - { - if (response == null) - { - throw new ArgumentNullException(nameof(response)); - } - - if (fileName == null) - { - throw new ArgumentNullException(nameof(fileName)); - } - var sendFile = response.HttpContext.Features.Get(); if (sendFile == null) { - return SendFileAsync(response.Body, fileName, offset, count, cancellationToken); + return SendFileAsyncCore(response.Body, fileName, offset, count, cancellationToken); } return sendFile.SendFileAsync(fileName, offset, count, cancellationToken); } // Not safe for overlapped writes. - private static async Task SendFileAsync(Stream outputStream, string fileName, long offset, long? count, - CancellationToken cancel = default(CancellationToken)) + private static async Task SendFileAsyncCore(Stream outputStream, string fileName, long offset, long? count, CancellationToken cancel = default) { cancel.ThrowIfCancellationRequested(); @@ -140,7 +146,6 @@ namespace Microsoft.AspNetCore.Http CheckRange(offset, count, fileInfo.Length); int bufferSize = 1024 * 16; - var fileStream = new FileStream( fileName, FileMode.Open, @@ -151,7 +156,11 @@ namespace Microsoft.AspNetCore.Http using (fileStream) { - fileStream.Seek(offset, SeekOrigin.Begin); + if (offset > 0) + { + fileStream.Seek(offset, SeekOrigin.Begin); + } + await StreamCopyOperation.CopyToAsync(fileStream, outputStream, count, cancel); } }