Add more unit tests
This commit is contained in:
parent
e3ed603b7e
commit
3a0d8c43ca
|
|
@ -16,6 +16,10 @@ namespace Microsoft.AspNetCore.StaticFiles.Infrastructure
|
|||
internal static IList<RangeItemHeaderValue> NormalizeRanges(ICollection<RangeItemHeaderValue> ranges, long length)
|
||||
{
|
||||
IList<RangeItemHeaderValue> normalizedRanges = new List<RangeItemHeaderValue>(ranges.Count);
|
||||
if (length == 0)
|
||||
{
|
||||
return normalizedRanges;
|
||||
}
|
||||
foreach (var range in ranges)
|
||||
{
|
||||
long? start = range.From;
|
||||
|
|
|
|||
|
|
@ -197,9 +197,11 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
|
||||
private void ComputeIfModifiedSince()
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
// 14.25 If-Modified-Since
|
||||
var ifModifiedSince = _requestHeaders.IfModifiedSince;
|
||||
if (ifModifiedSince.HasValue)
|
||||
if (ifModifiedSince.HasValue && ifModifiedSince <= now)
|
||||
{
|
||||
bool modified = ifModifiedSince < _lastModified;
|
||||
_ifModifiedSinceState = modified ? PreconditionState.ShouldProcess : PreconditionState.NotModified;
|
||||
|
|
@ -207,7 +209,7 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
|
||||
// 14.28 If-Unmodified-Since
|
||||
var ifUnmodifiedSince = _requestHeaders.IfUnmodifiedSince;
|
||||
if (ifUnmodifiedSince.HasValue)
|
||||
if (ifUnmodifiedSince.HasValue && ifModifiedSince <= now)
|
||||
{
|
||||
bool unmodified = ifUnmodifiedSince >= _lastModified;
|
||||
_ifUnmodifiedSinceState = unmodified ? PreconditionState.ShouldProcess : PreconditionState.PreconditionFailed;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -41,38 +43,52 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
// as PUT, from modifying a resource that has changed since the client
|
||||
// last retrieved it.
|
||||
|
||||
[Fact]
|
||||
public async Task IfMatchShouldReturn412WhenNotListed()
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task IfMatchShouldReturn412WhenNotListed(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/extra.xml");
|
||||
var req = new HttpRequestMessage(method, "http://localhost/SubFolder/extra.xml");
|
||||
req.Headers.Add("If-Match", "\"fake\"");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.PreconditionFailed, resp.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IfMatchShouldBeServedWhenListed()
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task IfMatchShouldBeServedWhenListed(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage original = await server.CreateClient().GetAsync("http://localhost/SubFolder/extra.xml");
|
||||
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/extra.xml");
|
||||
var req = new HttpRequestMessage(method, "http://localhost/SubFolder/extra.xml");
|
||||
req.Headers.Add("If-Match", original.Headers.ETag.ToString());
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IfMatchShouldBeServedForAstrisk()
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task IfMatchShouldBeServedForAstrisk(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/extra.xml");
|
||||
var req = new HttpRequestMessage(method, "http://localhost/SubFolder/extra.xml");
|
||||
req.Headers.Add("If-Match", "*");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(UnsupportedMethods))]
|
||||
public async Task IfMatchShouldBeIgnoredForUnsupportedMethods(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(method, "http://localhost/SubFolder/extra.xml");
|
||||
req.Headers.Add("If-Match", "*");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.NotFound, resp.StatusCode);
|
||||
}
|
||||
|
||||
// 14.26 If-None-Match
|
||||
// If any of the entity tags match the entity tag of the entity that
|
||||
// would have been returned in the response to a similar GET request
|
||||
|
|
@ -87,38 +103,43 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
// matched. For all other request methods, the server MUST respond with
|
||||
// a status of 412 (Precondition Failed).
|
||||
|
||||
[Fact]
|
||||
public async Task IfNoneMatchShouldReturn304ForMatchingOnGetAndHeadMethod()
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task IfNoneMatchShouldReturn304ForMatching(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage resp1 = await server.CreateClient().GetAsync("http://localhost/SubFolder/extra.xml");
|
||||
|
||||
var req2 = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/extra.xml");
|
||||
var req2 = new HttpRequestMessage(method, "http://localhost/SubFolder/extra.xml");
|
||||
req2.Headers.Add("If-None-Match", resp1.Headers.ETag.ToString());
|
||||
HttpResponseMessage resp2 = await server.CreateClient().SendAsync(req2);
|
||||
Assert.Equal(HttpStatusCode.NotModified, resp2.StatusCode);
|
||||
|
||||
var req3 = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/extra.xml");
|
||||
req3.Headers.Add("If-None-Match", resp1.Headers.ETag.ToString());
|
||||
HttpResponseMessage resp3 = await server.CreateClient().SendAsync(req3);
|
||||
Assert.Equal(HttpStatusCode.NotModified, resp3.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IfNoneMatchShouldBeIgnoredForNonTwoHundredAnd304Responses()
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task IfNoneMatchAllShouldReturn304ForMatching(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage resp1 = await server.CreateClient().GetAsync("http://localhost/SubFolder/extra.xml");
|
||||
|
||||
var req2 = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SubFolder/extra.xml");
|
||||
var req2 = new HttpRequestMessage(method, "http://localhost/SubFolder/extra.xml");
|
||||
req2.Headers.Add("If-None-Match", "*");
|
||||
HttpResponseMessage resp2 = await server.CreateClient().SendAsync(req2);
|
||||
Assert.Equal(HttpStatusCode.NotModified, resp2.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(UnsupportedMethods))]
|
||||
public async Task IfNoneMatchShouldBeIgnoredForNonTwoHundredAnd304Responses(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage resp1 = await server.CreateClient().GetAsync("http://localhost/SubFolder/extra.xml");
|
||||
|
||||
var req2 = new HttpRequestMessage(method, "http://localhost/SubFolder/extra.xml");
|
||||
req2.Headers.Add("If-None-Match", resp1.Headers.ETag.ToString());
|
||||
HttpResponseMessage resp2 = await server.CreateClient().SendAsync(req2);
|
||||
Assert.Equal(HttpStatusCode.NotFound, resp2.StatusCode);
|
||||
|
||||
var req3 = new HttpRequestMessage(HttpMethod.Put, "http://localhost/SubFolder/extra.xml");
|
||||
req3.Headers.Add("If-None-Match", resp1.Headers.ETag.ToString());
|
||||
HttpResponseMessage resp3 = await server.CreateClient().SendAsync(req3);
|
||||
Assert.Equal(HttpStatusCode.NotFound, resp3.StatusCode);
|
||||
}
|
||||
|
||||
// 14.26 If-None-Match
|
||||
|
|
@ -131,12 +152,15 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
// A server MUST use the strong comparison function (see section 13.3.3)
|
||||
// to compare the entity tags in If-Match.
|
||||
|
||||
[Fact]
|
||||
public async Task ServerShouldReturnLastModified()
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task ServerShouldReturnLastModified(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
|
||||
HttpResponseMessage response = await server.CreateClient().GetAsync("http://localhost/SubFolder/extra.xml");
|
||||
HttpResponseMessage response = await server.CreateClient().SendAsync(
|
||||
new HttpRequestMessage(method, "http://localhost/SubFolder/extra.xml"));
|
||||
|
||||
Assert.NotNull(response.Content.Headers.LastModified);
|
||||
// Verify that DateTimeOffset is UTC
|
||||
Assert.Equal(response.Content.Headers.LastModified.Value.Offset, TimeSpan.Zero);
|
||||
|
|
@ -151,30 +175,58 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
// unless doing so is consistent with all of the conditional header
|
||||
// fields in the request.
|
||||
|
||||
[Fact]
|
||||
public async Task MatchingBothConditionsReturnsNotModified()
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task MatchingBothConditionsReturnsNotModified(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage resp1 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
|
||||
HttpResponseMessage resp2 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.AddHeader("If-None-Match", resp1.Headers.ETag.ToString())
|
||||
.And(req => req.Headers.IfModifiedSince = resp1.Content.Headers.LastModified)
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotModified, resp2.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MissingEitherOrBothConditionsReturnsNormally()
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task MatchingAtLeastOneETagReturnsNotModified(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage resp1 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
var etag = resp1.Headers.ETag.ToString();
|
||||
|
||||
HttpResponseMessage resp2 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.AddHeader("If-Match", etag + ", " + etag)
|
||||
.SendAsync(method.Method);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, resp2.StatusCode);
|
||||
|
||||
HttpResponseMessage resp3 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.AddHeader("If-Match", etag+ ", \"badetag\"")
|
||||
.SendAsync(method.Method);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, resp3.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task MissingEitherOrBothConditionsReturnsNormally(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage resp1 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.SendAsync(method.Method);
|
||||
|
||||
DateTimeOffset lastModified = resp1.Content.Headers.LastModified.Value;
|
||||
DateTimeOffset pastDate = lastModified.AddHours(-1);
|
||||
|
|
@ -184,19 +236,19 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.AddHeader("If-None-Match", "\"fake\"")
|
||||
.And(req => req.Headers.IfModifiedSince = lastModified)
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
|
||||
HttpResponseMessage resp3 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.AddHeader("If-None-Match", resp1.Headers.ETag.ToString())
|
||||
.And(req => req.Headers.IfModifiedSince = pastDate)
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
|
||||
HttpResponseMessage resp4 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.AddHeader("If-None-Match", "\"fake\"")
|
||||
.And(req => req.Headers.IfModifiedSince = furtureDate)
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, resp2.StatusCode);
|
||||
Assert.Equal(HttpStatusCode.OK, resp3.StatusCode);
|
||||
|
|
@ -215,15 +267,30 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
// invalid, the response is exactly the same as for a normal GET.
|
||||
// A date which is later than the server's current time is
|
||||
// invalid.
|
||||
[Fact]
|
||||
public async Task InvalidIfModifiedSinceDateFormatGivesNormalGet()
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task InvalidIfModifiedSinceDateFormatGivesNormalGet(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
|
||||
HttpResponseMessage res = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.AddHeader("If-Modified-Since", "bad-date")
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, res.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task FutureIfModifiedSinceDateFormatGivesNormalGet(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
|
||||
HttpResponseMessage res = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.And(req => req.Headers.IfModifiedSince = DateTimeOffset.Now.AddYears(1))
|
||||
.SendAsync(method.Method);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, res.StatusCode);
|
||||
}
|
||||
|
|
@ -235,38 +302,82 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
// Modified-Since date, the server SHOULD return a 304 (Not
|
||||
// Modified) response.
|
||||
|
||||
[Fact]
|
||||
public async Task IfModifiedSinceDateGreaterThanLastModifiedShouldReturn304()
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task IfModifiedSinceDateGreaterThanLastModifiedShouldReturn304(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
|
||||
HttpResponseMessage res1 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
|
||||
HttpResponseMessage res2 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.And(req => req.Headers.IfModifiedSince = DateTimeOffset.Now)
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotModified, res2.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IfModifiedSinceDateLessThanLastModifiedShouldReturn200()
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task SuppportsIfModifiedDateFormats(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage res1 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.SendAsync(method.Method);
|
||||
|
||||
var formats = new[]
|
||||
{
|
||||
"ddd, dd MMM yyyy HH:mm:ss 'GMT'",
|
||||
"dddd, dd-MMM-yy HH:mm:ss 'GMT'",
|
||||
"ddd MMM d HH:mm:ss yyyy"
|
||||
};
|
||||
|
||||
foreach (var format in formats)
|
||||
{
|
||||
HttpResponseMessage res2 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.AddHeader("If-Modified-Since", DateTimeOffset.Now.ToString(format))
|
||||
.SendAsync(method.Method);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotModified, res2.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SupportedMethods))]
|
||||
public async Task IfModifiedSinceDateLessThanLastModifiedShouldReturn200(HttpMethod method)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
|
||||
HttpResponseMessage res1 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
|
||||
HttpResponseMessage res2 = await server
|
||||
.CreateRequest("/SubFolder/extra.xml")
|
||||
.And(req => req.Headers.IfModifiedSince = DateTimeOffset.MinValue)
|
||||
.GetAsync();
|
||||
.SendAsync(method.Method);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, res2.StatusCode);
|
||||
}
|
||||
|
||||
public static IEnumerable<object> SupportedMethods => new[]
|
||||
{
|
||||
new [] { HttpMethod.Get },
|
||||
new [] { HttpMethod.Head }
|
||||
};
|
||||
|
||||
public static IEnumerable<object> UnsupportedMethods => new[]
|
||||
{
|
||||
new [] { HttpMethod.Post },
|
||||
new [] { HttpMethod.Put },
|
||||
new [] { HttpMethod.Options },
|
||||
new [] { HttpMethod.Trace },
|
||||
new [] { new HttpMethod("VERB") }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,35 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
Assert.Equal("0123456789a", await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IfModifiedSinceWithPastDateShouldServePartialContent()
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage original = await server.CreateClient().GetAsync("http://localhost/SubFolder/ranges.txt");
|
||||
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/ranges.txt");
|
||||
req.Headers.Add("If-Modified-Since", original.Content.Headers.LastModified.Value.AddHours(-1).ToString("r"));
|
||||
req.Headers.Add("Range", "bytes=0-10");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.PartialContent, resp.StatusCode);
|
||||
Assert.Equal("bytes 0-10/62", resp.Content.Headers.ContentRange.ToString());
|
||||
Assert.Equal(11, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal("0123456789a", await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IfModifiedSinceWithCurrentDateShouldReturn304()
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage original = await server.CreateClient().GetAsync("http://localhost/SubFolder/ranges.txt");
|
||||
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/ranges.txt");
|
||||
req.Headers.Add("If-Modified-Since", original.Content.Headers.LastModified.Value.ToString("r"));
|
||||
req.Headers.Add("Range", "bytes=0-10");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.NotModified, resp.StatusCode);
|
||||
}
|
||||
|
||||
// 14.27 If-Range
|
||||
// If the client has no entity tag for an entity, but does have a Last- Modified date, it MAY use that date in an If-Range header.
|
||||
// HEAD requests should ignore the Range header
|
||||
|
|
@ -216,7 +245,9 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
// 14.35 Range
|
||||
[Theory]
|
||||
[InlineData("0-0", "0-0", 1, "0")]
|
||||
[InlineData("0-9", "0-9", 10, "0123456789")]
|
||||
[InlineData("0- 9", "0-9", 10, "0123456789")]
|
||||
[InlineData("0 -9", "0-9", 10, "0123456789")]
|
||||
[InlineData("0 - 9", "0-9", 10, "0123456789")]
|
||||
[InlineData("10-35", "10-35", 26, "abcdefghijklmnopqrstuvwxyz")]
|
||||
[InlineData("36-61", "36-61", 26, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
|
||||
[InlineData("36-", "36-61", 26, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")] // Last 26
|
||||
|
|
@ -236,6 +267,42 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
Assert.Equal(expectedData, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0-0", "0-0", 1, "A")]
|
||||
[InlineData("0-", "0-0", 1, "A")]
|
||||
[InlineData("-1", "0-0", 1, "A")]
|
||||
[InlineData("-2", "0-0", 1, "A")]
|
||||
[InlineData("0-1", "0-0", 1, "A")]
|
||||
[InlineData("0-2", "0-0", 1, "A")]
|
||||
public async Task SingleValidRangeShouldServePartialContentSingleByteFile(string range, string expectedRange, int length, string expectedData)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/SingleByte.txt");
|
||||
req.Headers.Add("Range", "bytes=" + range);
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.PartialContent, resp.StatusCode);
|
||||
Assert.NotNull(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal("bytes " + expectedRange + "/1", resp.Content.Headers.ContentRange.ToString());
|
||||
Assert.Equal(length, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal(expectedData, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0-0")]
|
||||
[InlineData("0-")]
|
||||
[InlineData("-1")]
|
||||
[InlineData("-2")]
|
||||
[InlineData("0-1")]
|
||||
[InlineData("0-2")]
|
||||
public async Task SingleValidRangeShouldServeRequestedRangeNotSatisfiableEmptyFile(string range)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/Empty.txt");
|
||||
req.Headers.Add("Range", "bytes=" + range);
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, resp.StatusCode);
|
||||
}
|
||||
|
||||
// 14.35 Range
|
||||
// HEAD ignores range headers
|
||||
[Theory]
|
||||
|
|
@ -287,6 +354,9 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
[InlineData("0")]
|
||||
[InlineData("1-0")]
|
||||
[InlineData("-")]
|
||||
[InlineData("a-")]
|
||||
[InlineData("-b")]
|
||||
[InlineData("a-b")]
|
||||
public async Task SingleInvalidRangeIgnored(string range)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
|
|
@ -305,6 +375,9 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
[InlineData("0")]
|
||||
[InlineData("1-0")]
|
||||
[InlineData("-")]
|
||||
[InlineData("a-")]
|
||||
[InlineData("-b")]
|
||||
[InlineData("a-b")]
|
||||
public async Task HEADSingleInvalidRangeIgnored(string range)
|
||||
{
|
||||
TestServer server = StaticFilesTestServer.Create(app => app.UseFileServer());
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
|
@ -29,6 +31,24 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
public async Task FoundFile_LastModifiedTrimsSeconds()
|
||||
{
|
||||
using (var fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory()))
|
||||
{
|
||||
var server = StaticFilesTestServer.Create(app => app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
FileProvider = fileProvider
|
||||
}));
|
||||
var fileInfo = fileProvider.GetFileInfo("TestDocument.txt");
|
||||
var response = await server.CreateRequest("TestDocument.txt").GetAsync();
|
||||
|
||||
var last = fileInfo.LastModified;
|
||||
var trimed = new DateTimeOffset(last.Year, last.Month, last.Day, last.Hour, last.Minute, last.Second, last.Offset).ToUniversalTime();
|
||||
|
||||
Assert.Equal(response.Content.Headers.LastModified.Value, trimed);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NullArguments()
|
||||
{
|
||||
|
|
@ -45,30 +65,7 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @".", "/missing.file")]
|
||||
[InlineData("/subdir", @".", "/subdir/missing.file")]
|
||||
[InlineData("/missing.file", @"./", "/missing.file")]
|
||||
[InlineData("", @"./", "/xunit.xml")]
|
||||
public async Task NoMatch_PassesThrough(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
using (var fileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), baseDir)))
|
||||
{
|
||||
var server = StaticFilesTestServer.Create(app => app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileProvider = fileProvider
|
||||
}));
|
||||
var response = await server.CreateRequest(requestUrl).GetAsync();
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @".", "/TestDocument.txt")]
|
||||
[InlineData("/somedir", @".", "/somedir/TestDocument.txt")]
|
||||
[InlineData("/SomeDir", @".", "/soMediR/TestDocument.txt")]
|
||||
[InlineData("", @"SubFolder", "/ranges.txt")]
|
||||
[InlineData("/somedir", @"SubFolder", "/somedir/ranges.txt")]
|
||||
[MemberData(nameof(ExistingFiles))]
|
||||
public async Task FoundFile_Served_All(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
await FoundFile_Served(baseUrl, baseDir, requestUrl);
|
||||
|
|
@ -95,41 +92,26 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
RequestPath = new PathString(baseUrl),
|
||||
FileProvider = fileProvider
|
||||
}));
|
||||
var fileInfo = fileProvider.GetFileInfo(Path.GetFileName(requestUrl));
|
||||
var response = await server.CreateRequest(requestUrl).GetAsync();
|
||||
var responseContent = await response.Content.ReadAsByteArrayAsync();
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.True(response.Content.Headers.ContentLength > 0);
|
||||
Assert.Equal(response.Content.Headers.ContentLength, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
}
|
||||
Assert.True(response.Content.Headers.ContentLength == fileInfo.Length);
|
||||
Assert.Equal(response.Content.Headers.ContentLength, responseContent.Length);
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @".", "/TestDocument.txt")]
|
||||
[InlineData("/somedir", @".", "/somedir/TestDocument.txt")]
|
||||
[InlineData("/SomeDir", @".", "/soMediR/TestDocument.txt")]
|
||||
[InlineData("", @"SubFolder", "/ranges.txt")]
|
||||
[InlineData("/somedir", @"SubFolder", "/somedir/ranges.txt")]
|
||||
public async Task PostFile_PassesThrough(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
using (var fileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), baseDir)))
|
||||
{
|
||||
var server = StaticFilesTestServer.Create(app => app.UseStaticFiles(new StaticFileOptions
|
||||
using (var stream = fileInfo.CreateReadStream())
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileProvider = fileProvider
|
||||
}));
|
||||
var response = await server.CreateRequest(requestUrl).PostAsync();
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
var fileContents = new byte[stream.Length];
|
||||
stream.Read(fileContents, 0, (int)stream.Length);
|
||||
Assert.True(responseContent.SequenceEqual(fileContents));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @".", "/TestDocument.txt")]
|
||||
[InlineData("/somedir", @".", "/somedir/TestDocument.txt")]
|
||||
[InlineData("/SomeDir", @".", "/soMediR/TestDocument.txt")]
|
||||
[InlineData("", @"SubFolder", "/ranges.txt")]
|
||||
[InlineData("/somedir", @"SubFolder", "/somedir/ranges.txt")]
|
||||
[MemberData(nameof(ExistingFiles))]
|
||||
public async Task HeadFile_HeadersButNotBodyServed(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
using (var fileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), baseDir)))
|
||||
|
|
@ -139,13 +121,87 @@ namespace Microsoft.AspNetCore.StaticFiles
|
|||
RequestPath = new PathString(baseUrl),
|
||||
FileProvider = fileProvider
|
||||
}));
|
||||
var fileInfo = fileProvider.GetFileInfo(Path.GetFileName(requestUrl));
|
||||
var response = await server.CreateRequest(requestUrl).SendAsync("HEAD");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.True(response.Content.Headers.ContentLength > 0);
|
||||
Assert.True(response.Content.Headers.ContentLength == fileInfo.Length);
|
||||
Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(MissingFiles))]
|
||||
public async Task Get_NoMatch_PassesThrough(string baseUrl, string baseDir, string requestUrl) =>
|
||||
await PassesThrough("GET", baseUrl, baseDir, requestUrl);
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(MissingFiles))]
|
||||
public async Task Head_NoMatch_PassesThrough(string baseUrl, string baseDir, string requestUrl) =>
|
||||
await PassesThrough("HEAD", baseUrl, baseDir, requestUrl);
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(MissingFiles))]
|
||||
public async Task Unknown_NoMatch_PassesThrough(string baseUrl, string baseDir, string requestUrl) =>
|
||||
await PassesThrough("VERB", baseUrl, baseDir, requestUrl);
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ExistingFiles))]
|
||||
public async Task Options_Match_PassesThrough(string baseUrl, string baseDir, string requestUrl) =>
|
||||
await PassesThrough("OPTIONS", baseUrl, baseDir, requestUrl);
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ExistingFiles))]
|
||||
public async Task Trace_Match_PassesThrough(string baseUrl, string baseDir, string requestUrl) =>
|
||||
await PassesThrough("TRACE", baseUrl, baseDir, requestUrl);
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ExistingFiles))]
|
||||
public async Task Post_Match_PassesThrough(string baseUrl, string baseDir, string requestUrl) =>
|
||||
await PassesThrough("POST", baseUrl, baseDir, requestUrl);
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ExistingFiles))]
|
||||
public async Task Put_Match_PassesThrough(string baseUrl, string baseDir, string requestUrl) =>
|
||||
await PassesThrough("PUT", baseUrl, baseDir, requestUrl);
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ExistingFiles))]
|
||||
public async Task Unknown_Match_PassesThrough(string baseUrl, string baseDir, string requestUrl) =>
|
||||
await PassesThrough("VERB", baseUrl, baseDir, requestUrl);
|
||||
|
||||
public async Task PassesThrough(string method, string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
using (var fileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), baseDir)))
|
||||
{
|
||||
var server = StaticFilesTestServer.Create(app => app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileProvider = fileProvider
|
||||
}));
|
||||
var response = await server.CreateRequest(requestUrl).SendAsync(method);
|
||||
Assert.Null(response.Content.Headers.LastModified);
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string[]> MissingFiles => new[]
|
||||
{
|
||||
new[] {"", @".", "/missing.file"},
|
||||
new[] {"/subdir", @".", "/subdir/missing.file"},
|
||||
new[] {"/missing.file", @"./", "/missing.file"},
|
||||
new[] {"", @"./", "/xunit.xml"}
|
||||
};
|
||||
|
||||
public static IEnumerable<string[]> ExistingFiles => new[]
|
||||
{
|
||||
new[] {"", @".", "/TestDocument.txt"},
|
||||
new[] {"/somedir", @".", "/somedir/TestDocument.txt"},
|
||||
new[] {"/SomeDir", @".", "/soMediR/TestDocument.txt"},
|
||||
new[] {"", @"SubFolder", "/ranges.txt"},
|
||||
new[] {"/somedir", @"SubFolder", "/somedir/ranges.txt"},
|
||||
new[] {"", @"SubFolder", "/Empty.txt"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
A
|
||||
Loading…
Reference in New Issue