Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.

Commit b08a3aa

Browse files
committed
#527 Add IFileInfo overloads for SendFileAsync.
1 parent 765a520 commit b08a3aa

File tree

4 files changed

+90
-23
lines changed

4 files changed

+90
-23
lines changed

src/Microsoft.AspNetCore.Http.Extensions/SendFileResponseExtensions.cs

Lines changed: 82 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading.Tasks;
88
using Microsoft.AspNetCore.Http.Extensions;
99
using Microsoft.AspNetCore.Http.Features;
10+
using Microsoft.Extensions.FileProviders;
1011

1112
namespace Microsoft.AspNetCore.Http
1213
{
@@ -15,13 +16,73 @@ namespace Microsoft.AspNetCore.Http
1516
/// </summary>
1617
public static class SendFileResponseExtensions
1718
{
19+
/// <summary>
20+
/// Sends the given file using the SendFile extension.
21+
/// </summary>
22+
/// <param name="response"></param>
23+
/// <param name="file">The file.</param>
24+
public static Task SendFileAsync(this HttpResponse response, IFileInfo file,
25+
CancellationToken cancellationToken = default(CancellationToken))
26+
{
27+
if (response == null)
28+
{
29+
throw new ArgumentNullException(nameof(response));
30+
}
31+
if (file == null)
32+
{
33+
throw new ArgumentNullException(nameof(file));
34+
}
35+
36+
return response.SendFileAsync(file, 0, null, cancellationToken);
37+
}
38+
39+
/// <summary>
40+
/// Sends the given file using the SendFile extension.
41+
/// </summary>
42+
/// <param name="response"></param>
43+
/// <param name="file">The file.</param>
44+
/// <param name="offset">The offset in the file.</param>
45+
/// <param name="count">The number of bytes to send, or null to send the remainder of the file.</param>
46+
/// <param name="cancellationToken"></param>
47+
/// <returns></returns>
48+
public static async Task SendFileAsync(this HttpResponse response, IFileInfo file, long offset, long? count,
49+
CancellationToken cancellationToken = default(CancellationToken))
50+
{
51+
if (response == null)
52+
{
53+
throw new ArgumentNullException(nameof(response));
54+
}
55+
if (file == null)
56+
{
57+
throw new ArgumentNullException(nameof(file));
58+
}
59+
CheckRange(offset, count, file.Length);
60+
61+
if (string.IsNullOrEmpty(file.PhysicalPath))
62+
{
63+
using (var fileContent = file.CreateReadStream())
64+
{
65+
if (offset > 0)
66+
{
67+
fileContent.Seek(offset, SeekOrigin.Begin);
68+
}
69+
await StreamCopyOperation.CopyToAsync(fileContent, response.Body, count, cancellationToken);
70+
}
71+
}
72+
else
73+
{
74+
await response.SendFileAsync(file.PhysicalPath, offset, count, cancellationToken);
75+
}
76+
}
77+
1878
/// <summary>
1979
/// Sends the given file using the SendFile extension.
2080
/// </summary>
2181
/// <param name="response"></param>
2282
/// <param name="fileName">The full path to the file.</param>
2383
/// <returns></returns>
24-
public static Task SendFileAsync(this HttpResponse response, string fileName)
84+
public static Task SendFileAsync(this HttpResponse response, string fileName,
85+
CancellationToken cancellationToken = default(CancellationToken))
2586
{
2687
if (response == null)
2788
{
@@ -33,7 +94,7 @@ public static Task SendFileAsync(this HttpResponse response, string fileName)
3394
throw new ArgumentNullException(nameof(fileName));
3495
}
3596

36-
return response.SendFileAsync(fileName, 0, null, CancellationToken.None);
97+
return response.SendFileAsync(fileName, 0, null, cancellationToken);
3798
}
3899

39100
/// <summary>
@@ -42,10 +103,11 @@ public static Task SendFileAsync(this HttpResponse response, string fileName)
42103
/// <param name="response"></param>
43104
/// <param name="fileName">The full path to the file.</param>
44105
/// <param name="offset">The offset in the file.</param>
45-
/// <param name="count">The number of types to send, or null to send the remainder of the file.</param>
106+
/// <param name="count">The number of bytes to send, or null to send the remainder of the file.</param>
46107
/// <param name="cancellationToken"></param>
47108
/// <returns></returns>
48-
public static Task SendFileAsync(this HttpResponse response, string fileName, long offset, long? count, CancellationToken cancellationToken)
109+
public static Task SendFileAsync(this HttpResponse response, string fileName, long offset, long? count,
110+
CancellationToken cancellationToken = default(CancellationToken))
49111
{
50112
if (response == null)
51113
{
@@ -67,21 +129,13 @@ public static Task SendFileAsync(this HttpResponse response, string fileName, lo
67129
}
68130

69131
// Not safe for overlapped writes.
70-
private static async Task SendFileAsync(Stream outputStream, string fileName, long offset, long? length, CancellationToken cancel)
132+
private static async Task SendFileAsync(Stream outputStream, string fileName, long offset, long? count,
133+
CancellationToken cancel = default(CancellationToken))
71134
{
72135
cancel.ThrowIfCancellationRequested();
73136

74137
var fileInfo = new FileInfo(fileName);
75-
if (offset < 0 || offset > fileInfo.Length)
76-
{
77-
throw new ArgumentOutOfRangeException(nameof(offset), offset, string.Empty);
78-
}
79-
80-
if (length.HasValue &&
81-
(length.Value < 0 || length.Value > fileInfo.Length - offset))
82-
{
83-
throw new ArgumentOutOfRangeException(nameof(length), length, string.Empty);
84-
}
138+
CheckRange(offset, count, fileInfo.Length);
85139

86140
int bufferSize = 1024 * 16;
87141

@@ -96,8 +150,20 @@ private static async Task SendFileAsync(Stream outputStream, string fileName, lo
96150
using (fileStream)
97151
{
98152
fileStream.Seek(offset, SeekOrigin.Begin);
153+
await StreamCopyOperation.CopyToAsync(fileStream, outputStream, count, cancel);
154+
}
155+
}
99156

100-
await StreamCopyOperation.CopyToAsync(fileStream, outputStream, length, cancel);
157+
private static void CheckRange(long offset, long? count, long fileLength)
158+
{
159+
if (offset < 0 || offset > fileLength)
160+
{
161+
throw new ArgumentOutOfRangeException(nameof(offset), offset, string.Empty);
162+
}
163+
if (count.HasValue &&
164+
(count.Value < 0 || count.Value > fileLength - offset))
165+
{
166+
throw new ArgumentOutOfRangeException(nameof(count), count, string.Empty);
101167
}
102168
}
103169
}

src/Microsoft.AspNetCore.Http.Extensions/StreamCopyOperation.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ public static class StreamCopyOperation
1515
{
1616
private const int DefaultBufferSize = 4096;
1717

18-
public static async Task CopyToAsync(Stream source, Stream destination, long? length, CancellationToken cancel)
18+
public static async Task CopyToAsync(Stream source, Stream destination, long? count, CancellationToken cancel)
1919
{
20-
long? bytesRemaining = length;
20+
long? bytesRemaining = count;
2121

2222
var buffer = ArrayPool<byte>.Shared.Rent(DefaultBufferSize);
2323
try
@@ -42,22 +42,22 @@ public static async Task CopyToAsync(Stream source, Stream destination, long? le
4242
{
4343
readLength = (int)Math.Min(bytesRemaining.Value, (long)readLength);
4444
}
45-
int count = await source.ReadAsync(buffer, 0, readLength, cancel);
45+
int read = await source.ReadAsync(buffer, 0, readLength, cancel);
4646

4747
if (bytesRemaining.HasValue)
4848
{
49-
bytesRemaining -= count;
49+
bytesRemaining -= read;
5050
}
5151

5252
// End of the source stream.
53-
if (count == 0)
53+
if (read == 0)
5454
{
5555
return;
5656
}
5757

5858
cancel.ThrowIfCancellationRequested();
5959

60-
await destination.WriteAsync(buffer, 0, count, cancel);
60+
await destination.WriteAsync(buffer, 0, read, cancel);
6161
}
6262
}
6363
finally

src/Microsoft.AspNetCore.Http.Extensions/project.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"dependencies": {
1313
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0-*",
14+
"Microsoft.Extensions.FileProviders.Abstractions": "1.0.0-*",
1415
"Microsoft.Net.Http.Headers": "1.0.0-*",
1516
"System.Buffers": "4.0.0-*"
1617
},

src/Microsoft.AspNetCore.Http.Features/IHttpSendFileFeature.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ namespace Microsoft.AspNetCore.Http.Features
88
{
99
public interface IHttpSendFileFeature
1010
{
11-
Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation);
11+
Task SendFileAsync(string path, long offset, long? count, CancellationToken cancellation);
1212
}
1313
}

0 commit comments

Comments
 (0)