diff --git a/src/Microsoft.AspNet.Http.Extensions/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Http.Extensions/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..a0d5a215a3 --- /dev/null +++ b/src/Microsoft.AspNet.Http.Extensions/Properties/Resources.Designer.cs @@ -0,0 +1,46 @@ +// +namespace Microsoft.AspNet.Http.Extensions +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.AspNet.Http.Extensions.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// This server does not support the sendfile.SendAsync extension. + /// + internal static string Exception_SendFileNotSupported + { + get { return GetString("Exception_SendFileNotSupported"); } + } + + /// + /// This server does not support the sendfile.SendAsync extension. + /// + internal static string FormatException_SendFileNotSupported() + { + return GetString("Exception_SendFileNotSupported"); + } + + private static string GetString(string name, params string[] formatterNames) + { + var value = _resourceManager.GetString(name); + + System.Diagnostics.Debug.Assert(value != null); + + if (formatterNames != null) + { + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } + } + + return value; + } + } +} diff --git a/src/Microsoft.AspNet.Http.Extensions/Resources.resx b/src/Microsoft.AspNet.Http.Extensions/Resources.resx new file mode 100644 index 0000000000..2059135d60 --- /dev/null +++ b/src/Microsoft.AspNet.Http.Extensions/Resources.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + This server does not support the sendfile.SendAsync extension. + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Http.Extensions/SendFileResponseExtensions.cs b/src/Microsoft.AspNet.Http.Extensions/SendFileResponseExtensions.cs new file mode 100644 index 0000000000..2dcbdafc8a --- /dev/null +++ b/src/Microsoft.AspNet.Http.Extensions/SendFileResponseExtensions.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.Http.Extensions; + +namespace Microsoft.AspNet.Http +{ + /// + /// Provides extensions for HttpResponse exposing the SendFile extension. + /// + public static class SendFileResponseExtensions + { + /// + /// Checks if the SendFile extension is supported. + /// + /// + /// True if sendfile feature exists in the response. + public static bool SupportsSendFile([NotNull] this HttpResponse response) + { + return response.HttpContext.GetFeature() != null; + } + + /// + /// Sends the given file using the SendFile extension. + /// + /// + /// + /// + public static Task SendFileAsync([NotNull] this HttpResponse response, [NotNull] string fileName) + { + return response.SendFileAsync(fileName, 0, null, CancellationToken.None); + } + + /// + /// Sends the given file using the SendFile extension. + /// + /// + /// The full or relative path to the file. + /// The offset in the file. + /// The number of types to send, or null to send the remainder of the file. + /// + /// + public static Task SendFileAsync([NotNull] this HttpResponse response, [NotNull] string fileName, long offset, long? count, CancellationToken cancellationToken) + { + var sendFile = response.HttpContext.GetFeature(); + if (sendFile == null) + { + throw new NotSupportedException(Resources.Exception_SendFileNotSupported); + } + + return sendFile.SendFileAsync(fileName, offset, count, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Http.Extensions/project.json b/src/Microsoft.AspNet.Http.Extensions/project.json index f761ed5f65..f2d71e2528 100644 --- a/src/Microsoft.AspNet.Http.Extensions/project.json +++ b/src/Microsoft.AspNet.Http.Extensions/project.json @@ -3,6 +3,7 @@ "description": "ASP.NET 5 common extension methods for HTTP abstractions and IApplicationBuilder.", "dependencies": { "Microsoft.AspNet.Http": "1.0.0-*", + "Microsoft.AspNet.Http.Interfaces": "1.0.0-*", "Microsoft.Framework.DependencyInjection": "1.0.0-*", "Microsoft.Net.Http.Headers": "1.0.0-*" }, diff --git a/test/Microsoft.AspNet.Http.Extensions.Tests/SendFileResponseExtensionsTests.cs b/test/Microsoft.AspNet.Http.Extensions.Tests/SendFileResponseExtensionsTests.cs new file mode 100644 index 0000000000..f42fec5efa --- /dev/null +++ b/test/Microsoft.AspNet.Http.Extensions.Tests/SendFileResponseExtensionsTests.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.Http.Core; +using Xunit; + +namespace Microsoft.AspNet.Http.Extensions.Tests +{ + public class SendFileResponseExtensionsTests + { + [Fact] + public void SendFileSupport() + { + var context = new DefaultHttpContext(); + var response = context.Response; + Assert.False(response.SupportsSendFile()); + context.SetFeature(new FakeSendFileFeature()); + Assert.True(response.SupportsSendFile()); + } + + [Fact] + public Task SendFileWhenNotSupported() + { + var response = new DefaultHttpContext().Response; + return Assert.ThrowsAsync(() => response.SendFileAsync("foo")); + } + + [Fact] + public async Task SendFileWorks() + { + var context = new DefaultHttpContext(); + var response = context.Response; + var fakeFeature = new FakeSendFileFeature(); + context.SetFeature(fakeFeature); + + await response.SendFileAsync("bob", 1, 3, CancellationToken.None); + + Assert.Equal("bob", fakeFeature.name); + Assert.Equal(1, fakeFeature.offset); + Assert.Equal(3, fakeFeature.length); + Assert.Equal(CancellationToken.None, fakeFeature.token); + } + + private class FakeSendFileFeature : IHttpSendFileFeature + { + public string name = null; + public long offset = 0; + public long? length = null; + public CancellationToken token; + + public Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) + { + this.name = path; + this.offset = offset; + this.length = length; + this.token = cancellation; + return Task.FromResult(0); + } + } + } +}