#527 Add IFileInfo overloads for SendFileAsync.
This commit is contained in:
parent
3e6c7171be
commit
04e9da4e88
|
|
@ -7,6 +7,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
namespace Microsoft.AspNetCore.Http
|
||||
{
|
||||
|
|
@ -15,13 +16,73 @@ namespace Microsoft.AspNetCore.Http
|
|||
/// </summary>
|
||||
public static class SendFileResponseExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends the given file using the SendFile extension.
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="file">The file.</param>
|
||||
public static Task SendFileAsync(this HttpResponse response, IFileInfo file,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(response));
|
||||
}
|
||||
if (file == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(file));
|
||||
}
|
||||
|
||||
return response.SendFileAsync(file, 0, null, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the given file using the SendFile extension.
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="file">The file.</param>
|
||||
/// <param name="offset">The offset in the file.</param>
|
||||
/// <param name="count">The number of bytes to send, or null to send the remainder of the file.</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task SendFileAsync(this HttpResponse response, IFileInfo file, long offset, long? count,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(response));
|
||||
}
|
||||
if (file == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(file));
|
||||
}
|
||||
CheckRange(offset, count, file.Length);
|
||||
|
||||
if (string.IsNullOrEmpty(file.PhysicalPath))
|
||||
{
|
||||
using (var fileContent = file.CreateReadStream())
|
||||
{
|
||||
if (offset > 0)
|
||||
{
|
||||
fileContent.Seek(offset, SeekOrigin.Begin);
|
||||
}
|
||||
await StreamCopyOperation.CopyToAsync(fileContent, response.Body, count, cancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await response.SendFileAsync(file.PhysicalPath, offset, count, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the given file using the SendFile extension.
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="fileName">The full path to the file.</param>
|
||||
/// <returns></returns>
|
||||
public static Task SendFileAsync(this HttpResponse response, string fileName)
|
||||
public static Task SendFileAsync(this HttpResponse response, string fileName,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
|
|
@ -33,7 +94,7 @@ namespace Microsoft.AspNetCore.Http
|
|||
throw new ArgumentNullException(nameof(fileName));
|
||||
}
|
||||
|
||||
return response.SendFileAsync(fileName, 0, null, CancellationToken.None);
|
||||
return response.SendFileAsync(fileName, 0, null, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -42,10 +103,11 @@ namespace Microsoft.AspNetCore.Http
|
|||
/// <param name="response"></param>
|
||||
/// <param name="fileName">The full path to the file.</param>
|
||||
/// <param name="offset">The offset in the file.</param>
|
||||
/// <param name="count">The number of types to send, or null to send the remainder of the file.</param>
|
||||
/// <param name="count">The number of bytes to send, or null to send the remainder of the file.</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static Task SendFileAsync(this HttpResponse response, string fileName, long offset, long? count, CancellationToken cancellationToken)
|
||||
public static Task SendFileAsync(this HttpResponse response, string fileName, long offset, long? count,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
|
|
@ -67,21 +129,13 @@ namespace Microsoft.AspNetCore.Http
|
|||
}
|
||||
|
||||
// Not safe for overlapped writes.
|
||||
private static async Task SendFileAsync(Stream outputStream, string fileName, long offset, long? length, CancellationToken cancel)
|
||||
private static async Task SendFileAsync(Stream outputStream, string fileName, long offset, long? count,
|
||||
CancellationToken cancel = default(CancellationToken))
|
||||
{
|
||||
cancel.ThrowIfCancellationRequested();
|
||||
|
||||
var fileInfo = new FileInfo(fileName);
|
||||
if (offset < 0 || offset > fileInfo.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(offset), offset, string.Empty);
|
||||
}
|
||||
|
||||
if (length.HasValue &&
|
||||
(length.Value < 0 || length.Value > fileInfo.Length - offset))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(length), length, string.Empty);
|
||||
}
|
||||
CheckRange(offset, count, fileInfo.Length);
|
||||
|
||||
int bufferSize = 1024 * 16;
|
||||
|
||||
|
|
@ -96,8 +150,20 @@ namespace Microsoft.AspNetCore.Http
|
|||
using (fileStream)
|
||||
{
|
||||
fileStream.Seek(offset, SeekOrigin.Begin);
|
||||
await StreamCopyOperation.CopyToAsync(fileStream, outputStream, count, cancel);
|
||||
}
|
||||
}
|
||||
|
||||
await StreamCopyOperation.CopyToAsync(fileStream, outputStream, length, cancel);
|
||||
private static void CheckRange(long offset, long? count, long fileLength)
|
||||
{
|
||||
if (offset < 0 || offset > fileLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(offset), offset, string.Empty);
|
||||
}
|
||||
if (count.HasValue &&
|
||||
(count.Value < 0 || count.Value > fileLength - offset))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(count), count, string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ namespace Microsoft.AspNetCore.Http.Extensions
|
|||
{
|
||||
private const int DefaultBufferSize = 4096;
|
||||
|
||||
public static async Task CopyToAsync(Stream source, Stream destination, long? length, CancellationToken cancel)
|
||||
public static async Task CopyToAsync(Stream source, Stream destination, long? count, CancellationToken cancel)
|
||||
{
|
||||
long? bytesRemaining = length;
|
||||
long? bytesRemaining = count;
|
||||
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(DefaultBufferSize);
|
||||
try
|
||||
|
|
@ -42,22 +42,22 @@ namespace Microsoft.AspNetCore.Http.Extensions
|
|||
{
|
||||
readLength = (int)Math.Min(bytesRemaining.Value, (long)readLength);
|
||||
}
|
||||
int count = await source.ReadAsync(buffer, 0, readLength, cancel);
|
||||
int read = await source.ReadAsync(buffer, 0, readLength, cancel);
|
||||
|
||||
if (bytesRemaining.HasValue)
|
||||
{
|
||||
bytesRemaining -= count;
|
||||
bytesRemaining -= read;
|
||||
}
|
||||
|
||||
// End of the source stream.
|
||||
if (count == 0)
|
||||
if (read == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cancel.ThrowIfCancellationRequested();
|
||||
|
||||
await destination.WriteAsync(buffer, 0, count, cancel);
|
||||
await destination.WriteAsync(buffer, 0, read, cancel);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*",
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": "1.0.0-*",
|
||||
"Microsoft.Net.Http.Headers": "1.0.0-*",
|
||||
"System.Buffers": "4.0.0-*"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,6 +8,6 @@ namespace Microsoft.AspNetCore.Http.Features
|
|||
{
|
||||
public interface IHttpSendFileFeature
|
||||
{
|
||||
Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation);
|
||||
Task SendFileAsync(string path, long offset, long? count, CancellationToken cancellation);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue