Reduce the amount of argument checking by flattening the call graph. (#995)

This commit is contained in:
David Fowler 2018-02-06 10:26:56 -08:00 committed by GitHub
parent 672a5f3c76
commit 816ecf5cda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 64 additions and 55 deletions

View File

@ -22,8 +22,7 @@ namespace Microsoft.AspNetCore.Http
/// <param name="response"></param> /// <param name="response"></param>
/// <param name="file">The file.</param> /// <param name="file">The file.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
public static Task SendFileAsync(this HttpResponse response, IFileInfo file, public static Task SendFileAsync(this HttpResponse response, IFileInfo file, CancellationToken cancellationToken = default)
CancellationToken cancellationToken = default(CancellationToken))
{ {
if (response == null) if (response == null)
{ {
@ -34,7 +33,7 @@ namespace Microsoft.AspNetCore.Http
throw new ArgumentNullException(nameof(file)); throw new ArgumentNullException(nameof(file));
} }
return response.SendFileAsync(file, 0, null, cancellationToken); return SendFileAsyncCore(response, file, 0, null, cancellationToken);
} }
/// <summary> /// <summary>
@ -46,8 +45,7 @@ namespace Microsoft.AspNetCore.Http
/// <param name="count">The number of bytes 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> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public static async Task SendFileAsync(this HttpResponse response, IFileInfo file, long offset, long? count, public static Task SendFileAsync(this HttpResponse response, IFileInfo file, long offset, long? count, CancellationToken cancellationToken = default)
CancellationToken cancellationToken = default(CancellationToken))
{ {
if (response == null) if (response == null)
{ {
@ -57,10 +55,62 @@ namespace Microsoft.AspNetCore.Http
{ {
throw new ArgumentNullException(nameof(file)); throw new ArgumentNullException(nameof(file));
} }
CheckRange(offset, count, file.Length);
return SendFileAsyncCore(response, file, 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>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
/// <returns></returns>
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);
}
/// <summary>
/// Sends the given file using the SendFile extension.
/// </summary>
/// <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 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 = 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)) if (string.IsNullOrEmpty(file.PhysicalPath))
{ {
CheckRange(offset, count, file.Length);
using (var fileContent = file.CreateReadStream()) using (var fileContent = file.CreateReadStream())
{ {
if (offset > 0) if (offset > 0)
@ -76,63 +126,19 @@ namespace Microsoft.AspNetCore.Http
} }
} }
/// <summary> private static Task SendFileAsyncCore(HttpResponse response, string fileName, long offset, long? count, CancellationToken cancellationToken = default)
/// Sends the given file using the SendFile extension.
/// </summary>
/// <param name="response"></param>
/// <param name="fileName">The full path to the file.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
/// <returns></returns>
public static Task SendFileAsync(this HttpResponse response, string fileName,
CancellationToken cancellationToken = default(CancellationToken))
{ {
if (response == null)
{
throw new ArgumentNullException(nameof(response));
}
if (fileName == null)
{
throw new ArgumentNullException(nameof(fileName));
}
return response.SendFileAsync(fileName, 0, null, 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>
/// <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 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<IHttpSendFileFeature>(); var sendFile = response.HttpContext.Features.Get<IHttpSendFileFeature>();
if (sendFile == null) 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); return sendFile.SendFileAsync(fileName, offset, count, cancellationToken);
} }
// Not safe for overlapped writes. // Not safe for overlapped writes.
private static async Task SendFileAsync(Stream outputStream, string fileName, long offset, long? count, private static async Task SendFileAsyncCore(Stream outputStream, string fileName, long offset, long? count, CancellationToken cancel = default)
CancellationToken cancel = default(CancellationToken))
{ {
cancel.ThrowIfCancellationRequested(); cancel.ThrowIfCancellationRequested();
@ -140,7 +146,6 @@ namespace Microsoft.AspNetCore.Http
CheckRange(offset, count, fileInfo.Length); CheckRange(offset, count, fileInfo.Length);
int bufferSize = 1024 * 16; int bufferSize = 1024 * 16;
var fileStream = new FileStream( var fileStream = new FileStream(
fileName, fileName,
FileMode.Open, FileMode.Open,
@ -151,7 +156,11 @@ namespace Microsoft.AspNetCore.Http
using (fileStream) using (fileStream)
{ {
fileStream.Seek(offset, SeekOrigin.Begin); if (offset > 0)
{
fileStream.Seek(offset, SeekOrigin.Begin);
}
await StreamCopyOperation.CopyToAsync(fileStream, outputStream, count, cancel); await StreamCopyOperation.CopyToAsync(fileStream, outputStream, count, cancel);
} }
} }